diff --git a/.eslintrc.js b/.eslintrc.js
index 36dc6d48..f8d9de4 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -10,6 +10,7 @@
   },
   'parserOptions': {
     'ecmaVersion': 2017,
+    'sourceType': 'module',
   },
   'rules': {
     // Enabled checks.
diff --git a/DEPS b/DEPS
index fe9d108f..2e245fe0 100644
--- a/DEPS
+++ b/DEPS
@@ -138,11 +138,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '66661df8e9f964b5113783a28a5aad7e29a0d21c',
+  'skia_revision': '2b650797a9920de9880c04b3df124e21a7c0fa80',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '2cb25737c9eb7893ac752674e75d400b4419f67c',
+  'v8_revision': 'a2dee8aa24bafb0b1aaacd0602fbc7d2c730a3c2',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -154,7 +154,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': 'ca8e3d7c153e7b89f881c02c8ca7ba0581afc5b1',
+  'swiftshader_revision': '4e61a3c6fa08ef25f37a7c93f298d6e5e78b9ce5',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -201,7 +201,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': '5db62d36c9b55e85168a772a66dcaa352d2754fd',
+  'catapult_revision': 'f5a5c539a5ee7cac023729939ae3258dd9c9b0f9',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -269,11 +269,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'shaderc_revision': '05c766a1f4615ee37d37d09271aaabca30ffd293',
+  'shaderc_revision': 'c7b49740a0c41a05a93e02877d4d5d7a0b1b5fb5',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '8b5fc36191d7bbe8da7af1b19d1cd509deda3880',
+  'dawn_revision': '26d3cf08c209c662a6e2298c301272e2eb8246e4',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -807,7 +807,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'a730bef0e7549ed488c1d4c797c51e0751f23a96',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'dc0353f46e1f0bb86c05da69e0634444852848e3',
       'condition': 'checkout_linux',
   },
 
@@ -822,7 +822,7 @@
 
   # For Linux and Chromium OS.
   'src/third_party/cros_system_api': {
-      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '9c6f6cc701b12f3af764e47165fe0d2804578862',
+      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + 'ad9db8abe4e8c4371a70539381392c412fff2a7d',
       'condition': 'checkout_linux',
   },
 
@@ -832,7 +832,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '4ce909c11c06bca34057e56ccefc72a1bf1e7e8c',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '2ee83757a109f65cd4e831b257385a258f99c9d5',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1159,7 +1159,7 @@
     Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + '6f26bce0b1c4e8ce0e13332f7c0083788def5fdf',
 
   'src/third_party/openscreen/src':
-    Var('chromium_git') + '/openscreen' + '@' + '2af36f667d72f58381e6bdd989b37a4f1d992008',
+    Var('chromium_git') + '/openscreen' + '@' + '6dcfbb6577554933548255799ed7b58bfbfc51fd',
 
   'src/third_party/ow2_asm': {
       'packages': [
@@ -1350,7 +1350,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '6f0b34abee8dba611c253738d955c59f703c147a',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'ce33b6a4cfa06ffa7faec4f33449569d6f319692',
+    Var('webrtc_git') + '/src.git' + '@' + '673784153395ec210c33041aba74018efd8993dd',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1391,7 +1391,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@76ce2f554e7af6822d19b014c7f451dcf0069562',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@e9944e4e052c99b18dda79a7585654188c665b77',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/WATCHLISTS b/WATCHLISTS
index 0611f08..f0d7df53 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -432,9 +432,6 @@
                   '|third_party/blink/renderer/platform/exported/web_rtc' \
                   '|third_party/blink/web_tests/fast/mediastream/'
     },
-    'blink_modules': {
-      'filepath': 'third_party/blink/renderer/modules'
-    },
     'blink_navigator_content_utils': {
       'filepath': 'third_party/blink/renderer/modules/navigatorcontentutils' \
                   '|third_party/blink/web_tests/fast/dom/navigatorcontentutils'
@@ -2005,7 +2002,7 @@
                     'rtoy@chromium.org'],
     'blink_battery_status': ['mlamouri+watch-blink@chromium.org',
                              'timvolodine@chromium.org'],
-    'blink_bindings': ['blink-reviews-bindings@chromium.org'],
+    'blink_bindings': ['blink-reviews-bindings@chromium.org', 'haraken@chromium.org'],
     'blink_bindings_serialization': ['jbroman+watch@chromium.org'],
     'blink_bluetooth': ['mattreynolds+watch@chromium.org',
                         'ortuno+watch@chromium.org',
@@ -2084,7 +2081,6 @@
     'blink_media_queries': ['kenneth.christiansen@gmail.com',
                             'yoavweiss@chromium.org'],
     'blink_mediastream': ['tommyw+watchlist@chromium.org'],
-    'blink_modules': ['haraken-watch@chromium.org'],
     'blink_navigator_content_utils': ['gyuyoung.kim@chromium.org'],
     'blink_out_of_process_frames': ['dcheng@chromium.org',
                                     'mlamouri+watch-blink@chromium.org'],
@@ -2109,7 +2105,7 @@
     'blink_quota': ['kinuko+fileapi@chromium.org',
                     'nhiroki@chromium.org',
                     'tzik@chromium.org'],
-    'blink_scheduler': ['scheduler-bugs+blink@chromium.org'],
+    'blink_scheduler': ['scheduler-bugs+blink@chromium.org', 'haraken@chromium.org'],
     'blink_screen_orientation': ['mlamouri+watch-blink@chromium.org'],
     'blink_script': ['kouhei+script@chromium.org',
                      'hiroshige+script@chromium.org'],
@@ -2153,7 +2149,7 @@
                       'horo+watch@chromium.org',
                       'kinuko+worker@chromium.org',
                       'shimazu+worker@chromium.org'],
-    'blink_wtf': ['blink-reviews-wtf@chromium.org'],
+    'blink_wtf': ['blink-reviews-wtf@chromium.org', 'haraken@chromium.org'],
     'blink_xml': ['dominicc+watchlist@chromium.org',
                   'joelhockey+watch@chromium.org'],
     'bottombar': ['donnd+watch@chromium.org',
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 4da37839..2df3a4b 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-8912196161732498096
\ No newline at end of file
+8912170263713353808
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index a024301..56371b1 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-8912200482316115744
\ No newline at end of file
+8912173536394146880
\ No newline at end of file
diff --git a/chrome/VERSION b/chrome/VERSION
index 4b72ac5..9c831de 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=76
 MINOR=0
-BUILD=3807
+BUILD=3808
 PATCH=0
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponentBridge.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponentBridge.java
index 21068647..6ffcc0f 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponentBridge.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingComponentBridge.java
@@ -46,7 +46,18 @@
 
     @CalledByNative
     private void onItemsAvailable(Object objAccessorySheetData) {
-        mSheetDataProvider.notifyObservers((AccessorySheetData) objAccessorySheetData);
+        AccessorySheetData accessorySheetData = (AccessorySheetData) objAccessorySheetData;
+        switch (accessorySheetData.getSheetType()) {
+            case AccessoryTabType.PASSWORDS:
+                mSheetDataProvider.notifyObservers(accessorySheetData);
+                return;
+            case AccessoryTabType.CREDIT_CARDS:
+                // TODO(crbug.com/926365): Implement.
+                return;
+            case AccessoryTabType.ADDRESSES:
+                // TODO(crbug.com/962548): Implement.
+                return;
+        }
     }
 
     @CalledByNative
@@ -120,16 +131,15 @@
     }
 
     @CalledByNative
-    private void addFieldToUserInfo(Object objUserInfo, String displayText, String a11yDescription,
-            boolean isObfuscated, boolean selectable) {
+    private void addFieldToUserInfo(Object objUserInfo, @AccessoryTabType int sheetType,
+            String displayText, String a11yDescription, boolean isObfuscated, boolean selectable) {
         Callback<UserInfoField> callback = null;
         if (selectable) {
             callback = (field) -> {
                 assert mNativeView != 0 : "Controller was destroyed but the bridge wasn't!";
-                ManualFillingMetricsRecorder.recordSuggestionSelected(AccessoryTabType.PASSWORDS,
-                        field.isObfuscated() ? AccessorySuggestionType.PASSWORD
-                                             : AccessorySuggestionType.USERNAME);
-                nativeOnFillingTriggered(mNativeView, field.isObfuscated(), field);
+                ManualFillingMetricsRecorder.recordSuggestionSelected(
+                        sheetType, field.isObfuscated());
+                nativeOnFillingTriggered(mNativeView, sheetType, field);
             };
         }
         ((UserInfo) objUserInfo)
@@ -167,7 +177,7 @@
     private native void nativeOnFaviconRequested(long nativeManualFillingViewAndroid,
             int desiredSizeInPx, Callback<Bitmap> faviconCallback);
     private native void nativeOnFillingTriggered(
-            long nativeManualFillingViewAndroid, boolean isObfuscated, UserInfoField userInfoField);
+            long nativeManualFillingViewAndroid, int tabType, UserInfoField userInfoField);
     private native void nativeOnOptionSelected(
             long nativeManualFillingViewAndroid, int accessoryAction);
     private native void nativeOnGenerationRequested(long nativeManualFillingViewAndroid);
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMetricsRecorder.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMetricsRecorder.java
index 81d755c..f725ec1e 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMetricsRecorder.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMetricsRecorder.java
@@ -6,6 +6,8 @@
 
 import org.chromium.base.metrics.RecordHistogram;
 
+import java.security.InvalidParameterException;
+
 /**
  * This class provides helpers to record metrics related to the keyboard accessory and its sheets.
  */
@@ -85,23 +87,36 @@
     }
 
     /**
-     * Records a selected suggestions.
+     * Records that a suggestion was selected in one of the accessory tabs.
      * @param tabType The sheet to record for. An {@link AccessoryTabType}.
-     * @param bucket An {@link AccessoryAction}.
+     * @param isFieldObfuscated denotes whether a field is obfuscated (e.g. a password field).
      */
-    static void recordSuggestionSelected(
-            @AccessoryTabType int tabType, @AccessorySuggestionType int bucket) {
-        // TODO(crbug.com/926372): Add metrics capabilities for credit cards.
-        if (tabType == AccessoryTabType.CREDIT_CARDS) return;
+    static void recordSuggestionSelected(@AccessoryTabType int tabType, boolean isFieldObfuscated) {
+        @AccessorySuggestionType
+        int suggestionRecordingType = AccessorySuggestionType.COUNT;
+        switch (tabType) {
+            case AccessoryTabType.PASSWORDS:
+                suggestionRecordingType = isFieldObfuscated ? AccessorySuggestionType.PASSWORD
+                                                            : AccessorySuggestionType.USERNAME;
+                break;
+            case AccessoryTabType.CREDIT_CARDS:
+                suggestionRecordingType = AccessorySuggestionType.PAYMENT_INFO;
+                break;
+            case AccessoryTabType.ADDRESSES:
+                // TODO(crbug.com/965494): Consider splitting and/or separate recording.
+                suggestionRecordingType = AccessorySuggestionType.ADDRESS_INFO;
+                break;
+            case AccessoryTabType.ALL:
+                throw new InvalidParameterException("Unable to handle tabType: " + tabType);
+        }
 
+        // TODO(crbug.com/965494): Double-check we don't record twice with new address filling.
         RecordHistogram.recordEnumeratedHistogram(
                 getHistogramForType(
                         UMA_KEYBOARD_ACCESSORY_SHEET_SUGGESTION_SELECTED, AccessoryTabType.ALL),
-                bucket, AccessorySuggestionType.COUNT);
-        if (tabType != AccessoryTabType.ALL) { // If recorded for all, don't record again.
-            RecordHistogram.recordEnumeratedHistogram(
-                    getHistogramForType(UMA_KEYBOARD_ACCESSORY_SHEET_SUGGESTION_SELECTED, tabType),
-                    bucket, AccessorySuggestionType.COUNT);
-        }
+                suggestionRecordingType, AccessorySuggestionType.COUNT);
+        RecordHistogram.recordEnumeratedHistogram(
+                getHistogramForType(UMA_KEYBOARD_ACCESSORY_SHEET_SUGGESTION_SELECTED, tabType),
+                suggestionRecordingType, AccessorySuggestionType.COUNT);
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionNavigationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionNavigationTest.java
index 9d667b07..ba80051 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionNavigationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionNavigationTest.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.permissions;
 
+import android.support.test.filters.MediumTest;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -11,13 +13,14 @@
 
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.DisabledTest;
+import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.RetryOnFailure;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.permissions.PermissionTestRule.DialogShownCriteria;
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.util.browser.LocationSettingsTestUtil;
 import org.chromium.content_public.browser.NavigationHandle;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
 
@@ -38,6 +41,11 @@
     @Before
     public void setUp() throws Exception {
         mPermissionRule.setUpActivity();
+
+        // Some bots on continuous integration may have the system-level location setting off, in
+        // which case the permission request would be auto-denied as it will not have a user
+        // gesture. See: GeolocationPermissionContextAndroid::CanShowLocationSettingsDialog().
+        LocationSettingsTestUtil.setSystemLocationSettingEnabled(true);
     }
 
     /**
@@ -47,11 +55,9 @@
      * @throws Exception
      */
     @Test
-    // @MediumTest
-    // @Feature({"Permissions"})
+    @MediumTest
+    @Feature({"Permissions"})
     @CommandLineFlags.Add("enable-features=" + PermissionTestRule.MODAL_FLAG)
-    // Flaky on official bots, https://crbug.com/699851#c8
-    @DisabledTest
     public void testNavigationDismissesModalPermissionPrompt() throws Exception {
         mPermissionRule.setUpUrl(TEST_FILE);
         mPermissionRule.runJavaScriptCodeInCurrentTab("requestGeolocationPermission()");
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index 7d1d321..6874e4d8 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-76.0.3806.0_rc-r1-merged.afdo.bz2
\ No newline at end of file
+chromeos-chrome-amd64-76.0.3807.0_rc-r1-merged.afdo.bz2
\ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index e7c65a9..ca421f5 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -3991,7 +3991,6 @@
       "background/background_mode_manager_win.cc",
       "background/background_mode_optimizer.cc",
       "background/background_mode_optimizer.h",
-      "background/background_trigger.h",
     ]
     if (!use_aura || is_win || is_chromeos) {
       sources -= [ "background/background_mode_manager_aura.cc" ]
diff --git a/chrome/browser/autofill/manual_filling_controller.h b/chrome/browser/autofill/manual_filling_controller.h
index 79127f1..120fbf6 100644
--- a/chrome/browser/autofill/manual_filling_controller.h
+++ b/chrome/browser/autofill/manual_filling_controller.h
@@ -42,8 +42,8 @@
 class ManualFillingController {
  public:
   // The controller checks if at least one of these sources needs the accessory
-  // to be displayed. Only if neither needs the accessory, it will not show up.
-  enum class FillingSource { AUTOFILL, PASSWORD_FALLBACKS };
+  // to be displayed.
+  enum class FillingSource { AUTOFILL, PASSWORD_FALLBACKS, ADDRESS_FALLBACKS };
 
   ManualFillingController() = default;
   virtual ~ManualFillingController() = default;
@@ -95,6 +95,7 @@
   // the currently focused field. Forwards the request to a type-specific
   // accessory controller.
   virtual void OnFillingTriggered(
+      autofill::AccessoryTabType type,
       const autofill::UserInfo::Field& selection) = 0;
 
   // Called by the UI code because a user triggered the |selected_action|,
diff --git a/chrome/browser/autofill/manual_filling_controller_impl.cc b/chrome/browser/autofill/manual_filling_controller_impl.cc
index 497855f..ce8690a 100644
--- a/chrome/browser/autofill/manual_filling_controller_impl.cc
+++ b/chrome/browser/autofill/manual_filling_controller_impl.cc
@@ -8,7 +8,7 @@
 
 #include "base/callback.h"
 #include "base/metrics/histogram_macros.h"
-#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/autofill/address_accessory_controller.h"
 #include "chrome/browser/password_manager/password_accessory_controller.h"
 #include "chrome/browser/password_manager/password_accessory_metrics_util.h"
 #include "chrome/browser/password_manager/password_generation_controller.h"
@@ -20,6 +20,7 @@
 
 using autofill::AccessoryAction;
 using autofill::AccessorySheetData;
+using autofill::AddressAccessoryController;
 using autofill::mojom::FocusedFieldType;
 
 ManualFillingControllerImpl::~ManualFillingControllerImpl() = default;
@@ -27,19 +28,27 @@
 // static
 base::WeakPtr<ManualFillingController> ManualFillingController::GetOrCreate(
     content::WebContents* contents) {
-  ManualFillingControllerImpl::CreateForWebContents(contents);
-  return ManualFillingControllerImpl::FromWebContents(contents)->AsWeakPtr();
+  ManualFillingControllerImpl* mf_controller =
+      ManualFillingControllerImpl::FromWebContents(contents);
+  if (!mf_controller) {
+    ManualFillingControllerImpl::CreateForWebContents(contents);
+    mf_controller = ManualFillingControllerImpl::FromWebContents(contents);
+    mf_controller->Initialize();
+  }
+  return mf_controller->AsWeakPtr();
 }
 
 // static
 void ManualFillingControllerImpl::CreateForWebContentsForTesting(
     content::WebContents* web_contents,
     base::WeakPtr<PasswordAccessoryController> pwd_controller,
+    base::WeakPtr<AddressAccessoryController> address_controller,
     PasswordGenerationController* pwd_generation_controller_for_testing,
     std::unique_ptr<ManualFillingViewInterface> view) {
   DCHECK(web_contents) << "Need valid WebContents to attach controller to!";
   DCHECK(!FromWebContents(web_contents)) << "Controller already attached!";
   DCHECK(pwd_controller);
+  DCHECK(address_controller);
   DCHECK(pwd_generation_controller_for_testing);
   DCHECK(view);
 
@@ -47,7 +56,10 @@
       UserDataKey(),
       base::WrapUnique(new ManualFillingControllerImpl(
           web_contents, std::move(pwd_controller),
-          pwd_generation_controller_for_testing, std::move(view))));
+          std::move(address_controller), pwd_generation_controller_for_testing,
+          std::move(view))));
+
+  FromWebContents(web_contents)->Initialize();
 }
 
 void ManualFillingControllerImpl::OnAutomaticGenerationStatusChanged(
@@ -68,6 +80,11 @@
     const AccessorySheetData& accessory_sheet_data) {
   view_->OnItemsAvailable(accessory_sheet_data);
 
+  // TODO(crbug.com/965478): Refresh visibility for non-PWDs in V2.
+  if (accessory_sheet_data.get_sheet_type() !=
+      autofill::AccessoryTabType::PASSWORDS)
+    return;
+
   // TODO(crbug.com/905669): The decision for showing the sheet or not will need
   // to take into account if Autofill suggestions are also available.
   if (autofill::IsFillable(focused_field_type))
@@ -110,36 +127,16 @@
 }
 
 void ManualFillingControllerImpl::OnFillingTriggered(
+    autofill::AccessoryTabType type,
     const autofill::UserInfo::Field& selection) {
-  DCHECK(pwd_controller_);
-  pwd_controller_->OnFillingTriggered(selection);
+  GetControllerForTab(type)->OnFillingTriggered(selection);
 }
 
 void ManualFillingControllerImpl::OnOptionSelected(
     AccessoryAction selected_action) const {
   UMA_HISTOGRAM_ENUMERATION("KeyboardAccessory.AccessoryActionSelected",
                             selected_action, AccessoryAction::COUNT);
-  switch (selected_action) {
-    case AccessoryAction::GENERATE_PASSWORD_MANUAL:
-    case AccessoryAction::MANAGE_PASSWORDS:
-      DCHECK(pwd_controller_);
-      pwd_controller_->OnOptionSelected(selected_action);
-      return;
-    case AccessoryAction::MANAGE_ADDRESSES:
-      // TODO(crbug.com/962548): Call address controller.
-      return;
-    case AccessoryAction::MANAGE_CREDIT_CARDS:
-      // TODO(crbug.com/902425): Call credit card controller.
-      return;
-    case AccessoryAction::AUTOFILL_SUGGESTION:
-    case AccessoryAction::COUNT:
-    case AccessoryAction::GENERATE_PASSWORD_AUTOMATIC:
-      NOTREACHED() << "Invalid action requested by options: "
-                   << static_cast<int>(selected_action);
-      return;
-  }
-  NOTREACHED() << "Unhandled action selected: "
-               << static_cast<int>(selected_action);
+  GetControllerForAction(selected_action)->OnOptionSelected(selected_action);
 }
 
 void ManualFillingControllerImpl::OnGenerationRequested() {
@@ -169,6 +166,12 @@
   return weak_factory_.GetWeakPtr();
 }
 
+void ManualFillingControllerImpl::Initialize() {
+  DCHECK(FromWebContents(web_contents_)) << "Don't call from constructor!";
+  if (address_controller_)
+    address_controller_->RefreshSuggestions();
+}
+
 ManualFillingControllerImpl::ManualFillingControllerImpl(
     content::WebContents* web_contents)
     : web_contents_(web_contents),
@@ -179,18 +182,62 @@
         PasswordAccessoryController::GetOrCreate(web_contents)->AsWeakPtr();
     DCHECK(pwd_controller_);
   }
+  if (AddressAccessoryController::AllowedForWebContents(web_contents)) {
+    address_controller_ =
+        AddressAccessoryController::GetOrCreate(web_contents)->AsWeakPtr();
+    DCHECK(address_controller_);
+  }
 }
 
 ManualFillingControllerImpl::ManualFillingControllerImpl(
     content::WebContents* web_contents,
     base::WeakPtr<PasswordAccessoryController> pwd_controller,
+    base::WeakPtr<AddressAccessoryController> address_controller,
     PasswordGenerationController* pwd_generation_controller_for_testing,
     std::unique_ptr<ManualFillingViewInterface> view)
     : web_contents_(web_contents),
       pwd_controller_(std::move(pwd_controller)),
+      address_controller_(std::move(address_controller)),
       pwd_generation_controller_for_testing_(
           pwd_generation_controller_for_testing),
       view_(std::move(view)),
       weak_factory_(this) {}
 
+AccessoryController* ManualFillingControllerImpl::GetControllerForTab(
+    autofill::AccessoryTabType type) {
+  switch (type) {
+    case autofill::AccessoryTabType::ADDRESSES:
+      return address_controller_.get();
+    case autofill::AccessoryTabType::PASSWORDS:
+      return pwd_controller_.get();
+    case autofill::AccessoryTabType::CREDIT_CARDS:
+      // TODO(crbug.com/902425): return credit card controller.
+    case autofill::AccessoryTabType::ALL:
+    case autofill::AccessoryTabType::COUNT:
+      break;  // Intentional failure.
+  }
+  NOTREACHED() << "Controller not defined for tab: " << static_cast<int>(type);
+  return nullptr;
+}
+
+AccessoryController* ManualFillingControllerImpl::GetControllerForAction(
+    AccessoryAction action) const {
+  switch (action) {
+    case AccessoryAction::GENERATE_PASSWORD_MANUAL:
+    case AccessoryAction::MANAGE_PASSWORDS:
+      return pwd_controller_.get();
+    case AccessoryAction::MANAGE_ADDRESSES:
+      return address_controller_.get();
+    case AccessoryAction::MANAGE_CREDIT_CARDS:
+      // TODO(crbug.com/902425): Return credit card controller.
+    case AccessoryAction::AUTOFILL_SUGGESTION:
+    case AccessoryAction::COUNT:
+    case AccessoryAction::GENERATE_PASSWORD_AUTOMATIC:
+      break;  // Intentional failure;
+  }
+  NOTREACHED() << "Controller not defined for action: "
+               << static_cast<int>(action);
+  return nullptr;
+}
+
 WEB_CONTENTS_USER_DATA_KEY_IMPL(ManualFillingControllerImpl)
diff --git a/chrome/browser/autofill/manual_filling_controller_impl.h b/chrome/browser/autofill/manual_filling_controller_impl.h
index db0a85b..0df241d 100644
--- a/chrome/browser/autofill/manual_filling_controller_impl.h
+++ b/chrome/browser/autofill/manual_filling_controller_impl.h
@@ -14,6 +14,10 @@
 #include "chrome/browser/autofill/manual_filling_view_interface.h"
 #include "content/public/browser/web_contents_user_data.h"
 
+namespace autofill {
+class AddressAccessoryController;
+}
+class AccessoryController;
 class PasswordAccessoryController;
 class PasswordGenerationController;
 
@@ -33,7 +37,8 @@
   void ShowTouchToFillSheet() override;
   void Hide(FillingSource source) override;
   void OnAutomaticGenerationStatusChanged(bool available) override;
-  void OnFillingTriggered(const autofill::UserInfo::Field& selection) override;
+  void OnFillingTriggered(autofill::AccessoryTabType type,
+                          const autofill::UserInfo::Field& selection) override;
   void OnOptionSelected(
       autofill::AccessoryAction selected_action) const override;
   void OnGenerationRequested() override;
@@ -51,6 +56,7 @@
   static void CreateForWebContentsForTesting(
       content::WebContents* web_contents,
       base::WeakPtr<PasswordAccessoryController> pwd_controller,
+      base::WeakPtr<autofill::AddressAccessoryController> address_controller,
       PasswordGenerationController* pwd_generation_controller_for_testing,
       std::unique_ptr<ManualFillingViewInterface> test_view);
 
@@ -63,6 +69,15 @@
     return pwd_controller_.get();
   }
 
+ protected:
+  friend class ManualFillingController;  // Allow protected access in factories.
+
+  // Enables calling initialization code that relies on a fully constructed
+  // ManualFillingController that is attached to a WebContents instance.
+  // This is matters for subcomponents which lazily trigger the creation of this
+  // class. If called in constructors, it would cause an infinite creation loop.
+  void Initialize();
+
  private:
   friend class content::WebContentsUserData<ManualFillingControllerImpl>;
 
@@ -73,9 +88,17 @@
   ManualFillingControllerImpl(
       content::WebContents* web_contents,
       base::WeakPtr<PasswordAccessoryController> pwd_controller,
+      base::WeakPtr<autofill::AddressAccessoryController> address_controller,
       PasswordGenerationController* pwd_generation_controller_for_testing,
       std::unique_ptr<ManualFillingViewInterface> view);
 
+  // Returns the controller that is responsible for a tab of given |type|.
+  AccessoryController* GetControllerForTab(autofill::AccessoryTabType type);
+
+  // Returns the controller that is responsible for a given |action|.
+  AccessoryController* GetControllerForAction(
+      autofill::AccessoryAction action) const;
+
   // The tab for which this class is scoped.
   content::WebContents* web_contents_;
 
@@ -85,6 +108,9 @@
   // The password accessory controller object to forward view requests to.
   base::WeakPtr<PasswordAccessoryController> pwd_controller_;
 
+  // The address accessory controller object to forward view requests to.
+  base::WeakPtr<autofill::AddressAccessoryController> address_controller_;
+
   // A password generation controller used in tests which receives requests
   // from the view.
   PasswordGenerationController* pwd_generation_controller_for_testing_ =
diff --git a/chrome/browser/autofill/manual_filling_controller_impl_unittest.cc b/chrome/browser/autofill/manual_filling_controller_impl_unittest.cc
index 8a3f1b6d..d2be9c6 100644
--- a/chrome/browser/autofill/manual_filling_controller_impl_unittest.cc
+++ b/chrome/browser/autofill/manual_filling_controller_impl_unittest.cc
@@ -7,11 +7,13 @@
 #include <map>
 #include <memory>
 #include <string>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_feature_list.h"
+#include "chrome/browser/autofill/address_accessory_controller.h"
 #include "chrome/browser/autofill/manual_filling_view_interface.h"
 #include "chrome/browser/password_manager/password_accessory_controller.h"
 #include "chrome/browser/password_manager/password_generation_controller.h"
@@ -22,6 +24,8 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
+using autofill::AccessoryAction;
+using autofill::AddressAccessoryController;
 using autofill::mojom::FocusedFieldType;
 using testing::_;
 using testing::AnyNumber;
@@ -43,8 +47,18 @@
   MOCK_METHOD2(GetFavicon,
                void(int, base::OnceCallback<void(const gfx::Image&)>));
   MOCK_METHOD1(OnFillingTriggered, void(const autofill::UserInfo::Field&));
-  MOCK_METHOD1(OnOptionSelected,
-               void(autofill::AccessoryAction selected_action));
+  MOCK_METHOD1(OnOptionSelected, void(AccessoryAction selected_action));
+};
+
+class MockAddressAccessoryController : public AddressAccessoryController {
+ public:
+  MOCK_METHOD2(
+      SavePasswordsForOrigin,
+      void(const std::map<base::string16, const autofill::PasswordForm*>&,
+           const url::Origin&));
+  MOCK_METHOD1(OnFillingTriggered, void(const autofill::UserInfo::Field&));
+  MOCK_METHOD1(OnOptionSelected, void(AccessoryAction selected_action));
+  MOCK_METHOD0(RefreshSuggestions, void());
 };
 
 class MockPasswordGenerationController : public PasswordGenerationController {
@@ -86,7 +100,7 @@
 autofill::AccessorySheetData dummy_accessory_sheet_data() {
   constexpr char kExampleAccessorySheetDataTitle[] = "Example title";
   return autofill::AccessorySheetData(
-      autofill::AccessoryTabType::CREDIT_CARDS,
+      autofill::AccessoryTabType::PASSWORDS,
       base::ASCIIToUTF16(kExampleAccessorySheetDataTitle));
 }
 
@@ -101,7 +115,7 @@
     NavigateAndCommit(GURL(kExampleSite));
     ManualFillingControllerImpl::CreateForWebContentsForTesting(
         web_contents(), mock_pwd_controller_.AsWeakPtr(),
-        &mock_pwd_generation_controller_,
+        mock_address_controller_.AsWeakPtr(), &mock_pwd_generation_controller_,
         std::make_unique<StrictMock<MockPasswordAccessoryView>>());
     NavigateAndCommit(GURL(kExampleSite));
   }
@@ -116,6 +130,7 @@
 
  protected:
   NiceMock<MockPasswordAccessoryController> mock_pwd_controller_;
+  NiceMock<MockAddressAccessoryController> mock_address_controller_;
   NiceMock<MockPasswordGenerationController> mock_pwd_generation_controller_;
 };
 
@@ -223,7 +238,26 @@
                                         true);
 
   EXPECT_CALL(mock_pwd_controller_, OnFillingTriggered(field));
-  controller()->OnFillingTriggered(field);
+  controller()->OnFillingTriggered(autofill::AccessoryTabType::PASSWORDS,
+                                   field);
+}
+
+TEST_F(ManualFillingControllerTest, ForwardsPasswordManagingToController) {
+  EXPECT_CALL(mock_pwd_controller_,
+              OnOptionSelected(AccessoryAction::MANAGE_PASSWORDS));
+  controller()->OnOptionSelected(AccessoryAction::MANAGE_PASSWORDS);
+}
+
+TEST_F(ManualFillingControllerTest, ForwardsPasswordGenerationToController) {
+  EXPECT_CALL(mock_pwd_controller_,
+              OnOptionSelected(AccessoryAction::GENERATE_PASSWORD_MANUAL));
+  controller()->OnOptionSelected(AccessoryAction::GENERATE_PASSWORD_MANUAL);
+}
+
+TEST_F(ManualFillingControllerTest, ForwardsAddressManagingToController) {
+  EXPECT_CALL(mock_address_controller_,
+              OnOptionSelected(AccessoryAction::MANAGE_ADDRESSES));
+  controller()->OnOptionSelected(AccessoryAction::MANAGE_ADDRESSES);
 }
 
 TEST_F(ManualFillingControllerTest, OnGenerationRequested) {
diff --git a/chrome/browser/autofill/manual_filling_view_interface.h b/chrome/browser/autofill/manual_filling_view_interface.h
index a3c8aa3c..f9e540b 100644
--- a/chrome/browser/autofill/manual_filling_view_interface.h
+++ b/chrome/browser/autofill/manual_filling_view_interface.h
@@ -52,8 +52,8 @@
 
   virtual ~ManualFillingViewInterface() = default;
 
-  // Called with data that should replace the data currently shown on the
-  // accessory sheet.
+  // Called with data that should replace the data currently shown in an
+  // accessory sheet of the same type.
   virtual void OnItemsAvailable(const autofill::AccessorySheetData& data) = 0;
 
   // Called when the generation action should be offered or rescinded
diff --git a/chrome/browser/autofill/mock_manual_filling_controller.h b/chrome/browser/autofill/mock_manual_filling_controller.h
index ee44205a..1bb82dc 100644
--- a/chrome/browser/autofill/mock_manual_filling_controller.h
+++ b/chrome/browser/autofill/mock_manual_filling_controller.h
@@ -26,7 +26,9 @@
   MOCK_METHOD1(Hide, void(ManualFillingController::FillingSource));
   MOCK_METHOD2(GetFavicon,
                void(int, base::OnceCallback<void(const gfx::Image&)>));
-  MOCK_METHOD1(OnFillingTriggered, void(const autofill::UserInfo::Field&));
+  MOCK_METHOD2(OnFillingTriggered,
+               void(autofill::AccessoryTabType type,
+                    const autofill::UserInfo::Field&));
   MOCK_CONST_METHOD1(OnOptionSelected,
                      void(autofill::AccessoryAction selected_action));
   MOCK_METHOD0(OnGenerationRequested, void());
diff --git a/chrome/browser/background/background_mode_manager.cc b/chrome/browser/background/background_mode_manager.cc
index 913b094a..90e5e3b 100644
--- a/chrome/browser/background/background_mode_manager.cc
+++ b/chrome/browser/background/background_mode_manager.cc
@@ -28,7 +28,6 @@
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/background/background_application_list_model.h"
 #include "chrome/browser/background/background_mode_optimizer.h"
-#include "chrome/browser/background/background_trigger.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/extension_service.h"
@@ -131,7 +130,7 @@
 }
 
 bool BackgroundModeManager::BackgroundModeData::HasBackgroundClient() const {
-  return applications_->size() > 0 || !registered_triggers_.empty();
+  return applications_->size() > 0;
 }
 
 void BackgroundModeManager::BackgroundModeData::BuildProfileMenu(
@@ -169,19 +168,6 @@
       }
     }
 
-    // Add a menu item for each trigger.
-    for (auto* trigger : registered_triggers_) {
-      const gfx::ImageSkia* icon = trigger->GetIcon();
-      const base::string16& name = trigger->GetName();
-      int command_id = command_id_handler_vector_->size();
-      // Check that the command ID is within the dynamic range.
-      DCHECK_LT(command_id, IDC_MinimumLabelValue);
-      command_id_handler_vector_->push_back(base::BindRepeating(
-          &BackgroundTrigger::OnMenuClick, base::Unretained(trigger)));
-      menu->AddItem(command_id, name);
-      if (icon)
-        menu->SetIcon(menu->GetItemCount() - 1, gfx::Image(*icon));
-    }
   } else {
     // When there are no background clients, we want to display just a label
     // stating that none are running.
@@ -234,41 +220,6 @@
   return bmd1->name_ < bmd2->name_;
 }
 
-void BackgroundModeManager::BackgroundModeData::AddPendingTrigger(
-    BackgroundTrigger* trigger, bool should_notify_user) {
-  if (HasTrigger(trigger))
-    return;
-  pending_trigger_data_[trigger] = should_notify_user;
-}
-
-BackgroundModeManager::PendingTriggerData
-BackgroundModeManager::BackgroundModeData::TakePendingTriggerData() {
-  return std::move(pending_trigger_data_);
-}
-
-bool BackgroundModeManager::BackgroundModeData::HasPendingTrigger() const {
-  return !pending_trigger_data_.empty();
-}
-
-void BackgroundModeManager::BackgroundModeData::RegisterTrigger(
-    BackgroundTrigger* trigger) {
-  if (HasTrigger(trigger))
-    return;
-  registered_triggers_.insert(trigger);
-}
-
-void BackgroundModeManager::BackgroundModeData::UnregisterTrigger(
-    BackgroundTrigger* trigger) {
-  registered_triggers_.erase(trigger);
-  pending_trigger_data_.erase(trigger);
-}
-
-bool BackgroundModeManager::BackgroundModeData::HasTrigger(
-    BackgroundTrigger* trigger) {
-  return base::ContainsKey(registered_triggers_, trigger) ||
-         base::ContainsKey(pending_trigger_data_, trigger);
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 //  BackgroundModeManager, public
 BackgroundModeManager::BackgroundModeManager(
@@ -428,51 +379,6 @@
   return background_mode_data_.size();
 }
 
-void BackgroundModeManager::RegisterTrigger(const Profile* profile,
-                                            BackgroundTrigger* trigger,
-                                            bool should_notify_user) {
-  BackgroundModeManager::BackgroundModeData* bmd =
-      GetBackgroundModeData(profile);
-  if (!bmd)
-    return;
-
-  // Only proceed if we don't have this trigger yet.
-  if (bmd->HasTrigger(trigger))
-    return;
-
-  // If the background pref is disabled, store it as a pending trigger that may
-  // be registered later if the pref gets enabled.
-  if (!IsBackgroundModePrefEnabled()) {
-    bmd->AddPendingTrigger(trigger, should_notify_user);
-    return;
-  }
-
-  bmd->RegisterTrigger(trigger);
-  std::vector<base::string16> new_client_names;
-  if (should_notify_user)
-    new_client_names.push_back(trigger->GetName());
-  OnClientsChanged(profile, new_client_names);
-}
-
-void BackgroundModeManager::UnregisterTrigger(const Profile* profile,
-                                              BackgroundTrigger* trigger) {
-  if (!IsBackgroundModePrefEnabled())
-    return;
-
-  BackgroundModeManager::BackgroundModeData* bmd =
-      GetBackgroundModeData(profile);
-  if (!bmd)
-    return;
-
-  // Only proceed if this is a known trigger.
-  if (!bmd->HasTrigger(trigger))
-    return;
-  bmd->UnregisterTrigger(trigger);
-
-  std::vector<base::string16> new_client_names;
-  OnClientsChanged(profile, new_client_names);
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 //  BackgroundModeManager, content::NotificationObserver overrides
 void BackgroundModeManager::Observe(
@@ -737,18 +643,6 @@
   if (!in_background_mode_ && ShouldBeInBackgroundMode()) {
     StartBackgroundMode();
 
-    // Register pending triggers.
-    for (const auto& bmd_iterator : background_mode_data_) {
-      PendingTriggerData pending_trigger_data =
-          bmd_iterator.second->TakePendingTriggerData();
-      for (const auto& trigger_data_iterator : pending_trigger_data) {
-        const Profile* profile = bmd_iterator.first;
-        BackgroundTrigger* trigger = trigger_data_iterator.first;
-        bool should_notify_user = trigger_data_iterator.second;
-        RegisterTrigger(profile, trigger, should_notify_user);
-      }
-    }
-
     EnableLaunchOnStartup(true);
   }
 }
@@ -845,17 +739,9 @@
   return bmd && bmd->HasBackgroundClient();
 }
 
-bool BackgroundModeManager::HasPendingTrigger() const {
-  for (const auto& it : background_mode_data_) {
-    if (it.second->HasPendingTrigger())
-      return true;
-  }
-  return false;
-}
-
 bool BackgroundModeManager::ShouldBeInBackgroundMode() const {
   return IsBackgroundModePrefEnabled() &&
-         (HasBackgroundClient() || HasPendingTrigger() || keep_alive_for_test_);
+         (HasBackgroundClient() || keep_alive_for_test_);
 }
 
 void BackgroundModeManager::OnBackgroundClientInstalled(
diff --git a/chrome/browser/background/background_mode_manager.h b/chrome/browser/background/background_mode_manager.h
index b2c35b6..ddf7449 100644
--- a/chrome/browser/background/background_mode_manager.h
+++ b/chrome/browser/background/background_mode_manager.h
@@ -28,7 +28,6 @@
 #include "extensions/common/extension_id.h"
 
 class BackgroundModeOptimizer;
-class BackgroundTrigger;
 class Browser;
 class PrefRegistrySimple;
 class Profile;
@@ -50,9 +49,9 @@
 // are no open browser windows.
 //
 // Chrome enters background mode whenever there is an application with the
-// "background" permission installed, or a "trigger" that requires Chrome to be
-// running. This class monitors the set of installed/loaded extensions to ensure
-// that Chrome enters/exits background mode at the appropriate time.
+// "background" permission installed. This class monitors the set of
+// installed/loaded extensions to ensure that Chrome enters/exits background
+// mode at the appropriate time.
 //
 // When Chrome is in background mode, it will continue running even after the
 // last browser window is closed, until the user explicitly exits the app.
@@ -109,15 +108,6 @@
   // For testing purposes.
   size_t NumberOfBackgroundModeData();
 
-  // Registers |trigger| as a reason for enabling background mode. Does not
-  // take ownership of |trigger|.
-  void RegisterTrigger(const Profile* profile,
-                       BackgroundTrigger* trigger,
-                       bool should_notify_user);
-
-  // Unregisters |trigger| as a reason for enabling background mode.
-  void UnregisterTrigger(const Profile* profile, BackgroundTrigger* trigger);
-
  private:
   friend class AppBackgroundPageApiTest;
   friend class BackgroundModeManagerTest;
@@ -145,10 +135,6 @@
                            ProfileAttributesStorageObserver);
   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
                            DeleteBackgroundProfile);
-  FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
-                           TriggerRegisterUnregister);
-  FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest,
-                           TriggerRegisterWhileDisabled);
   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerWithExtensionsTest,
                            BackgroundMenuGeneration);
   FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerWithExtensionsTest,
@@ -158,12 +144,8 @@
   FRIEND_TEST_ALL_PREFIXES(BackgroundAppBrowserTest,
                            ReloadBackgroundApp);
 
-  // A pending trigger may be registered later. The boolean indicates whether
-  // the user should be notified when it is registered.
-  using PendingTriggerData = std::map<BackgroundTrigger*, bool>;
-
   // Manages the background clients and menu items for a single profile. A
-  // client can be a trigger or an extension.
+  // client is an extension.
   class BackgroundModeData : public StatusIconMenuModel::Delegate {
    public:
     BackgroundModeData(Profile* profile,
@@ -182,8 +164,7 @@
     // Browser window.
     Browser* GetBrowserWindow();
 
-    // Returns if this profile has background clients. A client can be a trigger
-    // or an extension.
+    // Returns if this profile has background clients. A client is an extension.
     bool HasBackgroundClient() const;
 
     // Builds the profile specific parts of the menu. The menu passed in may
@@ -209,28 +190,6 @@
     // the last call to GetNewBackgroundApps()).
     std::set<const extensions::Extension*> GetNewBackgroundApps();
 
-    // Adds a pending |trigger| as a reason to enable background mode. A pending
-    // trigger does not activate background mode, but may be registered later by
-    // RegisterPendingTriggers. Does not take ownership of |trigger|.
-    void AddPendingTrigger(BackgroundTrigger* trigger, bool should_notify_user);
-
-    // Takes ownership of the pending trigger data.
-    PendingTriggerData TakePendingTriggerData();
-
-    // If there are pending triggers.
-    bool HasPendingTrigger() const;
-
-    // Registers |trigger| as a reason to enable background mode. Does not take
-    // ownership of |trigger|. Idempotent.
-    void RegisterTrigger(BackgroundTrigger* trigger);
-
-    // Removes |trigger| from the registered and pending triggers. Idempotent.
-    void UnregisterTrigger(BackgroundTrigger* trigger);
-
-    // Checks whether |trigger| is already registered or stored as a pending
-    // trigger.
-    bool HasTrigger(BackgroundTrigger* trigger);
-
    private:
     // The cached list of BackgroundApplications.
     std::unique_ptr<BackgroundApplicationListModel> applications_;
@@ -251,14 +210,6 @@
     // good about tracking changes to the background permission around
     // extension reloads, and will sometimes report spurious permission changes.
     std::set<extensions::ExtensionId> current_extensions_;
-
-    // This class does not own the triggers. If a trigger does not outlive this
-    // class it must be unregistered before destruction.
-    PendingTriggerData pending_trigger_data_;
-
-    // This class does not own the triggers. If a trigger does not outlive this
-    // class it must be unregistered before destruction.
-    std::set<BackgroundTrigger*> registered_triggers_;
   };
 
   using BackgroundModeInfoMap =
@@ -367,17 +318,13 @@
   void EnableBackgroundMode();
 
   // Returns if any profile on the system has a background client.
-  // A client can be a trigger or an extension.
-  // (virtual to allow overriding in unit tests)
+  // A client is an extension. (virtual to allow overriding in unit tests)
   virtual bool HasBackgroundClient() const;
 
-  // Returns if there are background clients for a profile. A client can be a
-  // trigger or an extension.
+  // Returns if there are background clients for a profile. A client is an
+  // extension.
   virtual bool HasBackgroundClientForProfile(const Profile* profile) const;
 
-  // Returns if the system has any pending triggers, for all profiles.
-  bool HasPendingTrigger() const;
-
   // Returns true if we should be in background mode.
   bool ShouldBeInBackgroundMode() const;
 
diff --git a/chrome/browser/background/background_mode_manager_unittest.cc b/chrome/browser/background/background_mode_manager_unittest.cc
index 46e6056..301a72262 100644
--- a/chrome/browser/background/background_mode_manager_unittest.cc
+++ b/chrome/browser/background/background_mode_manager_unittest.cc
@@ -17,7 +17,6 @@
 #include "base/test/test_simple_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
-#include "chrome/browser/background/background_trigger.h"
 #include "chrome/browser/extensions/extension_function_test_utils.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/test_extension_system.h"
@@ -64,34 +63,6 @@
   return profile_manager;
 }
 
-class FakeBackgroundTrigger : public BackgroundTrigger {
- public:
-  ~FakeBackgroundTrigger() override;
-  base::string16 GetName() override;
-  gfx::ImageSkia* GetIcon() override;
-  void OnMenuClick() override;
-  int get_name_call_count_ = 0;
-  int get_icon_call_count_ = 0;
-  int on_menu_click_call_count_ = 0;
-};
-
-FakeBackgroundTrigger::~FakeBackgroundTrigger() {
-}
-
-base::string16 FakeBackgroundTrigger::GetName() {
-  get_name_call_count_++;
-  return base::ASCIIToUTF16("FakeBackgroundTrigger");
-}
-
-gfx::ImageSkia* FakeBackgroundTrigger::GetIcon() {
-  get_icon_call_count_++;
-  return nullptr;
-}
-
-void FakeBackgroundTrigger::OnMenuClick() {
-  on_menu_click_call_count_++;
-}
-
 // Helper class that tracks state transitions in BackgroundModeManager and
 // exposes them via getters (or gmock for EnableLaunchOnStartup).
 class TestBackgroundModeManager : public StrictMock<BackgroundModeManager> {
@@ -919,57 +890,3 @@
   service->AddExtension(upgraded_no_bg_ext_has_bg.get());
   EXPECT_TRUE(manager_->HasShownBalloon());
 }
-
-TEST_F(BackgroundModeManagerTest, TriggerRegisterUnregister) {
-  FakeBackgroundTrigger trigger;
-  TestBackgroundModeManager manager(
-      *command_line_, profile_manager_->profile_attributes_storage());
-  manager.RegisterProfile(profile_);
-  AssertBackgroundModeInactive(manager);
-
-  // Registering a trigger turns on background mode and shows a notification to
-  // the user.
-  EXPECT_CALL(manager, EnableLaunchOnStartup(true));
-  manager.RegisterTrigger(profile_, &trigger, true /* should_notify_user */);
-  Mock::VerifyAndClearExpectations(&manager);
-  ASSERT_TRUE(manager.HasBackgroundClientForProfile(profile_));
-  AssertBackgroundModeActive(manager);
-  ASSERT_TRUE(manager.HasShownBalloon());
-
-  // Unregistering the trigger turns off background mode.
-  EXPECT_CALL(manager, EnableLaunchOnStartup(false));
-  manager.UnregisterTrigger(profile_, &trigger);
-  Mock::VerifyAndClearExpectations(&manager);
-  ASSERT_FALSE(manager.HasBackgroundClientForProfile(profile_));
-  AssertBackgroundModeInactive(manager);
-}
-
-// TODO(mvanouwerkerk): Make background mode behavior consistent when
-// registering a client while the pref is disabled - crbug.com/527032.
-TEST_F(BackgroundModeManagerTest, TriggerRegisterWhileDisabled) {
-  g_browser_process->local_state()->SetBoolean(prefs::kBackgroundModeEnabled,
-                                               false);
-  FakeBackgroundTrigger trigger;
-  TestBackgroundModeManager manager(
-      *command_line_, profile_manager_->profile_attributes_storage());
-  manager.RegisterProfile(profile_);
-  AssertBackgroundModeInactive(manager);
-  ASSERT_FALSE(manager.IsBackgroundModePrefEnabled());
-
-  // Registering a trigger while disabled has no immediate effect but it is
-  // stored as pending in case background mode is later enabled.
-  manager.RegisterTrigger(profile_, &trigger, true /* should_notify_user */);
-  ASSERT_FALSE(manager.HasBackgroundClientForProfile(profile_));
-  AssertBackgroundModeInactive(manager);
-  ASSERT_FALSE(manager.HasShownBalloon());
-
-  // When the background mode pref is enabled and there are pending triggers
-  // they will be registered and the user will be notified.
-  EXPECT_CALL(manager, EnableLaunchOnStartup(true));
-  g_browser_process->local_state()->SetBoolean(prefs::kBackgroundModeEnabled,
-                                               true);
-  Mock::VerifyAndClearExpectations(&manager);
-  ASSERT_TRUE(manager.HasBackgroundClientForProfile(profile_));
-  AssertBackgroundModeActive(manager);
-  ASSERT_TRUE(manager.HasShownBalloon());
-}
diff --git a/chrome/browser/background/background_trigger.h b/chrome/browser/background/background_trigger.h
deleted file mode 100644
index 9e9197e..0000000
--- a/chrome/browser/background/background_trigger.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_BACKGROUND_BACKGROUND_TRIGGER_H_
-#define CHROME_BROWSER_BACKGROUND_BACKGROUND_TRIGGER_H_
-
-#include "base/strings/string16.h"
-#include "ui/gfx/image/image_skia.h"
-
-// Enables background mode if registered with the BackgroundModeManager.
-class BackgroundTrigger {
- public:
-  virtual ~BackgroundTrigger() {}
-
-  // The name to be displayed in the status icon menu and the installation
-  // notification.
-  virtual base::string16 GetName() = 0;
-
-  // The icon to be displayed in the status icon menu.
-  virtual gfx::ImageSkia* GetIcon() = 0;
-
-  // Handles a user's click on the status icon menu item.
-  virtual void OnMenuClick() = 0;
-};
-
-#endif  // CHROME_BROWSER_BACKGROUND_BACKGROUND_TRIGGER_H_
diff --git a/chrome/browser/banners/app_banner_manager.cc b/chrome/browser/banners/app_banner_manager.cc
index 464ad92..afd0d72 100644
--- a/chrome/browser/banners/app_banner_manager.cc
+++ b/chrome/browser/banners/app_banner_manager.cc
@@ -13,8 +13,6 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/stl_util.h"
 #include "base/time/time.h"
-#include "build/build_config.h"
-#include "chrome/browser/banners/app_banner_manager_desktop.h"
 #include "chrome/browser/banners/app_banner_metrics.h"
 #include "chrome/browser/banners/app_banner_settings_helper.h"
 #include "chrome/browser/browser_process.h"
@@ -33,12 +31,6 @@
 #include "third_party/blink/public/mojom/installation/installation.mojom.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 
-#if defined(OS_ANDROID)
-#include "chrome/browser/banners/app_banner_manager_android.h"
-#else
-#include "chrome/browser/banners/app_banner_manager_desktop.h"
-#endif
-
 namespace {
 
 int gTimeDeltaInDaysForTesting = 0;
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 8cfd4f53..110fddf 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -478,6 +478,7 @@
 #include "chrome/browser/ui/passwords/google_password_manager_navigation_throttle.h"
 #include "chrome/browser/ui/search/new_tab_page_navigation_throttle.h"
 #include "chrome/common/importer/profile_import.mojom.h"
+#include "chrome/grit/chrome_unscaled_resources.h"
 #endif  //  !defined(OS_ANDROID)
 
 #if defined(OS_WIN) || defined(OS_MACOSX) || \
@@ -5763,6 +5764,19 @@
   return ::GetUserAgentMetadata();
 }
 
+base::Optional<gfx::ImageSkia> ChromeContentBrowserClient::GetProductLogo()
+    const {
+  // This icon is available on Android, but adds 19KiB to the APK. Since it
+  // isn't used on Android we exclude it to avoid bloat.
+#if !defined(OS_ANDROID)
+  return base::Optional<gfx::ImageSkia>(
+      *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
+          IDR_PRODUCT_LOGO_256));
+#else
+  return base::nullopt;
+#endif
+}
+
 bool ChromeContentBrowserClient::IsBuiltinComponent(
     content::BrowserContext* browser_context,
     const url::Origin& origin) {
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index 8160800..e1f750c8 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -576,6 +576,8 @@
   std::string GetUserAgent() const override;
   blink::UserAgentMetadata GetUserAgentMetadata() const override;
 
+  base::Optional<gfx::ImageSkia> GetProductLogo() const override;
+
   bool IsBuiltinComponent(content::BrowserContext* browser_context,
                           const url::Origin& origin) override;
 
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 22cd2278..b184c5f 100644
--- a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.cc
+++ b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.cc
@@ -588,11 +588,14 @@
 
 void ArcAccessibilityHelperBridge::OnAccessibilityStatusChanged(
     const chromeos::AccessibilityStatusEventDetails& event_details) {
-  // TODO(yawano): Add case for select to speak and switch access.
   if (event_details.notification_type !=
+          chromeos::ACCESSIBILITY_TOGGLE_FOCUS_HIGHLIGHT &&
+      event_details.notification_type !=
+          chromeos::ACCESSIBILITY_TOGGLE_SELECT_TO_SPEAK &&
+      event_details.notification_type !=
           chromeos::ACCESSIBILITY_TOGGLE_SPOKEN_FEEDBACK &&
       event_details.notification_type !=
-          chromeos::ACCESSIBILITY_TOGGLE_FOCUS_HIGHLIGHT) {
+          chromeos::ACCESSIBILITY_TOGGLE_SWITCH_ACCESS) {
     return;
   }
 
diff --git a/chrome/browser/chromeos/crostini/crostini_export_import.h b/chrome/browser/chromeos/crostini/crostini_export_import.h
index 8418838..d537d3e 100644
--- a/chrome/browser/chromeos/crostini/crostini_export_import.h
+++ b/chrome/browser/chromeos/crostini/crostini_export_import.h
@@ -92,6 +92,8 @@
   FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest, TestExportFail);
   FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest, TestImportSuccess);
   FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest, TestImportFail);
+  FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest,
+                           TestImportFailArchitecture);
 
   // ui::SelectFileDialog::Listener implementation.
   void FileSelected(const base::FilePath& path,
diff --git a/chrome/browser/chromeos/crostini/crostini_export_import_unittest.cc b/chrome/browser/chromeos/crostini/crostini_export_import_unittest.cc
index 41a386c..e4e523c 100644
--- a/chrome/browser/chromeos/crostini/crostini_export_import_unittest.cc
+++ b/chrome/browser/chromeos/crostini/crostini_export_import_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/files/file_path.h"
 #include "base/run_loop.h"
+#include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chromeos/crostini/crostini_util.h"
 #include "chrome/browser/chromeos/file_manager/path_util.h"
 #include "chrome/test/base/testing_profile.h"
@@ -43,6 +44,9 @@
     signal.set_container_name(kCrostiniDefaultContainerName);
     signal.set_status(status);
     signal.set_progress_percent(progress_percent);
+    signal.set_progress_percent(progress_percent);
+    signal.set_architecture_device("arch_dev");
+    signal.set_architecture_container("arch_con");
     fake_cicerone_client_->NotifyImportLxdContainerProgress(signal);
   }
 
@@ -223,5 +227,31 @@
       vm_tools::cicerone::ImportLxdContainerProgressSignal_Status_FAILED, 0);
   EXPECT_EQ(notification->get_status(),
             CrostiniExportImportNotification::Status::FAILED);
+  std::string msg("Restoring couldn't be completed due to an error");
+  EXPECT_EQ(notification->get_notification()->message(),
+            base::UTF8ToUTF16(msg));
+}
+
+TEST_F(CrostiniExportImportTest, TestImportFailArchitecture) {
+  crostini_export_import()->FileSelected(
+      tarball_, 0, reinterpret_cast<void*>(ExportImportType::IMPORT));
+  run_loop_->RunUntilIdle();
+  CrostiniExportImportNotification* notification =
+      crostini_export_import()->GetNotificationForTesting(container_id_);
+
+  // Failed Architecture.
+  SendImportProgress(
+      vm_tools::cicerone::
+          ImportLxdContainerProgressSignal_Status_FAILED_ARCHITECTURE,
+      0);
+  EXPECT_EQ(notification->get_status(),
+            CrostiniExportImportNotification::Status::FAILED);
+  std::string msg(
+      "Cannot import container architecture type arch_con with this device "
+      "which is arch_dev. You can try restoring this container into a "
+      "different device, or you can access the files inside this container "
+      "image by opening in Files app.");
+  EXPECT_EQ(notification->get_notification()->message(),
+            base::UTF8ToUTF16(msg));
 }
 }  // namespace crostini
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.cc b/chrome/browser/chromeos/crostini/crostini_manager.cc
index 594e2380..c2a88f5 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager.cc
+++ b/chrome/browser/chromeos/crostini/crostini_manager.cc
@@ -811,8 +811,7 @@
   // The type of disk image to be created.
   request.set_image_type(vm_tools::concierge::DISK_IMAGE_AUTO);
 
-  if (storage_location != vm_tools::concierge::STORAGE_CRYPTOHOME_ROOT &&
-      storage_location != vm_tools::concierge::STORAGE_CRYPTOHOME_DOWNLOADS) {
+  if (storage_location != vm_tools::concierge::STORAGE_CRYPTOHOME_ROOT) {
     LOG(ERROR) << "'" << storage_location
                << "' is not a valid storage location";
     std::move(callback).Run(
@@ -833,7 +832,6 @@
 
 void CrostiniManager::DestroyDiskImage(
     const base::FilePath& disk_path,
-    vm_tools::concierge::StorageLocation storage_location,
     DestroyDiskImageCallback callback) {
   std::string disk_path_string = disk_path.AsUTF8Unsafe();
   if (disk_path_string.empty()) {
@@ -846,15 +844,6 @@
   request.set_cryptohome_id(CryptohomeIdForProfile(profile_));
   request.set_disk_path(std::move(disk_path_string));
 
-  if (storage_location != vm_tools::concierge::STORAGE_CRYPTOHOME_ROOT &&
-      storage_location != vm_tools::concierge::STORAGE_CRYPTOHOME_DOWNLOADS) {
-    LOG(ERROR) << "'" << storage_location
-               << "' is not a valid storage location";
-    std::move(callback).Run(CrostiniResult::CLIENT_ERROR);
-    return;
-  }
-  request.set_storage_location(storage_location);
-
   GetConciergeClient()->DestroyDiskImage(
       std::move(request),
       base::BindOnce(&CrostiniManager::OnDestroyDiskImage,
@@ -1690,6 +1679,16 @@
   linux_package_operation_progress_observers_.RemoveObserver(observer);
 }
 
+void CrostiniManager::AddPendingAppListUpdatesObserver(
+    PendingAppListUpdatesObserver* observer) {
+  pending_app_list_updates_observers_.AddObserver(observer);
+}
+
+void CrostiniManager::RemovePendingAppListUpdatesObserver(
+    PendingAppListUpdatesObserver* observer) {
+  pending_app_list_updates_observers_.RemoveObserver(observer);
+}
+
 void CrostiniManager::AddExportContainerProgressObserver(
     ExportContainerProgressObserver* observer) {
   export_container_progress_observers_.AddObserver(observer);
@@ -2637,4 +2636,12 @@
   }
 }
 
+void CrostiniManager::OnPendingAppListUpdates(
+    const vm_tools::cicerone::PendingAppListUpdatesSignal& signal) {
+  for (auto& observer : pending_app_list_updates_observers_) {
+    observer.OnPendingAppListUpdates(signal.vm_name(), signal.container_name(),
+                                     signal.count());
+  }
+}
+
 }  // namespace crostini
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.h b/chrome/browser/chromeos/crostini/crostini_manager.h
index 9595676..e4d8f6a 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager.h
+++ b/chrome/browser/chromeos/crostini/crostini_manager.h
@@ -167,6 +167,14 @@
                                           int progress_percent) = 0;
 };
 
+class PendingAppListUpdatesObserver : public base::CheckedObserver {
+ public:
+  // Called whenever the kPendingAppListUpdatesMethod signal is sent.
+  virtual void OnPendingAppListUpdates(const std::string& vm_name,
+                                       const std::string& container_name,
+                                       int count) = 0;
+};
+
 class ExportContainerProgressObserver {
  public:
   // A successfully started container export will continually fire progress
@@ -355,8 +363,6 @@
       // The path to the disk image, including the name of
       // the image itself.
       const base::FilePath& disk_path,
-      // The storage location of the disk image
-      vm_tools::concierge::StorageLocation storage_location,
       DestroyDiskImageCallback callback);
 
   void ListVmDisks(ListVmDisksCallback callback);
@@ -568,6 +574,12 @@
   void RemoveLinuxPackageOperationProgressObserver(
       LinuxPackageOperationProgressObserver* observer);
 
+  // Add/remove observers for pending app list updates.
+  void AddPendingAppListUpdatesObserver(
+      PendingAppListUpdatesObserver* observer);
+  void RemovePendingAppListUpdatesObserver(
+      PendingAppListUpdatesObserver* observer);
+
   // Add/remove observers for container export/import.
   void AddExportContainerProgressObserver(
       ExportContainerProgressObserver* observer);
@@ -609,6 +621,8 @@
   void OnImportLxdContainerProgress(
       const vm_tools::cicerone::ImportLxdContainerProgressSignal& signal)
       override;
+  void OnPendingAppListUpdates(
+      const vm_tools::cicerone::PendingAppListUpdatesSignal& signal) override;
 
   void RemoveCrostini(std::string vm_name, RemoveCrostiniCallback callback);
 
@@ -887,6 +901,9 @@
   base::ObserverList<LinuxPackageOperationProgressObserver>::Unchecked
       linux_package_operation_progress_observers_;
 
+  base::ObserverList<PendingAppListUpdatesObserver>
+      pending_app_list_updates_observers_;
+
   base::ObserverList<ExportContainerProgressObserver>::Unchecked
       export_container_progress_observers_;
   base::ObserverList<ImportContainerProgressObserver>::Unchecked
diff --git a/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc b/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
index b0ab3f54..be0311a 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
+++ b/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
@@ -278,8 +278,7 @@
   const base::FilePath& disk_path = base::FilePath(kVmName);
 
   crostini_manager()->CreateDiskImage(
-      disk_path, vm_tools::concierge::STORAGE_CRYPTOHOME_DOWNLOADS,
-      kDiskSizeBytes,
+      disk_path, vm_tools::concierge::STORAGE_CRYPTOHOME_ROOT, kDiskSizeBytes,
       base::BindOnce(&CrostiniManagerTest::CreateDiskImageSuccessCallback,
                      base::Unretained(this), run_loop()->QuitClosure()));
   run_loop()->Run();
@@ -289,18 +288,7 @@
   const base::FilePath& disk_path = base::FilePath("");
 
   crostini_manager()->DestroyDiskImage(
-      disk_path, vm_tools::concierge::STORAGE_CRYPTOHOME_ROOT,
-      base::BindOnce(&CrostiniManagerTest::DestroyDiskImageClientErrorCallback,
-                     base::Unretained(this), run_loop()->QuitClosure()));
-  run_loop()->Run();
-}
-
-TEST_F(CrostiniManagerTest, DestroyDiskImageStorageLocationError) {
-  const base::FilePath& disk_path = base::FilePath(kVmName);
-
-  crostini_manager()->DestroyDiskImage(
       disk_path,
-      vm_tools::concierge::StorageLocation_INT_MIN_SENTINEL_DO_NOT_USE_,
       base::BindOnce(&CrostiniManagerTest::DestroyDiskImageClientErrorCallback,
                      base::Unretained(this), run_loop()->QuitClosure()));
   run_loop()->Run();
@@ -310,7 +298,7 @@
   const base::FilePath& disk_path = base::FilePath(kVmName);
 
   crostini_manager()->DestroyDiskImage(
-      disk_path, vm_tools::concierge::STORAGE_CRYPTOHOME_DOWNLOADS,
+      disk_path,
       base::BindOnce(&CrostiniManagerTest::DestroyDiskImageSuccessCallback,
                      base::Unretained(this), run_loop()->QuitClosure()));
   run_loop()->Run();
diff --git a/chrome/browser/chromeos/crostini/crostini_package_notification.cc b/chrome/browser/chromeos/crostini/crostini_package_notification.cc
index 1be09cd..0d12b0a 100644
--- a/chrome/browser/chromeos/crostini/crostini_package_notification.cc
+++ b/chrome/browser/chromeos/crostini/crostini_package_notification.cc
@@ -70,6 +70,10 @@
 
 CrostiniPackageNotification::~CrostiniPackageNotification() = default;
 
+PackageOperationStatus CrostiniPackageNotification::GetOperationStatus() const {
+  return current_status_;
+}
+
 // static
 CrostiniPackageNotification::NotificationSettings
 CrostiniPackageNotification::GetNotificationSettingsForTypeAndAppName(
@@ -154,11 +158,18 @@
           ash::kSystemNotificationColorCriticalWarning);
       break;
 
+    case PackageOperationStatus::WAITING_FOR_APP_REGISTRY_UPDATE:
+      // If a notification progress bar is set to a value outside of [0, 100],
+      // it becomes in infinite progress bar. Do that here because we have no
+      // way to know how long this will take or how close we are to completion.
+      progress_percent = -1;
+      FALLTHROUGH;
     case PackageOperationStatus::RUNNING:
       never_timeout = true;
       notification_type = message_center::NOTIFICATION_TYPE_PROGRESS;
       title = notification_settings_.progress_title;
-      if (notification_type_ == NotificationType::APPLICATION_UNINSTALL) {
+      if (notification_type_ == NotificationType::APPLICATION_UNINSTALL &&
+          progress_percent >= 0) {
         // Uninstalls have a time remaining instead of a fixed message.
         body = GetTimeRemainingMessage(running_start_time_, progress_percent);
 
diff --git a/chrome/browser/chromeos/crostini/crostini_package_notification.h b/chrome/browser/chromeos/crostini/crostini_package_notification.h
index c36c6b6..44429d4 100644
--- a/chrome/browser/chromeos/crostini/crostini_package_notification.h
+++ b/chrome/browser/chromeos/crostini/crostini_package_notification.h
@@ -44,6 +44,8 @@
 
   void ForceAllowAutoHide();
 
+  PackageOperationStatus GetOperationStatus() const;
+
   // message_center::NotificationObserver:
   void Close(bool by_user) override;
 
diff --git a/chrome/browser/chromeos/crostini/crostini_package_operation_status.h b/chrome/browser/chromeos/crostini/crostini_package_operation_status.h
index 69bcda82..f880462 100644
--- a/chrome/browser/chromeos/crostini/crostini_package_operation_status.h
+++ b/chrome/browser/chromeos/crostini/crostini_package_operation_status.h
@@ -11,7 +11,13 @@
 
 // Status of an operation in CrostiniPackageService &
 // CrostiniPackageNotification.
-enum class PackageOperationStatus { QUEUED, SUCCEEDED, FAILED, RUNNING };
+enum class PackageOperationStatus {
+  QUEUED,
+  SUCCEEDED,
+  FAILED,
+  RUNNING,
+  WAITING_FOR_APP_REGISTRY_UPDATE
+};
 
 }  // namespace crostini
 
diff --git a/chrome/browser/chromeos/crostini/crostini_package_service.cc b/chrome/browser/chromeos/crostini/crostini_package_service.cc
index 8179340..8439574 100644
--- a/chrome/browser/chromeos/crostini/crostini_package_service.cc
+++ b/chrome/browser/chromeos/crostini/crostini_package_service.cc
@@ -108,6 +108,7 @@
   CrostiniManager* manager = CrostiniManager::GetForProfile(profile);
 
   manager->AddLinuxPackageOperationProgressObserver(this);
+  manager->AddPendingAppListUpdatesObserver(this);
 }
 
 CrostiniPackageService::~CrostiniPackageService() = default;
@@ -115,6 +116,7 @@
 void CrostiniPackageService::Shutdown() {
   CrostiniManager* manager = CrostiniManager::GetForProfile(profile_);
   manager->RemoveLinuxPackageOperationProgressObserver(this);
+  manager->RemovePendingAppListUpdatesObserver(this);
 }
 
 void CrostiniPackageService::SetNotificationStateChangeCallbackForTesting(
@@ -278,6 +280,14 @@
       << ContainerIdToString(container_id) << " has no notification to update";
   DCHECK(it->second) << ContainerIdToString(container_id)
                      << " has null notification pointer";
+
+  // If an operation has finished, but there are still app list updates pending,
+  // don't finish the flow yet.
+  if (status == PackageOperationStatus::SUCCEEDED &&
+      has_pending_app_list_updates_.count(container_id)) {
+    status = PackageOperationStatus::WAITING_FOR_APP_REGISTRY_UPDATE;
+  }
+
   it->second->UpdateProgress(status, progress_percent);
 
   if (status == PackageOperationStatus::SUCCEEDED ||
@@ -297,6 +307,29 @@
   }
 }
 
+void CrostiniPackageService::OnPendingAppListUpdates(
+    const std::string& vm_name,
+    const std::string& container_name,
+    int count) {
+  const ContainerId container_id(vm_name, container_name);
+
+  if (count != 0) {
+    has_pending_app_list_updates_.insert(container_id);
+  } else {
+    has_pending_app_list_updates_.erase(container_id);
+  }
+
+  auto it = running_notifications_.find(container_id);
+  if (it != running_notifications_.end()) {
+    if (it->second->GetOperationStatus() ==
+            PackageOperationStatus::WAITING_FOR_APP_REGISTRY_UPDATE &&
+        count == 0) {
+      UpdatePackageOperationStatus(container_id,
+                                   PackageOperationStatus::SUCCEEDED, 100);
+    }
+  }
+}
+
 void CrostiniPackageService::OnGetLinuxPackageInfo(
     const std::string& vm_name,
     const std::string& container_name,
diff --git a/chrome/browser/chromeos/crostini/crostini_package_service.h b/chrome/browser/chromeos/crostini/crostini_package_service.h
index fc05177..9e047e9 100644
--- a/chrome/browser/chromeos/crostini/crostini_package_service.h
+++ b/chrome/browser/chromeos/crostini/crostini_package_service.h
@@ -25,7 +25,8 @@
 namespace crostini {
 
 class CrostiniPackageService : public KeyedService,
-                               public LinuxPackageOperationProgressObserver {
+                               public LinuxPackageOperationProgressObserver,
+                               public PendingAppListUpdatesObserver {
  public:
   using StateChangeCallback =
       base::RepeatingCallback<void(PackageOperationStatus)>;
@@ -81,6 +82,11 @@
                                   UninstallPackageProgressStatus status,
                                   int progress_percent) override;
 
+  // PendingAppListUpdatesObserver:
+  void OnPendingAppListUpdates(const std::string& vm_name,
+                               const std::string& container_name,
+                               int count) override;
+
   // (Eventually) uninstall the package identified by |app_id|. If successfully
   // started, a system notification will be used to display further updates.
   void QueueUninstallApplication(const std::string& app_id);
@@ -173,6 +179,11 @@
   std::vector<std::unique_ptr<CrostiniPackageNotification>>
       finished_notifications_;
 
+  // A map storing which containers have currently pending app list update
+  // operations. If a container is not present in the map, we assume no pending
+  // updates.
+  std::set<ContainerId> has_pending_app_list_updates_;
+
   // Called each time a notification is set to a new state.
   StateChangeCallback testing_state_change_callback_;
 
diff --git a/chrome/browser/chromeos/crostini/crostini_package_service_unittest.cc b/chrome/browser/chromeos/crostini/crostini_package_service_unittest.cc
index 72f500e..b620a4f0 100644
--- a/chrome/browser/chromeos/crostini/crostini_package_service_unittest.cc
+++ b/chrome/browser/chromeos/crostini/crostini_package_service_unittest.cc
@@ -51,6 +51,7 @@
 using ::vm_tools::cicerone::InstallLinuxPackageResponse;
 using ::vm_tools::cicerone::LinuxPackageInfoRequest;
 using ::vm_tools::cicerone::LinuxPackageInfoResponse;
+using ::vm_tools::cicerone::PendingAppListUpdatesSignal;
 using ::vm_tools::cicerone::UninstallPackageOwningFileRequest;
 using ::vm_tools::cicerone::UninstallPackageOwningFileResponse;
 using ::vm_tools::cicerone::UninstallPackageProgressSignal;
@@ -218,6 +219,16 @@
     return signal;
   }
 
+  void SendAppListUpdateSignal(const std::string& vm_name,
+                               const std::string& container_name,
+                               int count) {
+    PendingAppListUpdatesSignal signal;
+    signal.set_vm_name(vm_name);
+    signal.set_container_name(container_name);
+    signal.set_count(count);
+    fake_cicerone_client_->NotifyPendingAppListUpdates(signal);
+  }
+
   // Closes the notification as if the user had clicked 'close'.
   void CloseNotification(const message_center::Notification& notification) {
     notification_display_service_->RemoveNotification(
@@ -582,6 +593,17 @@
       expected_progress));
 }
 
+Matcher<PrintableNotification> IsUninstallWaitingForAppListNotification(
+    KnownApp app = DEFAULT_APP) {
+  return MakeMatcher(new NotificationMatcher(
+      l10n_util::GetStringUTF16(
+          IDS_CROSTINI_APPLICATION_UNINSTALL_NOTIFICATION_DISPLAY_SOURCE),
+      l10n_util::GetStringFUTF16(
+          IDS_CROSTINI_APPLICATION_UNINSTALL_NOTIFICATION_IN_PROGRESS_TITLE,
+          GetAppName(app)),
+      -1));
+}
+
 Matcher<PrintableNotification> IsUninstallQueuedNotification(
     KnownApp app = DEFAULT_APP) {
   return MakeMatcher(new NotificationMatcher(
@@ -604,6 +626,15 @@
       expected_progress));
 }
 
+Matcher<PrintableNotification> IsInstallWaitingForAppListNotification() {
+  return MakeMatcher(new NotificationMatcher(
+      l10n_util::GetStringUTF16(
+          IDS_CROSTINI_PACKAGE_INSTALL_NOTIFICATION_DISPLAY_SOURCE),
+      l10n_util::GetStringUTF16(
+          IDS_CROSTINI_PACKAGE_INSTALL_NOTIFICATION_IN_PROGRESS_TITLE),
+      -1));
+}
+
 Matcher<PrintableNotification> IsInstallSuccessNotification() {
   return MakeMatcher(new NotificationMatcher(
       l10n_util::GetStringUTF16(
@@ -918,6 +949,94 @@
                            IsUninstallSuccessNotification(THIRD_APP)));
 }
 
+TEST_F(CrostiniPackageServiceTest, UninstallNotificationWaitsForAppListUpdate) {
+  service_->QueueUninstallApplication(kDefaultAppId);
+
+  SendAppListUpdateSignal(kCrostiniDefaultVmName, kCrostiniDefaultContainerName,
+                          1);
+
+  StartAndSignalUninstall(UninstallPackageProgressSignal::SUCCEEDED);
+
+  EXPECT_THAT(
+      Printable(notification_display_service_->GetDisplayedNotificationsForType(
+          NotificationHandler::Type::TRANSIENT)),
+      UnorderedElementsAre(
+          IsUninstallWaitingForAppListNotification(DEFAULT_APP)));
+
+  SendAppListUpdateSignal(kCrostiniDefaultVmName, kCrostiniDefaultContainerName,
+                          0);
+
+  EXPECT_THAT(
+      Printable(notification_display_service_->GetDisplayedNotificationsForType(
+          NotificationHandler::Type::TRANSIENT)),
+      UnorderedElementsAre(IsUninstallSuccessNotification(DEFAULT_APP)));
+}
+
+TEST_F(CrostiniPackageServiceTest,
+       UninstallNotificationDoesntWaitForAppListUpdate) {
+  service_->QueueUninstallApplication(kDefaultAppId);
+
+  SendAppListUpdateSignal(kCrostiniDefaultVmName, kCrostiniDefaultContainerName,
+                          0);
+
+  StartAndSignalUninstall(UninstallPackageProgressSignal::SUCCEEDED);
+
+  EXPECT_THAT(
+      Printable(notification_display_service_->GetDisplayedNotificationsForType(
+          NotificationHandler::Type::TRANSIENT)),
+      UnorderedElementsAre(IsUninstallSuccessNotification(DEFAULT_APP)));
+
+  SendAppListUpdateSignal(kCrostiniDefaultVmName, kCrostiniDefaultContainerName,
+                          1);
+
+  EXPECT_THAT(
+      Printable(notification_display_service_->GetDisplayedNotificationsForType(
+          NotificationHandler::Type::TRANSIENT)),
+      UnorderedElementsAre(IsUninstallSuccessNotification(DEFAULT_APP)));
+}
+
+TEST_F(CrostiniPackageServiceTest,
+       UninstallNotificationAppListUpdatesAreVmSpecific) {
+  UninstallPackageOwningFileRequest request;
+  DBusMethodCallback<UninstallPackageOwningFileResponse> callback;
+
+  service_->QueueUninstallApplication(kDefaultAppId);
+  RunUntilUninstallRequestMade(fake_cicerone_client_, &request, &callback);
+  UninstallPackageProgressSignal signal_progress = MakeUninstallSignal(request);
+  signal_progress.set_status(UninstallPackageProgressSignal::SUCCEEDED);
+
+  service_->QueueUninstallApplication(kDifferentVmAppId);
+  RunUntilUninstallRequestMade(fake_cicerone_client_, &request, &callback);
+  UninstallPackageProgressSignal signal_progress2 =
+      MakeUninstallSignal(request);
+  signal_progress2.set_status(UninstallPackageProgressSignal::SUCCEEDED);
+
+  SendAppListUpdateSignal(kDifferentVmVmName, kCrostiniDefaultContainerName, 1);
+  fake_cicerone_client_->UninstallPackageProgress(signal_progress);
+  fake_cicerone_client_->UninstallPackageProgress(signal_progress2);
+
+  EXPECT_THAT(
+      Printable(notification_display_service_->GetDisplayedNotificationsForType(
+          NotificationHandler::Type::TRANSIENT)),
+      UnorderedElementsAre(
+          IsUninstallSuccessNotification(DEFAULT_APP),
+          IsUninstallWaitingForAppListNotification(DIFFERENT_VM)));
+}
+
+TEST_F(CrostiniPackageServiceTest,
+       UninstallNotificationAppListUpdatesFromUnknownContainersAreIgnored) {
+  service_->QueueUninstallApplication(kDefaultAppId);
+
+  SendAppListUpdateSignal(kDifferentVmVmName, kCrostiniDefaultContainerName, 1);
+
+  StartAndSignalUninstall(UninstallPackageProgressSignal::SUCCEEDED);
+
+  EXPECT_THAT(
+      Printable(notification_display_service_->GetDisplayedNotificationsForType(
+          NotificationHandler::Type::TRANSIENT)),
+      UnorderedElementsAre(IsUninstallSuccessNotification(DEFAULT_APP)));
+}
+
 TEST_F(CrostiniPackageServiceTest, ClosingSuccessNotificationWorks) {
   service_->QueueUninstallApplication(kDefaultAppId);
   StartAndSignalUninstall(UninstallPackageProgressSignal::SUCCEEDED);
@@ -1598,6 +1717,110 @@
       UnorderedElementsAre(IsInstallFailedNotification()));
 }
 
+TEST_F(CrostiniPackageServiceTest, InstallNotificationWaitsForAppListUpdate) {
+  service_->InstallLinuxPackage(kCrostiniDefaultVmName,
+                                kCrostiniDefaultContainerName, kPackageFilePath,
+                                base::DoNothing());
+  base::RunLoop().RunUntilIdle();
+
+  SendAppListUpdateSignal(kCrostiniDefaultVmName, kCrostiniDefaultContainerName,
+                          1);
+
+  StartAndSignalInstall(InstallLinuxPackageProgressSignal::SUCCEEDED);
+
+  EXPECT_THAT(
+      Printable(notification_display_service_->GetDisplayedNotificationsForType(
+          NotificationHandler::Type::TRANSIENT)),
+      UnorderedElementsAre(IsInstallWaitingForAppListNotification()));
+
+  SendAppListUpdateSignal(kCrostiniDefaultVmName, kCrostiniDefaultContainerName,
+                          0);
+
+  EXPECT_THAT(
+      Printable(notification_display_service_->GetDisplayedNotificationsForType(
+          NotificationHandler::Type::TRANSIENT)),
+      UnorderedElementsAre(IsInstallSuccessNotification()));
+}
+
+TEST_F(CrostiniPackageServiceTest,
+       InstallNotificationDoesntWaitForAppListUpdate) {
+  service_->InstallLinuxPackage(kCrostiniDefaultVmName,
+                                kCrostiniDefaultContainerName, kPackageFilePath,
+                                base::DoNothing());
+  base::RunLoop().RunUntilIdle();
+
+  SendAppListUpdateSignal(kCrostiniDefaultVmName, kCrostiniDefaultContainerName,
+                          0);
+
+  StartAndSignalInstall(InstallLinuxPackageProgressSignal::SUCCEEDED);
+
+  EXPECT_THAT(
+      Printable(notification_display_service_->GetDisplayedNotificationsForType(
+          NotificationHandler::Type::TRANSIENT)),
+      UnorderedElementsAre(IsInstallSuccessNotification()));
+
+  SendAppListUpdateSignal(kCrostiniDefaultVmName, kCrostiniDefaultContainerName,
+                          1);
+
+  EXPECT_THAT(
+      Printable(notification_display_service_->GetDisplayedNotificationsForType(
+          NotificationHandler::Type::TRANSIENT)),
+      UnorderedElementsAre(IsInstallSuccessNotification()));
+}
+
+TEST_F(CrostiniPackageServiceTest,
+       InstallNotificationAppListUpdatesAreVmSpecific) {
+  InstallLinuxPackageRequest request;
+
+  service_->InstallLinuxPackage(kCrostiniDefaultVmName,
+                                kCrostiniDefaultContainerName, kPackageFilePath,
+                                base::DoNothing());
+  request =
+      fake_cicerone_client_->get_most_recent_install_linux_package_request();
+  InstallLinuxPackageProgressSignal signal_progress =
+      MakeInstallSignal(request);
+  signal_progress.set_status(InstallLinuxPackageProgressSignal::SUCCEEDED);
+
+  service_->InstallLinuxPackage(kDifferentVmVmName,
+                                kCrostiniDefaultContainerName, kPackageFilePath,
+                                base::DoNothing());
+  request =
+      fake_cicerone_client_->get_most_recent_install_linux_package_request();
+  InstallLinuxPackageProgressSignal signal_progress2 =
+      MakeInstallSignal(request);
+  signal_progress2.set_status(InstallLinuxPackageProgressSignal::SUCCEEDED);
+
+  base::RunLoop().RunUntilIdle();
+
+  SendAppListUpdateSignal(kDifferentVmVmName, kCrostiniDefaultContainerName, 1);
+  fake_cicerone_client_->InstallLinuxPackageProgress(signal_progress);
+  fake_cicerone_client_->InstallLinuxPackageProgress(signal_progress2);
+
+  EXPECT_THAT(
+      Printable(notification_display_service_->GetDisplayedNotificationsForType(
+          NotificationHandler::Type::TRANSIENT)),
+      UnorderedElementsAre(IsInstallSuccessNotification(),
+                           IsInstallWaitingForAppListNotification()));
+}
+
+TEST_F(CrostiniPackageServiceTest,
+       InstallNotificationAppListUpdatesFromUnknownContainersAreIgnored) {
+  service_->InstallLinuxPackage(kCrostiniDefaultVmName,
+                                kCrostiniDefaultContainerName, kPackageFilePath,
+                                base::DoNothing());
+
+  base::RunLoop().RunUntilIdle();
+
+  SendAppListUpdateSignal(kDifferentVmVmName, kCrostiniDefaultContainerName, 1);
+
+  StartAndSignalInstall(InstallLinuxPackageProgressSignal::SUCCEEDED);
+
+  EXPECT_THAT(
+      Printable(notification_display_service_->GetDisplayedNotificationsForType(
+          NotificationHandler::Type::TRANSIENT)),
+      UnorderedElementsAre(IsInstallSuccessNotification()));
+}
+
 TEST_F(CrostiniPackageServiceTest, UninstallsQueuesBehindStartingUpInstall) {
   CrostiniResult result = CrostiniResult::UNKNOWN_ERROR;
   service_->InstallLinuxPackage(
diff --git a/chrome/browser/chromeos/crostini/crostini_remover.cc b/chrome/browser/chromeos/crostini/crostini_remover.cc
index 7664142..05b0ebf1 100644
--- a/chrome/browser/chromeos/crostini/crostini_remover.cc
+++ b/chrome/browser/chromeos/crostini/crostini_remover.cc
@@ -75,7 +75,6 @@
       vm_name_, "");
   CrostiniManager::GetForProfile(profile_)->DestroyDiskImage(
       base::FilePath(vm_name_),
-      vm_tools::concierge::StorageLocation::STORAGE_CRYPTOHOME_ROOT,
       base::BindOnce(&CrostiniRemover::DestroyDiskImageFinished, this));
 }
 
diff --git a/chrome/browser/chromeos/kiosk_next_home/app_controller_service.cc b/chrome/browser/chromeos/kiosk_next_home/app_controller_service.cc
index 32ef71d..5a44c492 100644
--- a/chrome/browser/chromeos/kiosk_next_home/app_controller_service.cc
+++ b/chrome/browser/chromeos/kiosk_next_home/app_controller_service.cc
@@ -65,7 +65,7 @@
       app_service_proxy_(apps::AppServiceProxyFactory::GetForProfile(profile)),
       intent_config_helper_(IntentConfigHelper::GetInstance()) {
   DCHECK(profile);
-  app_service_proxy_->AppRegistryCache().AddObserver(this);
+  Observe(&app_service_proxy_->AppRegistryCache());
 
   // Add the chrome://app-icon URL data source.
   // TODO(ltenorio): Move this to a more suitable location when we change
@@ -74,9 +74,7 @@
                               std::make_unique<apps::AppIconSource>(profile));
 }
 
-AppControllerService::~AppControllerService() {
-  app_service_proxy_->AppRegistryCache().RemoveObserver(this);
-}
+AppControllerService::~AppControllerService() = default;
 
 void AppControllerService::BindRequest(mojom::AppControllerRequest request) {
   bindings_.AddBinding(this, std::move(request));
@@ -171,6 +169,11 @@
   }
 }
 
+void AppControllerService::OnAppRegistryCacheWillBeDestroyed(
+    apps::AppRegistryCache* cache) {
+  Observe(nullptr);
+}
+
 void AppControllerService::SetIntentConfigHelperForTesting(
     std::unique_ptr<IntentConfigHelper> helper) {
   intent_config_helper_ = std::move(helper);
diff --git a/chrome/browser/chromeos/kiosk_next_home/app_controller_service.h b/chrome/browser/chromeos/kiosk_next_home/app_controller_service.h
index 2a41796..eb65413 100644
--- a/chrome/browser/chromeos/kiosk_next_home/app_controller_service.h
+++ b/chrome/browser/chromeos/kiosk_next_home/app_controller_service.h
@@ -59,6 +59,8 @@
 
   // apps::AppRegistryCache::Observer:
   void OnAppUpdate(const apps::AppUpdate& update) override;
+  void OnAppRegistryCacheWillBeDestroyed(
+      apps::AppRegistryCache* cache) override;
 
   // Allows overriding the intent config helper for tests.
   void SetIntentConfigHelperForTesting(
diff --git a/chrome/browser/extensions/extension_apitest.cc b/chrome/browser/extensions/extension_apitest.cc
index 5c903214..65051af 100644
--- a/chrome/browser/extensions/extension_apitest.cc
+++ b/chrome/browser/extensions/extension_apitest.cc
@@ -259,11 +259,6 @@
         browser_test_flags |=
             ExtensionBrowserTest::kFlagAllowOldManifestVersions;
       }
-      if (flags & kFlagRunAsServiceWorkerBasedExtension) {
-        browser_test_flags |=
-            ExtensionBrowserTest::kFlagRunAsServiceWorkerBasedExtension;
-      }
-
       extension = LoadExtensionWithFlags(extension_path, browser_test_flags);
     }
     if (!extension) {
diff --git a/chrome/browser/extensions/extension_apitest.h b/chrome/browser/extensions/extension_apitest.h
index 8253bf58..23400bc 100644
--- a/chrome/browser/extensions/extension_apitest.h
+++ b/chrome/browser/extensions/extension_apitest.h
@@ -61,10 +61,6 @@
     // Load the extension using //extensions/test/data/ as the root path instead
     // of loading from //chrome/test/data/extensions/api_test/.
     kFlagUseRootExtensionsDir = 1 << 7,
-
-    // Load the event page extension as a Service Worker based background
-    // extension.
-    kFlagRunAsServiceWorkerBasedExtension = 1 << 8,
   };
 
   ExtensionApiTest();
diff --git a/chrome/browser/extensions/extension_browsertest.cc b/chrome/browser/extensions/extension_browsertest.cc
index 0c4199a5..d6e9c59 100644
--- a/chrome/browser/extensions/extension_browsertest.cc
+++ b/chrome/browser/extensions/extension_browsertest.cc
@@ -16,7 +16,6 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
-#include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
@@ -68,12 +67,8 @@
 #include "extensions/browser/notification_types.h"
 #include "extensions/browser/test_extension_registry_observer.h"
 #include "extensions/browser/uninstall_reason.h"
-#include "extensions/common/constants.h"
 #include "extensions/common/extension_set.h"
-#include "extensions/common/file_test_util.h"
-#include "extensions/common/file_util.h"
 #include "extensions/common/switches.h"
-#include "extensions/common/value_builder.h"
 #include "net/url_request/url_request_file_job.h"
 
 #if defined(OS_CHROMEOS)
@@ -242,12 +237,7 @@
 
 const Extension* ExtensionBrowserTest::LoadExtensionWithFlags(
     const base::FilePath& path, int flags) {
-  base::FilePath extension_path = path;
-  if (flags & kFlagRunAsServiceWorkerBasedExtension) {
-    if (!CreateServiceWorkerBasedExtension(path, &extension_path))
-      return nullptr;
-  }
-  return LoadExtensionWithInstallParam(extension_path, flags, std::string());
+  return LoadExtensionWithInstallParam(path, flags, std::string());
 }
 
 const Extension* ExtensionBrowserTest::LoadExtensionWithInstallParam(
@@ -268,123 +258,6 @@
   return extension.get();
 }
 
-bool ExtensionBrowserTest::CreateServiceWorkerBasedExtension(
-    const base::FilePath& path,
-    base::FilePath* out_path) {
-  base::ScopedAllowBlockingForTesting allow_blocking;
-
-  // This dir will contain all files for the Service Worker based extension.
-  base::FilePath temp_extension_container;
-  if (!base::CreateTemporaryDirInDir(temp_dir_.GetPath(),
-                                     base::FilePath::StringType(),
-                                     &temp_extension_container)) {
-    ADD_FAILURE() << "Could not create temporary dir for test under "
-                  << temp_dir_.GetPath();
-    return false;
-  }
-
-  // Copy all files from test dir to temp dir.
-  if (!base::CopyDirectory(path, temp_extension_container,
-                           true /* recursive */)) {
-    ADD_FAILURE() << path.value() << " could not be copied to "
-                  << temp_extension_container.value();
-    return false;
-  }
-
-  const base::FilePath extension_root =
-      temp_extension_container.Append(path.BaseName());
-
-  std::string error;
-  std::unique_ptr<base::DictionaryValue> manifest_dict =
-      file_util::LoadManifest(extension_root, &error);
-  if (!manifest_dict) {
-    ADD_FAILURE() << path.value() << " could not load manifest: " << error;
-    return false;
-  }
-
-  // Retrieve the value of the "background" key and verify that it is
-  // non-persistent and specifies JS files.
-  // Persistent background pages or background pages that specify HTML files
-  // are not supported.
-  base::Value* background_dict =
-      manifest_dict->FindKeyOfType("background", base::Value::Type::DICTIONARY);
-  if (!background_dict) {
-    ADD_FAILURE() << path.value()
-                  << " 'background' key not found in manifest.json";
-    return false;
-  }
-  {
-    base::Value* background_persistent = background_dict->FindKeyOfType(
-        "persistent", base::Value::Type::BOOLEAN);
-    if (!background_persistent || background_persistent->GetBool()) {
-      ADD_FAILURE() << path.value()
-                    << ": Only event pages can be loaded as SW extension.";
-      return false;
-    }
-  }
-  base::Value* background_scripts_list =
-      background_dict->FindKeyOfType("scripts", base::Value::Type::LIST);
-  if (!background_scripts_list) {
-    ADD_FAILURE() << path.value()
-                  << ": Only event pages with JS script(s) can be loaded "
-                     "as SW extension.";
-    return false;
-  }
-
-  // Number of JS scripts must be > 1.
-  base::Value::ListStorage& scripts_list = background_scripts_list->GetList();
-  if (scripts_list.size() < 1) {
-    ADD_FAILURE() << path.value()
-                  << ": Only event pages with JS script(s) can be loaded "
-                     " as SW extension.";
-    return false;
-  }
-
-  // Generate combined script as Service Worker script using importScripts().
-  constexpr const char kGeneratedSWFileName[] = "generated_service_worker__.js";
-
-  std::vector<std::string> script_filenames;
-  for (const base::Value& script : scripts_list)
-    script_filenames.push_back(base::StrCat({"'", script.GetString(), "'"}));
-
-  base::FilePath combined_script_filepath =
-      extension_root.AppendASCII(kGeneratedSWFileName);
-  // Collision with generated script filename.
-  if (base::PathExists(combined_script_filepath)) {
-    ADD_FAILURE() << combined_script_filepath.value()
-                  << " already exists, make sure " << path.value()
-                  << " does not contained file named " << kGeneratedSWFileName;
-    return false;
-  }
-  std::string generated_sw_script_content = base::StringPrintf(
-      "importScripts(%s);", base::JoinString(script_filenames, ",").c_str());
-  if (!file_test_util::WriteFile(combined_script_filepath,
-                                 generated_sw_script_content)) {
-    ADD_FAILURE() << "Could not write combined Service Worker script to: "
-                  << combined_script_filepath.value();
-    return false;
-  }
-
-  // Remove the existing background specification and replace it with a service
-  // worker.
-  background_dict->RemoveKey("persistent");
-  background_dict->RemoveKey("scripts");
-  background_dict->SetStringPath("service_worker", kGeneratedSWFileName);
-
-  // Write out manifest.json.
-  DictionaryBuilder manifest_builder(*manifest_dict);
-  std::string manifest_contents = manifest_builder.ToJSON();
-  base::FilePath manifest_path = extension_root.Append(kManifestFilename);
-  if (!file_test_util::WriteFile(manifest_path, manifest_contents)) {
-    ADD_FAILURE() << "Could not write manifest file to "
-                  << manifest_path.value();
-    return false;
-  }
-
-  *out_path = extension_root;
-  return true;
-}
-
 const Extension* ExtensionBrowserTest::LoadExtensionAsComponentWithManifest(
     const base::FilePath& path,
     const base::FilePath::CharType* manifest_relative_path) {
diff --git a/chrome/browser/extensions/extension_browsertest.h b/chrome/browser/extensions/extension_browsertest.h
index e892d781..cd66718 100644
--- a/chrome/browser/extensions/extension_browsertest.h
+++ b/chrome/browser/extensions/extension_browsertest.h
@@ -62,9 +62,6 @@
     // Allow older manifest versions (typically these can't be loaded - we allow
     // them for testing).
     kFlagAllowOldManifestVersions = 1 << 3,
-
-    // Load the provided extension as Service Worker based extension.
-    kFlagRunAsServiceWorkerBasedExtension = 1 << 4,
   };
 
   ExtensionBrowserTest();
@@ -120,16 +117,6 @@
       int flags,
       const std::string& install_param);
 
-  // Converts an extension from |path| to a Service Worker based extension and
-  // returns true on success.
-  // If successful, |out_path| contains path of the converted extension.
-  //
-  // NOTE: The conversion works only for extensions with background.scripts and
-  // background.persistent = false; persistent background pages and
-  // background.page are not supported.
-  bool CreateServiceWorkerBasedExtension(const base::FilePath& path,
-                                         base::FilePath* out_path);
-
   // Loads unpacked extension from |path| with manifest |manifest_relative_path|
   // and imitates that it is a component extension.
   // |manifest_relative_path| is relative to |path|.
diff --git a/chrome/browser/extensions/service_worker_apitest.cc b/chrome/browser/extensions/service_worker_apitest.cc
index 99be1aa..504187e 100644
--- a/chrome/browser/extensions/service_worker_apitest.cc
+++ b/chrome/browser/extensions/service_worker_apitest.cc
@@ -1777,13 +1777,6 @@
   EXPECT_FALSE(ProcessManager::Get(profile())->HasServiceWorker(*worker_id));
 }
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerBasedBackgroundTest,
-                       ChromeRuntimeOpenOptionsPage) {
-  ASSERT_TRUE(RunExtensionTestWithFlags("runtime/open_options_page",
-                                        kFlagRunAsServiceWorkerBasedExtension))
-      << message_;
-}
-
 // Tests that console messages logged by extension service workers, both via
 // the typical console.* methods and via our custom bindings console, are
 // passed through the normal ServiceWorker console messaging and are
diff --git a/chrome/browser/notifications/scheduler/BUILD.gn b/chrome/browser/notifications/scheduler/BUILD.gn
index d101031..e749e31 100644
--- a/chrome/browser/notifications/scheduler/BUILD.gn
+++ b/chrome/browser/notifications/scheduler/BUILD.gn
@@ -26,6 +26,9 @@
     "notification_params.cc",
     "notification_params.h",
     "notification_schedule_service.h",
+    "notification_scheduler_client.h",
+    "notification_scheduler_client_registrar.cc",
+    "notification_scheduler_client_registrar.h",
     "notification_scheduler_types.h",
     "schedule_params.cc",
     "schedule_params.h",
@@ -35,6 +38,7 @@
   deps = [
     "//base",
     "//components/keyed_service/core",
+    "//skia",
   ]
 }
 
@@ -112,6 +116,7 @@
     "//chrome/browser/notifications/proto",
     "//components/keyed_service/core",
     "//components/leveldb_proto",
+    "//skia",
   ]
 }
 
diff --git a/chrome/browser/notifications/scheduler/notification_schedule_service_factory.cc b/chrome/browser/notifications/scheduler/notification_schedule_service_factory.cc
index 3dfe2e9..b884da0 100644
--- a/chrome/browser/notifications/scheduler/notification_schedule_service_factory.cc
+++ b/chrome/browser/notifications/scheduler/notification_schedule_service_factory.cc
@@ -9,6 +9,7 @@
 
 #include "chrome/browser/notifications/scheduler/notification_background_task_scheduler_impl.h"
 #include "chrome/browser/notifications/scheduler/notification_schedule_service.h"
+#include "chrome/browser/notifications/scheduler/notification_scheduler_client_registrar.h"
 #include "chrome/browser/notifications/scheduler/notification_scheduler_context.h"
 #include "chrome/browser/notifications/scheduler/schedule_service_factory_helper.h"
 #include "chrome/browser/profiles/incognito_helpers.h"
@@ -17,6 +18,18 @@
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/leveldb_proto/content/proto_database_provider_factory.h"
 
+namespace {
+std::unique_ptr<notifications::NotificationSchedulerClientRegistrar>
+RegisterClients() {
+  auto client_registrar =
+      std::make_unique<notifications::NotificationSchedulerClientRegistrar>();
+  // TODO(xingliu): Register clients here.
+
+  return client_registrar;
+}
+
+}  // namespace
+
 // static
 NotificationScheduleServiceFactory*
 NotificationScheduleServiceFactory::GetInstance() {
@@ -47,12 +60,14 @@
   auto* profile = Profile::FromBrowserContext(context);
   base::FilePath storage_dir =
       profile->GetPath().Append(chrome::kNotificationSchedulerStorageDirname);
+  auto client_registrar = RegisterClients();
   auto background_task_scheduler =
       std::make_unique<NotificationBackgroundTaskSchedulerImpl>();
   auto* db_provider = leveldb_proto::ProtoDatabaseProviderFactory::GetForKey(
       profile->GetProfileKey());
   return notifications::CreateNotificationScheduleService(
-      std::move(background_task_scheduler), db_provider, storage_dir);
+      std::move(client_registrar), std::move(background_task_scheduler),
+      db_provider, storage_dir);
 }
 
 content::BrowserContext*
diff --git a/chrome/browser/notifications/scheduler/notification_scheduler.cc b/chrome/browser/notifications/scheduler/notification_scheduler.cc
index 0695899..11f3a07 100644
--- a/chrome/browser/notifications/scheduler/notification_scheduler.cc
+++ b/chrome/browser/notifications/scheduler/notification_scheduler.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/notifications/scheduler/notification_scheduler.h"
 
 #include <utility>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/logging.h"
@@ -17,6 +18,8 @@
 #include "chrome/browser/notifications/scheduler/notification_background_task_scheduler.h"
 #include "chrome/browser/notifications/scheduler/notification_entry.h"
 #include "chrome/browser/notifications/scheduler/notification_params.h"
+#include "chrome/browser/notifications/scheduler/notification_scheduler_client.h"
+#include "chrome/browser/notifications/scheduler/notification_scheduler_client_registrar.h"
 #include "chrome/browser/notifications/scheduler/notification_scheduler_context.h"
 #include "chrome/browser/notifications/scheduler/scheduled_notification_manager.h"
 
@@ -160,8 +163,11 @@
     for (const auto& client_state : client_states) {
       client_state_ptrs.emplace(client_state.first, client_state.second.get());
     }
+    std::vector<SchedulerClientType> clients;
+    context_->client_registrar()->GetRegisteredClients(&clients);
+
     context_->display_decider()->FindNotificationsToShow(
-        context_->config(), context_->clients(), DistributionPolicy::Create(),
+        context_->config(), std::move(clients), DistributionPolicy::Create(),
         task_start_time, std::move(notifications), std::move(client_state_ptrs),
         &results);
 
diff --git a/chrome/browser/notifications/scheduler/notification_scheduler_client.h b/chrome/browser/notifications/scheduler/notification_scheduler_client.h
new file mode 100644
index 0000000..1272f6e
--- /dev/null
+++ b/chrome/browser/notifications/scheduler/notification_scheduler_client.h
@@ -0,0 +1,77 @@
+// 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_NOTIFICATIONS_SCHEDULER_NOTIFICATION_SCHEDULER_CLIENT_H_
+#define CHROME_BROWSER_NOTIFICATIONS_SCHEDULER_NOTIFICATION_SCHEDULER_CLIENT_H_
+
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/optional.h"
+#include "chrome/browser/notifications/scheduler/notification_data.h"
+#include "chrome/browser/notifications/scheduler/notification_scheduler_types.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+namespace notifications {
+
+// The client interface to receive events from notification scheduler.
+class NotificationSchedulerClient {
+ public:
+  struct DisplayData {
+    NotificationData notification_data;
+    SkBitmap icon;
+  };
+
+  // Defines user actions type.
+  enum class UserActionType {
+    // The user clicks on the notification body.
+    kClick = 0,
+    // The user clicks on the notification button.
+    kButtonClick = 1,
+    // The user dismisses the notification.
+    kDismiss = 2,
+  };
+
+  // Information about button clicks.
+  struct ButtonClickInfo {
+    // Unique id of the button.
+    std::string button_id;
+
+    // Associate impression type for the button.
+    ActionButtonType type = ActionButtonType::kUnknownAction;
+  };
+
+  using DisplayCallback =
+      base::OnceCallback<void(std::unique_ptr<DisplayData>)>;
+
+  NotificationSchedulerClient();
+  virtual ~NotificationSchedulerClient();
+
+  // Called when the notification should be displayed to the user. The clients
+  // can overwrite data in |display_data| and return the updated data in
+  // |callback|.
+  virtual void ShowNotification(std::unique_ptr<DisplayData> display_data,
+                                DisplayCallback callback) = 0;
+
+  // Called when scheduler is initialized, number of notification scheduled for
+  // this type is reported if initialization succeeded.
+  virtual void OnSchedulerInitialized(bool success,
+                                      std::set<std::string> guids) = 0;
+
+  // Called when the user interacts with the notification.
+  virtual void OnUserAction(UserActionType action_type,
+                            const std::string& notification_id,
+                            base::Optional<ButtonClickInfo> button_info) = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NotificationSchedulerClient);
+};
+
+}  // namespace notifications
+
+#endif  // CHROME_BROWSER_NOTIFICATIONS_SCHEDULER_NOTIFICATION_SCHEDULER_CLIENT_H_
diff --git a/chrome/browser/notifications/scheduler/notification_scheduler_client_registrar.cc b/chrome/browser/notifications/scheduler/notification_scheduler_client_registrar.cc
new file mode 100644
index 0000000..f753f7d
--- /dev/null
+++ b/chrome/browser/notifications/scheduler/notification_scheduler_client_registrar.cc
@@ -0,0 +1,44 @@
+// 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/notifications/scheduler/notification_scheduler_client_registrar.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "chrome/browser/notifications/scheduler/notification_scheduler_client.h"
+
+namespace notifications {
+
+NotificationSchedulerClientRegistrar::NotificationSchedulerClientRegistrar() =
+    default;
+
+NotificationSchedulerClientRegistrar::~NotificationSchedulerClientRegistrar() =
+    default;
+
+void NotificationSchedulerClientRegistrar::RegisterClient(
+    SchedulerClientType type,
+    std::unique_ptr<NotificationSchedulerClient> client) {
+  DCHECK(clients_.find(type) == clients_.end());
+  clients_.emplace(type, std::move(client));
+}
+
+NotificationSchedulerClient* NotificationSchedulerClientRegistrar::GetClient(
+    SchedulerClientType type) {
+  auto it = clients_.find(type);
+  if (it == clients_.end())
+    return nullptr;
+  return it->second.get();
+}
+
+void NotificationSchedulerClientRegistrar::GetRegisteredClients(
+    std::vector<SchedulerClientType>* clients) const {
+  DCHECK(clients);
+  clients->clear();
+  for (const auto& pair : clients_) {
+    clients->emplace_back(pair.first);
+  }
+}
+
+}  // namespace notifications
diff --git a/chrome/browser/notifications/scheduler/notification_scheduler_client_registrar.h b/chrome/browser/notifications/scheduler/notification_scheduler_client_registrar.h
new file mode 100644
index 0000000..ed463cb
--- /dev/null
+++ b/chrome/browser/notifications/scheduler/notification_scheduler_client_registrar.h
@@ -0,0 +1,47 @@
+// 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_NOTIFICATIONS_SCHEDULER_NOTIFICATION_SCHEDULER_CLIENT_REGISTRAR_H_
+#define CHROME_BROWSER_NOTIFICATIONS_SCHEDULER_NOTIFICATION_SCHEDULER_CLIENT_REGISTRAR_H_
+
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "chrome/browser/notifications/scheduler/notification_scheduler_types.h"
+
+namespace notifications {
+
+class NotificationSchedulerClient;
+
+// Registers and maintains a list of NotificationSchedulerClient
+// implementations.
+class NotificationSchedulerClientRegistrar {
+ public:
+  NotificationSchedulerClientRegistrar();
+  ~NotificationSchedulerClientRegistrar();
+
+  // Registers a client into notification scheduler system.
+  void RegisterClient(SchedulerClientType type,
+                      std::unique_ptr<NotificationSchedulerClient> client);
+
+  // Gets a NotificationSchedulerClient, nullptr if the type doesn't exist.
+  NotificationSchedulerClient* GetClient(SchedulerClientType type);
+
+  // Gets a list of registered clients, sorted by integer value of
+  // SchedulerClientType.
+  void GetRegisteredClients(std::vector<SchedulerClientType>* clients) const;
+
+ private:
+  using ClientsMap = std::map<SchedulerClientType,
+                              std::unique_ptr<NotificationSchedulerClient>>;
+  ClientsMap clients_;
+
+  DISALLOW_COPY_AND_ASSIGN(NotificationSchedulerClientRegistrar);
+};
+
+}  // namespace notifications
+
+#endif  // CHROME_BROWSER_NOTIFICATIONS_SCHEDULER_NOTIFICATION_SCHEDULER_CLIENT_REGISTRAR_H_
diff --git a/chrome/browser/notifications/scheduler/notification_scheduler_context.cc b/chrome/browser/notifications/scheduler/notification_scheduler_context.cc
index 7920d19..799dd68 100644
--- a/chrome/browser/notifications/scheduler/notification_scheduler_context.cc
+++ b/chrome/browser/notifications/scheduler/notification_scheduler_context.cc
@@ -10,19 +10,22 @@
 #include "chrome/browser/notifications/scheduler/icon_store.h"
 #include "chrome/browser/notifications/scheduler/impression_history_tracker.h"
 #include "chrome/browser/notifications/scheduler/notification_background_task_scheduler.h"
+#include "chrome/browser/notifications/scheduler/notification_scheduler_client_registrar.h"
 #include "chrome/browser/notifications/scheduler/scheduled_notification_manager.h"
 #include "chrome/browser/notifications/scheduler/scheduler_config.h"
 
 namespace notifications {
 
 NotificationSchedulerContext::NotificationSchedulerContext(
+    std::unique_ptr<NotificationSchedulerClientRegistrar> client_registrar,
     std::unique_ptr<NotificationBackgroundTaskScheduler> scheduler,
     std::unique_ptr<IconStore> icon_store,
     std::unique_ptr<ImpressionHistoryTracker> impression_tracker,
     std::unique_ptr<ScheduledNotificationManager> notification_manager,
     std::unique_ptr<DisplayDecider> display_decider,
     std::unique_ptr<SchedulerConfig> config)
-    : background_task_scheduler_(std::move(scheduler)),
+    : client_registrar_(std::move(client_registrar)),
+      background_task_scheduler_(std::move(scheduler)),
       impression_tracker_(std::move(impression_tracker)),
       notification_manager_(std::move(notification_manager)),
       display_decider_(std::move(display_decider)),
diff --git a/chrome/browser/notifications/scheduler/notification_scheduler_context.h b/chrome/browser/notifications/scheduler/notification_scheduler_context.h
index ccf466f..87d2a52 100644
--- a/chrome/browser/notifications/scheduler/notification_scheduler_context.h
+++ b/chrome/browser/notifications/scheduler/notification_scheduler_context.h
@@ -17,6 +17,7 @@
 class IconStore;
 class ImpressionHistoryTracker;
 class NotificationBackgroundTaskScheduler;
+class NotificationSchedulerClientRegistrar;
 class ScheduledNotificationManager;
 struct SchedulerConfig;
 
@@ -25,6 +26,7 @@
 class NotificationSchedulerContext {
  public:
   NotificationSchedulerContext(
+      std::unique_ptr<NotificationSchedulerClientRegistrar> client_registrar,
       std::unique_ptr<NotificationBackgroundTaskScheduler> scheduler,
       std::unique_ptr<IconStore> icon_store,
       std::unique_ptr<ImpressionHistoryTracker> impression_tracker,
@@ -33,7 +35,9 @@
       std::unique_ptr<SchedulerConfig> config);
   ~NotificationSchedulerContext();
 
-  const std::vector<SchedulerClientType>& clients() const { return clients_; }
+  NotificationSchedulerClientRegistrar* client_registrar() {
+    return client_registrar_.get();
+  }
 
   NotificationBackgroundTaskScheduler* background_task_scheduler() {
     return background_task_scheduler_.get();
@@ -54,9 +58,8 @@
   const SchedulerConfig* config() const { return config_.get(); }
 
  private:
-  // List of clients using the notification scheduler system.
-  // TODO(xingliu): Pass in the registered the clients.
-  std::vector<SchedulerClientType> clients_;
+  // Holds a list of clients using the notification scheduler system.
+  std::unique_ptr<NotificationSchedulerClientRegistrar> client_registrar_;
 
   // Used to schedule background task in OS level.
   std::unique_ptr<NotificationBackgroundTaskScheduler>
diff --git a/chrome/browser/notifications/scheduler/notification_scheduler_types.h b/chrome/browser/notifications/scheduler/notification_scheduler_types.h
index 95decdff..2bb7488 100644
--- a/chrome/browser/notifications/scheduler/notification_scheduler_types.h
+++ b/chrome/browser/notifications/scheduler/notification_scheduler_types.h
@@ -52,7 +52,8 @@
   kMaxValue = kIgnore
 };
 
-// The user impression of a particular notification.
+// The user impression of a particular notification, which may impact the
+// notification display frenquency.
 enum class ImpressionResult {
   // Invalid user impression.
   kInvalid = 0,
@@ -65,6 +66,19 @@
   kMaxValue = kNeutral
 };
 
+// Categorizes type of notification buttons. Different type of button clicks
+// may result in change of notification shown frequency.
+enum class ActionButtonType {
+  // The action button is not categorized.
+  kUnknownAction = 0,
+
+  // Helpful button indicates the user likes to interact with the notification.
+  kHelpful = 1,
+
+  // Unhelpful button indicates dislike of the notification.
+  kUnhelpful = 2,
+};
+
 }  // namespace notifications
 
 #endif  // CHROME_BROWSER_NOTIFICATIONS_SCHEDULER_NOTIFICATION_SCHEDULER_TYPES_H_
diff --git a/chrome/browser/notifications/scheduler/schedule_service_factory_helper.cc b/chrome/browser/notifications/scheduler/schedule_service_factory_helper.cc
index abe5f4b5..f9f19a9f 100644
--- a/chrome/browser/notifications/scheduler/schedule_service_factory_helper.cc
+++ b/chrome/browser/notifications/scheduler/schedule_service_factory_helper.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/notifications/scheduler/init_aware_scheduler.h"
 #include "chrome/browser/notifications/scheduler/notification_background_task_scheduler.h"
 #include "chrome/browser/notifications/scheduler/notification_schedule_service_impl.h"
+#include "chrome/browser/notifications/scheduler/notification_scheduler_client_registrar.h"
 #include "chrome/browser/notifications/scheduler/notification_scheduler_context.h"
 #include "chrome/browser/notifications/scheduler/notification_store.h"
 #include "chrome/browser/notifications/scheduler/scheduled_notification_manager.h"
@@ -32,6 +33,7 @@
 }  // namespace
 
 KeyedService* CreateNotificationScheduleService(
+    std::unique_ptr<NotificationSchedulerClientRegistrar> client_registrar,
     std::unique_ptr<NotificationBackgroundTaskScheduler>
         background_task_scheduler,
     leveldb_proto::ProtoDatabaseProvider* db_provider,
@@ -71,9 +73,10 @@
   notification_manager->Create(std::move(notification_store));
 
   auto context = std::make_unique<NotificationSchedulerContext>(
-      std::move(background_task_scheduler), std::move(icon_store),
-      std::move(impression_tracker), std::move(notification_manager),
-      DisplayDecider::Create(), std::move(config));
+      std::move(client_registrar), std::move(background_task_scheduler),
+      std::move(icon_store), std::move(impression_tracker),
+      std::move(notification_manager), DisplayDecider::Create(),
+      std::move(config));
 
   auto scheduler = NotificationScheduler::Create(std::move(context));
   auto init_aware_scheduler =
diff --git a/chrome/browser/notifications/scheduler/schedule_service_factory_helper.h b/chrome/browser/notifications/scheduler/schedule_service_factory_helper.h
index dc63610..e2a6a9f 100644
--- a/chrome/browser/notifications/scheduler/schedule_service_factory_helper.h
+++ b/chrome/browser/notifications/scheduler/schedule_service_factory_helper.h
@@ -18,11 +18,13 @@
 namespace notifications {
 
 class NotificationBackgroundTaskScheduler;
+class NotificationSchedulerClientRegistrar;
 
 // Creates the notification schedule service with all the embedder level
 // dependencies. This layer is mainly to forbid the embedder to depend on
 // notification scheduler internal code.
 KeyedService* CreateNotificationScheduleService(
+    std::unique_ptr<NotificationSchedulerClientRegistrar> client_registrar,
     std::unique_ptr<NotificationBackgroundTaskScheduler>
         background_task_scheduler,
     leveldb_proto::ProtoDatabaseProvider* db_provider,
diff --git a/chrome/browser/notifications/scheduler/user_action_handler.h b/chrome/browser/notifications/scheduler/user_action_handler.h
index 7f92465..d06b7fc 100644
--- a/chrome/browser/notifications/scheduler/user_action_handler.h
+++ b/chrome/browser/notifications/scheduler/user_action_handler.h
@@ -11,19 +11,6 @@
 
 namespace notifications {
 
-// Categorizes type of notification buttons. Different type of button clicks
-// may result in change of notification shown frequency.
-enum class ActionButtonType {
-  // The action button is not categorized.
-  kUnknownAction = 0,
-
-  // Helpful button indicates the user likes to interact with the notification.
-  kHelpful = 1,
-
-  // Unhelpful button indicates dislike of the notification.
-  kUnhelpful = 2,
-};
-
 // An interface to plumb user actions events to notification scheduling system.
 // Each event needs to provide an unique id of the notification shown.
 class UserActionHandler {
diff --git a/chrome/browser/password_manager/account_chooser_dialog_android_unittest.cc b/chrome/browser/password_manager/account_chooser_dialog_android_unittest.cc
index 14b0607..7fec5b2c 100644
--- a/chrome/browser/password_manager/account_chooser_dialog_android_unittest.cc
+++ b/chrome/browser/password_manager/account_chooser_dialog_android_unittest.cc
@@ -21,7 +21,7 @@
 namespace {
 
 password_manager::PasswordFormData kFormData = {
-    autofill::PasswordForm::SCHEME_HTML,
+    autofill::PasswordForm::Scheme::kHtml,
     "http://example.com/",
     "http://example.com/origin",
     "http://example.com/action",
diff --git a/chrome/browser/password_manager/native_backend_gnome_x.cc b/chrome/browser/password_manager/native_backend_gnome_x.cc
index 617ccf09c..e2b0f4d 100644
--- a/chrome/browser/password_manager/native_backend_gnome_x.cc
+++ b/chrome/browser/password_manager/native_backend_gnome_x.cc
@@ -377,7 +377,7 @@
   if (!password_manager::ShouldPSLDomainMatchingApply(
           password_manager::GetRegistryControlledDomain(
               GURL(form.signon_realm))) &&
-      form.scheme != PasswordForm::SCHEME_HTML) {
+      form.scheme != PasswordForm::Scheme::kHtml) {
     // Don't retrieve the PSL matched and federated credentials.
     AppendString(&attrs, "signon_realm", form.signon_realm);
   }
diff --git a/chrome/browser/password_manager/native_backend_gnome_x_unittest.cc b/chrome/browser/password_manager/native_backend_gnome_x_unittest.cc
index 1d8786ab..2753095 100644
--- a/chrome/browser/password_manager/native_backend_gnome_x_unittest.cc
+++ b/chrome/browser/password_manager/native_backend_gnome_x_unittest.cc
@@ -368,7 +368,7 @@
     form_google_.password_value = UTF8ToUTF16("seekrit");
     form_google_.submit_element = UTF8ToUTF16("submit");
     form_google_.signon_realm = "http://www.google.com/";
-    form_google_.type = PasswordForm::TYPE_GENERATED;
+    form_google_.type = PasswordForm::Type::kGenerated;
     form_google_.date_created = base::Time::Now();
     form_google_.date_synced = base::Time::Now();
     form_google_.display_name = UTF8ToUTF16("Joe Schmoe");
@@ -376,7 +376,8 @@
     form_google_.federation_origin =
         url::Origin::Create(GURL("http://www.google.com/"));
     form_google_.skip_zero_click = true;
-    form_google_.generation_upload_status = PasswordForm::POSITIVE_SIGNAL_SENT;
+    form_google_.generation_upload_status =
+        PasswordForm::GenerationUploadStatus::kPositiveSignalSent;
     form_google_.form_data.name = UTF8ToUTF16("form_name");
 
     form_facebook_.origin = GURL("http://www.facebook.com/");
@@ -394,7 +395,8 @@
     form_facebook_.federation_origin =
         url::Origin::Create(GURL("http://www.facebook.com/"));
     form_facebook_.skip_zero_click = true;
-    form_facebook_.generation_upload_status = PasswordForm::NO_SIGNAL_SENT;
+    form_facebook_.generation_upload_status =
+        PasswordForm::GenerationUploadStatus::kNoSignalSent;
 
     form_isc_.origin = GURL("http://www.isc.org/");
     form_isc_.action = GURL("http://www.isc.org/auth");
@@ -459,9 +461,9 @@
     CheckUint32Attribute(item, "preferred", form.preferred);
     // We don't check the date created. It varies.
     CheckUint32Attribute(item, "blacklisted_by_user", form.blacklisted_by_user);
-    CheckUint32Attribute(item, "type", form.type);
+    CheckUint32Attribute(item, "type", static_cast<uint32_t>(form.type));
     CheckUint32Attribute(item, "times_used", form.times_used);
-    CheckUint32Attribute(item, "scheme", form.scheme);
+    CheckUint32Attribute(item, "scheme", static_cast<uint32_t>(form.scheme));
     CheckStringAttribute(
         item, "date_synced",
         base::NumberToString(form.date_synced.ToInternalValue()));
@@ -475,7 +477,7 @@
                              : form.federation_origin.Serialize());
     CheckUint32Attribute(item, "should_skip_zero_click", form.skip_zero_click);
     CheckUint32Attribute(item, "generation_upload_status",
-                         form.generation_upload_status);
+                         static_cast<uint32_t>(form.generation_upload_status));
     CheckStringAttribute(item, "application", app_string);
     autofill::FormData actual;
     DeserializeFormDataFromBase64String(
@@ -500,7 +502,7 @@
                        base::Unretained(&backend), credentials));
 
     PasswordStore::FormDigest target_form = {scheme, url.spec(), url};
-    if (scheme != PasswordForm::SCHEME_HTML) {
+    if (scheme != PasswordForm::Scheme::kHtml) {
       // For non-HTML forms, the realm used for authentication
       // (http://tools.ietf.org/html/rfc1945#section-10.2) is appended to the
       // signon_realm. Just use a default value for now.
@@ -550,7 +552,7 @@
     // Get the PSL-matched copy of the saved login for m.facebook.
     const GURL kMobileURL("http://m.facebook.com/");
     PasswordStore::FormDigest m_facebook_lookup = {
-        PasswordForm::SCHEME_HTML, kMobileURL.spec(), kMobileURL};
+        PasswordForm::Scheme::kHtml, kMobileURL.spec(), kMobileURL};
     std::vector<std::unique_ptr<PasswordForm>> form_list;
     base::PostTaskAndReplyWithResult(
         backend.GetBackgroundTaskRunner().get(), FROM_HERE,
@@ -656,9 +658,9 @@
     other_auth_.scheme = scheme;
 
     // Don't match a non-HTML form with an HTML form.
-    EXPECT_FALSE(CheckCredentialAvailability(
-        other_auth_, GURL("http://www.example.com"),
-        PasswordForm::SCHEME_HTML, nullptr));
+    EXPECT_FALSE(
+        CheckCredentialAvailability(other_auth_, GURL("http://www.example.com"),
+                                    PasswordForm::Scheme::kHtml, nullptr));
     // Don't match an HTML form with non-HTML auth form.
     EXPECT_FALSE(CheckCredentialAvailability(
         form_google_, GURL("http://www.google.com/"), scheme, nullptr));
@@ -795,7 +797,7 @@
   PasswordForm result;
   const GURL kMobileURL("http://m.facebook.com/");
   EXPECT_TRUE(CheckCredentialAvailability(
-      form_facebook_, kMobileURL, PasswordForm::SCHEME_HTML, &result));
+      form_facebook_, kMobileURL, PasswordForm::Scheme::kHtml, &result));
   EXPECT_EQ(form_facebook_.origin, result.origin);
   EXPECT_EQ(form_facebook_.signon_realm, result.signon_realm);
 }
@@ -805,21 +807,21 @@
 TEST_F(NativeBackendGnomeTest, PSLMatchingNegativeDomainMismatch) {
   EXPECT_FALSE(CheckCredentialAvailability(
       form_facebook_, GURL("http://m-facebook.com/"),
-      PasswordForm::SCHEME_HTML, nullptr));
+      PasswordForm::Scheme::kHtml, nullptr));
 }
 
 // Test PSL matching is off for domains excluded from it.
 TEST_F(NativeBackendGnomeTest, PSLMatchingDisabledDomains) {
-  EXPECT_FALSE(CheckCredentialAvailability(
-      form_google_, GURL("http://one.google.com/"),
-      PasswordForm::SCHEME_HTML, nullptr));
+  EXPECT_FALSE(
+      CheckCredentialAvailability(form_google_, GURL("http://one.google.com/"),
+                                  PasswordForm::Scheme::kHtml, nullptr));
 }
 
 // Make sure PSL matches aren't available for non-HTML forms.
 TEST_F(NativeBackendGnomeTest, PSLMatchingDisabledForNonHTMLForms) {
-  CheckMatchingWithScheme(PasswordForm::SCHEME_BASIC);
-  CheckMatchingWithScheme(PasswordForm::SCHEME_DIGEST);
-  CheckMatchingWithScheme(PasswordForm::SCHEME_OTHER);
+  CheckMatchingWithScheme(PasswordForm::Scheme::kBasic);
+  CheckMatchingWithScheme(PasswordForm::Scheme::kDigest);
+  CheckMatchingWithScheme(PasswordForm::Scheme::kOther);
 }
 
 TEST_F(NativeBackendGnomeTest, PSLUpdatingStrictUpdateLogin) {
@@ -835,9 +837,9 @@
   other_auth_.origin = GURL("https://www.example.com/");
   other_auth_.federation_origin =
       url::Origin::Create(GURL("https://google.com/"));
-  EXPECT_TRUE(CheckCredentialAvailability(other_auth_,
-                                          GURL("https://www.example.com/"),
-                                          PasswordForm::SCHEME_HTML, nullptr));
+  EXPECT_TRUE(
+      CheckCredentialAvailability(other_auth_, GURL("https://www.example.com/"),
+                                  PasswordForm::Scheme::kHtml, nullptr));
 }
 
 TEST_F(NativeBackendGnomeTest, FetchFederatedCredentialOnLocalhost) {
@@ -845,9 +847,9 @@
   other_auth_.origin = GURL("http://localhost:8080/");
   other_auth_.federation_origin =
       url::Origin::Create(GURL("https://google.com/"));
-  EXPECT_TRUE(CheckCredentialAvailability(other_auth_,
-                                          GURL("http://localhost:8080/"),
-                                          PasswordForm::SCHEME_HTML, nullptr));
+  EXPECT_TRUE(
+      CheckCredentialAvailability(other_auth_, GURL("http://localhost:8080/"),
+                                  PasswordForm::Scheme::kHtml, nullptr));
 }
 
 TEST_F(NativeBackendGnomeTest, DontFetchFederatedCredentialOnHTTP) {
@@ -855,9 +857,9 @@
   other_auth_.origin = GURL("https://www.example.com/");
   other_auth_.federation_origin =
       url::Origin::Create(GURL("https://google.com/"));
-  EXPECT_FALSE(CheckCredentialAvailability(other_auth_,
-                                           GURL("http://www.example.com/"),
-                                           PasswordForm::SCHEME_HTML, nullptr));
+  EXPECT_FALSE(
+      CheckCredentialAvailability(other_auth_, GURL("http://www.example.com/"),
+                                  PasswordForm::Scheme::kHtml, nullptr));
 }
 
 TEST_F(NativeBackendGnomeTest, FetchPSLMatchedFederatedCredentialOnHTTPS) {
@@ -865,9 +867,9 @@
   other_auth_.origin = GURL("https://www.sub.example.com/");
   other_auth_.federation_origin =
       url::Origin::Create(GURL("https://google.com/"));
-  EXPECT_TRUE(CheckCredentialAvailability(other_auth_,
-                                          GURL("https://www.example.com/"),
-                                          PasswordForm::SCHEME_HTML, nullptr));
+  EXPECT_TRUE(
+      CheckCredentialAvailability(other_auth_, GURL("https://www.example.com/"),
+                                  PasswordForm::Scheme::kHtml, nullptr));
 }
 
 TEST_F(NativeBackendGnomeTest, DontFetchPSLMatchedFederatedCredentialOnHTTP) {
@@ -875,9 +877,9 @@
   other_auth_.origin = GURL("https://www.sub.example.com/");
   other_auth_.federation_origin =
       url::Origin::Create(GURL("https://google.com/"));
-  EXPECT_FALSE(CheckCredentialAvailability(other_auth_,
-                                           GURL("http://www.example.com/"),
-                                           PasswordForm::SCHEME_HTML, nullptr));
+  EXPECT_FALSE(
+      CheckCredentialAvailability(other_auth_, GURL("http://www.example.com/"),
+                                  PasswordForm::Scheme::kHtml, nullptr));
 }
 
 TEST_F(NativeBackendGnomeTest, BasicUpdateLogin) {
@@ -1125,7 +1127,7 @@
   backend.Init();
 
   PasswordForm saved_android_form;
-  saved_android_form.scheme = PasswordForm::SCHEME_HTML;
+  saved_android_form.scheme = PasswordForm::Scheme::kHtml;
   saved_android_form.signon_realm =
       "android://7x7IDboo8u9YKraUsbmVkuf1-@net.rateflix.app/";
   saved_android_form.username_value = base::UTF8ToUTF16("randomusername");
diff --git a/chrome/browser/password_manager/native_backend_kwallet_x.cc b/chrome/browser/password_manager/native_backend_kwallet_x.cc
index ec4ade5..ecff203fe 100644
--- a/chrome/browser/password_manager/native_backend_kwallet_x.cc
+++ b/chrome/browser/password_manager/native_backend_kwallet_x.cc
@@ -255,7 +255,7 @@
   pickle->WriteInt(kPickleVersion);
   pickle->WriteUInt64(forms.size());
   for (const auto& form : forms) {
-    pickle->WriteInt(form->scheme);
+    pickle->WriteInt(static_cast<int>(form->scheme));
     pickle->WriteString(form->origin.spec());
     pickle->WriteString(form->action.spec());
     pickle->WriteString16(form->username_element);
@@ -266,7 +266,7 @@
     pickle->WriteBool(form->preferred);
     pickle->WriteBool(form->blacklisted_by_user);
     pickle->WriteInt64(form->date_created.ToInternalValue());
-    pickle->WriteInt(form->type);
+    pickle->WriteInt(static_cast<int>(form->type));
     pickle->WriteInt(form->times_used);
     autofill::SerializeFormData(form->form_data, pickle);
     pickle->WriteInt64(form->date_synced.ToInternalValue());
@@ -278,7 +278,7 @@
                             ? std::string()
                             : form->federation_origin.Serialize());
     pickle->WriteBool(form->skip_zero_click);
-    pickle->WriteInt(form->generation_upload_status);
+    pickle->WriteInt(static_cast<int>(form->generation_upload_status));
   }
 }
 
diff --git a/chrome/browser/password_manager/native_backend_kwallet_x_unittest.cc b/chrome/browser/password_manager/native_backend_kwallet_x_unittest.cc
index 3b9ee75..fc406544 100644
--- a/chrome/browser/password_manager/native_backend_kwallet_x_unittest.cc
+++ b/chrome/browser/password_manager/native_backend_kwallet_x_unittest.cc
@@ -141,7 +141,7 @@
 }
 
 void WriteHTMLAttributes(const PasswordForm& form, base::Pickle* pickle) {
-  pickle->WriteInt(form.scheme);
+  pickle->WriteInt(static_cast<int>(form.scheme));
   pickle->WriteString(form.origin.spec());
   pickle->WriteString(form.action.spec());
   pickle->WriteString16(form.username_element);
@@ -190,7 +190,7 @@
 
     form_google_ = old_form_google_;
     form_google_.times_used = 3;
-    form_google_.type = PasswordForm::TYPE_GENERATED;
+    form_google_.type = PasswordForm::Type::kGenerated;
     form_google_.form_data.name = UTF8ToUTF16("form_name");
     form_google_.date_synced = base::Time::Now();
     form_google_.date_created = old_form_google_.date_created;
@@ -199,7 +199,8 @@
     form_google_.federation_origin =
         url::Origin::Create(GURL("http://www.google.com/"));
     form_google_.skip_zero_click = true;
-    form_google_.generation_upload_status = PasswordForm::NEGATIVE_SIGNAL_SENT;
+    form_google_.generation_upload_status =
+        PasswordForm::GenerationUploadStatus::kNegativeSignalSent;
 
     form_isc_.origin = GURL("http://www.isc.org/");
     form_isc_.action = GURL("http://www.isc.org/auth");
@@ -918,7 +919,7 @@
   EXPECT_TRUE(backend.InitWithBus(mock_session_bus_));
 
   PasswordForm saved_android_form;
-  saved_android_form.scheme = PasswordForm::SCHEME_HTML;
+  saved_android_form.scheme = PasswordForm::Scheme::kHtml;
   saved_android_form.signon_realm =
       "android://7x7IDboo8u9YKraUsbmVkuf1-@net.rateflix.app/";
   saved_android_form.username_value = base::UTF8ToUTF16("randomusername");
@@ -1171,7 +1172,7 @@
   pickle->WriteInt64(form.date_created.ToInternalValue());
   if (effective_version < 2)
     return;
-  pickle->WriteInt(form.type);
+  pickle->WriteInt(static_cast<int>(form.type));
   pickle->WriteInt(form.times_used);
   autofill::SerializeFormData(form.form_data, pickle);
   if (effective_version < 3)
@@ -1185,7 +1186,7 @@
   pickle->WriteBool(form.skip_zero_click);
   if (effective_version < 7)
     return;
-  pickle->WriteInt(form.generation_upload_status);
+  pickle->WriteInt(static_cast<int>(form.generation_upload_status));
 }
 
 void NativeBackendKWalletPickleTest::CreateVersion0Pickle(
@@ -1360,19 +1361,19 @@
 // read all combinations in any event.
 
 TEST_F(NativeBackendKWalletPickleTest, ReadsOld32BitHTMLPickles) {
-  CheckVersion0Pickle(true, PasswordForm::SCHEME_HTML);
+  CheckVersion0Pickle(true, PasswordForm::Scheme::kHtml);
 }
 
 TEST_F(NativeBackendKWalletPickleTest, ReadsOld32BitHTTPPickles) {
-  CheckVersion0Pickle(true, PasswordForm::SCHEME_BASIC);
+  CheckVersion0Pickle(true, PasswordForm::Scheme::kBasic);
 }
 
 TEST_F(NativeBackendKWalletPickleTest, ReadsOld64BitHTMLPickles) {
-  CheckVersion0Pickle(false, PasswordForm::SCHEME_HTML);
+  CheckVersion0Pickle(false, PasswordForm::Scheme::kHtml);
 }
 
 TEST_F(NativeBackendKWalletPickleTest, ReadsOld64BitHTTPPickles) {
-  CheckVersion0Pickle(false, PasswordForm::SCHEME_BASIC);
+  CheckVersion0Pickle(false, PasswordForm::Scheme::kBasic);
 }
 
 TEST_F(NativeBackendKWalletPickleTest, CheckVersion1Pickle) {
diff --git a/chrome/browser/password_manager/native_backend_libsecret.cc b/chrome/browser/password_manager/native_backend_libsecret.cc
index 789ecec..dfff4837 100644
--- a/chrome/browser/password_manager/native_backend_libsecret.cc
+++ b/chrome/browser/password_manager/native_backend_libsecret.cc
@@ -407,7 +407,7 @@
       !password_manager::ShouldPSLDomainMatchingApply(
           password_manager::GetRegistryControlledDomain(
               GURL(lookup_form->signon_realm))) &&
-      lookup_form->scheme != PasswordForm::SCHEME_HTML)
+      lookup_form->scheme != PasswordForm::Scheme::kHtml)
     attrs.Append("signon_realm", lookup_form->signon_realm);
 
   LibsecretLoader::SearchHelper helper;
diff --git a/chrome/browser/password_manager/native_backend_libsecret_unittest.cc b/chrome/browser/password_manager/native_backend_libsecret_unittest.cc
index 9651a533..cfdb0d4 100644
--- a/chrome/browser/password_manager/native_backend_libsecret_unittest.cc
+++ b/chrome/browser/password_manager/native_backend_libsecret_unittest.cc
@@ -306,7 +306,7 @@
     form_google_.password_value = UTF8ToUTF16("seekrit");
     form_google_.submit_element = UTF8ToUTF16("submit");
     form_google_.signon_realm = "http://www.google.com/";
-    form_google_.type = PasswordForm::TYPE_GENERATED;
+    form_google_.type = PasswordForm::Type::kGenerated;
     form_google_.date_created = base::Time::Now();
     form_google_.date_synced = base::Time::Now();
     form_google_.display_name = UTF8ToUTF16("Joe Schmoe");
@@ -314,7 +314,8 @@
     form_google_.federation_origin =
         url::Origin::Create(GURL("http://www.google.com/"));
     form_google_.skip_zero_click = true;
-    form_google_.generation_upload_status = PasswordForm::POSITIVE_SIGNAL_SENT;
+    form_google_.generation_upload_status =
+        PasswordForm::GenerationUploadStatus::kPositiveSignalSent;
     form_google_.form_data.name = UTF8ToUTF16("form_name");
 
     form_facebook_.origin = GURL("http://www.facebook.com/");
@@ -332,7 +333,8 @@
     form_facebook_.federation_origin =
         url::Origin::Create(GURL("http://www.facebook.com/"));
     form_facebook_.skip_zero_click = true;
-    form_facebook_.generation_upload_status = PasswordForm::NO_SIGNAL_SENT;
+    form_facebook_.generation_upload_status =
+        PasswordForm::GenerationUploadStatus::kNoSignalSent;
 
     form_isc_.origin = GURL("http://www.isc.org/");
     form_isc_.action = GURL("http://www.isc.org/auth");
@@ -410,9 +412,9 @@
     CheckUint32Attribute(item, "preferred", form.preferred);
     // We don't check the date created. It varies.
     CheckUint32Attribute(item, "blacklisted_by_user", form.blacklisted_by_user);
-    CheckUint32Attribute(item, "type", form.type);
+    CheckUint32Attribute(item, "type", static_cast<uint32_t>(form.type));
     CheckUint32Attribute(item, "times_used", form.times_used);
-    CheckUint32Attribute(item, "scheme", form.scheme);
+    CheckUint32Attribute(item, "scheme", static_cast<uint32_t>(form.scheme));
     CheckStringAttribute(
         item, "date_synced",
         base::NumberToString(form.date_synced.ToInternalValue()));
@@ -426,7 +428,7 @@
                              : form.federation_origin.Serialize());
     CheckUint32Attribute(item, "should_skip_zero_click", form.skip_zero_click);
     CheckUint32Attribute(item, "generation_upload_status",
-                         form.generation_upload_status);
+                         static_cast<uint32_t>(form.generation_upload_status));
     CheckStringAttribute(item, "application", app_string);
     autofill::FormData actual;
     DeserializeFormDataFromBase64String(
@@ -447,9 +449,9 @@
 
     VerifiedAdd(&backend, credentials);
 
-    PasswordStore::FormDigest target_form = {PasswordForm::SCHEME_HTML,
+    PasswordStore::FormDigest target_form = {PasswordForm::Scheme::kHtml,
                                              url.spec(), url};
-    if (scheme != PasswordForm::SCHEME_HTML) {
+    if (scheme != PasswordForm::Scheme::kHtml) {
       // For non-HTML forms, the realm used for authentication
       // (http://tools.ietf.org/html/rfc1945#section-10.2) is appended to the
       // signon_realm. Just use a default value for now.
@@ -485,7 +487,7 @@
     // Get the PSL-matched copy of the saved login for m.facebook.
     const GURL kMobileURL("http://m.facebook.com/");
     PasswordStore::FormDigest m_facebook_lookup = {
-        PasswordForm::SCHEME_HTML, kMobileURL.spec(), kMobileURL};
+        PasswordForm::Scheme::kHtml, kMobileURL.spec(), kMobileURL};
     std::vector<std::unique_ptr<PasswordForm>> form_list;
     EXPECT_TRUE(backend.GetLogins(m_facebook_lookup, &form_list));
 
@@ -548,13 +550,13 @@
 
   // Checks various types of matching for forms with a non-HTML |scheme|.
   void CheckMatchingWithScheme(const PasswordForm::Scheme& scheme) {
-    ASSERT_NE(PasswordForm::SCHEME_HTML, scheme);
+    ASSERT_NE(PasswordForm::Scheme::kHtml, scheme);
     other_auth_.scheme = scheme;
 
     // Don't match a non-HTML form with an HTML form.
     EXPECT_FALSE(
         CheckCredentialAvailability(other_auth_, GURL("http://www.example.com"),
-                                    PasswordForm::SCHEME_HTML, nullptr));
+                                    PasswordForm::Scheme::kHtml, nullptr));
     // Don't match an HTML form with non-HTML auth form.
     EXPECT_FALSE(CheckCredentialAvailability(
         form_google_, GURL("http://www.google.com/"), scheme, nullptr));
@@ -675,8 +677,8 @@
 TEST_F(NativeBackendLibsecretTest, PSLMatchingPositive) {
   PasswordForm result;
   const GURL kMobileURL("http://m.facebook.com/");
-  EXPECT_TRUE(CheckCredentialAvailability(form_facebook_, kMobileURL,
-                                          PasswordForm::SCHEME_HTML, &result));
+  EXPECT_TRUE(CheckCredentialAvailability(
+      form_facebook_, kMobileURL, PasswordForm::Scheme::kHtml, &result));
   EXPECT_EQ(form_facebook_.origin, result.origin);
   EXPECT_EQ(form_facebook_.signon_realm, result.signon_realm);
 }
@@ -684,23 +686,23 @@
 // Save a password for www.facebook.com and see it not suggested for
 // m-facebook.com.
 TEST_F(NativeBackendLibsecretTest, PSLMatchingNegativeDomainMismatch) {
-  EXPECT_FALSE(CheckCredentialAvailability(form_facebook_,
-                                           GURL("http://m-facebook.com/"),
-                                           PasswordForm::SCHEME_HTML, nullptr));
+  EXPECT_FALSE(CheckCredentialAvailability(
+      form_facebook_, GURL("http://m-facebook.com/"),
+      PasswordForm::Scheme::kHtml, nullptr));
 }
 
 // Test PSL matching is off for domains excluded from it.
 TEST_F(NativeBackendLibsecretTest, PSLMatchingDisabledDomains) {
-  EXPECT_FALSE(CheckCredentialAvailability(form_google_,
-                                           GURL("http://one.google.com/"),
-                                           PasswordForm::SCHEME_HTML, nullptr));
+  EXPECT_FALSE(
+      CheckCredentialAvailability(form_google_, GURL("http://one.google.com/"),
+                                  PasswordForm::Scheme::kHtml, nullptr));
 }
 
 // Make sure PSL matches aren't available for non-HTML forms.
 TEST_F(NativeBackendLibsecretTest, PSLMatchingDisabledForNonHTMLForms) {
-  CheckMatchingWithScheme(PasswordForm::SCHEME_BASIC);
-  CheckMatchingWithScheme(PasswordForm::SCHEME_DIGEST);
-  CheckMatchingWithScheme(PasswordForm::SCHEME_OTHER);
+  CheckMatchingWithScheme(PasswordForm::Scheme::kBasic);
+  CheckMatchingWithScheme(PasswordForm::Scheme::kDigest);
+  CheckMatchingWithScheme(PasswordForm::Scheme::kOther);
 }
 
 TEST_F(NativeBackendLibsecretTest, PSLUpdatingStrictUpdateLogin) {
@@ -716,9 +718,9 @@
   other_auth_.origin = GURL("https://www.example.com/");
   other_auth_.federation_origin =
       url::Origin::Create(GURL("https://google.com/"));
-  EXPECT_TRUE(CheckCredentialAvailability(other_auth_,
-                                          GURL("https://www.example.com/"),
-                                          PasswordForm::SCHEME_HTML, nullptr));
+  EXPECT_TRUE(
+      CheckCredentialAvailability(other_auth_, GURL("https://www.example.com/"),
+                                  PasswordForm::Scheme::kHtml, nullptr));
 }
 
 TEST_F(NativeBackendLibsecretTest, FetchFederatedCredentialOnLocalhost) {
@@ -726,9 +728,9 @@
   other_auth_.origin = GURL("http://localhost:8080/");
   other_auth_.federation_origin =
       url::Origin::Create(GURL("https://google.com/"));
-  EXPECT_TRUE(CheckCredentialAvailability(other_auth_,
-                                          GURL("http://localhost:8080/"),
-                                          PasswordForm::SCHEME_HTML, nullptr));
+  EXPECT_TRUE(
+      CheckCredentialAvailability(other_auth_, GURL("http://localhost:8080/"),
+                                  PasswordForm::Scheme::kHtml, nullptr));
 }
 
 TEST_F(NativeBackendLibsecretTest, DontFetchFederatedCredentialOnHTTP) {
@@ -736,9 +738,9 @@
   other_auth_.origin = GURL("https://www.example.com/");
   other_auth_.federation_origin =
       url::Origin::Create(GURL("https://google.com/"));
-  EXPECT_FALSE(CheckCredentialAvailability(other_auth_,
-                                           GURL("http://www.example.com/"),
-                                           PasswordForm::SCHEME_HTML, nullptr));
+  EXPECT_FALSE(
+      CheckCredentialAvailability(other_auth_, GURL("http://www.example.com/"),
+                                  PasswordForm::Scheme::kHtml, nullptr));
 }
 
 TEST_F(NativeBackendLibsecretTest, FetchPSLMatchedFederatedCredentialOnHTTPS) {
@@ -746,9 +748,9 @@
   other_auth_.origin = GURL("https://www.sub.example.com/");
   other_auth_.federation_origin =
       url::Origin::Create(GURL("https://google.com/"));
-  EXPECT_TRUE(CheckCredentialAvailability(other_auth_,
-                                          GURL("https://www.example.com/"),
-                                          PasswordForm::SCHEME_HTML, nullptr));
+  EXPECT_TRUE(
+      CheckCredentialAvailability(other_auth_, GURL("https://www.example.com/"),
+                                  PasswordForm::Scheme::kHtml, nullptr));
 }
 
 TEST_F(NativeBackendLibsecretTest,
@@ -757,9 +759,9 @@
   other_auth_.origin = GURL("https://www.sub.example.com/");
   other_auth_.federation_origin =
       url::Origin::Create(GURL("https://google.com/"));
-  EXPECT_FALSE(CheckCredentialAvailability(other_auth_,
-                                           GURL("http://www.example.com/"),
-                                           PasswordForm::SCHEME_HTML, nullptr));
+  EXPECT_FALSE(
+      CheckCredentialAvailability(other_auth_, GURL("http://www.example.com/"),
+                                  PasswordForm::Scheme::kHtml, nullptr));
 }
 
 TEST_F(NativeBackendLibsecretTest, BasicUpdateLogin) {
@@ -922,7 +924,7 @@
   backend.Init();
 
   PasswordForm observed_android_form;
-  observed_android_form.scheme = PasswordForm::SCHEME_HTML;
+  observed_android_form.scheme = PasswordForm::Scheme::kHtml;
   observed_android_form.signon_realm =
       "android://7x7IDboo8u9YKraUsbmVkuf1-@net.rateflix.app/";
   PasswordForm saved_android_form = observed_android_form;
diff --git a/chrome/browser/password_manager/password_accessory_metrics_util.h b/chrome/browser/password_manager/password_accessory_metrics_util.h
index 1e4fcdb..240d9a4 100644
--- a/chrome/browser/password_manager/password_accessory_metrics_util.h
+++ b/chrome/browser/password_manager/password_accessory_metrics_util.h
@@ -41,7 +41,8 @@
 enum class AccessorySuggestionType {
   USERNAME = 0,
   PASSWORD = 1,
-  CREDIT_CARDS = 2,
+  PAYMENT_INFO = 2,
+  ADDRESS_INFO = 3,
   COUNT,
 };
 
diff --git a/chrome/browser/password_manager/password_manager_browsertest.cc b/chrome/browser/password_manager/password_manager_browsertest.cc
index b30346b3..72b669d 100644
--- a/chrome/browser/password_manager/password_manager_browsertest.cc
+++ b/chrome/browser/password_manager/password_manager_browsertest.cc
@@ -2927,7 +2927,7 @@
               browser()->profile(), ServiceAccessType::IMPLICIT_ACCESS)
               .get());
   autofill::PasswordForm creds;
-  creds.scheme = autofill::PasswordForm::SCHEME_BASIC;
+  creds.scheme = autofill::PasswordForm::Scheme::kBasic;
   creds.signon_realm = http_test_server.base_url().spec() + "test realm";
   creds.password_value = base::ASCIIToUTF16("pw");
   creds.username_value = base::ASCIIToUTF16("temp");
@@ -2976,7 +2976,7 @@
               browser()->profile(), ServiceAccessType::IMPLICIT_ACCESS)
               .get());
   autofill::PasswordForm creds;
-  creds.scheme = autofill::PasswordForm::SCHEME_BASIC;
+  creds.scheme = autofill::PasswordForm::Scheme::kBasic;
   creds.origin = test_page;
   creds.signon_realm = embedded_test_server()->base_url().spec() + "testrealm";
   creds.password_value = base::ASCIIToUTF16("pw");
@@ -3756,7 +3756,7 @@
                 .get());
 
     autofill::PasswordForm blacklisted_form;
-    blacklisted_form.scheme = autofill::PasswordForm::SCHEME_HTML;
+    blacklisted_form.scheme = autofill::PasswordForm::Scheme::kHtml;
     blacklisted_form.signon_realm = http_test_server.base_url().spec();
     blacklisted_form.blacklisted_by_user = true;
     password_store->AddLogin(blacklisted_form);
@@ -3821,7 +3821,7 @@
                 .get());
 
     autofill::PasswordForm blacklisted_form;
-    blacklisted_form.scheme = autofill::PasswordForm::SCHEME_BASIC;
+    blacklisted_form.scheme = autofill::PasswordForm::Scheme::kBasic;
     blacklisted_form.signon_realm = embedded_test_server()->base_url().spec();
     if (!is_realm_empty)
       blacklisted_form.signon_realm += "test realm";
diff --git a/chrome/browser/password_manager/password_store_mac_unittest.cc b/chrome/browser/password_manager/password_store_mac_unittest.cc
index 7fdd6d6..b1f87b0 100644
--- a/chrome/browser/password_manager/password_store_mac_unittest.cc
+++ b/chrome/browser/password_manager/password_store_mac_unittest.cc
@@ -245,7 +245,7 @@
 
   // Add a new autofillable login + a blacklisted login.
   password_manager::PasswordFormData www_form_data = {
-      PasswordForm::SCHEME_HTML,
+      PasswordForm::Scheme::kHtml,
       "http://www.facebook.com/",
       "http://www.facebook.com/index.html",
       "login",
diff --git a/chrome/browser/password_manager/password_store_x_unittest.cc b/chrome/browser/password_manager/password_store_x_unittest.cc
index 246bd5a..11629d1 100644
--- a/chrome/browser/password_manager/password_store_x_unittest.cc
+++ b/chrome/browser/password_manager/password_store_x_unittest.cc
@@ -296,7 +296,7 @@
     std::string action =
         base::StringPrintf("http://%zu.%s.com/action", i, domain);
     password_manager::PasswordFormData data = {
-        PasswordForm::SCHEME_HTML,
+        PasswordForm::Scheme::kHtml,
         realm.c_str(),
         origin.c_str(),
         action.c_str(),
@@ -478,7 +478,7 @@
   store->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
 
   password_manager::PasswordFormData form_data = {
-      PasswordForm::SCHEME_HTML,
+      PasswordForm::Scheme::kHtml,
       "http://bar.example.com",
       "http://bar.example.com/origin",
       "http://bar.example.com/action",
@@ -655,7 +655,7 @@
   // verify where the store serves from. The migration is triggered
   // opportunistically during access to the store.
   const auto new_form = password_manager::FillPasswordFormWithData(
-      {PasswordForm::SCHEME_HTML, "https://www.fakebook.com",
+      {PasswordForm::Scheme::kHtml, "https://www.fakebook.com",
        "https://www.fakebook.com/li", "https://www.fakebook.com/a",
        L"submit_element", L"username_element", L"password_element",
        L"username_value", L"password_value", true, 1.0});
diff --git a/chrome/browser/permissions/chooser_context_base.cc b/chrome/browser/permissions/chooser_context_base.cc
index 75d7271b..ba36421 100644
--- a/chrome/browser/permissions/chooser_context_base.cc
+++ b/chrome/browser/permissions/chooser_context_base.cc
@@ -86,7 +86,7 @@
     if (IsValidObject(object)) {
       results.push_back(std::make_unique<Object>(
           requesting_origin, embedding_origin, std::move(object), info.source,
-          host_content_settings_map_->is_incognito()));
+          host_content_settings_map_->IsOffTheRecord()));
     }
   }
   return results;
diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc
index f9d9232..71d736c 100644
--- a/chrome/browser/profiles/profile.cc
+++ b/chrome/browser/profiles/profile.cc
@@ -237,10 +237,6 @@
   return GetProfileType() == INCOGNITO_PROFILE;
 }
 
-bool Profile::IsGuestProfile() const {
-  return GetProfileType() == GUEST_PROFILE;
-}
-
 bool Profile::IsGuestSession() const {
 #if defined(OS_CHROMEOS)
   static bool is_guest_session =
diff --git a/chrome/browser/profiles/profile.h b/chrome/browser/profiles/profile.h
index 7a87981c..15d2512d 100644
--- a/chrome/browser/profiles/profile.h
+++ b/chrome/browser/profiles/profile.h
@@ -307,11 +307,10 @@
 
   std::string GetDebugName();
 
-  // IsRegularProfile(), IsIncognitoProfile(), and IsGuestProfile() are mutually
-  // exclusive.
+  // IsRegularProfile() and IsIncognitoProfile() are mutually exclusive.
   // IsSystemProfile() implies that IsRegularProfile() is true.
-  // IsOffTheRecord() is an equivalent of IsIncognitoProfile() ||
-  // IsGuestProfile().
+  // IsOffTheRecord() is true for the off the record profile of incognito mode
+  // and guest sessions.
 
   // Returns whether it's a regular profile.
   bool IsRegularProfile() const;
@@ -320,10 +319,6 @@
   // off-the-record profile that is not a guest profile.
   bool IsIncognitoProfile() const;
 
-  // Returns whether it is a Guest profile. A Guest profile is an off-the-record
-  // profile in a guest session.
-  bool IsGuestProfile() const;
-
   // Returns whether it is a guest session. This covers both the guest profile
   // and its parent.
   virtual bool IsGuestSession() const;
diff --git a/chrome/browser/profiles/profile_manager_browsertest.cc b/chrome/browser/profiles/profile_manager_browsertest.cc
index a59ce5d..07e6be78 100644
--- a/chrome/browser/profiles/profile_manager_browsertest.cc
+++ b/chrome/browser/profiles/profile_manager_browsertest.cc
@@ -579,7 +579,7 @@
   ASSERT_TRUE(profile);
 
   autofill::PasswordForm form;
-  form.scheme = autofill::PasswordForm::SCHEME_HTML;
+  form.scheme = autofill::PasswordForm::Scheme::kHtml;
   form.origin = GURL("http://accounts.google.com/LoginAuth");
   form.signon_realm = "http://accounts.google.com/";
   form.username_value = base::ASCIIToUTF16("my_username");
diff --git a/chrome/browser/resources/print_preview/polymer3/demo.html b/chrome/browser/resources/print_preview/polymer3/demo.html
new file mode 100644
index 0000000..731c568
--- /dev/null
+++ b/chrome/browser/resources/print_preview/polymer3/demo.html
@@ -0,0 +1,11 @@
+<!doctype html>
+<html lang="en">
+<head>
+  <meta charset="utf-8">
+  <title>Polymer 3 WebUI demo</title>
+  <script type="module" src="demo.js"></script>
+</head>
+<body>
+  <hello-polymer3></hello-polymer3>
+</body>
+</html>
diff --git a/chrome/browser/resources/print_preview/polymer3/demo.js b/chrome/browser/resources/print_preview/polymer3/demo.js
new file mode 100644
index 0000000..2e1415c
--- /dev/null
+++ b/chrome/browser/resources/print_preview/polymer3/demo.js
@@ -0,0 +1,31 @@
+// 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://resources/polymer/v3_0/paper-button/paper-button.js';
+
+import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer-element.js';
+
+class HelloPolymer3Element extends PolymerElement {
+  static get template() {
+    return html`
+      <div>Hello Polymer3 [[time]]</div>
+      <paper-button on-click="onClick_">Update time</paper-button>
+    `;
+  }
+
+  static get properties() {
+    return {
+      time: {
+        type: Number,
+        value: Date.now(),
+      },
+    };
+  }
+
+  onClick_() {
+    this.time = Date.now();
+  }
+}  // class HelloPolymer3
+
+customElements.define('hello-polymer3', HelloPolymer3Element);
diff --git a/chrome/browser/resources/print_preview/print_preview_resources.grd b/chrome/browser/resources/print_preview/print_preview_resources.grd
index ae1e4dcb..7803cd3 100644
--- a/chrome/browser/resources/print_preview/print_preview_resources.grd
+++ b/chrome/browser/resources/print_preview/print_preview_resources.grd
@@ -429,6 +429,18 @@
       <structure name="IDR_PRINT_PREVIEW_ICONS_HTML"
                  file="icons.html"
                  type="chrome_html" />
+
+      <if expr="not optimize_webui">
+        <!-- TODO(crbug.com/965770): The folowing 2 files are unrelated to Print
+             Preview, they are only used during Polymer 3 experimentation, and
+             should be removed after experimentation concludes. -->
+        <structure name="IDR_PRINT_PREVIEW_POLYMER3_DEMO_HTML"
+                   file="polymer3/demo.html"
+                   type="chrome_html" />
+        <structure name="IDR_PRINT_PREVIEW_POLYMER3_DEMO_JS"
+                   file="polymer3/demo.js"
+                   type="chrome_html" />
+      </if>
     </structures>
   </release>
 </grit>
diff --git a/chrome/browser/sync/test/integration/passwords_helper.cc b/chrome/browser/sync/test/integration/passwords_helper.cc
index bdd61e0..99687bc 100644
--- a/chrome/browser/sync/test/integration/passwords_helper.cc
+++ b/chrome/browser/sync/test/integration/passwords_helper.cc
@@ -100,7 +100,7 @@
 std::vector<std::unique_ptr<PasswordForm>> GetLogins(PasswordStore* store) {
   EXPECT_TRUE(store);
   password_manager::PasswordStore::FormDigest matcher_form = {
-      PasswordForm::SCHEME_HTML, kFakeSignonRealm, GURL()};
+      PasswordForm::Scheme::kHtml, kFakeSignonRealm, GURL()};
   PasswordStoreConsumerHelper consumer;
   store->GetLogins(matcher_form, &consumer);
   return consumer.WaitForResult();
diff --git a/chrome/browser/ui/android/passwords/manual_filling_view_android.cc b/chrome/browser/ui/android/passwords/manual_filling_view_android.cc
index e59b608..f4ffb7c2 100644
--- a/chrome/browser/ui/android/passwords/manual_filling_view_android.cc
+++ b/chrome/browser/ui/android/passwords/manual_filling_view_android.cc
@@ -44,7 +44,6 @@
     ManualFillingController* controller)
     : controller_(controller) {
   ui::ViewAndroid* view_android = controller_->container_view();
-
   DCHECK(view_android);
   java_object_.Reset(Java_ManualFillingComponentBridge_create(
       base::android::AttachCurrentThread(), reinterpret_cast<intptr_t>(this),
@@ -105,10 +104,10 @@
 void ManualFillingViewAndroid::OnFaviconRequested(
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& obj,
-    jint desiredSizeInPx,
+    jint desired_size_in_px,
     const base::android::JavaParamRef<jobject>& j_callback) {
   controller_->GetFavicon(
-      desiredSizeInPx,
+      desired_size_in_px,
       base::BindOnce(&ManualFillingViewAndroid::OnImageFetched,
                      base::Unretained(this),  // Outlives or cancels request.
                      base::android::ScopedJavaGlobalRef<jobject>(j_callback)));
@@ -117,18 +116,19 @@
 void ManualFillingViewAndroid::OnFillingTriggered(
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& obj,
-    jboolean isPassword,
+    jint tab_type,
     const base::android::JavaParamRef<jobject>& j_user_info_field) {
   controller_->OnFillingTriggered(
+      static_cast<autofill::AccessoryTabType>(tab_type),
       ConvertJavaUserInfoField(env, j_user_info_field));
 }
 
 void ManualFillingViewAndroid::OnOptionSelected(
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& obj,
-    jint selectedAction) {
+    jint selected_action) {
   controller_->OnOptionSelected(
-      static_cast<autofill::AccessoryAction>(selectedAction));
+      static_cast<autofill::AccessoryAction>(selected_action));
 }
 
 void ManualFillingViewAndroid::OnGenerationRequested(
@@ -163,6 +163,7 @@
     for (const UserInfo::Field& field : user_info.fields()) {
       Java_ManualFillingComponentBridge_addFieldToUserInfo(
           env, java_object_, j_user_info,
+          static_cast<int>(tab_data.get_sheet_type()),
           ConvertUTF16ToJavaString(env, field.display_text()),
           ConvertUTF16ToJavaString(env, field.a11y_description()),
           field.is_obfuscated(), field.selectable());
diff --git a/chrome/browser/ui/android/passwords/manual_filling_view_android.h b/chrome/browser/ui/android/passwords/manual_filling_view_android.h
index 9b8be5d..99914e3c 100644
--- a/chrome/browser/ui/android/passwords/manual_filling_view_android.h
+++ b/chrome/browser/ui/android/passwords/manual_filling_view_android.h
@@ -39,16 +39,16 @@
   void OnFaviconRequested(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
-      jint desiredSizeInPx,
+      jint desired_size_in_px,
       const base::android::JavaParamRef<jobject>& j_callback);
   void OnFillingTriggered(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
-      jboolean isPassword,
+      jint tab_type,
       const base::android::JavaParamRef<jobject>& j_user_info_field);
   void OnOptionSelected(JNIEnv* env,
                         const base::android::JavaParamRef<jobject>& obj,
-                        jint selectedAction);
+                        jint selected_action);
   void OnGenerationRequested(JNIEnv* env,
                              const base::android::JavaParamRef<jobject>& obj);
 
diff --git a/chrome/browser/ui/app_list/app_launch_event_logger.cc b/chrome/browser/ui/app_list/app_launch_event_logger.cc
index de92e2a4..f486fc9 100644
--- a/chrome/browser/ui/app_list/app_launch_event_logger.cc
+++ b/chrome/browser/ui/app_list/app_launch_event_logger.cc
@@ -21,6 +21,7 @@
 #include "chrome/browser/metrics/chrome_metrics_service_client.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
 #include "components/arc/arc_prefs.h"
 #include "components/prefs/pref_service.h"
 #include "components/ukm/app_source_url_recorder.h"
@@ -123,7 +124,6 @@
   task_runner_ = base::CreateSequencedTaskRunnerWithTraits(
       {base::TaskPriority::BEST_EFFORT,
        base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
-  PopulatePwaIdUrlMap();
 }
 
 AppLaunchEventLogger::~AppLaunchEventLogger() {}
@@ -192,20 +192,9 @@
   return app_id;
 }
 
-void AppLaunchEventLogger::PopulatePwaIdUrlMap() {
-  pwa_id_url_map_ = base::flat_map<std::string, std::string>{
-      // Google+
-      {"dcdbodpaldbchkfinnjphocleggfceip", "https://plus.google.com/discover"},
-      // Photos
-      {"ncmjhecbjeaamljdfahankockkkdmedg", "https://photos.google.com/"}};
-}
-
-const std::string& AppLaunchEventLogger::GetPwaUrl(const std::string& id) {
-  auto search = pwa_id_url_map_.find(id);
-  if (search != pwa_id_url_map_.end()) {
-    return search->second;
-  }
-  return base::EmptyString();
+const GURL& AppLaunchEventLogger::GetLaunchWebURL(
+    const extensions::Extension* extension) {
+  return extensions::AppLaunchInfo::GetLaunchWebURL(extension);
 }
 
 void AppLaunchEventLogger::OkApp(AppLaunchEvent_AppType app_type,
@@ -247,7 +236,7 @@
     app.second.set_is_policy_compliant(false);
   }
 
-  // Store all Chrome and PWA apps.
+  // Store all Chrome, PWA and bookmark apps.
   // registry_ can be nullptr in tests.
   if (registry_) {
     std::unique_ptr<extensions::ExtensionSet> extensions =
@@ -257,13 +246,11 @@
       if (extension->from_webstore()) {
         OkApp(AppLaunchEvent_AppType_CHROME, extension->id(),
               base::EmptyString(), base::EmptyString());
-      } else {
-        // Only allow PWA apps on the whitelist.
-        auto search = pwa_id_url_map_.find(extension->id());
-        if (search != pwa_id_url_map_.end()) {
-          OkApp(AppLaunchEvent_AppType_PWA, extension->id(),
-                base::EmptyString(), search->second);
-        }
+        // PWA apps have from_bookmark() true. This will also categorize
+        // bookmark apps as AppLaunchEvent_AppType_PWA.
+      } else if (extension->from_bookmark()) {
+        OkApp(AppLaunchEvent_AppType_PWA, extension->id(), base::EmptyString(),
+              GetLaunchWebURL(extension.get()).spec());
       }
     }
   }
@@ -351,7 +338,7 @@
     return ukm::AppSourceUrlRecorder::GetSourceIdForArc(arc_package_name);
   } else {
     // Either app is Crostini; or Chrome but not in app store; or Arc but not
-    // syncable; or PWA but not in whitelist.
+    // syncable.
     return ukm::kInvalidSourceId;
   }
 }
diff --git a/chrome/browser/ui/app_list/app_launch_event_logger.h b/chrome/browser/ui/app_list/app_launch_event_logger.h
index abfae3b..c827155 100644
--- a/chrome/browser/ui/app_list/app_launch_event_logger.h
+++ b/chrome/browser/ui/app_list/app_launch_event_logger.h
@@ -36,11 +36,11 @@
 
 // This class logs metrics associated with clicking on apps in ChromeOS.
 // Logging is restricted to Arc apps with sync enabled, Chrome apps from the
-// app store and PWAs from a whitelist. This class uses UKM for logging,
+// app store, PWAs and bookmark apps. This class uses UKM for logging,
 // however, the metrics are not keyed by navigational urls. Instead, for Chrome
 // apps the keys are based upon the app id, for Arc apps the keys are based upon
-// a hash of the package name and for PWAs the keys are the urls associated with
-// the PWA.
+// a hash of the package name, and for PWAs and bookmark apps the keys are the
+// urls associated with the PWA/bookmark.
 // At the time of app launch this class logs metrics about the app clicked on
 // and another five apps that were not clicked on, chosen at random.
 class AppLaunchEventLogger {
@@ -65,23 +65,21 @@
   static const char kPackageName[];
   static const char kShouldSync[];
 
+ protected:
+  // Get the url used to launch a PWA or bookmark app.
+  virtual const GURL& GetLaunchWebURL(const extensions::Extension* extension);
+
  private:
   // Removes any leading "chrome-extension://" or "arc://". Also remove any
   // trailing "/".
   std::string RemoveScheme(const std::string& id);
-  // Creates the mapping from PWA app id to PWA url. This mapping also acts as a
-  // whitelist for which PWA apps can be logged here.
-  void PopulatePwaIdUrlMap();
-  // Gets the PWA url from its app id. Returns base::EmptyString() if no match
-  // found.
-  const std::string& GetPwaUrl(const std::string& id);
+
   // Marks app as ok for policy compliance. If the app is not in
   // |app_features_map_| then add it.
   void OkApp(AppLaunchEvent_AppType app_type,
              const std::string& app_id,
              const std::string& arc_package_name,
              const std::string& pwa_url);
-
   // Enforces logging policy, ensuring that the |app_features_map_| only
   // contains apps that are allowed to be logged. All apps are rechecked in case
   // they have been uninstalled since the previous check.
@@ -89,7 +87,7 @@
   // Updates the app data following a click.
   void ProcessClick(const AppLaunchEvent& event, const base::Time& now);
   // Returns a source id. |arc_package_name| is only required for Arc apps,
-  // |pwa_url| is only required for PWA apps.
+  // |pwa_url| is only required for PWAs and bookmark apps.
   ukm::SourceId GetSourceId(AppLaunchEvent_AppType app_type,
                             const std::string& app_id,
                             const std::string& arc_package_name,
@@ -110,10 +108,6 @@
   // Logs the app click using UKM.
   void Log(AppLaunchEvent app_launch_event);
 
-  // Map from PWA app id to PWA url. This also acts as a whitelist of PWA apps
-  // the can be logged.
-  base::flat_map<std::string, std::string> pwa_id_url_map_;
-
   // The arc apps installed on the device.
   const base::DictionaryValue* arc_apps_;
   // The arc packages installed on the device.
diff --git a/chrome/browser/ui/app_list/app_launch_event_logger.proto b/chrome/browser/ui/app_list/app_launch_event_logger.proto
index 878315c..528f3c6 100644
--- a/chrome/browser/ui/app_list/app_launch_event_logger.proto
+++ b/chrome/browser/ui/app_list/app_launch_event_logger.proto
@@ -22,6 +22,7 @@
     OTHER = 0;
     CHROME = 1;
     PLAY = 2;
+    // PWA AppType includes bookmark apps in addition to PWAs.
     PWA = 3;
   }
   // The type of App.
diff --git a/chrome/browser/ui/app_list/app_launch_event_logger_unittest.cc b/chrome/browser/ui/app_list/app_launch_event_logger_unittest.cc
index 5bc3796..40ce5aa 100644
--- a/chrome/browser/ui/app_list/app_launch_event_logger_unittest.cc
+++ b/chrome/browser/ui/app_list/app_launch_event_logger_unittest.cc
@@ -26,6 +26,7 @@
 const char kGmailChromeApp[] = "pjkljhegncpnkpknbcohdijeoejaedia";
 const char kMapsArcApp[] = "gmhipfhgnoelkiiofcnimehjnpaejiel";
 const char kPhotosPWAApp[] = "ncmjhecbjeaamljdfahankockkkdmedg";
+const GURL kPhotosPWAUrl = GURL("http://photos.google.com/");
 
 const char kMapsPackageName[] = "com.google.android.apps.maps";
 
@@ -37,6 +38,13 @@
 
 }  // namespace
 
+class AppLaunchEventLoggerForTest : public AppLaunchEventLogger {
+ protected:
+  const GURL& GetLaunchWebURL(const extensions::Extension* extension) override {
+    return kPhotosPWAUrl;
+  }
+};
+
 class AppLaunchEventLoggerTest : public testing::Test {
  protected:
   void SetUp() override {
@@ -51,12 +59,14 @@
 TEST_F(AppLaunchEventLoggerTest, CheckUkmCodePWA) {
   extensions::ExtensionRegistry registry(nullptr);
   scoped_refptr<const extensions::Extension> extension =
-      extensions::ExtensionBuilder("test").SetID(kPhotosPWAApp).Build();
+      extensions::ExtensionBuilder("test")
+          .SetID(kPhotosPWAApp)
+          .AddFlags(extensions::Extension::FROM_BOOKMARK)
+          .Build();
+
   registry.AddEnabled(extension);
 
-  GURL url("https://photos.google.com/");
-
-  AppLaunchEventLogger app_launch_event_logger_;
+  AppLaunchEventLoggerForTest app_launch_event_logger_;
   app_launch_event_logger_.SetAppDataForTesting(&registry, nullptr, nullptr);
   app_launch_event_logger_.OnGridClicked(kPhotosPWAApp);
 
@@ -65,7 +75,7 @@
   const auto entries = test_ukm_recorder_.GetEntriesByName("AppListAppLaunch");
   ASSERT_EQ(1ul, entries.size());
   const auto* entry = entries.back();
-  test_ukm_recorder_.ExpectEntrySourceHasUrl(entry, url);
+  test_ukm_recorder_.ExpectEntrySourceHasUrl(entry, kPhotosPWAUrl);
   test_ukm_recorder_.ExpectEntryMetric(entry, "AllClicksLast24Hours", 1);
   test_ukm_recorder_.ExpectEntryMetric(entry, "AllClicksLastHour", 1);
   test_ukm_recorder_.ExpectEntryMetric(entry, "AppType", 3);
@@ -76,7 +86,7 @@
       test_ukm_recorder_.GetEntriesByName("AppListAppClickData");
   ASSERT_EQ(1ul, click_entries.size());
   const auto* photos_entry = click_entries.back();
-  test_ukm_recorder_.ExpectEntrySourceHasUrl(photos_entry, url);
+  test_ukm_recorder_.ExpectEntrySourceHasUrl(photos_entry, kPhotosPWAUrl);
   test_ukm_recorder_.ExpectEntryMetric(photos_entry, "AppLaunchId",
                                        entry->source_id);
   test_ukm_recorder_.ExpectEntryMetric(photos_entry, "AppType", 3);
@@ -97,7 +107,7 @@
   test_ukm_recorder_.SetIsWebstoreExtensionCallback(
       base::BindRepeating(&TestIsWebstoreExtension));
 
-  AppLaunchEventLogger app_launch_event_logger_;
+  AppLaunchEventLoggerForTest app_launch_event_logger_;
   app_launch_event_logger_.SetAppDataForTesting(&registry, nullptr, nullptr);
   app_launch_event_logger_.OnGridClicked(kGmailChromeApp);
 
@@ -126,7 +136,7 @@
 
   GURL url("app://play/gbpfhehadcpcndihhameeacbdmbjbhgi");
 
-  AppLaunchEventLogger app_launch_event_logger_;
+  AppLaunchEventLoggerForTest app_launch_event_logger_;
   app_launch_event_logger_.SetAppDataForTesting(nullptr, arc_apps.get(),
                                                 packages.get());
   app_launch_event_logger_.OnGridClicked(kMapsArcApp);
@@ -145,11 +155,12 @@
   // Click on PWA photos, then Chrome Maps, then PWA Photos again.
   extensions::ExtensionRegistry registry(nullptr);
   scoped_refptr<const extensions::Extension> extension =
-      extensions::ExtensionBuilder("test").SetID(kPhotosPWAApp).Build();
+      extensions::ExtensionBuilder("test")
+          .SetID(kPhotosPWAApp)
+          .AddFlags(extensions::Extension::FROM_BOOKMARK)
+          .Build();
   registry.AddEnabled(extension);
 
-  GURL photos_url("https://photos.google.com/");
-
   base::Value package(base::Value::Type::DICTIONARY);
   package.SetKey(AppLaunchEventLogger::kShouldSync, base::Value(true));
 
@@ -164,7 +175,7 @@
 
   GURL maps_url("app://play/gbpfhehadcpcndihhameeacbdmbjbhgi");
 
-  AppLaunchEventLogger app_launch_event_logger_;
+  AppLaunchEventLoggerForTest app_launch_event_logger_;
   app_launch_event_logger_.SetAppDataForTesting(&registry, arc_apps.get(),
                                                 packages.get());
   app_launch_event_logger_.OnGridClicked(kPhotosPWAApp);
@@ -178,7 +189,7 @@
   const auto entries = test_ukm_recorder_.GetEntriesByName("AppListAppLaunch");
   ASSERT_EQ(4ul, entries.size());
   const auto* entry = entries.back();
-  test_ukm_recorder_.ExpectEntrySourceHasUrl(entry, photos_url);
+  test_ukm_recorder_.ExpectEntrySourceHasUrl(entry, kPhotosPWAUrl);
   test_ukm_recorder_.ExpectEntryMetric(entry, "AllClicksLast24Hours", 4);
   test_ukm_recorder_.ExpectEntryMetric(entry, "AllClicksLastHour", 4);
   test_ukm_recorder_.ExpectEntryMetric(entry, "AppType", 3);
@@ -192,12 +203,12 @@
   const auto* maps_entry = click_entries.at(6);
   const auto* photos_entry = click_entries.at(7);
   if (test_ukm_recorder_.GetSourceForSourceId(maps_entry->source_id)->url() ==
-      photos_url) {
+      kPhotosPWAUrl) {
     const auto* tmp_entry = photos_entry;
     photos_entry = maps_entry;
     maps_entry = tmp_entry;
   }
-  test_ukm_recorder_.ExpectEntrySourceHasUrl(photos_entry, photos_url);
+  test_ukm_recorder_.ExpectEntrySourceHasUrl(photos_entry, kPhotosPWAUrl);
   test_ukm_recorder_.ExpectEntrySourceHasUrl(maps_entry, maps_url);
   test_ukm_recorder_.ExpectEntryMetric(photos_entry, "AppLaunchId",
                                        entry->source_id);
@@ -220,12 +231,13 @@
 TEST_F(AppLaunchEventLoggerTest, CheckUkmCodeSuggestionChip) {
   extensions::ExtensionRegistry registry(nullptr);
   scoped_refptr<const extensions::Extension> extension =
-      extensions::ExtensionBuilder("test").SetID(kPhotosPWAApp).Build();
+      extensions::ExtensionBuilder("test")
+          .SetID(kPhotosPWAApp)
+          .AddFlags(extensions::Extension::FROM_BOOKMARK)
+          .Build();
   registry.AddEnabled(extension);
 
-  GURL url("https://photos.google.com/");
-
-  AppLaunchEventLogger app_launch_event_logger_;
+  AppLaunchEventLoggerForTest app_launch_event_logger_;
   app_launch_event_logger_.SetAppDataForTesting(&registry, nullptr, nullptr);
   app_launch_event_logger_.OnSuggestionChipOrSearchBoxClicked(kPhotosPWAApp, 3,
                                                               2);
@@ -235,7 +247,7 @@
   const auto entries = test_ukm_recorder_.GetEntriesByName("AppListAppLaunch");
   ASSERT_EQ(1ul, entries.size());
   const auto* entry = entries.back();
-  test_ukm_recorder_.ExpectEntrySourceHasUrl(entry, url);
+  test_ukm_recorder_.ExpectEntrySourceHasUrl(entry, kPhotosPWAUrl);
   test_ukm_recorder_.ExpectEntryMetric(entry, "PositionIndex", 3);
   test_ukm_recorder_.ExpectEntryMetric(entry, "LaunchedFrom", 2);
 }
@@ -243,12 +255,13 @@
 TEST_F(AppLaunchEventLoggerTest, CheckUkmCodeSearchBox) {
   extensions::ExtensionRegistry registry(nullptr);
   scoped_refptr<const extensions::Extension> extension =
-      extensions::ExtensionBuilder("test").SetID(kPhotosPWAApp).Build();
+      extensions::ExtensionBuilder("test")
+          .SetID(kPhotosPWAApp)
+          .AddFlags(extensions::Extension::FROM_BOOKMARK)
+          .Build();
   registry.AddEnabled(extension);
 
-  GURL url("https://photos.google.com/");
-
-  AppLaunchEventLogger app_launch_event_logger_;
+  AppLaunchEventLoggerForTest app_launch_event_logger_;
   app_launch_event_logger_.SetAppDataForTesting(&registry, nullptr, nullptr);
   app_launch_event_logger_.OnSuggestionChipOrSearchBoxClicked(kPhotosPWAApp, 3,
                                                               4);
@@ -258,7 +271,7 @@
   const auto entries = test_ukm_recorder_.GetEntriesByName("AppListAppLaunch");
   ASSERT_EQ(1ul, entries.size());
   const auto* entry = entries.back();
-  test_ukm_recorder_.ExpectEntrySourceHasUrl(entry, url);
+  test_ukm_recorder_.ExpectEntrySourceHasUrl(entry, kPhotosPWAUrl);
   test_ukm_recorder_.ExpectEntryMetric(entry, "PositionIndex", 3);
   test_ukm_recorder_.ExpectEntryMetric(entry, "LaunchedFrom", 4);
 }
diff --git a/chrome/browser/ui/app_list/app_service_app_model_builder.cc b/chrome/browser/ui/app_list/app_service_app_model_builder.cc
index 23f9542..5a0f4a4c 100644
--- a/chrome/browser/ui/app_list/app_service_app_model_builder.cc
+++ b/chrome/browser/ui/app_list/app_service_app_model_builder.cc
@@ -105,3 +105,8 @@
         profile(), model_updater(), GetSyncItem(update.AppId()), update));
   }
 }
+
+void AppServiceAppModelBuilder::OnAppRegistryCacheWillBeDestroyed(
+    apps::AppRegistryCache* cache) {
+  Observe(nullptr);
+}
diff --git a/chrome/browser/ui/app_list/app_service_app_model_builder.h b/chrome/browser/ui/app_list/app_service_app_model_builder.h
index 8034ef3..c3a2a5b 100644
--- a/chrome/browser/ui/app_list/app_service_app_model_builder.h
+++ b/chrome/browser/ui/app_list/app_service_app_model_builder.h
@@ -26,6 +26,8 @@
 
   // apps::AppRegistryCache::Observer overrides:
   void OnAppUpdate(const apps::AppUpdate& update) override;
+  void OnAppRegistryCacheWillBeDestroyed(
+      apps::AppRegistryCache* cache) override;
 
   std::unique_ptr<AppListModelUpdaterObserver> crostini_folder_observer_;
 
diff --git a/chrome/browser/ui/app_list/search/app_search_provider.cc b/chrome/browser/ui/app_list/search/app_search_provider.cc
index 234832d..1f2e9fc4 100644
--- a/chrome/browser/ui/app_list/search/app_search_provider.cc
+++ b/chrome/browser/ui/app_list/search/app_search_provider.cc
@@ -361,6 +361,11 @@
     }
   }
 
+  void OnAppRegistryCacheWillBeDestroyed(
+      apps::AppRegistryCache* cache) override {
+    Observe(nullptr);
+  }
+
   // The AppServiceDataSource seems like one (but not the only) good place to
   // add an App Service icon caching wrapper, because (1) the AppSearchProvider
   // destroys and creates multiple search results in a short period of time,
diff --git a/chrome/browser/ui/app_list/search/search_controller.cc b/chrome/browser/ui/app_list/search/search_controller.cc
index c873594..e15351aa 100644
--- a/chrome/browser/ui/app_list/search/search_controller.cc
+++ b/chrome/browser/ui/app_list/search/search_controller.cc
@@ -38,6 +38,8 @@
 constexpr char kLogDisplayTypeClickedResultZeroState[] =
     "Apps.LogDisplayTypeClickedResultZeroState";
 
+// TODO(931149): Move the string manipulation utilities into a helper class.
+
 // Normalizes training targets by removing any scheme prefix and trailing slash:
 // "arc://[id]/" to "[id]". This is necessary because apps launched from
 // different parts of the launcher have differently formatted IDs.
@@ -52,6 +54,16 @@
   return result;
 }
 
+// Remove the Arc app shortcut label from an app ID, if it exists, so that
+// "[app]/[label]" becomes "[app]".
+std::string RemoveAppShortcutLabel(const std::string& id) {
+  std::string result(id);
+  std::size_t delimiter_index = result.find_last_of('/');
+  if (delimiter_index != std::string::npos)
+    result.erase(delimiter_index);
+  return result;
+}
+
 }  // namespace
 
 SearchController::SearchController(AppListModelUpdater* model_updater,
@@ -189,10 +201,18 @@
       launch_type = ChromeOSAppListLaunchEventProto::RESULTS_LIST;
     }
 
-    // TODO(951287): Record the last-used domain and app.
+    // TODO(951287): Record the last-used domain.
     AppListLaunchRecorder::GetInstance()->Record(
         {launch_type, NormalizeId(id), base::UTF16ToUTF8(last_query_),
-         std::string(), std::string()});
+         std::string(), last_launched_app_id_});
+
+    // Only record the last launched app if the hashed logging feature flag is
+    // enabled, because it is only used by hashed logging.
+    if (type == RankingItemType::kApp) {
+      last_launched_app_id_ = NormalizeId(id);
+    } else if (type == RankingItemType::kArcAppShortcut) {
+      last_launched_app_id_ = RemoveAppShortcutLabel(NormalizeId(id));
+    }
   }
 
   for (const auto& provider : providers_)
diff --git a/chrome/browser/ui/app_list/search/search_controller.h b/chrome/browser/ui/app_list/search/search_controller.h
index 1eb26c7..a97c2aefd 100644
--- a/chrome/browser/ui/app_list/search/search_controller.h
+++ b/chrome/browser/ui/app_list/search/search_controller.h
@@ -80,6 +80,10 @@
   // The query associated with the most recent search.
   base::string16 last_query_;
 
+  // The ID of the most recently launched app. This is used for app list launch
+  // recording.
+  std::string last_launched_app_id_;
+
   std::unique_ptr<Mixer> mixer_;
   using Providers = std::vector<std::unique_ptr<SearchProvider>>;
   Providers providers_;
diff --git a/chrome/browser/ui/ash/chrome_new_window_client.cc b/chrome/browser/ui/ash/chrome_new_window_client.cc
index 894f6b54..7a90535 100644
--- a/chrome/browser/ui/ash/chrome_new_window_client.cc
+++ b/chrome/browser/ui/ash/chrome_new_window_client.cc
@@ -70,7 +70,7 @@
 
 bool IsIncognitoAllowed() {
   Profile* profile = ProfileManager::GetActiveUserProfile();
-  return profile && !profile->IsGuestProfile() &&
+  return profile && !profile->IsGuestSession() &&
          IncognitoModePrefs::GetAvailability(profile->GetPrefs()) !=
              IncognitoModePrefs::DISABLED;
 }
diff --git a/chrome/browser/ui/browser_window.h b/chrome/browser/ui/browser_window.h
index 910dbe1..d81bb3611 100644
--- a/chrome/browser/ui/browser_window.h
+++ b/chrome/browser/ui/browser_window.h
@@ -241,6 +241,10 @@
   // the TabStripModel has an active tab.
   virtual gfx::Size GetContentsSize() const = 0;
 
+  // Resizes the window to fit a WebContents of a certain size. This should only
+  // be called after the TabStripModel has an active tab.
+  virtual void SetContentsSize(const gfx::Size& size) = 0;
+
   // Returns the container of page action icons.
   virtual PageActionIconContainer* GetOmniboxPageActionIconContainer() = 0;
 
diff --git a/chrome/browser/ui/extensions/hosted_app_browser_controller.cc b/chrome/browser/ui/extensions/hosted_app_browser_controller.cc
index efb0113..b9a45fe3 100644
--- a/chrome/browser/ui/extensions/hosted_app_browser_controller.cc
+++ b/chrome/browser/ui/extensions/hosted_app_browser_controller.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/ssl/security_state_tab_helper.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/browser_window_state.h"
 #include "chrome/browser/ui/location_bar/location_bar.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
@@ -151,8 +152,7 @@
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
 
-  // Don't show a toolbar until a navigation has occurred.
-  if (!web_contents || web_contents->GetLastCommittedURL().is_empty())
+  if (!web_contents)
     return false;
 
   GURL launch_url = AppLaunchInfo::GetLaunchWebURL(extension);
@@ -161,13 +161,6 @@
   bool is_internal_launch_scheme = launch_scheme == kExtensionScheme ||
                                    launch_scheme == content::kChromeUIScheme;
 
-  GURL last_committed_url = web_contents->GetLastCommittedURL();
-
-  // We check the visible URL to indicate to the user that they are navigating
-  // to a different origin than that of the app as soon as the navigation
-  // starts, even if the navigation hasn't committed yet.
-  GURL visible_url = web_contents->GetVisibleURL();
-
   // The current page must be secure for us to hide the toolbar. However,
   // the chrome-extension:// and chrome:// launch URL apps can hide the toolbar,
   // if the current WebContents URLs are the same as the launch scheme.
@@ -177,28 +170,44 @@
   base::StringPiece secure_page_scheme =
       is_internal_launch_scheme ? launch_scheme : url::kHttpsScheme;
 
-  // Insecure page schemes show the toolbar.
-  if (last_committed_url.scheme_piece() != secure_page_scheme ||
-      visible_url.scheme_piece() != secure_page_scheme) {
+  auto should_show_toolbar_for_url = [&](const GURL& url) -> bool {
+    // If the url is unset, it doesn't give a signal as to whether the toolbar
+    // should be shown or not. In lieu of more information, do not show the
+    // toolbar.
+    if (url.is_empty())
+      return false;
+
+    if (url.scheme_piece() != secure_page_scheme)
+      return true;
+
+    if (IsForSystemWebApp()) {
+      DCHECK_EQ(url.scheme_piece(), content::kChromeUIScheme);
+      return false;
+    }
+
+    // Page URLs that are not within scope
+    // (https://www.w3.org/TR/appmanifest/#dfn-within-scope) of the app
+    // corresponding to |launch_url| show the toolbar.
+    return !IsSameScope(launch_url, url, web_contents->GetBrowserContext());
+  };
+
+  GURL visible_url = web_contents->GetVisibleURL();
+  GURL last_committed_url = web_contents->GetLastCommittedURL();
+
+  if (last_committed_url.is_empty() && visible_url.is_empty())
+    return should_show_toolbar_for_url(initial_url());
+
+  if (should_show_toolbar_for_url(visible_url) ||
+      should_show_toolbar_for_url(last_committed_url)) {
     return true;
   }
 
-  if (IsForSystemWebApp()) {
-    DCHECK_EQ(last_committed_url.scheme_piece(), content::kChromeUIScheme);
-    return false;
-  }
-
-  // Page URLs that are not within scope
-  // (https://www.w3.org/TR/appmanifest/#dfn-within-scope) of the app
-  // corresponding to |launch_url| show the toolbar.
-  if (!IsSameScope(launch_url, last_committed_url,
-                   web_contents->GetBrowserContext()) ||
-      !IsSameScope(launch_url, visible_url, web_contents->GetBrowserContext()))
-    return true;
-
   // Insecure external web sites show the toolbar.
-  if (!is_internal_launch_scheme && !IsSiteSecure(web_contents))
+  // Note: IsSiteSecure is false until a url is committed.
+  if (!last_committed_url.is_empty() && !is_internal_launch_scheme &&
+      !IsSiteSecure(web_contents)) {
     return true;
+  }
 
   return false;
 }
@@ -308,6 +317,21 @@
   return GetExtension();
 }
 
+void HostedAppBrowserController::OnReceivedInitialURL() {
+  UpdateToolbarVisibility(false);
+
+  // If the window bounds have not been overridden, there is no need to resize
+  // the window.
+  if (!browser()->bounds_overridden())
+    return;
+
+  DCHECK(chrome::SavedBoundsAreContentBounds(browser()));
+  // TODO(crbug.com/964825): Correctly set the window size at creation time.
+  // This is currently not possible because the current url is not easily known
+  // at popup construction time.
+  browser()->window()->SetContentsSize(browser()->override_bounds().size());
+}
+
 void HostedAppBrowserController::OnTabInserted(content::WebContents* contents) {
   AppBrowserController::OnTabInserted(contents);
   extensions::HostedAppBrowserController::SetAppPrefsForWebContents(this,
diff --git a/chrome/browser/ui/extensions/hosted_app_browser_controller.h b/chrome/browser/ui/extensions/hosted_app_browser_controller.h
index d86cc625..a985c3c 100644
--- a/chrome/browser/ui/extensions/hosted_app_browser_controller.h
+++ b/chrome/browser/ui/extensions/hosted_app_browser_controller.h
@@ -98,6 +98,7 @@
   bool IsHostedApp() const override;
 
  protected:
+  void OnReceivedInitialURL() override;
   void OnTabInserted(content::WebContents* contents) override;
   void OnTabRemoved(content::WebContents* contents) override;
 
diff --git a/chrome/browser/ui/extensions/hosted_app_browsertest.cc b/chrome/browser/ui/extensions/hosted_app_browsertest.cc
index a047edf..b154ee4 100644
--- a/chrome/browser/ui/extensions/hosted_app_browsertest.cc
+++ b/chrome/browser/ui/extensions/hosted_app_browsertest.cc
@@ -1150,6 +1150,36 @@
   EXPECT_EQ(size, popup_browser->window()->GetContentsSize());
 }
 
+// Tests that using window.open to create a popup window in scope results in
+// a correctly sized window.
+IN_PROC_BROWSER_TEST_P(HostedAppPWAOnlyTest, InScopePWAPopupsHaveCorrectSize) {
+  ASSERT_TRUE(https_server()->Start());
+
+  InstallSecurePWA();
+
+  LaunchApp();
+  EXPECT_TRUE(web_app::AppBrowserController::IsForWebAppBrowser(app_browser_));
+
+  gfx::Size size(500, 500);
+  Browser* popup_browser =
+      OpenPopupAndWait(app_browser_, GetSecureAppURL(), size);
+
+  // The navigation should have happened in a new window.
+  EXPECT_NE(popup_browser, app_browser_);
+
+  // The popup browser should be a PWA.
+  EXPECT_TRUE(web_app::AppBrowserController::IsForWebAppBrowser(popup_browser));
+
+  // Toolbar should not be shown, as the popup is in scope.
+  EXPECT_FALSE(popup_browser->app_controller()->ShouldShowToolbar());
+
+  // Skip animating the toolbar visibility.
+  popup_browser->app_controller()->UpdateToolbarVisibility(false);
+
+  // The popup window should be the size we specified.
+  EXPECT_EQ(size, popup_browser->window()->GetContentsSize());
+}
+
 // Tests that desktop PWAs open links in the browser.
 IN_PROC_BROWSER_TEST_P(HostedAppPWAOnlyTest,
                        DesktopPWAsOpenLinksInBrowserWhenFeatureDisabled) {
diff --git a/chrome/browser/ui/login/login_handler.cc b/chrome/browser/ui/login/login_handler.cc
index d24c518..498c3985 100644
--- a/chrome/browser/ui/login/login_handler.cc
+++ b/chrome/browser/ui/login/login_handler.cc
@@ -377,12 +377,12 @@
     const net::AuthChallengeInfo& auth_info) {
   PasswordForm dialog_form;
   if (base::LowerCaseEqualsASCII(auth_info.scheme, net::kBasicAuthScheme)) {
-    dialog_form.scheme = PasswordForm::SCHEME_BASIC;
+    dialog_form.scheme = PasswordForm::Scheme::kBasic;
   } else if (base::LowerCaseEqualsASCII(auth_info.scheme,
                                         net::kDigestAuthScheme)) {
-    dialog_form.scheme = PasswordForm::SCHEME_DIGEST;
+    dialog_form.scheme = PasswordForm::Scheme::kDigest;
   } else {
-    dialog_form.scheme = PasswordForm::SCHEME_OTHER;
+    dialog_form.scheme = PasswordForm::Scheme::kOther;
   }
   dialog_form.origin = auth_info.challenger.GetURL();
   DCHECK(auth_info.is_proxy || auth_info.challenger.IsSameOriginWith(
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 570320c..02d72d6 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -967,6 +967,25 @@
   return contents_web_view_->size();
 }
 
+void BrowserView::SetContentsSize(const gfx::Size& size) {
+  DCHECK(!GetContentsSize().IsEmpty());
+
+  const int width_diff = size.width() - GetContentsSize().width();
+  const int height_diff = size.height() - GetContentsSize().height();
+
+  // Resizing the window may be expensive, so only do it if the size is wrong.
+  if (width_diff == 0 && height_diff == 0)
+    return;
+
+  gfx::Rect bounds = GetBounds();
+  bounds.set_width(bounds.width() + width_diff);
+  bounds.set_height(bounds.height() + height_diff);
+  SetBounds(bounds);
+
+  DCHECK_EQ(GetContentsSize().width(), size.width());
+  DCHECK_EQ(GetContentsSize().height(), size.height());
+}
+
 bool BrowserView::IsMaximized() const {
   return frame_->IsMaximized();
 }
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h
index 734d2a152..0d111bd 100644
--- a/chrome/browser/ui/views/frame/browser_view.h
+++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -322,6 +322,7 @@
   ui::WindowShowState GetRestoredState() const override;
   gfx::Rect GetBounds() const override;
   gfx::Size GetContentsSize() const override;
+  void SetContentsSize(const gfx::Size& size) override;
   bool IsMaximized() const override;
   bool IsMinimized() const override;
   void Maximize() override;
diff --git a/chrome/browser/ui/web_applications/app_browser_controller.cc b/chrome/browser/ui/web_applications/app_browser_controller.cc
index 69f5281..a20c8b0 100644
--- a/chrome/browser/ui/web_applications/app_browser_controller.cc
+++ b/chrome/browser/ui/web_applications/app_browser_controller.cc
@@ -16,6 +16,7 @@
 #include "components/url_formatter/url_formatter.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/web_contents.h"
 #include "net/base/escape.h"
 #include "url/gurl.h"
@@ -105,6 +106,17 @@
       .IsSystemWebApp(*GetAppId());
 }
 
+void AppBrowserController::DidStartNavigation(
+    content::NavigationHandle* navigation_handle) {
+  if (!initial_url().is_empty())
+    return;
+  if (!navigation_handle->IsInMainFrame())
+    return;
+  if (navigation_handle->GetURL().is_empty())
+    return;
+  SetInitialURL(navigation_handle->GetURL());
+}
+
 void AppBrowserController::DidChangeThemeColor(
     base::Optional<SkColor> theme_color) {
   browser_->window()->UpdateFrameColor();
@@ -157,6 +169,9 @@
   DCHECK(!web_contents()) << " App windows are single tabbed only";
   content::WebContentsObserver::Observe(contents);
   DidChangeThemeColor(GetThemeColor());
+
+  if (!contents->GetVisibleURL().is_empty())
+    SetInitialURL(contents->GetVisibleURL());
 }
 
 void AppBrowserController::OnTabRemoved(content::WebContents* contents) {
@@ -164,4 +179,11 @@
   content::WebContentsObserver::Observe(nullptr);
 }
 
+void AppBrowserController::SetInitialURL(const GURL& initial_url) {
+  DCHECK(initial_url_.is_empty());
+  initial_url_ = initial_url;
+
+  OnReceivedInitialURL();
+}
+
 }  // namespace web_app
diff --git a/chrome/browser/ui/web_applications/app_browser_controller.h b/chrome/browser/ui/web_applications/app_browser_controller.h
index d587ed03..29590ea4 100644
--- a/chrome/browser/ui/web_applications/app_browser_controller.h
+++ b/chrome/browser/ui/web_applications/app_browser_controller.h
@@ -95,7 +95,12 @@
 
   Browser* browser() const { return browser_; }
 
+  // Gets the url that the app browser controller was created with. Note: This
+  // may be empty until the web contents begins navigating.
+  const GURL& initial_url() const { return initial_url_; }
+
   // content::WebContentsObserver:
+  void DidStartNavigation(content::NavigationHandle* handle) override;
   void DidChangeThemeColor(base::Optional<SkColor> theme_color) override;
 
   // TabStripModelObserver:
@@ -106,12 +111,20 @@
 
  protected:
   explicit AppBrowserController(Browser* browser);
+
+  // Called once the app browser controller has determined its initial url.
+  virtual void OnReceivedInitialURL() {}
+
   // Called by OnTabstripModelChanged().
   virtual void OnTabInserted(content::WebContents* contents);
   virtual void OnTabRemoved(content::WebContents* contents);
 
  private:
+  // Sets the url that the app browser controller was created with.
+  void SetInitialURL(const GURL& initial_url);
+
   Browser* const browser_;
+  GURL initial_url_;
 
   DISALLOW_COPY_AND_ASSIGN(AppBrowserController);
 };
diff --git a/chrome/browser/ui/webui/app_management/app_management_page_handler.cc b/chrome/browser/ui/webui/app_management/app_management_page_handler.cc
index 0766eed..2235200 100644
--- a/chrome/browser/ui/webui/app_management/app_management_page_handler.cc
+++ b/chrome/browser/ui/webui/app_management/app_management_page_handler.cc
@@ -220,3 +220,8 @@
     page_->OnAppChanged(CreateUIAppPtr(update));
   }
 }
+
+void AppManagementPageHandler::OnAppRegistryCacheWillBeDestroyed(
+    apps::AppRegistryCache* cache) {
+  Observe(nullptr);
+}
diff --git a/chrome/browser/ui/webui/app_management/app_management_page_handler.h b/chrome/browser/ui/webui/app_management/app_management_page_handler.h
index 0d78023..0c7cb77 100644
--- a/chrome/browser/ui/webui/app_management/app_management_page_handler.h
+++ b/chrome/browser/ui/webui/app_management/app_management_page_handler.h
@@ -44,6 +44,8 @@
 
   // apps::AppRegistryCache::Observer overrides:
   void OnAppUpdate(const apps::AppUpdate& update) override;
+  void OnAppRegistryCacheWillBeDestroyed(
+      apps::AppRegistryCache* cache) override;
 
   mojo::Binding<app_management::mojom::PageHandler> binding_;
 
diff --git a/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.cc b/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.cc
index bc4371d..e8d848a 100644
--- a/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.cc
+++ b/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.cc
@@ -47,21 +47,15 @@
 // We only support sending username for named users but just in case.
 const char kUsernamePlaceholder[] = "chronos";
 
-// Store the name used in CUPS, Printer#id in |printer_name|, the description
-// as the system_driverinfo option value, and the Printer#display_name in
-// the |printer_description| field.  This will match how Mac OS X presents
-// printer information.
 PrinterBasicInfo ToBasicInfo(const chromeos::Printer& printer) {
   PrinterBasicInfo basic_info;
 
-  // TODO(skau): Unify Mac with the other platforms for display name
-  // presentation so I can remove this strange code.
-  basic_info.options[kDriverInfoTagName] = printer.description();
   basic_info.options[kCUPSEnterprisePrinter] =
       (printer.source() == chromeos::Printer::SRC_POLICY) ? kValueTrue
                                                           : kValueFalse;
   basic_info.printer_name = printer.id();
-  basic_info.printer_description = printer.display_name();
+  basic_info.display_name = printer.display_name();
+  basic_info.printer_description = printer.description();
   return basic_info;
 }
 
diff --git a/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos_unittest.cc b/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos_unittest.cc
index 4c05553..e968ba22 100644
--- a/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos_unittest.cc
+++ b/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos_unittest.cc
@@ -59,16 +59,20 @@
   capabilities_out->reset(capability.DeepCopy());
 }
 
-Printer CreateTestPrinter(const std::string& id, const std::string& name) {
+Printer CreateTestPrinter(const std::string& id,
+                          const std::string& name,
+                          const std::string& description) {
   Printer printer;
   printer.set_id(id);
   printer.set_display_name(name);
+  printer.set_description(description);
   return printer;
 }
 
 Printer CreateEnterprisePrinter(const std::string& id,
-                                const std::string& name) {
-  Printer printer = CreateTestPrinter(id, name);
+                                const std::string& name,
+                                const std::string& description) {
+  Printer printer = CreateTestPrinter(id, name, description);
   printer.set_source(Printer::SRC_POLICY);
   return printer;
 }
@@ -152,10 +156,12 @@
   std::unique_ptr<base::ListValue> printers;
   bool is_done = false;
 
-  Printer saved_printer = CreateTestPrinter("printer1", "saved");
+  Printer saved_printer =
+      CreateTestPrinter("printer1", "saved", "description1");
   Printer enterprise_printer =
-      CreateEnterprisePrinter("printer2", "enterprise");
-  Printer automatic_printer = CreateTestPrinter("printer3", "automatic");
+      CreateEnterprisePrinter("printer2", "enterprise", "description2");
+  Printer automatic_printer =
+      CreateTestPrinter("printer3", "automatic", "description3");
 
   printers_manager_.AddPrinter(saved_printer, PrinterClass::kSaved);
   printers_manager_.AddPrinter(enterprise_printer, PrinterClass::kEnterprise);
@@ -174,31 +180,28 @@
       {
         "cupsEnterprisePrinter": false,
         "deviceName": "printer1",
-        "printerDescription": "",
+        "printerDescription": "description1",
         "printerName": "saved",
         "printerOptions": {
-          "cupsEnterprisePrinter": "false",
-          "system_driverinfo": ""
+          "cupsEnterprisePrinter": "false"
         }
       },
       {
         "cupsEnterprisePrinter": true,
         "deviceName": "printer2",
-        "printerDescription": "",
+        "printerDescription": "description2",
         "printerName": "enterprise",
         "printerOptions": {
-          "cupsEnterprisePrinter": "true",
-          "system_driverinfo": ""
+          "cupsEnterprisePrinter": "true"
         }
       },
       {
         "cupsEnterprisePrinter": false,
         "deviceName": "printer3",
-        "printerDescription": "",
+        "printerDescription": "description3",
         "printerName": "automatic",
         "printerOptions": {
-          "cupsEnterprisePrinter": "false",
-          "system_driverinfo": ""
+          "cupsEnterprisePrinter": "false"
         }
       }
     ]
@@ -213,7 +216,8 @@
 // Tests that fetching capabilities for an existing installed printer is
 // successful.
 TEST_F(LocalPrinterHandlerChromeosTest, StartGetCapabilityValidPrinter) {
-  Printer saved_printer = CreateTestPrinter("printer1", "saved");
+  Printer saved_printer =
+      CreateTestPrinter("printer1", "saved", "description1");
   printers_manager_.AddPrinter(saved_printer, PrinterClass::kSaved);
   printers_manager_.InstallPrinter("printer1");
 
@@ -238,7 +242,8 @@
 // Test that printers which have not yet been installed are installed with
 // SetUpPrinter before their capabilities are fetched.
 TEST_F(LocalPrinterHandlerChromeosTest, StartGetCapabilityPrinterNotInstalled) {
-  Printer discovered_printer = CreateTestPrinter("printer1", "discovered");
+  Printer discovered_printer =
+      CreateTestPrinter("printer1", "discovered", "description1");
   // NOTE: The printer |discovered_printer| is not installed using
   // InstallPrinter.
   printers_manager_.AddPrinter(discovered_printer, PrinterClass::kDiscovered);
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_utils.cc b/chrome/browser/ui/webui/print_preview/print_preview_utils.cc
index 928cd004..b5bbf38 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_utils.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_utils.cc
@@ -48,11 +48,9 @@
     auto printer_info = std::make_unique<base::DictionaryValue>();
     printer_info->SetString(kSettingDeviceName, printer.printer_name);
 
-    const auto printer_name_description = GetPrinterNameAndDescription(printer);
-    const std::string& printer_name = printer_name_description.first;
-    const std::string& printer_description = printer_name_description.second;
-    printer_info->SetString(kSettingPrinterName, printer_name);
-    printer_info->SetString(kSettingPrinterDescription, printer_description);
+    printer_info->SetString(kSettingPrinterName, printer.display_name);
+    printer_info->SetString(kSettingPrinterDescription,
+                            printer.printer_description);
 
     auto options = std::make_unique<base::DictionaryValue>();
     for (const auto opt_it : printer.options)
@@ -67,7 +65,7 @@
 
     printers->Append(std::move(printer_info));
 
-    VLOG(1) << "Found printer " << printer_name << " with device name "
+    VLOG(1) << "Found printer " << printer.display_name << " with device name "
             << printer.printer_name;
   }
 }
diff --git a/chrome/browser/ui/webui/site_settings_helper.cc b/chrome/browser/ui/webui/site_settings_helper.cc
index fa12149..6dd81e1 100644
--- a/chrome/browser/ui/webui/site_settings_helper.cc
+++ b/chrome/browser/ui/webui/site_settings_helper.cc
@@ -426,7 +426,7 @@
     // Off-the-record HostContentSettingsMap contains incognito content settings
     // as well as normal content settings. Here, we use the incongnito settings
     // only.
-    if (map->is_incognito() && !i->incognito)
+    if (map->IsOffTheRecord() && !i->incognito)
       continue;
 
     if (filter && i->primary_pattern.ToString() != *filter)
diff --git a/chrome/browser/vr/service/xr_device_impl.cc b/chrome/browser/vr/service/xr_device_impl.cc
index 12f3a88e..c2cc547 100644
--- a/chrome/browser/vr/service/xr_device_impl.cc
+++ b/chrome/browser/vr/service/xr_device_impl.cc
@@ -8,6 +8,7 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/trace_event/common/trace_event_common.h"
 #include "build/build_config.h"
 #include "chrome/browser/vr/metrics/session_metrics_helper.h"
@@ -71,7 +72,8 @@
   binding_.Bind(std::move(request));
 }
 
-void XRDeviceImpl::OnNonImmersiveSessionCreated(
+void XRDeviceImpl::OnInlineSessionCreated(
+    device::mojom::XRDeviceId session_runtime_id,
     device::mojom::XRDevice::RequestSessionCallback callback,
     device::mojom::XRSessionPtr session,
     device::mojom::XRSessionControllerPtr controller) {
@@ -85,10 +87,11 @@
 
   magic_window_controllers_.AddPtr(std::move(controller));
 
-  OnSessionCreated(std::move(callback), std::move(session));
+  OnSessionCreated(session_runtime_id, std::move(callback), std::move(session));
 }
 
 void XRDeviceImpl::OnSessionCreated(
+    device::mojom::XRDeviceId session_runtime_id,
     device::mojom::XRDevice::RequestSessionCallback callback,
     device::mojom::XRSessionPtr session) {
   if (!session) {
@@ -96,6 +99,8 @@
     return;
   }
 
+  UMA_HISTOGRAM_ENUMERATION("XR.RuntimeUsed", session_runtime_id);
+
   device::mojom::XRSessionClientPtr client;
   session->client_request = mojo::MakeRequest(&client);
 
@@ -110,7 +115,6 @@
 
 void XRDeviceImpl::RequestSession(
     device::mojom::XRSessionOptionsPtr options,
-    bool triggered_by_displayactive,
     device::mojom::XRDevice::RequestSessionCallback callback) {
   DCHECK(options);
 
@@ -140,18 +144,16 @@
         GetWebContents(),
         base::BindOnce(&XRDeviceImpl::OnUserConsent,
                        weak_ptr_factory_.GetWeakPtr(), std::move(options),
-                       triggered_by_displayactive, std::move(callback)));
+                       std::move(callback)));
     return;
   }
 #endif
 
-  OnUserConsent(std::move(options), triggered_by_displayactive,
-                std::move(callback), true);
+  OnUserConsent(std::move(options), std::move(callback), true);
 }
 
 void XRDeviceImpl::OnUserConsent(
     device::mojom::XRSessionOptionsPtr options,
-    bool triggered_by_displayactive,
     device::mojom::XRDevice::RequestSessionCallback callback,
     bool allowed) {
   if (!allowed) {
@@ -169,14 +171,15 @@
   // Get the runtime we'll be creating a session with.
   BrowserXRRuntime* runtime =
       XRRuntimeManager::GetInstance()->GetRuntimeForOptions(options.get());
-  int id_for_event = runtime ? static_cast<int>(runtime->GetId()) : -1;
-  TRACE_EVENT_INSTANT1("xr", "GetRuntimeForOptions", TRACE_EVENT_SCOPE_THREAD,
-                       "id", id_for_event);
   if (!runtime) {
     std::move(callback).Run(nullptr);
     return;
   }
 
+  device::mojom::XRDeviceId session_runtime_id = runtime->GetId();
+  TRACE_EVENT_INSTANT1("xr", "GetRuntimeForOptions", TRACE_EVENT_SCOPE_THREAD,
+                       "id", session_runtime_id);
+
   auto runtime_options = GetRuntimeOptions(options.get());
   runtime_options->render_process_id =
       render_frame_host_ ? render_frame_host_->GetProcess()->GetID() : -1;
@@ -184,21 +187,21 @@
       render_frame_host_ ? render_frame_host_->GetRoutingID() : -1;
 
   if (runtime_options->immersive) {
-    if (!triggered_by_displayactive) {
-      ReportRequestPresent();
-    }
+    ReportRequestPresent();
 
     base::OnceCallback<void(device::mojom::XRSessionPtr)> immersive_callback =
         base::BindOnce(&XRDeviceImpl::OnSessionCreated,
-                       weak_ptr_factory_.GetWeakPtr(), std::move(callback));
+                       weak_ptr_factory_.GetWeakPtr(), session_runtime_id,
+                       std::move(callback));
     runtime->RequestSession(this, std::move(runtime_options),
                             std::move(immersive_callback));
   } else {
     base::OnceCallback<void(device::mojom::XRSessionPtr,
                             device::mojom::XRSessionControllerPtr)>
         non_immersive_callback =
-            base::BindOnce(&XRDeviceImpl::OnNonImmersiveSessionCreated,
-                           weak_ptr_factory_.GetWeakPtr(), std::move(callback));
+            base::BindOnce(&XRDeviceImpl::OnInlineSessionCreated,
+                           weak_ptr_factory_.GetWeakPtr(), session_runtime_id,
+                           std::move(callback));
     runtime->GetRuntime()->RequestSession(std::move(runtime_options),
                                           std::move(non_immersive_callback));
   }
diff --git a/chrome/browser/vr/service/xr_device_impl.h b/chrome/browser/vr/service/xr_device_impl.h
index cc166cc..7f2b53b 100644
--- a/chrome/browser/vr/service/xr_device_impl.h
+++ b/chrome/browser/vr/service/xr_device_impl.h
@@ -39,7 +39,6 @@
   // device::mojom::XRDevice
   void RequestSession(
       device::mojom::XRSessionOptionsPtr options,
-      bool triggered_by_displayactive,
       device::mojom::XRDevice::RequestSessionCallback callback) override;
   void SupportsSession(
       device::mojom::XRSessionOptionsPtr options,
@@ -76,15 +75,16 @@
   bool IsAnotherHostPresenting();
 
   bool InternalSupportsSession(device::mojom::XRSessionOptions* options);
-  void OnNonImmersiveSessionCreated(
+  void OnInlineSessionCreated(
+      device::mojom::XRDeviceId session_runtime_id,
       device::mojom::XRDevice::RequestSessionCallback callback,
       device::mojom::XRSessionPtr session,
       device::mojom::XRSessionControllerPtr controller);
   void OnSessionCreated(
+      device::mojom::XRDeviceId session_runtime_id,
       device::mojom::XRDevice::RequestSessionCallback callback,
       device::mojom::XRSessionPtr session);
   void OnUserConsent(device::mojom::XRSessionOptionsPtr options,
-                     bool triggered_by_displayactive,
                      device::mojom::XRDevice::RequestSessionCallback callback,
                      bool allowed);
 
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
index d94290e..94fa168 100644
--- a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
+++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
@@ -337,7 +337,7 @@
 bool ChromeAuthenticatorRequestDelegate::ShouldDisablePlatformAuthenticators() {
 #if defined(OS_MACOSX)
   // Touch ID is available in Incognito, but not in Guest mode.
-  return Profile::FromBrowserContext(browser_context())->IsGuestProfile();
+  return Profile::FromBrowserContext(browser_context())->IsGuestSession();
 #else  // Windows, Android
   return browser_context()->IsOffTheRecord();
 #endif
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 30772a0..ef4abe8 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -362,8 +362,14 @@
 
 #if !defined(OS_ANDROID)
 // Enables or disables intent picker.
-const base::Feature kIntentPicker{"IntentPicker",
-                                  base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kIntentPicker {
+  "IntentPicker",
+#if defined(OS_CHROMEOS)
+      base::FEATURE_ENABLED_BY_DEFAULT
+#else
+      base::FEATURE_DISABLED_BY_DEFAULT
+#endif  //  defined(OS_CHROMEOS)
+};
 #endif  // !defined(OS_ANDROID)
 
 // Uses KidsManagement UrlClassification instead of SafeSearch for supervised
diff --git a/chrome/renderer/autofill/password_autofill_agent_browsertest.cc b/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
index 8c1dd6b..71b495b 100644
--- a/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
+++ b/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
@@ -743,28 +743,6 @@
 // Tests that the password login is autocompleted as expected when the browser
 // sends back the password info.
 TEST_F(PasswordAutofillAgentTest, InitialAutocomplete) {
-  /*
-   * Right now we are not sending the message to the browser because we are
-   * loading a data URL and the security origin canAccessPasswordManager()
-   * returns false.  May be we should mock URL loading to cirmcuvent this?
-   TODO(jcivelli): find a way to make the security origin not deny access to the
-                   password manager and then reenable this code.
-
-  // The form has been loaded, we should have sent the browser a message about
-  // the form.
-  const IPC::Message* msg = render_thread_.sink().GetFirstMessageMatching(
-      AutofillHostMsg_PasswordFormsParsed::ID);
-  ASSERT_TRUE(msg != NULL);
-
-  std::tuple<std::vector<PasswordForm> > forms;
-  AutofillHostMsg_PasswordFormsParsed::Read(msg, &forms);
-  ASSERT_EQ(1U, forms.a.size());
-  PasswordForm password_form = forms.a[0];
-  EXPECT_EQ(PasswordForm::SCHEME_HTML, password_form.scheme);
-  EXPECT_EQ(ASCIIToUTF16(kUsernameName), password_form.username_element);
-  EXPECT_EQ(ASCIIToUTF16(kPasswordName), password_form.password_element);
-  */
-
   // Simulate the browser sending back the login info, it triggers the
   // autocomplete.
   SimulateOnFillPasswordForm(fill_data_);
diff --git a/chrome/services/app_service/public/cpp/app_registry_cache.cc b/chrome/services/app_service/public/cpp/app_registry_cache.cc
index d40171c7..bc1352ad 100644
--- a/chrome/services/app_service/public/cpp/app_registry_cache.cc
+++ b/chrome/services/app_service/public/cpp/app_registry_cache.cc
@@ -36,7 +36,12 @@
 
 AppRegistryCache::AppRegistryCache() = default;
 
-AppRegistryCache::~AppRegistryCache() = default;
+AppRegistryCache::~AppRegistryCache() {
+  for (auto& obs : observers_) {
+    obs.OnAppRegistryCacheWillBeDestroyed(this);
+  }
+  DCHECK(!observers_.might_have_observers());
+}
 
 void AppRegistryCache::AddObserver(Observer* observer) {
   observers_.AddObserver(observer);
diff --git a/chrome/services/app_service/public/cpp/app_registry_cache.h b/chrome/services/app_service/public/cpp/app_registry_cache.h
index 7183ed9..07eeac6 100644
--- a/chrome/services/app_service/public/cpp/app_registry_cache.h
+++ b/chrome/services/app_service/public/cpp/app_registry_cache.h
@@ -37,20 +37,27 @@
     // returns.
     virtual void OnAppUpdate(const AppUpdate& update) = 0;
 
+    // Called when the AppRegistryCache object (the thing that this observer
+    // observes) will be destroyed. In response, the observer, |this|, should
+    // call "cache->RemoveObserver(this)", whether directly or indirectly (e.g.
+    // via ScopedObserver::Remove or via Observe(nullptr)).
+    virtual void OnAppRegistryCacheWillBeDestroyed(AppRegistryCache* cache) = 0;
+
    protected:
-    // Use this constructor when the object is tied to a single
-    // AppRegistryCache for its entire lifetime.
+    // Use this constructor when the observer |this| is tied to a single
+    // AppRegistryCache for its entire lifetime, or until the observee (the
+    // AppRegistryCache) is destroyed, whichever comes first.
     explicit Observer(AppRegistryCache* cache);
 
-    // Use this constructor when the object wants to observe a AppRegistryCache
-    // for part of its lifetime. It can then call Observe() to start and stop
-    // observing.
+    // Use this constructor when the observer |this| wants to observe a
+    // AppRegistryCache for part of its lifetime. It can then call Observe() to
+    // start and stop observing.
     Observer();
 
     ~Observer() override;
 
-    // Start observing a different AppRegistryCache; used with the default
-    // constructor.
+    // Start observing a different AppRegistryCache. |cache| may be nullptr,
+    // meaning to stop observing.
     void Observe(AppRegistryCache* cache);
 
    private:
diff --git a/chrome/services/app_service/public/cpp/app_registry_cache_unittest.cc b/chrome/services/app_service/public/cpp/app_registry_cache_unittest.cc
index df473c1..3a4e465 100644
--- a/chrome/services/app_service/public/cpp/app_registry_cache_unittest.cc
+++ b/chrome/services/app_service/public/cpp/app_registry_cache_unittest.cc
@@ -47,6 +47,12 @@
     updated_names_.insert(update.Name());
   }
 
+  void OnAppRegistryCacheWillBeDestroyed(
+      apps::AppRegistryCache* cache) override {
+    // The test code explicitly calls both AddObserver and RemoveObserver.
+    NOTREACHED();
+  }
+
   int num_freshly_installed_ = 0;
   std::set<std::string> updated_ids_;
   std::set<std::string> updated_names_;
@@ -63,10 +69,10 @@
 class RecursiveObserver : public apps::AppRegistryCache::Observer {
  public:
   explicit RecursiveObserver(apps::AppRegistryCache* cache) : cache_(cache) {
-    cache_->AddObserver(this);
+    Observe(cache);
   }
 
-  ~RecursiveObserver() override { cache_->RemoveObserver(this); }
+  ~RecursiveObserver() override = default;
 
   void PrepareForOnApps(
       int expected_num_apps,
@@ -156,6 +162,11 @@
     num_apps_seen_on_app_update_++;
   }
 
+  void OnAppRegistryCacheWillBeDestroyed(
+      apps::AppRegistryCache* cache) override {
+    Observe(nullptr);
+  }
+
   static void ExpectEq(const apps::AppUpdate& outer,
                        const apps::AppUpdate& inner) {
     EXPECT_EQ(outer.AppType(), inner.AppType());
diff --git a/chrome/test/base/test_browser_window.cc b/chrome/test/base/test_browser_window.cc
index ef7983b..9adf436 100644
--- a/chrome/test/base/test_browser_window.cc
+++ b/chrome/test/base/test_browser_window.cc
@@ -108,6 +108,8 @@
   return gfx::Size();
 }
 
+void TestBrowserWindow::SetContentsSize(const gfx::Size& size) {}
+
 bool TestBrowserWindow::IsMaximized() const {
   return false;
 }
diff --git a/chrome/test/base/test_browser_window.h b/chrome/test/base/test_browser_window.h
index 54f25e2..f8f433a 100644
--- a/chrome/test/base/test_browser_window.h
+++ b/chrome/test/base/test_browser_window.h
@@ -84,6 +84,7 @@
   ui::WindowShowState GetRestoredState() const override;
   gfx::Rect GetBounds() const override;
   gfx::Size GetContentsSize() const override;
+  void SetContentsSize(const gfx::Size& size) override;
   bool IsMaximized() const override;
   bool IsMinimized() const override;
   void Maximize() override {}
diff --git a/chrome/test/data/extensions/api_test/runtime/open_options_page/manifest.json b/chrome/test/data/extensions/api_test/runtime/open_options_page/manifest.json
index eaa1628..81f6f54 100644
--- a/chrome/test/data/extensions/api_test/runtime/open_options_page/manifest.json
+++ b/chrome/test/data/extensions/api_test/runtime/open_options_page/manifest.json
@@ -4,8 +4,7 @@
   "manifest_version": 2,
   "description": "Browser test for chrome.runtime.openOptionsPage, success case.",
   "background": {
-    "scripts": ["test.js"],
-    "persistent": false
+    "scripts": ["test.js"]
   },
   "options_ui": {
     "page": "options.html"
diff --git a/chrome/test/data/webui/settings/chromeos/smb_shares_page_tests.js b/chrome/test/data/webui/settings/chromeos/smb_shares_page_tests.js
index 5fdc0bf2..713d70c 100644
--- a/chrome/test/data/webui/settings/chromeos/smb_shares_page_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/smb_shares_page_tests.js
@@ -69,6 +69,44 @@
     expectFalse(addButton.disabled);
   });
 
+  test('AddDisabledWithInvalidUrl', function() {
+    const url = addDialog.$.address;
+    const addButton = addDialog.$$('.action-button');
+
+    url.value = '';
+    expectTrue(addButton.disabled);
+
+    // Invalid scheme (must start with smb:// or \\)
+    url.value = 'foobar';
+    expectTrue(addButton.disabled);
+    url.value = 'foo\\\\bar\\baz';
+    expectTrue(addButton.disabled);
+    url.value = 'smb:/foo/bar';
+    expectTrue(addButton.disabled);
+
+    // Incomplete (must be of the form \\server\share)
+    url.value = '\\\\foo';
+    expectTrue(addButton.disabled);
+    url.value = '\\\\foo\\';
+    expectTrue(addButton.disabled);
+    url.value = '\\\\foo\\\\';
+    expectTrue(addButton.disabled);
+
+    // Incomplete (must be of the form smb://server/share)
+    url.value = 'smb://';
+    expectTrue(addButton.disabled);
+    url.value = 'smb://foo';
+    expectTrue(addButton.disabled);
+    url.value = 'smb://foo/';
+    expectTrue(addButton.disabled);
+
+    // Valid URLs.
+    url.value = '\\\\foo\\bar';
+    expectFalse(addButton.disabled);
+    url.value = 'smb://foo/bar';
+    expectFalse(addButton.disabled);
+  });
+
   test('ClickAdd', function() {
     const expectedSmbUrl = 'smb://192.168.1.1/testshare';
     const expectedSmbName = 'testname';
diff --git a/chrome/utility/importer/firefox_importer_unittest.cc b/chrome/utility/importer/firefox_importer_unittest.cc
index 096a81e..28743b1 100644
--- a/chrome/utility/importer/firefox_importer_unittest.cc
+++ b/chrome/utility/importer/firefox_importer_unittest.cc
@@ -156,8 +156,8 @@
       decryptor_proxy.ParseSignons(signons_path);
 
   ASSERT_EQ(2u, forms.size());
-  EXPECT_EQ(autofill::PasswordForm::SCHEME_BASIC, forms[0].scheme);
-  EXPECT_EQ(autofill::PasswordForm::SCHEME_HTML, forms[1].scheme);
+  EXPECT_EQ(autofill::PasswordForm::Scheme::kBasic, forms[0].scheme);
+  EXPECT_EQ(autofill::PasswordForm::Scheme::kHtml, forms[1].scheme);
 }
 
 TEST(FirefoxImporterTest, ImportBookmarks_Firefox48) {
diff --git a/chrome/utility/importer/nss_decryptor.cc b/chrome/utility/importer/nss_decryptor.cc
index 9842ee2..e080ef8 100644
--- a/chrome/utility/importer/nss_decryptor.cc
+++ b/chrome/utility/importer/nss_decryptor.cc
@@ -378,7 +378,7 @@
     // Non-empty realm indicates that it's not html form authentication entry.
     // Extracted data doesn't allow us to distinguish basic_auth entry from
     // digest_auth entry, so let's assume basic_auth.
-    form->scheme = autofill::PasswordForm::SCHEME_BASIC;
+    form->scheme = autofill::PasswordForm::Scheme::kBasic;
   }
   form->username_element = raw_password_info.username_element;
   form->username_value = Decrypt(raw_password_info.encrypted_username);
diff --git a/chromecast/media/cma/backend/audio_decoder_software_wrapper.cc b/chromecast/media/cma/backend/audio_decoder_software_wrapper.cc
index 908e68d3..a3fdfaa5 100644
--- a/chromecast/media/cma/backend/audio_decoder_software_wrapper.cc
+++ b/chromecast/media/cma/backend/audio_decoder_software_wrapper.cc
@@ -113,6 +113,7 @@
   output_config_.bytes_per_channel = 2;
   output_config_.samples_per_second = config.samples_per_second;
   output_config_.encryption_scheme = EncryptionScheme::kUnencrypted;
+  output_config_.channel_layout = config.channel_layout;
   return backend_decoder_->SetConfig(output_config_);
 }
 
diff --git a/chromecast/media/cma/base/decoder_config_adapter.cc b/chromecast/media/cma/base/decoder_config_adapter.cc
index 9075813c..766e2455 100644
--- a/chromecast/media/cma/base/decoder_config_adapter.cc
+++ b/chromecast/media/cma/base/decoder_config_adapter.cc
@@ -55,6 +55,7 @@
     case ::media::ChannelLayout::CHANNEL_LAYOUT_STEREO:
       return ChannelLayout::STEREO;
     case ::media::ChannelLayout::CHANNEL_LAYOUT_5_1:
+    case ::media::ChannelLayout::CHANNEL_LAYOUT_5_1_BACK:
       return ChannelLayout::SURROUND_5_1;
     case ::media::ChannelLayout::CHANNEL_LAYOUT_BITSTREAM:
       return ChannelLayout::BITSTREAM;
diff --git a/chromeos/dbus/cicerone_client.cc b/chromeos/dbus/cicerone_client.cc
index 15a12de..da592b8 100644
--- a/chromeos/dbus/cicerone_client.cc
+++ b/chromeos/dbus/cicerone_client.cc
@@ -479,6 +479,13 @@
             weak_ptr_factory_.GetWeakPtr()),
         base::BindOnce(&CiceroneClientImpl::OnSignalConnected,
                        weak_ptr_factory_.GetWeakPtr()));
+    cicerone_proxy_->ConnectToSignal(
+        vm_tools::cicerone::kVmCiceroneInterface,
+        vm_tools::cicerone::kPendingAppListUpdatesSignal,
+        base::BindRepeating(&CiceroneClientImpl::OnPendingAppListUpdatesSignal,
+                            weak_ptr_factory_.GetWeakPtr()),
+        base::BindOnce(&CiceroneClientImpl::OnSignalConnected,
+                       weak_ptr_factory_.GetWeakPtr()));
   }
 
  private:
@@ -631,6 +638,18 @@
     }
   }
 
+  void OnPendingAppListUpdatesSignal(dbus::Signal* signal) {
+    vm_tools::cicerone::PendingAppListUpdatesSignal proto;
+    dbus::MessageReader reader(signal);
+    if (!reader.PopArrayOfBytesAsProto(&proto)) {
+      LOG(ERROR) << "Failed to parse proto from DBus Signal";
+      return;
+    }
+    for (auto& observer : observer_list_) {
+      observer.OnPendingAppListUpdates(proto);
+    }
+  }
+
   void OnSignalConnected(const std::string& interface_name,
                          const std::string& signal_name,
                          bool is_connected) {
diff --git a/chromeos/dbus/cicerone_client.h b/chromeos/dbus/cicerone_client.h
index 19ee0e1..f087803 100644
--- a/chromeos/dbus/cicerone_client.h
+++ b/chromeos/dbus/cicerone_client.h
@@ -78,6 +78,11 @@
     virtual void OnImportLxdContainerProgress(
         const vm_tools::cicerone::ImportLxdContainerProgressSignal& signal) = 0;
 
+    // OnPendingAppListUpdates is signalled from Cicerone when the number of
+    // pending app list updates changes.
+    virtual void OnPendingAppListUpdates(
+        const vm_tools::cicerone::PendingAppListUpdatesSignal& signal) = 0;
+
    protected:
     virtual ~Observer() = default;
   };
diff --git a/chromeos/dbus/fake_cicerone_client.cc b/chromeos/dbus/fake_cicerone_client.cc
index d0d87d6..7f850b4 100644
--- a/chromeos/dbus/fake_cicerone_client.cc
+++ b/chromeos/dbus/fake_cicerone_client.cc
@@ -320,4 +320,11 @@
   }
 }
 
+void FakeCiceroneClient::NotifyPendingAppListUpdates(
+    const vm_tools::cicerone::PendingAppListUpdatesSignal& proto) {
+  for (auto& observer : observer_list_) {
+    observer.OnPendingAppListUpdates(proto);
+  }
+}
+
 }  // namespace chromeos
diff --git a/chromeos/dbus/fake_cicerone_client.h b/chromeos/dbus/fake_cicerone_client.h
index 0925d1e1..aac705b 100644
--- a/chromeos/dbus/fake_cicerone_client.h
+++ b/chromeos/dbus/fake_cicerone_client.h
@@ -340,6 +340,8 @@
       const vm_tools::cicerone::InstallLinuxPackageProgressSignal& signal);
   void UninstallPackageProgress(
       const vm_tools::cicerone::UninstallPackageProgressSignal& signal);
+  void NotifyPendingAppListUpdates(
+      const vm_tools::cicerone::PendingAppListUpdatesSignal& signal);
 
  protected:
   void Init(dbus::Bus* bus) override {}
diff --git a/chromeos/services/cellular_setup/cellular_setup_impl.cc b/chromeos/services/cellular_setup/cellular_setup_impl.cc
index 4c76c65a..c8ef02b7c 100644
--- a/chromeos/services/cellular_setup/cellular_setup_impl.cc
+++ b/chromeos/services/cellular_setup/cellular_setup_impl.cc
@@ -37,7 +37,6 @@
 CellularSetupImpl::~CellularSetupImpl() = default;
 
 void CellularSetupImpl::StartActivation(
-    const std::string& cellular_network_guid,
     mojom::ActivationDelegatePtr delegate,
     StartActivationCallback callback) {
   // TODO(khorimoto): Actually return a CarrierPortalObserver instead of
diff --git a/chromeos/services/cellular_setup/cellular_setup_impl.h b/chromeos/services/cellular_setup/cellular_setup_impl.h
index 3e606276..4590002 100644
--- a/chromeos/services/cellular_setup/cellular_setup_impl.h
+++ b/chromeos/services/cellular_setup/cellular_setup_impl.h
@@ -29,8 +29,7 @@
   CellularSetupImpl();
 
   // mojom::CellularSetup:
-  void StartActivation(const std::string& cellular_network_guid,
-                       mojom::ActivationDelegatePtr delegate,
+  void StartActivation(mojom::ActivationDelegatePtr delegate,
                        StartActivationCallback callback) override;
 
   DISALLOW_COPY_AND_ASSIGN(CellularSetupImpl);
diff --git a/chromeos/services/cellular_setup/cellular_setup_service_unittest.cc b/chromeos/services/cellular_setup/cellular_setup_service_unittest.cc
index 01efeefa..1515e4c 100644
--- a/chromeos/services/cellular_setup/cellular_setup_service_unittest.cc
+++ b/chromeos/services/cellular_setup/cellular_setup_service_unittest.cc
@@ -29,7 +29,6 @@
 using CarrierPortalHandlerPair =
     std::pair<mojom::CarrierPortalHandlerPtr, FakeCarrierPortalHandler*>;
 
-const char kTestCellularNetworkGuid[] = "testCellularNetworkGuid";
 const char kTestPaymentUrl[] = "testPaymentUrl";
 const char kTestPaymentPostData[] = "testPaymentPostData";
 const char kTestCarrier[] = "testCarrier";
@@ -86,7 +85,6 @@
   // Calls StartActivation() and returns the fake CarrierPortalHandler and its
   // associated InterfacePtr.
   CarrierPortalHandlerPair CallStartActivation(
-      const std::string& cellular_network_guid,
       FakeActivationDelegate* fake_activation_delegate) {
     std::vector<std::unique_ptr<FakeCellularSetup::StartActivationInvocation>>&
         start_activation_invocations =
@@ -96,15 +94,13 @@
 
     // Make StartActivation() call and propagate it to the service.
     cellular_setup_ptr_->StartActivation(
-        cellular_network_guid, fake_activation_delegate->GenerateInterfacePtr(),
+        fake_activation_delegate->GenerateInterfacePtr(),
         base::BindOnce(&CellularSetupServiceTest::OnStartActivationResult,
                        base::Unretained(this), run_loop.QuitClosure()));
     cellular_setup_ptr_.FlushForTesting();
 
     // Verify that the call was made successfully.
     EXPECT_EQ(num_args_before_call + 1u, start_activation_invocations.size());
-    EXPECT_EQ(cellular_network_guid,
-              start_activation_invocations.back()->cellular_network_guid());
 
     // Execute the callback and retrieve the returned CarrierPortalHandler.
     FakeCarrierPortalHandler* fake_carrier_portal_observer =
@@ -215,8 +211,8 @@
 TEST_F(CellularSetupServiceTest, StartActivation_Success) {
   auto fake_activation_delegate = std::make_unique<FakeActivationDelegate>();
 
-  CarrierPortalHandlerPair pair = CallStartActivation(
-      kTestCellularNetworkGuid, fake_activation_delegate.get());
+  CarrierPortalHandlerPair pair =
+      CallStartActivation(fake_activation_delegate.get());
   NotifyLastDelegateThatActivationStarted(fake_activation_delegate.get());
 
   SendCarrierPortalStatusUpdate(
@@ -232,8 +228,8 @@
 TEST_F(CellularSetupServiceTest, StartActivation_PortalFailsToLoad) {
   auto fake_activation_delegate = std::make_unique<FakeActivationDelegate>();
 
-  CarrierPortalHandlerPair pair = CallStartActivation(
-      kTestCellularNetworkGuid, fake_activation_delegate.get());
+  CarrierPortalHandlerPair pair =
+      CallStartActivation(fake_activation_delegate.get());
   NotifyLastDelegateThatActivationStarted(fake_activation_delegate.get());
 
   SendCarrierPortalStatusUpdate(mojom::CarrierPortalStatus::kPortalFailedToLoad,
@@ -247,8 +243,8 @@
 TEST_F(CellularSetupServiceTest, StartActivation_ErrorDuringPayment) {
   auto fake_activation_delegate = std::make_unique<FakeActivationDelegate>();
 
-  CarrierPortalHandlerPair pair = CallStartActivation(
-      kTestCellularNetworkGuid, fake_activation_delegate.get());
+  CarrierPortalHandlerPair pair =
+      CallStartActivation(fake_activation_delegate.get());
   NotifyLastDelegateThatActivationStarted(fake_activation_delegate.get());
 
   SendCarrierPortalStatusUpdate(
diff --git a/chromeos/services/cellular_setup/public/cpp/fake_cellular_setup.cc b/chromeos/services/cellular_setup/public/cpp/fake_cellular_setup.cc
index 36745a66..d606a40 100644
--- a/chromeos/services/cellular_setup/public/cpp/fake_cellular_setup.cc
+++ b/chromeos/services/cellular_setup/public/cpp/fake_cellular_setup.cc
@@ -13,11 +13,9 @@
 namespace cellular_setup {
 
 FakeCellularSetup::StartActivationInvocation::StartActivationInvocation(
-    const std::string& cellular_network_guid,
     mojom::ActivationDelegatePtr activation_delegate,
     StartActivationCallback callback)
-    : cellular_network_guid_(cellular_network_guid),
-      activation_delegate_(std::move(activation_delegate)),
+    : activation_delegate_(std::move(activation_delegate)),
       callback_(std::move(callback)) {}
 
 FakeCellularSetup::StartActivationInvocation::~StartActivationInvocation() =
@@ -40,7 +38,6 @@
 FakeCellularSetup::~FakeCellularSetup() = default;
 
 void FakeCellularSetup::StartActivation(
-    const std::string& cellular_network_guid,
     mojom::ActivationDelegatePtr activation_delegate,
     StartActivationCallback callback) {
   DCHECK(activation_delegate);
@@ -48,8 +45,7 @@
 
   start_activation_invocations_.emplace_back(
       std::make_unique<StartActivationInvocation>(
-          cellular_network_guid, std::move(activation_delegate),
-          std::move(callback)));
+          std::move(activation_delegate), std::move(callback)));
 }
 
 }  // namespace cellular_setup
diff --git a/chromeos/services/cellular_setup/public/cpp/fake_cellular_setup.h b/chromeos/services/cellular_setup/public/cpp/fake_cellular_setup.h
index 9ab51f9..16e3567c 100644
--- a/chromeos/services/cellular_setup/public/cpp/fake_cellular_setup.h
+++ b/chromeos/services/cellular_setup/public/cpp/fake_cellular_setup.h
@@ -23,15 +23,10 @@
  public:
   class StartActivationInvocation {
    public:
-    StartActivationInvocation(const std::string& cellular_network_guid,
-                              mojom::ActivationDelegatePtr activation_delegate,
+    StartActivationInvocation(mojom::ActivationDelegatePtr activation_delegate,
                               StartActivationCallback callback);
     ~StartActivationInvocation();
 
-    const std::string& cellular_network_guid() const {
-      return cellular_network_guid_;
-    }
-
     mojom::ActivationDelegatePtr& activation_delegate() {
       return activation_delegate_;
     }
@@ -42,7 +37,6 @@
     FakeCarrierPortalHandler* ExecuteCallback();
 
    private:
-    std::string cellular_network_guid_;
     mojom::ActivationDelegatePtr activation_delegate_;
     StartActivationCallback callback_;
 
@@ -62,8 +56,7 @@
 
  private:
   // mojom::CellularSetup:
-  void StartActivation(const std::string& cellular_network_guid,
-                       mojom::ActivationDelegatePtr activation_delegate,
+  void StartActivation(mojom::ActivationDelegatePtr activation_delegate,
                        StartActivationCallback callback) override;
 
   std::vector<std::unique_ptr<StartActivationInvocation>>
diff --git a/chromeos/services/cellular_setup/public/mojom/cellular_setup.mojom b/chromeos/services/cellular_setup/public/mojom/cellular_setup.mojom
index 055b74f..8bf9792 100644
--- a/chromeos/services/cellular_setup/public/mojom/cellular_setup.mojom
+++ b/chromeos/services/cellular_setup/public/mojom/cellular_setup.mojom
@@ -80,12 +80,8 @@
 
 // Interface used to set up a cellular connection.
 interface CellularSetup {
-  // Entrypoint to the activation flow. |cellular_network_guid| corresponds to
-  // the GUID associated with the cellular network, obtained via
-  // chromeos::NetworkState::guid(). |delegate|'s OnActivationFinished()
-  // function is guaranteed to be called. If |delegate| becomes disconnected
+  // Entrypoint to the activation flow. If |delegate| becomes disconnected
   // during the activation process, activation is cancelled.
-  StartActivation(
-      string cellular_network_guid,
-      ActivationDelegate delegate) => (CarrierPortalHandler observer);
+  StartActivation(ActivationDelegate delegate)
+      => (CarrierPortalHandler observer);
 };
diff --git a/chromeos/services/ime/ime_service.cc b/chromeos/services/ime/ime_service.cc
index 09ceb63f..e50eefa1 100644
--- a/chromeos/services/ime/ime_service.cc
+++ b/chromeos/services/ime/ime_service.cc
@@ -15,16 +15,17 @@
 namespace chromeos {
 namespace ime {
 
-ImeService::ImeService(service_manager::mojom::ServiceRequest request)
-    : service_binding_(this, std::move(request)) {}
+ImeService::ImeService(
+    mojo::PendingReceiver<service_manager::mojom::Service> receiver)
+    : service_binding_(this, std::move(receiver)) {}
 
 ImeService::~ImeService() = default;
 
 void ImeService::OnStart() {
-  binder_registry_.AddInterface<mojom::InputEngineManager>(base::BindRepeating(
-      &ImeService::BindInputEngineManagerRequest, base::Unretained(this)));
+  binders_.Add(base::BindRepeating(&ImeService::AddInputEngineManagerReceiver,
+                                   base::Unretained(this)));
 
-  engine_manager_bindings_.set_connection_error_handler(base::BindRepeating(
+  manager_receivers_.set_disconnect_handler(base::BindRepeating(
       &ImeService::OnConnectionLost, base::Unretained(this)));
 
 #if BUILDFLAG(ENABLE_CROS_IME_DECODER)
@@ -38,14 +39,14 @@
 void ImeService::OnBindInterface(
     const service_manager::BindSourceInfo& source_info,
     const std::string& interface_name,
-    mojo::ScopedMessagePipeHandle interface_pipe) {
-  binder_registry_.BindInterface(interface_name, std::move(interface_pipe));
+    mojo::ScopedMessagePipeHandle receiver_pipe) {
+  binders_.TryBind(interface_name, &receiver_pipe);
 }
 
 void ImeService::ConnectToImeEngine(
     const std::string& ime_spec,
-    mojom::InputChannelRequest to_engine_request,
-    mojom::InputChannelPtr from_engine,
+    mojo::PendingReceiver<mojom::InputChannel> to_engine_request,
+    mojo::PendingRemote<mojom::InputChannel> from_engine,
     const std::vector<uint8_t>& extra,
     ConnectToImeEngineCallback callback) {
   DCHECK(input_engine_);
@@ -54,14 +55,14 @@
   std::move(callback).Run(bound);
 }
 
-void ImeService::BindInputEngineManagerRequest(
-    mojom::InputEngineManagerRequest request) {
-  engine_manager_bindings_.AddBinding(this, std::move(request));
+void ImeService::AddInputEngineManagerReceiver(
+    mojo::PendingReceiver<mojom::InputEngineManager> receiver) {
+  manager_receivers_.Add(this, std::move(receiver));
   // TODO(https://crbug.com/837156): Reset the cleanup timer.
 }
 
 void ImeService::OnConnectionLost() {
-  if (engine_manager_bindings_.empty()) {
+  if (manager_receivers_.empty()) {
     service_binding_.RequestClose();
     // TODO(https://crbug.com/837156): Set a timer to start a cleanup.
   }
diff --git a/chromeos/services/ime/ime_service.h b/chromeos/services/ime/ime_service.h
index c8a5a86..9cd050da 100644
--- a/chromeos/services/ime/ime_service.h
+++ b/chromeos/services/ime/ime_service.h
@@ -7,8 +7,10 @@
 
 #include "chromeos/services/ime/input_engine.h"
 #include "chromeos/services/ime/public/mojom/input_engine.mojom.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
-#include "services/service_manager/public/cpp/binder_registry.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "services/service_manager/public/cpp/binder_map.h"
 #include "services/service_manager/public/cpp/service.h"
 #include "services/service_manager/public/cpp/service_binding.h"
 #include "services/service_manager/public/mojom/service.mojom.h"
@@ -19,7 +21,8 @@
 class ImeService : public service_manager::Service,
                    public mojom::InputEngineManager {
  public:
-  explicit ImeService(service_manager::mojom::ServiceRequest request);
+  explicit ImeService(
+      mojo::PendingReceiver<service_manager::mojom::Service> receiver);
   ~ImeService() override;
 
  private:
@@ -30,14 +33,16 @@
                        mojo::ScopedMessagePipeHandle interface_pipe) override;
 
   // mojom::InputEngineManager overrides:
-  void ConnectToImeEngine(const std::string& ime_spec,
-                          mojom::InputChannelRequest to_engine_request,
-                          mojom::InputChannelPtr from_engine,
-                          const std::vector<uint8_t>& extra,
-                          ConnectToImeEngineCallback callback) override;
+  void ConnectToImeEngine(
+      const std::string& ime_spec,
+      mojo::PendingReceiver<mojom::InputChannel> to_engine_request,
+      mojo::PendingRemote<mojom::InputChannel> from_engine,
+      const std::vector<uint8_t>& extra,
+      ConnectToImeEngineCallback callback) override;
 
-  // Binds the mojom::InputEngineManager interface to this object.
-  void BindInputEngineManagerRequest(mojom::InputEngineManagerRequest request);
+  // Adds a mojom::InputEngineManager receiver to this object.
+  void AddInputEngineManagerReceiver(
+      mojo::PendingReceiver<mojom::InputEngineManager> receiver);
 
   void OnConnectionLost();
 
@@ -47,9 +52,9 @@
   // input engine instance.
   std::unique_ptr<InputEngine> input_engine_;
 
-  mojo::BindingSet<mojom::InputEngineManager> engine_manager_bindings_;
+  mojo::ReceiverSet<mojom::InputEngineManager> manager_receivers_;
 
-  service_manager::BinderRegistry binder_registry_;
+  service_manager::BinderMap binders_;
 
   DISALLOW_COPY_AND_ASSIGN(ImeService);
 };
diff --git a/chromeos/services/ime/ime_service_unittest.cc b/chromeos/services/ime/ime_service_unittest.cc
index fc84403..ff8024ba 100644
--- a/chromeos/services/ime/ime_service_unittest.cc
+++ b/chromeos/services/ime/ime_service_unittest.cc
@@ -8,9 +8,10 @@
 #include "base/test/scoped_task_environment.h"
 #include "chromeos/services/ime/public/mojom/constants.mojom.h"
 #include "chromeos/services/ime/public/mojom/input_engine.mojom.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
-#include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/service_manager/public/cpp/service_binding.h"
 #include "services/service_manager/public/cpp/test/test_connector_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -37,12 +38,10 @@
 
 class TestClientChannel : mojom::InputChannel {
  public:
-  TestClientChannel() : binding_(this) {}
+  TestClientChannel() : receiver_(this) {}
 
-  mojom::InputChannelPtr CreateInterfacePtrAndBind() {
-    mojom::InputChannelPtr ptr;
-    binding_.Bind(mojo::MakeRequest(&ptr));
-    return ptr;
+  mojo::PendingRemote<mojom::InputChannel> CreatePendingRemote() {
+    return receiver_.BindNewPipeAndPassRemote();
   }
 
   // mojom::InputChannel implementation.
@@ -52,7 +51,7 @@
                     ProcessMessageCallback));
 
  private:
-  mojo::Binding<mojom::InputChannel> binding_;
+  mojo::Receiver<mojom::InputChannel> receiver_;
 
   DISALLOW_COPY_AND_ASSIGN(TestClientChannel);
 };
@@ -60,8 +59,8 @@
 class ImeServiceTest : public testing::Test {
  public:
   ImeServiceTest()
-      : service_(test_connector_factory_.RegisterInstance(mojom::kServiceName)),
-        connector_(test_connector_factory_.CreateConnector()) {}
+      : service_(
+            test_connector_factory_.RegisterInstance(mojom::kServiceName)) {}
   ~ImeServiceTest() override = default;
 
   MOCK_METHOD1(SentTextCallback, void(const std::string&));
@@ -69,20 +68,16 @@
 
  protected:
   void SetUp() override {
-    connector_->BindInterface(mojom::kServiceName,
-                              mojo::MakeRequest(&ime_manager_));
-
-    // TODO(https://crbug.com/837156): Start or bind other services used.
-    // Eg.  connector()->StartService(mojom::kSomeServiceName);
+    test_connector_factory_.GetDefaultConnector()->Connect(
+        mojom::kServiceName, remote_manager_.BindNewPipeAndPassReceiver());
   }
 
-  mojom::InputEngineManagerPtr ime_manager_;
+  mojo::Remote<mojom::InputEngineManager> remote_manager_;
 
  private:
   base::test::ScopedTaskEnvironment task_environment_;
   service_manager::TestConnectorFactory test_connector_factory_;
   ImeService service_;
-  std::unique_ptr<service_manager::Connector> connector_;
 
   DISALLOW_COPY_AND_ASSIGN(ImeServiceTest);
 };
@@ -94,58 +89,58 @@
 TEST_F(ImeServiceTest, ConnectInvalidImeEngine) {
   bool success = true;
   TestClientChannel test_channel;
-  mojom::InputChannelPtr to_engine_ptr;
+  mojo::Remote<mojom::InputChannel> remote_engine;
 
-  ime_manager_->ConnectToImeEngine(
-      kInvalidImeSpec, mojo::MakeRequest(&to_engine_ptr),
-      test_channel.CreateInterfacePtrAndBind(), extra,
+  remote_manager_->ConnectToImeEngine(
+      kInvalidImeSpec, remote_engine.BindNewPipeAndPassReceiver(),
+      test_channel.CreatePendingRemote(), extra,
       base::BindOnce(&ConnectCallback, &success));
-  ime_manager_.FlushForTesting();
+  remote_manager_.FlushForTesting();
   EXPECT_FALSE(success);
 }
 
 TEST_F(ImeServiceTest, MultipleClients) {
   bool success = false;
-  TestClientChannel test_channel1;
-  TestClientChannel test_channel2;
-  mojom::InputChannelPtr to_engine_ptr1;
-  mojom::InputChannelPtr to_engine_ptr2;
+  TestClientChannel test_channel_1;
+  TestClientChannel test_channel_2;
+  mojo::Remote<mojom::InputChannel> remote_engine_1;
+  mojo::Remote<mojom::InputChannel> remote_engine_2;
 
-  ime_manager_->ConnectToImeEngine(
-      "m17n:ar", mojo::MakeRequest(&to_engine_ptr1),
-      test_channel1.CreateInterfacePtrAndBind(), extra,
+  remote_manager_->ConnectToImeEngine(
+      "m17n:ar", remote_engine_1.BindNewPipeAndPassReceiver(),
+      test_channel_1.CreatePendingRemote(), extra,
       base::BindOnce(&ConnectCallback, &success));
-  ime_manager_.FlushForTesting();
+  remote_manager_.FlushForTesting();
 
-  ime_manager_->ConnectToImeEngine(
-      "m17n:ar", mojo::MakeRequest(&to_engine_ptr2),
-      test_channel2.CreateInterfacePtrAndBind(), extra,
+  remote_manager_->ConnectToImeEngine(
+      "m17n:ar", remote_engine_2.BindNewPipeAndPassReceiver(),
+      test_channel_2.CreatePendingRemote(), extra,
       base::BindOnce(&ConnectCallback, &success));
-  ime_manager_.FlushForTesting();
+  remote_manager_.FlushForTesting();
 
   std::string response;
   std::string process_text_key =
       "{\"method\":\"keyEvent\",\"type\":\"keydown\""
       ",\"code\":\"KeyA\",\"shift\":true,\"altgr\":false,\"caps\":false}";
-  to_engine_ptr1->ProcessText(
+  remote_engine_1->ProcessText(
       process_text_key, base::BindOnce(&TestProcessTextCallback, &response));
-  to_engine_ptr1.FlushForTesting();
+  remote_engine_1.FlushForTesting();
 
-  to_engine_ptr2->ProcessText(
+  remote_engine_2->ProcessText(
       process_text_key, base::BindOnce(&TestProcessTextCallback, &response));
-  to_engine_ptr2.FlushForTesting();
+  remote_engine_2.FlushForTesting();
 
   std::string process_text_key_count = "{\"method\":\"countKey\"}";
-  to_engine_ptr1->ProcessText(
+  remote_engine_1->ProcessText(
       process_text_key_count,
       base::BindOnce(&TestProcessTextCallback, &response));
-  to_engine_ptr1.FlushForTesting();
+  remote_engine_1.FlushForTesting();
   EXPECT_EQ("1", response);
 
-  to_engine_ptr2->ProcessText(
+  remote_engine_2->ProcessText(
       process_text_key_count,
       base::BindOnce(&TestProcessTextCallback, &response));
-  to_engine_ptr2.FlushForTesting();
+  remote_engine_2.FlushForTesting();
   EXPECT_EQ("1", response);
 }
 
@@ -153,66 +148,66 @@
 TEST_F(ImeServiceTest, RuleBasedArabic) {
   bool success = false;
   TestClientChannel test_channel;
-  mojom::InputChannelPtr to_engine_ptr;
+  mojo::Remote<mojom::InputChannel> remote_engine;
 
-  ime_manager_->ConnectToImeEngine("m17n:ar", mojo::MakeRequest(&to_engine_ptr),
-                                   test_channel.CreateInterfacePtrAndBind(),
-                                   extra,
-                                   base::BindOnce(&ConnectCallback, &success));
-  ime_manager_.FlushForTesting();
+  remote_manager_->ConnectToImeEngine(
+      "m17n:ar", remote_engine.BindNewPipeAndPassReceiver(),
+      test_channel.CreatePendingRemote(), extra,
+      base::BindOnce(&ConnectCallback, &success));
+  remote_manager_.FlushForTesting();
   EXPECT_TRUE(success);
 
   // Test Shift+KeyA.
   std::string response;
-  to_engine_ptr->ProcessText(
+  remote_engine->ProcessText(
       "{\"method\":\"keyEvent\",\"type\":\"keydown\",\"code\":\"KeyA\","
       "\"shift\":true,\"altgr\":false,\"caps\":false}",
       base::BindOnce(&TestProcessTextCallback, &response));
-  to_engine_ptr.FlushForTesting();
+  remote_engine.FlushForTesting();
   const wchar_t* expected_response =
       L"{\"result\":true,\"operations\":[{\"method\":\"commitText\","
       L"\"arguments\":[\"\u0650\"]}]}";
   EXPECT_EQ(base::WideToUTF8(expected_response), response);
 
   // Test KeyB.
-  to_engine_ptr->ProcessText(
+  remote_engine->ProcessText(
       "{\"method\":\"keyEvent\",\"type\":\"keydown\",\"code\":\"KeyB\","
       "\"shift\":false,\"altgr\":false,\"caps\":false}",
       base::BindOnce(&TestProcessTextCallback, &response));
-  to_engine_ptr.FlushForTesting();
+  remote_engine.FlushForTesting();
   expected_response =
       L"{\"result\":true,\"operations\":[{\"method\":\"commitText\","
       L"\"arguments\":[\"\u0644\u0627\"]}]}";
   EXPECT_EQ(base::WideToUTF8(expected_response), response);
 
   // Test unhandled key.
-  to_engine_ptr->ProcessText(
+  remote_engine->ProcessText(
       "{\"method\":\"keyEvent\",\"type\":\"keydown\",\"code\":\"Enter\","
       "\"shift\":false,\"altgr\":false,\"caps\":false}",
       base::BindOnce(&TestProcessTextCallback, &response));
-  to_engine_ptr.FlushForTesting();
+  remote_engine.FlushForTesting();
   EXPECT_EQ("{\"result\":false}", response);
 
   // Test keyup.
-  to_engine_ptr->ProcessText(
+  remote_engine->ProcessText(
       "{\"method\":\"keyEvent\",\"type\":\"keyup\",\"code\":\"Enter\","
       "\"shift\":false,\"altgr\":false,\"caps\":false}",
       base::BindOnce(&TestProcessTextCallback, &response));
-  to_engine_ptr.FlushForTesting();
+  remote_engine.FlushForTesting();
   EXPECT_EQ("{\"result\":false}", response);
 
   // Test reset.
-  to_engine_ptr->ProcessText(
+  remote_engine->ProcessText(
       "{\"method\":\"reset\"}",
       base::BindOnce(&TestProcessTextCallback, &response));
-  to_engine_ptr.FlushForTesting();
+  remote_engine.FlushForTesting();
   EXPECT_EQ("{\"result\":true}", response);
 
   // Test invalid request.
-  to_engine_ptr->ProcessText(
+  remote_engine->ProcessText(
       "{\"method\":\"keyEvent\",\"type\":\"keydown\"}",
       base::BindOnce(&TestProcessTextCallback, &response));
-  to_engine_ptr.FlushForTesting();
+  remote_engine.FlushForTesting();
   EXPECT_EQ("{\"result\":false}", response);
 }
 
@@ -220,60 +215,60 @@
 TEST_F(ImeServiceTest, RuleBasedDevaPhone) {
   bool success = false;
   TestClientChannel test_channel;
-  mojom::InputChannelPtr to_engine_ptr;
+  mojo::Remote<mojom::InputChannel> remote_engine;
 
-  ime_manager_->ConnectToImeEngine(
-      "m17n:deva_phone", mojo::MakeRequest(&to_engine_ptr),
-      test_channel.CreateInterfacePtrAndBind(), extra,
+  remote_manager_->ConnectToImeEngine(
+      "m17n:deva_phone", remote_engine.BindNewPipeAndPassReceiver(),
+      test_channel.CreatePendingRemote(), extra,
       base::BindOnce(&ConnectCallback, &success));
-  ime_manager_.FlushForTesting();
+  remote_manager_.FlushForTesting();
   EXPECT_TRUE(success);
 
   std::string response;
 
   // KeyN.
-  to_engine_ptr->ProcessText(
+  remote_engine->ProcessText(
       "{\"method\":\"keyEvent\",\"type\":\"keydown\",\"code\":\"KeyN\","
       "\"shift\":false,\"altgr\":false,\"caps\":false}",
       base::BindOnce(&TestProcessTextCallback, &response));
-  to_engine_ptr.FlushForTesting();
+  remote_engine.FlushForTesting();
   const char* expected_response =
       u8"{\"result\":true,\"operations\":[{\"method\":\"setComposition\","
       u8"\"arguments\":[\"\u0928\"]}]}";
   EXPECT_EQ(expected_response, response);
 
   // Backspace.
-  to_engine_ptr->ProcessText(
+  remote_engine->ProcessText(
       "{\"method\":\"keyEvent\",\"type\":\"keydown\",\"code\":\"Backspace\","
       "\"shift\":false,\"altgr\":false,\"caps\":false}",
       base::BindOnce(&TestProcessTextCallback, &response));
-  to_engine_ptr.FlushForTesting();
+  remote_engine.FlushForTesting();
   expected_response =
       u8"{\"result\":true,\"operations\":[{\"method\":\"setComposition\","
       u8"\"arguments\":[\"\"]}]}";
   EXPECT_EQ(expected_response, response);
 
   // KeyN + KeyC.
-  to_engine_ptr->ProcessText(
+  remote_engine->ProcessText(
       "{\"method\":\"keyEvent\",\"type\":\"keydown\",\"code\":\"KeyN\","
       "\"shift\":false,\"altgr\":false,\"caps\":false}",
       base::BindOnce(&TestProcessTextCallback, &response));
-  to_engine_ptr->ProcessText(
+  remote_engine->ProcessText(
       "{\"method\":\"keyEvent\",\"type\":\"keydown\",\"code\":\"KeyC\","
       "\"shift\":false,\"altgr\":false,\"caps\":false}",
       base::BindOnce(&TestProcessTextCallback, &response));
-  to_engine_ptr.FlushForTesting();
+  remote_engine.FlushForTesting();
   expected_response =
       u8"{\"result\":true,\"operations\":[{\"method\":\"setComposition\","
       u8"\"arguments\":[\"\u091e\u094d\u091a\"]}]}";
   EXPECT_EQ(expected_response, response);
 
   // Space.
-  to_engine_ptr->ProcessText(
+  remote_engine->ProcessText(
       "{\"method\":\"keyEvent\",\"type\":\"keydown\",\"code\":\"Space\","
       "\"shift\":false,\"altgr\":false,\"caps\":false}",
       base::BindOnce(&TestProcessTextCallback, &response));
-  to_engine_ptr.FlushForTesting();
+  remote_engine.FlushForTesting();
   expected_response =
       u8"{\"result\":true,\"operations\":[{\"method\":\"commitText\","
       u8"\"arguments\":[\"\u091e\u094d\u091a \"]}]}";
diff --git a/chromeos/services/ime/input_engine.cc b/chromeos/services/ime/input_engine.cc
index f62c7ec4..f96fa81 100644
--- a/chromeos/services/ime/input_engine.cc
+++ b/chromeos/services/ime/input_engine.cc
@@ -41,15 +41,16 @@
 
 InputEngine::~InputEngine() {}
 
-bool InputEngine::BindRequest(const std::string& ime_spec,
-                              mojom::InputChannelRequest request,
-                              mojom::InputChannelPtr client,
-                              const std::vector<uint8_t>& extra) {
+bool InputEngine::BindRequest(
+    const std::string& ime_spec,
+    mojo::PendingReceiver<mojom::InputChannel> receiver,
+    mojo::PendingRemote<mojom::InputChannel> remote,
+    const std::vector<uint8_t>& extra) {
   if (!IsImeSupported(ime_spec))
     return false;
 
-  channel_bindings_.AddBinding(this, std::move(request),
-                               std::make_unique<InputEngineContext>(ime_spec));
+  channel_receivers_.Add(this, std::move(receiver),
+                         std::make_unique<InputEngineContext>(ime_spec));
 
   return true;
   // TODO(https://crbug.com/837156): Registry connection error handler.
@@ -61,7 +62,7 @@
 
 void InputEngine::ProcessText(const std::string& message,
                               ProcessTextCallback callback) {
-  auto& context = channel_bindings_.dispatch_context();
+  auto& context = channel_receivers_.current_context();
   std::string result = Process(message, context.get());
   std::move(callback).Run(result);
 }
diff --git a/chromeos/services/ime/input_engine.h b/chromeos/services/ime/input_engine.h
index 2d03087..c6e43f6 100644
--- a/chromeos/services/ime/input_engine.h
+++ b/chromeos/services/ime/input_engine.h
@@ -6,7 +6,9 @@
 #define CHROMEOS_SERVICES_IME_INPUT_ENGINE_H_
 
 #include "chromeos/services/ime/public/mojom/input_engine.mojom.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
 
 namespace chromeos {
 namespace ime {
@@ -36,8 +38,8 @@
   // Binds the mojom::InputChannel interface to this object and returns true if
   // the given ime_spec is supported by the engine.
   virtual bool BindRequest(const std::string& ime_spec,
-                           mojom::InputChannelRequest request,
-                           mojom::InputChannelPtr client,
+                           mojo::PendingReceiver<mojom::InputChannel> receiver,
+                           mojo::PendingRemote<mojom::InputChannel> remote,
                            const std::vector<uint8_t>& extra);
 
   // Returns whether the given ime_spec is supported by this engine.
@@ -55,8 +57,8 @@
   std::string Process(const std::string& message,
                       const InputEngineContext* context);
 
-  mojo::BindingSet<mojom::InputChannel, std::unique_ptr<InputEngineContext>>
-      channel_bindings_;
+  mojo::ReceiverSet<mojom::InputChannel, std::unique_ptr<InputEngineContext>>
+      channel_receivers_;
 
   DISALLOW_COPY_AND_ASSIGN(InputEngine);
 };
diff --git a/chromeos/services/ime/public/mojom/input_engine.mojom b/chromeos/services/ime/public/mojom/input_engine.mojom
index a990ecf..4af3f89 100644
--- a/chromeos/services/ime/public/mojom/input_engine.mojom
+++ b/chromeos/services/ime/public/mojom/input_engine.mojom
@@ -14,8 +14,8 @@
   // is implmented on the client and used to receive data sent from the engine.
   // On failure (e.g. input engine is not found), |success| is false.
   ConnectToImeEngine(string ime_spec,
-                     InputChannel& to_engine_request,
-                     InputChannel from_engine,
+                     pending_receiver<InputChannel> to_engine_request,
+                     pending_remote<InputChannel> from_engine,
                      array<uint8> extra)
                      => (bool success);
 };
diff --git a/components/autofill/content/renderer/password_autofill_agent.cc b/components/autofill/content/renderer/password_autofill_agent.cc
index dcb74ec..8acc035 100644
--- a/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/components/autofill/content/renderer/password_autofill_agent.cc
@@ -1207,7 +1207,7 @@
         HasPasswordField(*frame)) {
       // Set everything that |FormDigest| needs.
       password_forms.push_back(PasswordForm());
-      password_forms.back().scheme = PasswordForm::SCHEME_HTML;
+      password_forms.back().scheme = PasswordForm::Scheme::kHtml;
       password_forms.back().origin =
           form_util::GetCanonicalOriginForDocument(frame->GetDocument());
       password_forms.back().signon_realm =
diff --git a/components/autofill/content/renderer/password_form_conversion_utils.cc b/components/autofill/content/renderer/password_form_conversion_utils.cc
index 891376a..f1309e7 100644
--- a/components/autofill/content/renderer/password_form_conversion_utils.cc
+++ b/components/autofill/content/renderer/password_form_conversion_utils.cc
@@ -428,7 +428,7 @@
     case PasswordContents::kOnlyDisabled:
       // The current parser gives up, but returns a fallback form so that the
       // newer parser can try parsing as well.
-      password_form->scheme = PasswordForm::SCHEME_HTML;
+      password_form->scheme = PasswordForm::Scheme::kHtml;
       password_form->origin = form_origin;
       password_form->signon_realm = GetSignOnRealm(password_form->origin);
       return true;
@@ -781,10 +781,10 @@
 
   password_form->origin = std::move(form_origin);
   password_form->signon_realm = GetSignOnRealm(password_form->origin);
-  password_form->scheme = PasswordForm::SCHEME_HTML;
+  password_form->scheme = PasswordForm::Scheme::kHtml;
   password_form->preferred = false;
   password_form->blacklisted_by_user = false;
-  password_form->type = PasswordForm::TYPE_MANUAL;
+  password_form->type = PasswordForm::Type::kManual;
 
   return true;
 }
diff --git a/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc b/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc
index a4620a1..5436a0a 100644
--- a/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc
+++ b/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc
@@ -311,10 +311,10 @@
   EXPECT_EQ(base::UTF8ToUTF16("johnsmith"), password_form->username_value);
   EXPECT_EQ(base::UTF8ToUTF16("password"), password_form->password_element);
   EXPECT_EQ(base::UTF8ToUTF16("secret"), password_form->password_value);
-  EXPECT_EQ(PasswordForm::SCHEME_HTML, password_form->scheme);
+  EXPECT_EQ(PasswordForm::Scheme::kHtml, password_form->scheme);
   EXPECT_FALSE(password_form->preferred);
   EXPECT_FALSE(password_form->blacklisted_by_user);
-  EXPECT_EQ(PasswordForm::TYPE_MANUAL, password_form->type);
+  EXPECT_EQ(PasswordForm::Type::kManual, password_form->type);
 }
 
 TEST_F(PasswordFormConversionUtilsTest, DisabledFieldsAreIgnored) {
diff --git a/components/autofill/content/renderer/password_generation_agent.cc b/components/autofill/content/renderer/password_generation_agent.cc
index 03ffa2fc..afa6671 100644
--- a/components/autofill/content/renderer/password_generation_agent.cc
+++ b/components/autofill/content/renderer/password_generation_agent.cc
@@ -504,7 +504,7 @@
     password_form = password_agent_->GetPasswordFormFromUnownedInputElements();
   }
   if (password_form) {
-    password_form->type = PasswordForm::TYPE_GENERATED;
+    password_form->type = PasswordForm::Type::kGenerated;
     password_form->password_value =
         current_generation_item_->generation_element_.Value().Utf16();
   }
diff --git a/components/autofill/core/common/mojom/autofill_types.mojom b/components/autofill/core/common/mojom/autofill_types.mojom
index 91c16b3..1db3a1d 100644
--- a/components/autofill/core/common/mojom/autofill_types.mojom
+++ b/components/autofill/core/common/mojom/autofill_types.mojom
@@ -11,30 +11,6 @@
 import "url/mojom/origin.mojom";
 import "url/mojom/url.mojom";
 
-// autofill::PasswordForm::GenerationUploadStatus
-enum GenerationUploadStatus {
-  NO_SIGNAL_SENT,
-  POSITIVE_SIGNAL_SENT,
-  NEGATIVE_SIGNAL_SENT,
-  UNKNOWN_STATUS = 10
-};
-
-// autofill::PasswordForm::Type
-enum PasswordFormType {
-  TYPE_MANUAL,
-  TYPE_GENERATED,
-  TYPE_API
-};
-
-// autofill::PasswordForm::Scheme
-enum PasswordFormScheme {
-  SCHEME_HTML,
-  SCHEME_BASIC,
-  SCHEME_DIGEST,
-  SCHEME_OTHER,
-  SCHEME_USERNAME_ONLY
-};
-
 // autofill::SubmissionIndicatorEvent
 enum SubmissionIndicatorEvent {
     NONE,
@@ -248,7 +224,40 @@
 
 // autofill::PasswordForm
 struct PasswordForm {
-  PasswordFormScheme scheme;
+  // Enum to differentiate between HTML form based authentication, and dialogs
+  // using basic or digest schemes. Default is kHtml. Only PasswordForms of the
+  // same Scheme will be matched/autofilled against each other.
+  enum Scheme {
+    kHtml,
+    kBasic,
+    kDigest,
+    kOther,
+    kUsernameOnly,
+  };
+
+  // Enum to differentiate between manually filled forms, forms with auto-
+  // generated passwords, and forms generated from the DOM API.
+  //
+  // Always append new types at the end. This enum is converted to int and
+  // stored in password store backends, so it is important to keep each
+  // value assigned to the same integer.
+  enum Type {
+    kManual,
+    kGenerated,
+    kApi,
+  };
+
+  // Enum to keep track of what information has been sent to the server about
+  // this form regarding password generation.
+  enum GenerationUploadStatus {
+    kNoSignalSent,
+    kPositiveSignalSent,
+    kNegativeSignalSent,
+    // Reserve a few values for future use.
+    kUnknownStatus = 10,
+  };
+
+  Scheme scheme;
   string signon_realm;
   url.mojom.Url origin_with_path;
   url.mojom.Url action;
@@ -270,7 +279,7 @@
   mojo_base.mojom.Time date_created;
   mojo_base.mojom.Time date_synced;
   bool blacklisted_by_user;
-  PasswordFormType type;
+  Type type;
   int32 times_used;
   FormData form_data;
   GenerationUploadStatus generation_upload_status;
diff --git a/components/autofill/core/common/mojom/autofill_types.typemap b/components/autofill/core/common/mojom/autofill_types.typemap
index 434f80fe..3d0b6eae 100644
--- a/components/autofill/core/common/mojom/autofill_types.typemap
+++ b/components/autofill/core/common/mojom/autofill_types.typemap
@@ -35,7 +35,6 @@
   "autofill.mojom.FormFieldData=autofill::FormFieldData",
   "autofill.mojom.FormFieldDataPredictions=autofill::FormFieldDataPredictions",
   "autofill.mojom.FormsPredictionsMap=autofill::FormsPredictionsMap",
-  "autofill.mojom.GenerationUploadStatus=autofill::PasswordForm::GenerationUploadStatus",
   "autofill.mojom.NewPasswordFormGenerationData=autofill::NewPasswordFormGenerationData",
   "autofill.mojom.PasswordAndRealm=autofill::PasswordAndRealm",
   "autofill.mojom.PasswordForm=autofill::PasswordForm",
@@ -43,10 +42,7 @@
   "autofill.mojom.PasswordFormFieldPredictionType=autofill::PasswordFormFieldPredictionType",
   "autofill.mojom.PasswordFormFillData=autofill::PasswordFormFillData",
   "autofill.mojom.PasswordFormGenerationData=autofill::PasswordFormGenerationData",
-  "autofill.mojom.PasswordFormLayout=autofill::PasswordForm::Layout",
-  "autofill.mojom.PasswordFormScheme=autofill::PasswordForm::Scheme",
   "autofill.mojom.SubmissionIndicatorEvent=autofill::SubmissionIndicatorEvent",
-  "autofill.mojom.PasswordFormType=autofill::PasswordForm::Type",
   "autofill.mojom.PasswordGenerationUIData=autofill::password_generation::PasswordGenerationUIData",
   "autofill.mojom.SubmissionSource=autofill::SubmissionSource",
   "autofill.mojom.ValueElementPair=autofill::ValueElementPair",
diff --git a/components/autofill/core/common/mojom/autofill_types_struct_traits.cc b/components/autofill/core/common/mojom/autofill_types_struct_traits.cc
index 1f5dd74..df8b4924 100644
--- a/components/autofill/core/common/mojom/autofill_types_struct_traits.cc
+++ b/components/autofill/core/common/mojom/autofill_types_struct_traits.cc
@@ -14,139 +14,6 @@
 namespace mojo {
 
 // static
-autofill::mojom::GenerationUploadStatus
-EnumTraits<autofill::mojom::GenerationUploadStatus,
-           autofill::PasswordForm::GenerationUploadStatus>::
-    ToMojom(autofill::PasswordForm::GenerationUploadStatus input) {
-  switch (input) {
-    case autofill::PasswordForm::GenerationUploadStatus::NO_SIGNAL_SENT:
-      return autofill::mojom::GenerationUploadStatus::NO_SIGNAL_SENT;
-    case autofill::PasswordForm::GenerationUploadStatus::POSITIVE_SIGNAL_SENT:
-      return autofill::mojom::GenerationUploadStatus::POSITIVE_SIGNAL_SENT;
-    case autofill::PasswordForm::GenerationUploadStatus::NEGATIVE_SIGNAL_SENT:
-      return autofill::mojom::GenerationUploadStatus::NEGATIVE_SIGNAL_SENT;
-    case autofill::PasswordForm::GenerationUploadStatus::UNKNOWN_STATUS:
-      return autofill::mojom::GenerationUploadStatus::UNKNOWN_STATUS;
-  }
-
-  NOTREACHED();
-  return autofill::mojom::GenerationUploadStatus::UNKNOWN_STATUS;
-}
-
-// static
-bool EnumTraits<autofill::mojom::GenerationUploadStatus,
-                autofill::PasswordForm::GenerationUploadStatus>::
-    FromMojom(autofill::mojom::GenerationUploadStatus input,
-              autofill::PasswordForm::GenerationUploadStatus* output) {
-  switch (input) {
-    case autofill::mojom::GenerationUploadStatus::NO_SIGNAL_SENT:
-      *output = autofill::PasswordForm::GenerationUploadStatus::NO_SIGNAL_SENT;
-      return true;
-    case autofill::mojom::GenerationUploadStatus::POSITIVE_SIGNAL_SENT:
-      *output =
-          autofill::PasswordForm::GenerationUploadStatus::POSITIVE_SIGNAL_SENT;
-      return true;
-    case autofill::mojom::GenerationUploadStatus::NEGATIVE_SIGNAL_SENT:
-      *output =
-          autofill::PasswordForm::GenerationUploadStatus::NEGATIVE_SIGNAL_SENT;
-      return true;
-    case autofill::mojom::GenerationUploadStatus::UNKNOWN_STATUS:
-      *output = autofill::PasswordForm::GenerationUploadStatus::UNKNOWN_STATUS;
-      return true;
-  }
-
-  NOTREACHED();
-  return false;
-}
-
-// static
-autofill::mojom::PasswordFormType EnumTraits<
-    autofill::mojom::PasswordFormType,
-    autofill::PasswordForm::Type>::ToMojom(autofill::PasswordForm::Type input) {
-  switch (input) {
-    case autofill::PasswordForm::Type::TYPE_MANUAL:
-      return autofill::mojom::PasswordFormType::TYPE_MANUAL;
-    case autofill::PasswordForm::Type::TYPE_GENERATED:
-      return autofill::mojom::PasswordFormType::TYPE_GENERATED;
-    case autofill::PasswordForm::Type::TYPE_API:
-      return autofill::mojom::PasswordFormType::TYPE_API;
-  }
-
-  NOTREACHED();
-  return autofill::mojom::PasswordFormType::TYPE_MANUAL;
-}
-
-// static
-bool EnumTraits<autofill::mojom::PasswordFormType,
-                autofill::PasswordForm::Type>::
-    FromMojom(autofill::mojom::PasswordFormType input,
-              autofill::PasswordForm::Type* output) {
-  switch (input) {
-    case autofill::mojom::PasswordFormType::TYPE_MANUAL:
-      *output = autofill::PasswordForm::Type::TYPE_MANUAL;
-      return true;
-    case autofill::mojom::PasswordFormType::TYPE_GENERATED:
-      *output = autofill::PasswordForm::Type::TYPE_GENERATED;
-      return true;
-    case autofill::mojom::PasswordFormType::TYPE_API:
-      *output = autofill::PasswordForm::Type::TYPE_API;
-      return true;
-  }
-
-  NOTREACHED();
-  return false;
-}
-
-// static
-autofill::mojom::PasswordFormScheme EnumTraits<
-    autofill::mojom::PasswordFormScheme,
-    autofill::PasswordForm::Scheme>::ToMojom(autofill::PasswordForm::Scheme
-                                                 input) {
-  switch (input) {
-    case autofill::PasswordForm::Scheme::SCHEME_HTML:
-      return autofill::mojom::PasswordFormScheme::SCHEME_HTML;
-    case autofill::PasswordForm::Scheme::SCHEME_BASIC:
-      return autofill::mojom::PasswordFormScheme::SCHEME_BASIC;
-    case autofill::PasswordForm::Scheme::SCHEME_DIGEST:
-      return autofill::mojom::PasswordFormScheme::SCHEME_DIGEST;
-    case autofill::PasswordForm::Scheme::SCHEME_OTHER:
-      return autofill::mojom::PasswordFormScheme::SCHEME_OTHER;
-    case autofill::PasswordForm::Scheme::SCHEME_USERNAME_ONLY:
-      return autofill::mojom::PasswordFormScheme::SCHEME_USERNAME_ONLY;
-  }
-
-  NOTREACHED();
-  return autofill::mojom::PasswordFormScheme::SCHEME_OTHER;
-}
-
-// static
-bool EnumTraits<autofill::mojom::PasswordFormScheme,
-                autofill::PasswordForm::Scheme>::
-    FromMojom(autofill::mojom::PasswordFormScheme input,
-              autofill::PasswordForm::Scheme* output) {
-  switch (input) {
-    case autofill::mojom::PasswordFormScheme::SCHEME_HTML:
-      *output = autofill::PasswordForm::Scheme::SCHEME_HTML;
-      return true;
-    case autofill::mojom::PasswordFormScheme::SCHEME_BASIC:
-      *output = autofill::PasswordForm::Scheme::SCHEME_BASIC;
-      return true;
-    case autofill::mojom::PasswordFormScheme::SCHEME_DIGEST:
-      *output = autofill::PasswordForm::Scheme::SCHEME_DIGEST;
-      return true;
-    case autofill::mojom::PasswordFormScheme::SCHEME_OTHER:
-      *output = autofill::PasswordForm::Scheme::SCHEME_OTHER;
-      return true;
-    case autofill::mojom::PasswordFormScheme::SCHEME_USERNAME_ONLY:
-      *output = autofill::PasswordForm::Scheme::SCHEME_USERNAME_ONLY;
-      return true;
-  }
-
-  NOTREACHED();
-  return false;
-}
-
-// static
 autofill::mojom::SubmissionIndicatorEvent
 EnumTraits<autofill::mojom::SubmissionIndicatorEvent,
            autofill::SubmissionIndicatorEvent>::
diff --git a/components/autofill/core/common/mojom/autofill_types_struct_traits.h b/components/autofill/core/common/mojom/autofill_types_struct_traits.h
index 2f8c2b1..f8b767b5 100644
--- a/components/autofill/core/common/mojom/autofill_types_struct_traits.h
+++ b/components/autofill/core/common/mojom/autofill_types_struct_traits.h
@@ -31,33 +31,6 @@
 namespace mojo {
 
 template <>
-struct EnumTraits<autofill::mojom::GenerationUploadStatus,
-                  autofill::PasswordForm::GenerationUploadStatus> {
-  static autofill::mojom::GenerationUploadStatus ToMojom(
-      autofill::PasswordForm::GenerationUploadStatus input);
-  static bool FromMojom(autofill::mojom::GenerationUploadStatus input,
-                        autofill::PasswordForm::GenerationUploadStatus* output);
-};
-
-template <>
-struct EnumTraits<autofill::mojom::PasswordFormType,
-                  autofill::PasswordForm::Type> {
-  static autofill::mojom::PasswordFormType ToMojom(
-      autofill::PasswordForm::Type input);
-  static bool FromMojom(autofill::mojom::PasswordFormType input,
-                        autofill::PasswordForm::Type* output);
-};
-
-template <>
-struct EnumTraits<autofill::mojom::PasswordFormScheme,
-                  autofill::PasswordForm::Scheme> {
-  static autofill::mojom::PasswordFormScheme ToMojom(
-      autofill::PasswordForm::Scheme input);
-  static bool FromMojom(autofill::mojom::PasswordFormScheme input,
-                        autofill::PasswordForm::Scheme* output);
-};
-
-template <>
 struct EnumTraits<autofill::mojom::PasswordFormFieldPredictionType,
                   autofill::PasswordFormFieldPredictionType> {
   static autofill::mojom::PasswordFormFieldPredictionType ToMojom(
diff --git a/components/autofill/core/common/mojom/autofill_types_struct_traits_unittest.cc b/components/autofill/core/common/mojom/autofill_types_struct_traits_unittest.cc
index e3725e1e..d3afa5b 100644
--- a/components/autofill/core/common/mojom/autofill_types_struct_traits_unittest.cc
+++ b/components/autofill/core/common/mojom/autofill_types_struct_traits_unittest.cc
@@ -64,7 +64,7 @@
 }
 
 void CreateTestPasswordForm(PasswordForm* form) {
-  form->scheme = PasswordForm::Scheme::SCHEME_HTML;
+  form->scheme = PasswordForm::Scheme::kHtml;
   form->signon_realm = "https://foo.com/";
   form->origin = GURL("https://foo.com/");
   form->action = GURL("https://foo.com/login");
@@ -92,11 +92,11 @@
   form->date_created = base::Time::Now();
   form->date_synced = base::Time::Now();
   form->blacklisted_by_user = false;
-  form->type = PasswordForm::Type::TYPE_GENERATED;
+  form->type = PasswordForm::Type::kGenerated;
   form->times_used = 999;
   test::CreateTestAddressFormData(&form->form_data);
   form->generation_upload_status =
-      PasswordForm::GenerationUploadStatus::POSITIVE_SIGNAL_SENT;
+      PasswordForm::GenerationUploadStatus::kPositiveSignalSent;
   form->display_name = base::ASCIIToUTF16("test display name");
   form->icon_url = GURL("https://foo.com/icon.png");
   form->federation_origin = url::Origin::Create(GURL("http://wwww.google.com"));
diff --git a/components/autofill/core/common/password_form.cc b/components/autofill/core/common/password_form.cc
index 580c494..82b8425 100644
--- a/components/autofill/core/common/password_form.cc
+++ b/components/autofill/core/common/password_form.cc
@@ -18,10 +18,19 @@
 
 namespace {
 
+// Utility function that creates a std::string from an object supporting the
+// ostream operator<<.
+template <typename T>
+std::string ToString(const T& obj) {
+  std::ostringstream ostream;
+  ostream << obj;
+  return ostream.str();
+}
+
 // Serializes a PasswordForm to a JSON object. Used only for logging in tests.
 void PasswordFormToJSON(const PasswordForm& form,
                         base::DictionaryValue* target) {
-  target->SetInteger("scheme", form.scheme);
+  target->SetString("scheme", ToString(form.scheme));
   target->SetString("signon_realm", form.signon_realm);
   target->SetBoolean("is_public_suffix_match", form.is_public_suffix_match);
   target->SetBoolean("is_affiliation_based_match",
@@ -57,12 +66,11 @@
   target->SetBoolean("preferred", form.preferred);
   target->SetDouble("date_created", form.date_created.ToDoubleT());
   target->SetDouble("date_synced", form.date_synced.ToDoubleT());
-  target->SetInteger("type", form.type);
+  target->SetString("type", ToString(form.type));
   target->SetInteger("times_used", form.times_used);
-  std::ostringstream form_data_string_stream;
-  form_data_string_stream << form.form_data;
-  target->SetString("form_data", form_data_string_stream.str());
-  target->SetInteger("generation_upload_status", form.generation_upload_status);
+  target->SetString("form_data", ToString(form.form_data));
+  target->SetString("generation_upload_status",
+                    ToString(form.generation_upload_status));
   target->SetString("display_name", form.display_name);
   target->SetString("icon_url", form.icon_url.possibly_invalid_spec());
   target->SetString("federation_origin", form.federation_origin.Serialize());
@@ -72,9 +80,7 @@
   target->SetString("affiliated_web_realm", form.affiliated_web_realm);
   target->SetString("app_display_name", form.app_display_name);
   target->SetString("app_icon_url", form.app_icon_url.possibly_invalid_spec());
-  std::ostringstream submission_event_string_stream;
-  submission_event_string_stream << form.submission_event;
-  target->SetString("submission_event", submission_event_string_stream.str());
+  target->SetString("submission_event", ToString(form.submission_event));
   target->SetBoolean("only_for_fallback", form.only_for_fallback);
   target->SetBoolean("is_gaia_with_skip_save_password_form",
                      form.is_gaia_with_skip_save_password_form);
@@ -83,23 +89,7 @@
 
 }  // namespace
 
-PasswordForm::PasswordForm()
-    : scheme(SCHEME_HTML),
-      username_marked_by_site(false),
-      form_has_autofilled_value(false),
-      new_password_marked_by_site(false),
-      preferred(false),
-      blacklisted_by_user(false),
-      type(TYPE_MANUAL),
-      times_used(0),
-      generation_upload_status(NO_SIGNAL_SENT),
-      skip_zero_click(false),
-      was_parsed_using_autofill_predictions(false),
-      is_public_suffix_match(false),
-      is_affiliation_based_match(false),
-      submission_event(SubmissionIndicatorEvent::NONE),
-      only_for_fallback(false),
-      is_gaia_with_skip_save_password_form(false) {}
+PasswordForm::PasswordForm() = default;
 
 PasswordForm::PasswordForm(const PasswordForm& other) = default;
 
@@ -223,9 +213,9 @@
 }
 
 bool IsHttpAuthScheme(PasswordForm::Scheme scheme) {
-  return scheme == PasswordForm::SCHEME_BASIC ||
-         scheme == PasswordForm::SCHEME_DIGEST ||
-         scheme == PasswordForm::SCHEME_OTHER;
+  return scheme == PasswordForm::Scheme::kBasic ||
+         scheme == PasswordForm::Scheme::kDigest ||
+         scheme == PasswordForm::Scheme::kOther;
 }
 
 std::ostream& operator<<(std::ostream& os, const PasswordForm& form) {
diff --git a/components/autofill/core/common/password_form.h b/components/autofill/core/common/password_form.h
index 9ef420e3..661b2bd 100644
--- a/components/autofill/core/common/password_form.h
+++ b/components/autofill/core/common/password_form.h
@@ -13,6 +13,7 @@
 
 #include "base/time/time.h"
 #include "components/autofill/core/common/form_data.h"
+#include "components/autofill/core/common/mojom/autofill_types.mojom-shared.h"
 #include "components/autofill/core/common/submission_indicator_event.h"
 #include "url/gurl.h"
 #include "url/origin.h"
@@ -50,28 +51,11 @@
 // entry to the database and how they can affect the matching process.
 
 struct PasswordForm {
-  // Enum to keep track of what information has been sent to the server about
-  // this form regarding password generation.
-  enum GenerationUploadStatus {
-    NO_SIGNAL_SENT,
-    POSITIVE_SIGNAL_SENT,
-    NEGATIVE_SIGNAL_SENT,
-    // Reserve a few values for future use.
-    UNKNOWN_STATUS = 10
-  };
+  using Scheme = mojom::PasswordForm_Scheme;
+  using Type = mojom::PasswordForm_Type;
+  using GenerationUploadStatus = mojom::PasswordForm_GenerationUploadStatus;
 
-  // Enum to differentiate between HTML form based authentication, and dialogs
-  // using basic or digest schemes. Default is SCHEME_HTML. Only PasswordForms
-  // of the same Scheme will be matched/autofilled against each other.
-  enum Scheme : int {
-    SCHEME_HTML,
-    SCHEME_BASIC,
-    SCHEME_DIGEST,
-    SCHEME_OTHER,
-    SCHEME_USERNAME_ONLY,
-
-    SCHEME_LAST = SCHEME_USERNAME_ONLY
-  } scheme;
+  Scheme scheme = Scheme::kHtml;
 
   // The "Realm" for the sign-on. This is scheme, host, port for SCHEME_HTML.
   // Dialog based forms also contain the HTTP realm. Android based forms will
@@ -154,7 +138,7 @@
 
   // Whether the |username_element| has an autocomplete=username attribute. This
   // is only used in parsed HTML forms.
-  bool username_marked_by_site;
+  bool username_marked_by_site = false;
 
   // The username. Optional.
   //
@@ -175,7 +159,7 @@
   ValueElementVector all_possible_passwords;
 
   // True if |all_possible_passwords| have autofilled value or its part.
-  bool form_has_autofilled_value;
+  bool form_has_autofilled_value = false;
 
   // The name of the input element corresponding to the current password.
   // Optional (improves scoring).
@@ -219,7 +203,7 @@
 
   // Whether the |new_password_element| has an autocomplete=new-password
   // attribute. This is only used in parsed HTML forms.
-  bool new_password_marked_by_site;
+  bool new_password_marked_by_site = false;
 
   // True if this PasswordForm represents the last username/password login the
   // user selected to log in to the site. If there is only one saved entry for
@@ -228,7 +212,7 @@
   // to true. Default to false.
   //
   // When parsing an HTML form, this is not used.
-  bool preferred;
+  bool preferred = false;
 
   // When the login was saved (by chrome).
   //
@@ -245,24 +229,16 @@
   // to false.
   //
   // When parsing an HTML form, this is not used.
-  bool blacklisted_by_user;
-
-  // Enum to differentiate between manually filled forms, forms with auto-
-  // generated passwords, and forms generated from the DOM API.
-  //
-  // Always append new types at the end. This enum is converted to int and
-  // stored in password store backends, so it is important to keep each
-  // value assigned to the same integer.
-  enum Type { TYPE_MANUAL, TYPE_GENERATED, TYPE_API, TYPE_LAST = TYPE_API };
+  bool blacklisted_by_user = false;
 
   // The form type.
-  Type type;
+  Type type = Type::kManual;
 
   // The number of times that this username/password has been used to
   // authenticate the user.
   //
   // When parsing an HTML form, this is not used.
-  int times_used;
+  int times_used = 0;
 
   // Autofill representation of this form. Used to communicate with the
   // Autofill servers if necessary. Currently this is only used to help
@@ -272,7 +248,8 @@
   FormData form_data;
 
   // What information has been sent to the Autofill server about this form.
-  GenerationUploadStatus generation_upload_status;
+  GenerationUploadStatus generation_upload_status =
+      GenerationUploadStatus::kNoSignalSent;
 
   // These following fields are set by a website using the Credential Manager
   // API. They will be empty and remain unused for sites which do not use that
@@ -295,30 +272,30 @@
   // If true, Chrome will not return this credential to a site in response to
   // 'navigator.credentials.request()' without user interaction.
   // Once user selects this credential the flag is reseted.
-  bool skip_zero_click;
+  bool skip_zero_click = false;
 
   // If true, this form was parsed using Autofill predictions.
-  bool was_parsed_using_autofill_predictions;
+  bool was_parsed_using_autofill_predictions = false;
 
   // If true, this match was found using public suffix matching.
-  bool is_public_suffix_match;
+  bool is_public_suffix_match = false;
 
   // If true, this is a credential saved through an Android application, and
   // found using affiliation-based match.
-  bool is_affiliation_based_match;
+  bool is_affiliation_based_match = false;
 
   // The type of the event that was taken as an indication that this form is
   // being or has already been submitted. This field is not persisted and filled
   // out only for submitted forms.
-  SubmissionIndicatorEvent submission_event;
+  SubmissionIndicatorEvent submission_event = SubmissionIndicatorEvent::NONE;
 
   // True iff heuristics declined this form for normal saving or filling (e.g.
   // only credit card fields were found). But this form can be saved or filled
   // only with the fallback.
-  bool only_for_fallback;
+  bool only_for_fallback = false;
 
   // True iff this is Gaia form which should be skipped on saving.
-  bool is_gaia_with_skip_save_password_form;
+  bool is_gaia_with_skip_save_password_form = false;
 
   // True iff the new password field was found with server hints or autocomplete
   // attributes. Only set on form parsing for filling, and not persisted. Used
diff --git a/components/autofill/core/common/password_form_fill_data_unittest.cc b/components/autofill/core/common/password_form_fill_data_unittest.cc
index 03eaf74..c6f5002 100644
--- a/components/autofill/core/common/password_form_fill_data_unittest.cc
+++ b/components/autofill/core/common/password_form_fill_data_unittest.cc
@@ -32,7 +32,7 @@
   form_on_page.submit_element = ASCIIToUTF16("");
   form_on_page.signon_realm = "https://foo.com/";
   form_on_page.preferred = false;
-  form_on_page.scheme = PasswordForm::SCHEME_HTML;
+  form_on_page.scheme = PasswordForm::Scheme::kHtml;
 
   // Create an exact match in the database.
   PasswordForm preferred_match;
@@ -45,7 +45,7 @@
   preferred_match.submit_element = ASCIIToUTF16("");
   preferred_match.signon_realm = "https://foo.com/";
   preferred_match.preferred = true;
-  preferred_match.scheme = PasswordForm::SCHEME_HTML;
+  preferred_match.scheme = PasswordForm::Scheme::kHtml;
 
   std::map<base::string16, const PasswordForm*> matches;
 
@@ -81,7 +81,7 @@
   form_on_page.submit_element = ASCIIToUTF16("");
   form_on_page.signon_realm = "https://foo.com/";
   form_on_page.preferred = false;
-  form_on_page.scheme = PasswordForm::SCHEME_HTML;
+  form_on_page.scheme = PasswordForm::Scheme::kHtml;
 
   // Create a match from the database that matches using public suffix.
   PasswordForm preferred_match;
@@ -95,7 +95,7 @@
   preferred_match.signon_realm = "https://foo.com/";
   preferred_match.is_public_suffix_match = true;
   preferred_match.preferred = true;
-  preferred_match.scheme = PasswordForm::SCHEME_HTML;
+  preferred_match.scheme = PasswordForm::Scheme::kHtml;
 
   // Create a match that matches exactly, so |is_public_suffix_match| has a
   // default value false.
@@ -109,7 +109,7 @@
   exact_match.submit_element = ASCIIToUTF16("");
   exact_match.signon_realm = "https://foo.com/";
   exact_match.preferred = false;
-  exact_match.scheme = PasswordForm::SCHEME_HTML;
+  exact_match.scheme = PasswordForm::Scheme::kHtml;
 
   // Create a match that was matched using public suffix, so
   // |is_public_suffix_match| == true.
@@ -124,7 +124,7 @@
   public_suffix_match.is_public_suffix_match = true;
   public_suffix_match.signon_realm = "https://foo.com/";
   public_suffix_match.preferred = false;
-  public_suffix_match.scheme = PasswordForm::SCHEME_HTML;
+  public_suffix_match.scheme = PasswordForm::Scheme::kHtml;
 
   // Add one exact match and one public suffix match.
   std::map<base::string16, const PasswordForm*> matches;
@@ -165,7 +165,7 @@
   form_on_page.submit_element = ASCIIToUTF16("");
   form_on_page.signon_realm = "https://foo.com/";
   form_on_page.preferred = false;
-  form_on_page.scheme = PasswordForm::SCHEME_HTML;
+  form_on_page.scheme = PasswordForm::Scheme::kHtml;
 
   // Create a match from the database that matches using affiliation.
   PasswordForm preferred_match;
@@ -188,7 +188,7 @@
   exact_match.submit_element = ASCIIToUTF16("");
   exact_match.signon_realm = "https://foo.com/";
   exact_match.preferred = false;
-  exact_match.scheme = PasswordForm::SCHEME_HTML;
+  exact_match.scheme = PasswordForm::Scheme::kHtml;
 
   // Create a match that was matched using public suffix, so
   // |is_public_suffix_match| == true.
@@ -199,7 +199,7 @@
   affiliated_match.is_affiliation_based_match = true;
   affiliated_match.signon_realm = "https://foo1.com/";
   affiliated_match.preferred = false;
-  affiliated_match.scheme = PasswordForm::SCHEME_HTML;
+  affiliated_match.scheme = PasswordForm::Scheme::kHtml;
 
   // Add one exact match and one affiliation based match.
   std::map<base::string16, const PasswordForm*> matches;
diff --git a/components/autofill/core/common/save_password_progress_logger.cc b/components/autofill/core/common/save_password_progress_logger.cc
index 22e8630..5de4e63f 100644
--- a/components/autofill/core/common/save_password_progress_logger.cc
+++ b/components/autofill/core/common/save_password_progress_logger.cc
@@ -35,15 +35,15 @@
 SavePasswordProgressLogger::StringID FormSchemeToStringID(
     PasswordForm::Scheme scheme) {
   switch (scheme) {
-    case PasswordForm::SCHEME_HTML:
+    case PasswordForm::Scheme::kHtml:
       return SavePasswordProgressLogger::STRING_SCHEME_HTML;
-    case PasswordForm::SCHEME_BASIC:
+    case PasswordForm::Scheme::kBasic:
       return SavePasswordProgressLogger::STRING_SCHEME_BASIC;
-    case PasswordForm::SCHEME_DIGEST:
+    case PasswordForm::Scheme::kDigest:
       return SavePasswordProgressLogger::STRING_SCHEME_DIGEST;
-    case PasswordForm::SCHEME_OTHER:
+    case PasswordForm::Scheme::kOther:
       return SavePasswordProgressLogger::STRING_OTHER;
-    case PasswordForm::SCHEME_USERNAME_ONLY:
+    case PasswordForm::Scheme::kUsernameOnly:
       return SavePasswordProgressLogger::STRING_SCHEME_USERNAME_ONLY;
   }
   NOTREACHED();
@@ -96,7 +96,7 @@
     }
   }
   log.SetBoolean(GetStringFromID(STRING_PASSWORD_GENERATED),
-                 form.type == PasswordForm::TYPE_GENERATED);
+                 form.type == PasswordForm::Type::kGenerated);
   log.SetInteger(GetStringFromID(STRING_TIMES_USED), form.times_used);
   log.SetBoolean(GetStringFromID(STRING_PSL_MATCH),
                  form.is_public_suffix_match);
diff --git a/components/content_settings/core/browser/content_settings_utils.cc b/components/content_settings/core/browser/content_settings_utils.cc
index cb34da5..4cba738 100644
--- a/components/content_settings/core/browser/content_settings_utils.cc
+++ b/components/content_settings/core/browser/content_settings_utils.cc
@@ -131,7 +131,7 @@
       ContentSettingsPattern::Wildcard(), ContentSettingsPattern::Wildcard(),
       base::Value::FromUniquePtrValue(
           ContentSettingToValue(CONTENT_SETTING_ALLOW)),
-      std::string(), map->is_incognito()));
+      std::string(), map->IsOffTheRecord()));
 #endif
   map->GetSettingsForOneType(
       CONTENT_SETTINGS_TYPE_JAVASCRIPT,
diff --git a/components/content_settings/core/browser/host_content_settings_map.cc b/components/content_settings/core/browser/host_content_settings_map.cc
index f12c4e94..d15daf8b 100644
--- a/components/content_settings/core/browser/host_content_settings_map.cc
+++ b/components/content_settings/core/browser/host_content_settings_map.cc
@@ -248,7 +248,7 @@
       used_from_thread_id_(base::PlatformThread::CurrentId()),
 #endif
       prefs_(prefs),
-      is_incognito_(is_off_the_record),
+      is_off_the_record_(is_off_the_record),
       store_last_modified_(store_last_modified),
       weak_ptr_factory_(this) {
   TRACE_EVENT0("startup", "HostContentSettingsMap::HostContentSettingsMap");
@@ -259,8 +259,8 @@
       base::WrapUnique(policy_provider);
   policy_provider->AddObserver(this);
 
-  pref_provider_ = new content_settings::PrefProvider(prefs_, is_incognito_,
-                                                      store_last_modified_);
+  pref_provider_ = new content_settings::PrefProvider(
+      prefs_, is_off_the_record_, store_last_modified_);
   content_settings_providers_[PREF_PROVIDER] = base::WrapUnique(pref_provider_);
   user_modifiable_providers_.push_back(pref_provider_);
   pref_provider_->AddObserver(this);
@@ -273,7 +273,7 @@
   ephemeral_provider->AddObserver(this);
 
   auto default_provider = std::make_unique<content_settings::DefaultProvider>(
-      prefs_, is_incognito_);
+      prefs_, is_off_the_record_);
   default_provider->AddObserver(this);
   content_settings_providers_[DEFAULT_PROVIDER] = std::move(default_provider);
 
@@ -354,7 +354,7 @@
       continue;
     ContentSetting default_setting = GetDefaultContentSettingFromProvider(
         content_type, provider_pair.second.get());
-    if (is_incognito_) {
+    if (is_off_the_record_) {
       default_setting = content_settings::ValueToContentSetting(
           ProcessIncognitoInheritanceBehavior(
               content_type,
@@ -419,7 +419,7 @@
   for (const auto& provider_pair : content_settings_providers_) {
     // For each provider, iterate first the incognito-specific rules, then the
     // normal rules.
-    if (is_incognito_) {
+    if (is_off_the_record_) {
       AddSettingsForOneType(provider_pair.second.get(), provider_pair.first,
                             content_type, resource_identifier, settings, true);
     }
@@ -581,8 +581,8 @@
     ContentSettingsPattern temp_patterns[2];
     std::unique_ptr<base::Value> value(GetContentSettingValueAndPatterns(
         content_settings_providers_[PREF_PROVIDER].get(), url, url,
-        CONTENT_SETTINGS_TYPE_PLUGINS_DATA, resource_identifier, is_incognito_,
-        temp_patterns, temp_patterns + 1));
+        CONTENT_SETTINGS_TYPE_PLUGINS_DATA, resource_identifier,
+        is_off_the_record_, temp_patterns, temp_patterns + 1));
 
     UMA_HISTOGRAM_ENUMERATION(
         "ContentSettings.EphemeralFlashPermission",
@@ -891,7 +891,8 @@
   for (; it != content_settings_providers_.end(); ++it) {
     std::unique_ptr<base::Value> value = GetContentSettingValueAndPatterns(
         it->second.get(), primary_url, secondary_url, content_type,
-        resource_identifier, is_incognito_, primary_pattern, secondary_pattern);
+        resource_identifier, is_off_the_record_, primary_pattern,
+        secondary_pattern);
     if (value) {
       if (info)
         info->source = kProviderNamesSourceMap[it->first].provider_source;
diff --git a/components/content_settings/core/browser/host_content_settings_map.h b/components/content_settings/core/browser/host_content_settings_map.h
index e5f16bb..db7e011 100644
--- a/components/content_settings/core/browser/host_content_settings_map.h
+++ b/components/content_settings/core/browser/host_content_settings_map.h
@@ -289,10 +289,7 @@
   static ProviderType GetProviderTypeFromSource(const std::string& source);
 
   // Whether this settings map is for an incognito or guest session.
-  // TODO(https://crbug.com/3333): Should be renamed.
-  bool is_incognito() const {
-    return is_incognito_;
-  }
+  bool IsOffTheRecord() const { return is_off_the_record_; }
 
   // Adds/removes an observer for content settings changes.
   void AddObserver(content_settings::Observer* observer);
@@ -416,8 +413,7 @@
   PrefService* prefs_;
 
   // Whether this settings map is for an incognito or guest session.
-  // TODO(https://crbug.com/3333): Should be renamed.
-  bool is_incognito_;
+  bool is_off_the_record_;
 
   // Whether ContentSettings in the PrefProvider will store a last_modified
   // timestamp.
diff --git a/components/exo/wayland/zcr_gaming_input.cc b/components/exo/wayland/zcr_gaming_input.cc
index 47f9ef9..e5d880d 100644
--- a/components/exo/wayland/zcr_gaming_input.cc
+++ b/components/exo/wayland/zcr_gaming_input.cc
@@ -164,11 +164,10 @@
           GetGamepadBusType(device.type), device.vendor_id, device.product_id,
           device.version);
 
-      for (size_t i = 0; i < device.axes.size(); ++i) {
-        const auto& axis = device.axes[i];
-        zcr_gamepad_v2_send_axis_added(gamepad_resource, i, axis.min_value,
-                                       axis.max_value, axis.flat, axis.fuzz,
-                                       axis.resolution);
+      for (const auto& axis : device.axes) {
+        zcr_gamepad_v2_send_axis_added(gamepad_resource, axis.code,
+                                       axis.min_value, axis.max_value,
+                                       axis.flat, axis.fuzz, axis.resolution);
       }
       zcr_gamepad_v2_send_activated(gamepad_resource);
     } else {
diff --git a/components/omnibox/browser/autocomplete_result.cc b/components/omnibox/browser/autocomplete_result.cc
index 67a2abb..3555722 100644
--- a/components/omnibox/browser/autocomplete_result.cc
+++ b/components/omnibox/browser/autocomplete_result.cc
@@ -179,6 +179,12 @@
   auto it = FindTopMatch(input.current_page_classification(), &matches_);
   if (it != matches_.end())
     std::rotate(matches_.begin(), it, it + 1);
+
+  size_t max_url_count = 0;
+  if (OmniboxFieldTrial::IsCapURLMatchesFeatureEnabled() &&
+      (max_url_count = OmniboxFieldTrial::GetMaxURLMatches()) != 0)
+    LimitNumberOfURLsShown(max_url_count, comparing_object);
+
   // In the process of trimming, drop all matches with a demoted relevance
   // score of 0.
   const size_t max_num_matches = std::min(GetMaxMatches(), matches_.size());
@@ -197,9 +203,8 @@
 
   // There is no default match for chromeOS launcher zero prefix query
   // suggestions.
-  if ((input.text().empty() &&
-       input.current_page_classification() ==
-           metrics::OmniboxEventProto::CHROMEOS_APP_LIST)) {
+  if (input.text().empty() && (input.current_page_classification() ==
+                               metrics::OmniboxEventProto::CHROMEOS_APP_LIST)) {
     default_match_ = end();
     alternate_nav_url_ = GURL();
     return;
@@ -737,3 +742,31 @@
   return std::make_pair(match.stripped_destination_url,
                         match.type == ACMatchType::CALCULATOR);
 }
+
+void AutocompleteResult::LimitNumberOfURLsShown(
+    size_t max_url_count,
+    const CompareWithDemoteByType<AutocompleteMatch>& comparing_object) {
+  size_t search_count = std::count_if(
+      matches_.begin(), matches_.end(), [&](const AutocompleteMatch& m) {
+        return AutocompleteMatch::IsSearchType(m.type) &&
+               // Don't count if would be removed.
+               comparing_object.GetDemotedRelevance(m) > 0;
+      });
+  // Display more than GetMaxURLMatches() if there are no non-URL suggestions
+  // to replace them. Avoid signed math.
+  if (GetMaxMatches() > search_count &&
+      GetMaxMatches() - search_count > max_url_count)
+    max_url_count = GetMaxMatches() - search_count;
+  size_t url_count = 0, total_count = 0;
+  // Erase URL suggestions past the count of allowed ones, or anything past
+  // maximum.
+  matches_.erase(
+      std::remove_if(matches_.begin(), matches_.end(),
+                     [&url_count, max_url_count,
+                      &total_count](const AutocompleteMatch& m) {
+                       return (!AutocompleteMatch::IsSearchType(m.type) &&
+                               ++url_count > max_url_count) ||
+                              ++total_count > GetMaxMatches();
+                     }),
+      matches_.end());
+}
diff --git a/components/omnibox/browser/autocomplete_result.h b/components/omnibox/browser/autocomplete_result.h
index ed334bd..505f12c7 100644
--- a/components/omnibox/browser/autocomplete_result.h
+++ b/components/omnibox/browser/autocomplete_result.h
@@ -13,6 +13,7 @@
 #include "base/macros.h"
 #include "build/build_config.h"
 #include "components/omnibox/browser/autocomplete_match.h"
+#include "components/omnibox/browser/match_compare.h"
 #include "third_party/metrics_proto/omnibox_event.pb.h"
 #include "url/gurl.h"
 
@@ -190,6 +191,13 @@
   static std::pair<GURL, bool> GetMatchComparisonFields(
       const AutocompleteMatch& match);
 
+  // This method reduces the number of navigation suggestions to that of
+  // |max_url_matches| but will allow more if there are no other types to
+  // replace them.
+  void LimitNumberOfURLsShown(
+      size_t max_url_count,
+      const CompareWithDemoteByType<AutocompleteMatch>& comparing_object);
+
   ACMatches matches_;
 
   const_iterator default_match_;
diff --git a/components/omnibox/browser/autocomplete_result_unittest.cc b/components/omnibox/browser/autocomplete_result_unittest.cc
index 2704d3e9..a6d984f0 100644
--- a/components/omnibox/browser/autocomplete_result_unittest.cc
+++ b/components/omnibox/browser/autocomplete_result_unittest.cc
@@ -11,6 +11,7 @@
 #include <vector>
 
 #include "base/metrics/field_trial.h"
+#include "base/metrics/field_trial_params.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
@@ -1048,6 +1049,88 @@
   AssertResultMatches(result, expected_data, base::size(expected_data));
 }
 
+TEST_F(AutocompleteResultTest, SortAndCullCapURLMatches) {
+  base::test::ScopedFeatureList feature_list;
+  std::map<std::string, std::string> parameters = {
+      {OmniboxFieldTrial::kOmniboxMaxURLMatchesParam, "3"}};
+  feature_list.InitAndEnableFeatureWithParameters(
+      omnibox::kOmniboxCapURLMatches, parameters);
+  EXPECT_TRUE(OmniboxFieldTrial::IsCapURLMatchesFeatureEnabled());
+  EXPECT_EQ(OmniboxFieldTrial::GetMaxURLMatches(), 3u);
+
+  // Case 1: Eject URL match for a search.
+  {
+    ACMatches matches;
+    const AutocompleteMatchTestData data[] = {
+        {"http://search-what-you-typed/",
+         AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED},
+        {"http://search-history/", AutocompleteMatchType::SEARCH_HISTORY},
+        {"http://history-url/", AutocompleteMatchType::HISTORY_URL},
+        {"http://history-title/", AutocompleteMatchType::HISTORY_TITLE},
+        {"http://url-what-you-typed/",
+         AutocompleteMatchType::URL_WHAT_YOU_TYPED},
+        {"http://clipboard-url/", AutocompleteMatchType::CLIPBOARD_URL},
+        {"http://search-suggest/", AutocompleteMatchType::SEARCH_SUGGEST},
+    };
+    PopulateAutocompleteMatchesFromTestData(data, base::size(data), &matches);
+
+    AutocompleteInput input(base::ASCIIToUTF16("a"),
+                            metrics::OmniboxEventProto::OTHER,
+                            TestSchemeClassifier());
+    AutocompleteResult result;
+    result.AppendMatches(input, matches);
+    result.SortAndCull(input, template_url_service_.get());
+
+    EXPECT_EQ(result.size(), 6u);
+    AutocompleteMatchType::Type expected_types[] = {
+        AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
+        AutocompleteMatchType::SEARCH_HISTORY,
+        AutocompleteMatchType::HISTORY_URL,
+        AutocompleteMatchType::HISTORY_TITLE,
+        AutocompleteMatchType::URL_WHAT_YOU_TYPED,
+        AutocompleteMatchType::SEARCH_SUGGEST,
+    };
+    for (size_t i = 0; i < result.size(); ++i)
+      EXPECT_EQ(result.match_at(i)->type, expected_types[i]);
+  }
+
+  // Case 2: Do not eject URL match because there's no replacement.
+  {
+    ACMatches matches;
+    const AutocompleteMatchTestData data[] = {
+        {"http://search-what-you-typed/",
+         AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED},
+        {"http://search-history/", AutocompleteMatchType::SEARCH_HISTORY},
+        {"http://history-url/", AutocompleteMatchType::HISTORY_URL},
+        {"http://history-title/", AutocompleteMatchType::HISTORY_TITLE},
+        {"http://url-what-you-typed/",
+         AutocompleteMatchType::URL_WHAT_YOU_TYPED},
+        {"http://clipboard-url/", AutocompleteMatchType::CLIPBOARD_URL},
+        {"http://bookmark-title/", AutocompleteMatchType::BOOKMARK_TITLE},
+    };
+    PopulateAutocompleteMatchesFromTestData(data, base::size(data), &matches);
+
+    AutocompleteInput input(base::ASCIIToUTF16("a"),
+                            metrics::OmniboxEventProto::OTHER,
+                            TestSchemeClassifier());
+    AutocompleteResult result;
+    result.AppendMatches(input, matches);
+    result.SortAndCull(input, template_url_service_.get());
+
+    EXPECT_EQ(result.size(), 6u);
+    AutocompleteMatchType::Type expected_types[] = {
+        AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
+        AutocompleteMatchType::SEARCH_HISTORY,
+        AutocompleteMatchType::HISTORY_URL,
+        AutocompleteMatchType::HISTORY_TITLE,
+        AutocompleteMatchType::URL_WHAT_YOU_TYPED,
+        AutocompleteMatchType::CLIPBOARD_URL,
+    };
+    for (size_t i = 0; i < result.size(); ++i)
+      EXPECT_EQ(result.match_at(i)->type, expected_types[i]);
+  }
+}
+
 TEST_F(AutocompleteResultTest, TopMatchIsStandaloneVerbatimMatch) {
   ACMatches matches;
   AutocompleteResult result;
diff --git a/components/omnibox/browser/omnibox_field_trial.cc b/components/omnibox/browser/omnibox_field_trial.cc
index dfb6e738..593482bc7 100644
--- a/components/omnibox/browser/omnibox_field_trial.cc
+++ b/components/omnibox/browser/omnibox_field_trial.cc
@@ -647,6 +647,13 @@
   return static_cast<EmphasizeTitlesCondition>(value);
 }
 
+size_t OmniboxFieldTrial::GetMaxURLMatches() {
+  return base::GetFieldTrialParamByFeatureAsInt(
+      omnibox::kOmniboxCapURLMatches,
+      OmniboxFieldTrial::kOmniboxMaxURLMatchesParam,
+      0);  // default
+}
+
 bool OmniboxFieldTrial::IsPreserveDefaultMatchScoreEnabled() {
   return base::FeatureList::IsEnabled(
       omnibox::kOmniboxPreserveDefaultMatchScore);
@@ -709,6 +716,10 @@
       omnibox::kOmniboxGroupSuggestionsBySearchVsUrl);
 }
 
+bool OmniboxFieldTrial::IsCapURLMatchesFeatureEnabled() {
+  return base::FeatureList::IsEnabled(omnibox::kOmniboxCapURLMatches);
+}
+
 const char OmniboxFieldTrial::kBundledExperimentFieldTrialName[] =
     "OmniboxBundledExperimentV1";
 const char OmniboxFieldTrial::kDisableProvidersRule[] = "DisableProviders";
@@ -745,6 +756,9 @@
     "KeywordScoreForSufficientlyCompleteMatch";
 const char OmniboxFieldTrial::kEmphasizeTitlesRule[] = "EmphasizeTitles";
 
+const char OmniboxFieldTrial::kOmniboxMaxURLMatchesParam[] =
+    "OmniboxMaxURLMatches";
+
 const char OmniboxFieldTrial::kHUPNewScoringTypedCountRelevanceCapParam[] =
     "TypedCountRelevanceCap";
 const char OmniboxFieldTrial::kHUPNewScoringTypedCountHalfLifeTimeParam[] =
diff --git a/components/omnibox/browser/omnibox_field_trial.h b/components/omnibox/browser/omnibox_field_trial.h
index 0c98b65..b1e4c04 100644
--- a/components/omnibox/browser/omnibox_field_trial.h
+++ b/components/omnibox/browser/omnibox_field_trial.h
@@ -390,6 +390,12 @@
 EmphasizeTitlesCondition GetEmphasizeTitlesConditionForInput(
     const AutocompleteInput& input);
 
+// Returns the maximum number of URL matches that should be allowed within
+// the Omnibox if there are search-type matches available to replace them.
+// If the capping feature is not enabled, or the parameter cannot be
+// parsed, it returns 0.
+size_t GetMaxURLMatches();
+
 // ---------------------------------------------------------
 // For UI experiments.
 
@@ -431,6 +437,10 @@
 // which "bunches" search suggestions (except for the default match).
 bool IsGroupSuggestionsBySearchVsUrlFeatureEnabled();
 
+// Returns whether the feature to limit the number of shown URL matches
+// is enabled.
+bool IsCapURLMatchesFeatureEnabled();
+
 // ---------------------------------------------------------
 // Clipboard URL suggestions:
 
@@ -468,6 +478,9 @@
 extern const char kHQPAllowDupMatchesForScoringRule[];
 extern const char kEmphasizeTitlesRule[];
 
+// Parameter name used by the Omnibox match capping experiment.
+extern const char kOmniboxMaxURLMatchesParam[];
+
 // Parameter names used by the HUP new scoring experiments.
 extern const char kHUPNewScoringTypedCountRelevanceCapParam[];
 extern const char kHUPNewScoringTypedCountHalfLifeTimeParam[];
diff --git a/components/omnibox/common/omnibox_features.cc b/components/omnibox/common/omnibox_features.cc
index 862e7d1..efb50f1 100644
--- a/components/omnibox/common/omnibox_features.cc
+++ b/components/omnibox/common/omnibox_features.cc
@@ -80,6 +80,14 @@
 const base::Feature kOmniboxLocalEntitySuggestions{
     "OmniboxLocalEntitySuggestions", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Feature used to cap the number of URL-type matches shown within the
+// Omnibox. If enabled, the number of URL-type matches is limited (unless
+// there are no more non-URL matches available.) If enabled, there is a
+// companion parameter - OmniboxMaxURLMatches - which specifies the maximum
+// desired number of URL-type matches.
+const base::Feature kOmniboxCapURLMatches{"OmniboxCapURLMatches",
+                                          base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Feature used to enable entity suggestion images and enhanced presentation
 // showing more context and descriptive text about the entity.
 const base::Feature kOmniboxRichEntitySuggestions{
diff --git a/components/omnibox/common/omnibox_features.h b/components/omnibox/common/omnibox_features.h
index 828ec10..c0fa186b 100644
--- a/components/omnibox/common/omnibox_features.h
+++ b/components/omnibox/common/omnibox_features.h
@@ -18,6 +18,7 @@
 extern const base::Feature kSimplifyHttpsIndicator;
 extern const base::Feature kOmniboxGroupSuggestionsBySearchVsUrl;
 extern const base::Feature kOmniboxLocalEntitySuggestions;
+extern const base::Feature kOmniboxCapURLMatches;
 extern const base::Feature kOmniboxRichEntitySuggestions;
 extern const base::Feature kOmniboxNewAnswerLayout;
 extern const base::Feature kOmniboxReverseAnswers;
diff --git a/components/password_manager/content/browser/content_password_manager_driver_unittest.cc b/components/password_manager/content/browser/content_password_manager_driver_unittest.cc
index 189aa69..3cc7e3b0 100644
--- a/components/password_manager/content/browser/content_password_manager_driver_unittest.cc
+++ b/components/password_manager/content/browser/content_password_manager_driver_unittest.cc
@@ -109,7 +109,7 @@
   form_on_page.origin = GURL("https://foo.com/");
   form_on_page.action = GURL("https://foo.com/login");
   form_on_page.signon_realm = "https://foo.com/";
-  form_on_page.scheme = PasswordForm::SCHEME_HTML;
+  form_on_page.scheme = PasswordForm::Scheme::kHtml;
 
   // Create an exact match in the database.
   PasswordForm preferred_match = form_on_page;
diff --git a/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.cc b/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.cc
index 8f3e67e..9e8cef0 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.cc
+++ b/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.cc
@@ -23,7 +23,7 @@
 bool IsAndroidApplicationCredential(const autofill::PasswordForm& form,
                                     FacetURI* facet_uri) {
   DCHECK(facet_uri);
-  if (form.scheme != autofill::PasswordForm::SCHEME_HTML)
+  if (form.scheme != autofill::PasswordForm::Scheme::kHtml)
     return false;
 
   *facet_uri = FacetURI::FromPotentiallyInvalidSpec(form.signon_realm);
@@ -152,7 +152,7 @@
 // static
 bool AffiliatedMatchHelper::IsValidAndroidCredential(
     const PasswordStore::FormDigest& form) {
-  return form.scheme == autofill::PasswordForm::SCHEME_HTML &&
+  return form.scheme == autofill::PasswordForm::Scheme::kHtml &&
          IsValidAndroidFacetURI(form.signon_realm);
 }
 
@@ -160,7 +160,7 @@
 bool AffiliatedMatchHelper::IsValidWebCredential(
     const PasswordStore::FormDigest& form) {
   FacetURI facet_uri(FacetURI::FromPotentiallyInvalidSpec(form.signon_realm));
-  return form.scheme == autofill::PasswordForm::SCHEME_HTML &&
+  return form.scheme == autofill::PasswordForm::Scheme::kHtml &&
          facet_uri.IsValidWebFacetURI();
 }
 
diff --git a/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc b/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc
index e873d72..e1ad3d4 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc
+++ b/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc
@@ -149,7 +149,7 @@
 
 autofill::PasswordForm GetTestAndroidCredentials(const char* signon_realm) {
   autofill::PasswordForm form;
-  form.scheme = autofill::PasswordForm::SCHEME_HTML;
+  form.scheme = autofill::PasswordForm::Scheme::kHtml;
   form.signon_realm = signon_realm;
   form.username_value = base::ASCIIToUTF16(kTestUsername);
   form.password_value = base::ASCIIToUTF16(kTestPassword);
@@ -165,7 +165,7 @@
 
 PasswordStore::FormDigest GetTestObservedWebForm(const char* signon_realm,
                                                  const char* origin) {
-  return {autofill::PasswordForm::SCHEME_HTML, signon_realm,
+  return {autofill::PasswordForm::Scheme::kHtml, signon_realm,
           origin ? GURL(origin) : GURL()};
 }
 
@@ -395,7 +395,7 @@
        GetAffiliatedAndroidRealmsYieldsEmptyResultsForHTTPBasicAuthForms) {
   PasswordStore::FormDigest http_auth_observed_form(
       GetTestObservedWebForm(kTestWebRealmAlpha1, nullptr));
-  http_auth_observed_form.scheme = autofill::PasswordForm::SCHEME_BASIC;
+  http_auth_observed_form.scheme = autofill::PasswordForm::Scheme::kBasic;
   EXPECT_THAT(GetAffiliatedAndroidRealms(http_auth_observed_form),
               testing::IsEmpty());
 }
@@ -404,7 +404,7 @@
        GetAffiliatedAndroidRealmsYieldsEmptyResultsForHTTPDigestAuthForms) {
   PasswordStore::FormDigest http_auth_observed_form(
       GetTestObservedWebForm(kTestWebRealmAlpha1, nullptr));
-  http_auth_observed_form.scheme = autofill::PasswordForm::SCHEME_DIGEST;
+  http_auth_observed_form.scheme = autofill::PasswordForm::Scheme::kDigest;
   EXPECT_THAT(GetAffiliatedAndroidRealms(http_auth_observed_form),
               testing::IsEmpty());
 }
diff --git a/components/password_manager/core/browser/blacklisted_credentials_cleaner_unittest.cc b/components/password_manager/core/browser/blacklisted_credentials_cleaner_unittest.cc
index 96a63bf..2f4a072 100644
--- a/components/password_manager/core/browser/blacklisted_credentials_cleaner_unittest.cc
+++ b/components/password_manager/core/browser/blacklisted_credentials_cleaner_unittest.cc
@@ -36,7 +36,7 @@
 
 PasswordForm GetTestCredential() {
   PasswordForm form;
-  form.scheme = PasswordForm::SCHEME_HTML;
+  form.scheme = PasswordForm::Scheme::kHtml;
   form.signon_realm = GURL(kTestURL).GetOrigin().spec();
   form.origin = GURL(kTestURL);
   form.username_element = base::ASCIIToUTF16(kTestUsernameElement);
@@ -118,7 +118,7 @@
 
   PasswordForm blacklisted_form;
   blacklisted_form.blacklisted_by_user = true;
-  blacklisted_form.scheme = PasswordForm::SCHEME_HTML;
+  blacklisted_form.scheme = PasswordForm::Scheme::kHtml;
   blacklisted_form.signon_realm = GURL(kTestURL).GetOrigin().spec();
   blacklisted_form.origin = GURL(kTestURL).GetOrigin();
   blacklisted_form.date_created = kTestCreationDate;
@@ -164,7 +164,7 @@
   // Only one credential for the signon realm is left.
   PasswordForm blacklisted_form;
   blacklisted_form.blacklisted_by_user = true;
-  blacklisted_form.scheme = PasswordForm::SCHEME_HTML;
+  blacklisted_form.scheme = PasswordForm::Scheme::kHtml;
   blacklisted_form.signon_realm = GURL(kTestURL).GetOrigin().spec();
   blacklisted_form.origin = GURL(kTestURL).GetOrigin();
   blacklisted_form.date_created = kTestCreationDate;
diff --git a/components/password_manager/core/browser/credential_manager_impl.cc b/components/password_manager/core/browser/credential_manager_impl.cc
index ab96f76..fceebe1 100644
--- a/components/password_manager/core/browser/credential_manager_impl.cc
+++ b/components/password_manager/core/browser/credential_manager_impl.cc
@@ -146,7 +146,7 @@
 
 PasswordStore::FormDigest CredentialManagerImpl::GetSynthesizedFormForOrigin()
     const {
-  PasswordStore::FormDigest digest = {autofill::PasswordForm::SCHEME_HTML,
+  PasswordStore::FormDigest digest = {autofill::PasswordForm::Scheme::kHtml,
                                       std::string(),
                                       GetLastCommittedURL().GetOrigin()};
   digest.signon_realm = digest.origin.spec();
diff --git a/components/password_manager/core/browser/credential_manager_impl_unittest.cc b/components/password_manager/core/browser/credential_manager_impl_unittest.cc
index 8e9b331..065563a 100644
--- a/components/password_manager/core/browser/credential_manager_impl_unittest.cc
+++ b/components/password_manager/core/browser/credential_manager_impl_unittest.cc
@@ -191,7 +191,7 @@
     form_.password_value = base::ASCIIToUTF16("Password");
     form_.origin = client_->GetLastCommittedEntryURL();
     form_.signon_realm = form_.origin.GetOrigin().spec();
-    form_.scheme = autofill::PasswordForm::SCHEME_HTML;
+    form_.scheme = autofill::PasswordForm::Scheme::kHtml;
     form_.skip_zero_click = false;
 
     affiliated_form1_.username_value = base::ASCIIToUTF16("Affiliated 1");
@@ -199,7 +199,7 @@
     affiliated_form1_.password_value = base::ASCIIToUTF16("Password");
     affiliated_form1_.origin = GURL();
     affiliated_form1_.signon_realm = kTestAndroidRealm1;
-    affiliated_form1_.scheme = autofill::PasswordForm::SCHEME_HTML;
+    affiliated_form1_.scheme = autofill::PasswordForm::Scheme::kHtml;
     affiliated_form1_.skip_zero_click = false;
 
     affiliated_form2_.username_value = base::ASCIIToUTF16("Affiliated 2");
@@ -207,7 +207,7 @@
     affiliated_form2_.password_value = base::ASCIIToUTF16("Password");
     affiliated_form2_.origin = GURL();
     affiliated_form2_.signon_realm = kTestAndroidRealm2;
-    affiliated_form2_.scheme = autofill::PasswordForm::SCHEME_HTML;
+    affiliated_form2_.scheme = autofill::PasswordForm::Scheme::kHtml;
     affiliated_form2_.skip_zero_click = false;
 
     origin_path_form_.username_value = base::ASCIIToUTF16("Username 2");
@@ -216,7 +216,7 @@
     origin_path_form_.origin = GURL("https://example.com/path");
     origin_path_form_.signon_realm =
         origin_path_form_.origin.GetOrigin().spec();
-    origin_path_form_.scheme = autofill::PasswordForm::SCHEME_HTML;
+    origin_path_form_.scheme = autofill::PasswordForm::Scheme::kHtml;
     origin_path_form_.skip_zero_click = false;
 
     subdomain_form_.username_value = base::ASCIIToUTF16("Username 2");
@@ -224,7 +224,7 @@
     subdomain_form_.password_value = base::ASCIIToUTF16("Password 2");
     subdomain_form_.origin = GURL("https://subdomain.example.com/path");
     subdomain_form_.signon_realm = subdomain_form_.origin.GetOrigin().spec();
-    subdomain_form_.scheme = autofill::PasswordForm::SCHEME_HTML;
+    subdomain_form_.scheme = autofill::PasswordForm::Scheme::kHtml;
     subdomain_form_.skip_zero_click = false;
 
     cross_origin_form_.username_value = base::ASCIIToUTF16("Username");
@@ -233,7 +233,7 @@
     cross_origin_form_.origin = GURL("https://example.net/");
     cross_origin_form_.signon_realm =
         cross_origin_form_.origin.GetOrigin().spec();
-    cross_origin_form_.scheme = autofill::PasswordForm::SCHEME_HTML;
+    cross_origin_form_.scheme = autofill::PasswordForm::Scheme::kHtml;
     cross_origin_form_.skip_zero_click = false;
 
     store_->Clear();
@@ -388,7 +388,7 @@
   EXPECT_TRUE(new_form.federation_origin.opaque());
   EXPECT_EQ(form_.icon_url, new_form.icon_url);
   EXPECT_FALSE(form_.skip_zero_click);
-  EXPECT_EQ(autofill::PasswordForm::SCHEME_HTML, new_form.scheme);
+  EXPECT_EQ(autofill::PasswordForm::Scheme::kHtml, new_form.scheme);
 }
 
 TEST_F(CredentialManagerImplTest, CredentialManagerOnStoreFederated) {
@@ -421,7 +421,7 @@
   EXPECT_EQ(form_.federation_origin, new_form.federation_origin);
   EXPECT_EQ(form_.icon_url, new_form.icon_url);
   EXPECT_FALSE(form_.skip_zero_click);
-  EXPECT_EQ(autofill::PasswordForm::SCHEME_HTML, new_form.scheme);
+  EXPECT_EQ(autofill::PasswordForm::Scheme::kHtml, new_form.scheme);
 }
 
 TEST_F(CredentialManagerImplTest, StoreFederatedAfterPassword) {
@@ -430,7 +430,7 @@
 
   autofill::PasswordForm federated = form_;
   federated.password_value.clear();
-  federated.type = autofill::PasswordForm::TYPE_API;
+  federated.type = autofill::PasswordForm::Type::kApi;
   federated.preferred = true;
   federated.federation_origin =
       url::Origin::Create(GURL("https://google.com/"));
@@ -1507,7 +1507,7 @@
       cm_service_impl_->GetSynthesizedFormForOrigin();
   EXPECT_EQ(kTestWebOrigin, synthesized.origin.spec());
   EXPECT_EQ(kTestWebOrigin, synthesized.signon_realm);
-  EXPECT_EQ(autofill::PasswordForm::SCHEME_HTML, synthesized.scheme);
+  EXPECT_EQ(autofill::PasswordForm::Scheme::kHtml, synthesized.scheme);
 }
 
 TEST_F(CredentialManagerImplTest, GetBlacklistedPasswordCredential) {
diff --git a/components/password_manager/core/browser/form_fetcher_impl_unittest.cc b/components/password_manager/core/browser/form_fetcher_impl_unittest.cc
index 7850558..3f2137f 100644
--- a/components/password_manager/core/browser/form_fetcher_impl_unittest.cc
+++ b/components/password_manager/core/browser/form_fetcher_impl_unittest.cc
@@ -106,7 +106,7 @@
                             const char* username_value,
                             const char* password_value) {
   PasswordForm form;
-  form.scheme = PasswordForm::SCHEME_HTML;
+  form.scheme = PasswordForm::Scheme::kHtml;
   form.origin = GURL(origin_url);
   form.signon_realm = origin_url;
   form.username_value = ASCIIToUTF16(username_value);
@@ -178,7 +178,7 @@
 class FormFetcherImplTest : public testing::Test {
  public:
   FormFetcherImplTest()
-      : form_digest_(PasswordForm::SCHEME_HTML,
+      : form_digest_(PasswordForm::Scheme::kHtml,
                      kTestHttpURL,
                      GURL(kTestHttpURL)) {
     mock_store_ = new MockPasswordStore;
@@ -442,7 +442,7 @@
   http_rep.SetSchemeStr(url::kHttpScheme);
   const GURL http_origin = form_digest_.origin.ReplaceComponents(http_rep);
   form_digest_ = PasswordStore::FormDigest(
-      PasswordForm::SCHEME_HTML, http_origin.GetOrigin().spec(), http_origin);
+      PasswordForm::Scheme::kHtml, http_origin.GetOrigin().spec(), http_origin);
 
   // A new form fetcher is created to be able to set the form digest and
   // migration flag.
@@ -489,8 +489,9 @@
   GURL::Replacements https_rep;
   https_rep.SetSchemeStr(url::kHttpsScheme);
   const GURL https_origin = form_digest_.origin.ReplaceComponents(https_rep);
-  form_digest_ = PasswordStore::FormDigest(
-      PasswordForm::SCHEME_HTML, https_origin.GetOrigin().spec(), https_origin);
+  form_digest_ =
+      PasswordStore::FormDigest(PasswordForm::Scheme::kHtml,
+                                https_origin.GetOrigin().spec(), https_origin);
 
   // A new form fetcher is created to be able to set the form digest and
   // migration flag.
@@ -516,7 +517,7 @@
   const GURL form_digest_http_origin =
       form_digest_.origin.ReplaceComponents(http_rep);
   PasswordStore::FormDigest http_form_digest(
-      PasswordForm::SCHEME_HTML, form_digest_http_origin.GetOrigin().spec(),
+      PasswordForm::Scheme::kHtml, form_digest_http_origin.GetOrigin().spec(),
       form_digest_http_origin);
   Fetch();
   base::WeakPtr<PasswordStoreConsumer> migrator_ptr;
@@ -564,8 +565,9 @@
   GURL::Replacements https_rep;
   https_rep.SetSchemeStr(url::kHttpsScheme);
   const GURL https_origin = form_digest_.origin.ReplaceComponents(https_rep);
-  form_digest_ = PasswordStore::FormDigest(
-      PasswordForm::SCHEME_HTML, https_origin.GetOrigin().spec(), https_origin);
+  form_digest_ =
+      PasswordStore::FormDigest(PasswordForm::Scheme::kHtml,
+                                https_origin.GetOrigin().spec(), https_origin);
 
   // A new form fetcher is created to be able to set the form digest and
   // migration flag.
@@ -589,7 +591,7 @@
   const GURL form_digest_http_origin =
       form_digest_.origin.ReplaceComponents(http_rep);
   PasswordStore::FormDigest http_form_digest(
-      PasswordForm::SCHEME_HTML, form_digest_http_origin.GetOrigin().spec(),
+      PasswordForm::Scheme::kHtml, form_digest_http_origin.GetOrigin().spec(),
       form_digest_http_origin);
   Fetch();
   // First the FormFetcher is waiting for the initial response from
diff --git a/components/password_manager/core/browser/form_parsing/form_parser.cc b/components/password_manager/core/browser/form_parsing/form_parser.cc
index dbd0261..a7bc72b 100644
--- a/components/password_manager/core/browser/form_parsing/form_parser.cc
+++ b/components/password_manager/core/browser/form_parsing/form_parser.cc
@@ -904,10 +904,10 @@
   // TODO(crbug.com/881346) Rename PasswordForm::other_possible_usernames to
   // all_possible_usernames once the old parser is gone.
   result->other_possible_usernames = std::move(all_possible_usernames);
-  result->scheme = PasswordForm::SCHEME_HTML;
+  result->scheme = PasswordForm::Scheme::kHtml;
   result->preferred = false;
   result->blacklisted_by_user = false;
-  result->type = PasswordForm::TYPE_MANUAL;
+  result->type = PasswordForm::Type::kManual;
   result->username_may_use_prefilled_placeholder =
       GetMayUsePrefilledPlaceholder(form_predictions, significant_fields);
   result->is_new_password_reliable =
diff --git a/components/password_manager/core/browser/form_parsing/form_parser_unittest.cc b/components/password_manager/core/browser/form_parsing/form_parser_unittest.cc
index ff90370..1075890 100644
--- a/components/password_manager/core/browser/form_parsing/form_parser_unittest.cc
+++ b/components/password_manager/core/browser/form_parsing/form_parser_unittest.cc
@@ -358,10 +358,10 @@
         EXPECT_FALSE(parsed_form) << "Expected no parsed results";
       } else {
         ASSERT_TRUE(parsed_form) << "Expected successful parsing";
-        EXPECT_EQ(PasswordForm::SCHEME_HTML, parsed_form->scheme);
+        EXPECT_EQ(PasswordForm::Scheme::kHtml, parsed_form->scheme);
         EXPECT_FALSE(parsed_form->preferred);
         EXPECT_FALSE(parsed_form->blacklisted_by_user);
-        EXPECT_EQ(PasswordForm::TYPE_MANUAL, parsed_form->type);
+        EXPECT_EQ(PasswordForm::Type::kManual, parsed_form->type);
 #if defined(OS_IOS)
         EXPECT_FALSE(parsed_form->has_renderer_ids);
 #else
diff --git a/components/password_manager/core/browser/http_auth_manager_impl.cc b/components/password_manager/core/browser/http_auth_manager_impl.cc
index d496123a..3785547 100644
--- a/components/password_manager/core/browser/http_auth_manager_impl.cc
+++ b/components/password_manager/core/browser/http_auth_manager_impl.cc
@@ -73,7 +73,7 @@
 void HttpAuthManagerImpl::Autofill(
     const PasswordForm& preferred_match,
     const PasswordFormManagerForUI* form_manager) const {
-  DCHECK_NE(PasswordForm::SCHEME_HTML, preferred_match.scheme);
+  DCHECK_NE(PasswordForm::Scheme::kHtml, preferred_match.scheme);
   if (observer_ && (form_manager_.get() == form_manager) &&
       client_->IsFillingEnabled(form_manager_->GetOrigin())) {
     observer_->OnAutofillDataAvailable(preferred_match.username_value,
diff --git a/components/password_manager/core/browser/http_auth_manager_unittest.cc b/components/password_manager/core/browser/http_auth_manager_unittest.cc
index 67487d6..11bd42d 100644
--- a/components/password_manager/core/browser/http_auth_manager_unittest.cc
+++ b/components/password_manager/core/browser/http_auth_manager_unittest.cc
@@ -135,7 +135,7 @@
         .WillRepeatedly(Return(filling_enabled));
 
     PasswordForm observed_form;
-    observed_form.scheme = PasswordForm::SCHEME_BASIC;
+    observed_form.scheme = PasswordForm::Scheme::kBasic;
     observed_form.origin = GURL("http://proxy.com/");
     observed_form.signon_realm = "proxy.com/realm";
 
@@ -169,7 +169,7 @@
     EXPECT_CALL(client_, IsSavingAndFillingEnabled(_))
         .WillRepeatedly(Return(filling_and_saving_enabled));
     PasswordForm observed_form;
-    observed_form.scheme = PasswordForm::SCHEME_BASIC;
+    observed_form.scheme = PasswordForm::Scheme::kBasic;
     observed_form.origin = GURL("http://proxy.com/");
     observed_form.signon_realm = "proxy.com/realm";
 
diff --git a/components/password_manager/core/browser/http_credentials_cleaner_unittest.cc b/components/password_manager/core/browser/http_credentials_cleaner_unittest.cc
index a61e7c3..ee1374f0 100644
--- a/components/password_manager/core/browser/http_credentials_cleaner_unittest.cc
+++ b/components/password_manager/core/browser/http_credentials_cleaner_unittest.cc
@@ -53,49 +53,49 @@
 
 constexpr static TestCase kCases[] = {
 
-    {true, autofill::PasswordForm::Scheme::SCHEME_HTML, false, true, true, true,
+    {true, autofill::PasswordForm::Scheme::kHtml, false, true, true, true,
      HttpCredentialType::kNoMatching},
-    {true, autofill::PasswordForm::Scheme::SCHEME_HTML, true, false, true, true,
+    {true, autofill::PasswordForm::Scheme::kHtml, true, false, true, true,
      HttpCredentialType::kNoMatching},
-    {true, autofill::PasswordForm::Scheme::SCHEME_HTML, true, true, false, true,
+    {true, autofill::PasswordForm::Scheme::kHtml, true, true, false, true,
      HttpCredentialType::kNoMatching},
-    {true, autofill::PasswordForm::Scheme::SCHEME_HTML, true, true, true, false,
+    {true, autofill::PasswordForm::Scheme::kHtml, true, true, true, false,
      HttpCredentialType::kConflicting},
-    {true, autofill::PasswordForm::Scheme::SCHEME_HTML, true, true, true, true,
+    {true, autofill::PasswordForm::Scheme::kHtml, true, true, true, true,
      HttpCredentialType::kEquivalent},
 
-    {false, autofill::PasswordForm::Scheme::SCHEME_HTML, false, true, true,
-     true, HttpCredentialType::kNoMatching},
-    {false, autofill::PasswordForm::Scheme::SCHEME_HTML, true, false, true,
-     true, HttpCredentialType::kNoMatching},
-    {false, autofill::PasswordForm::Scheme::SCHEME_HTML, true, true, false,
-     true, HttpCredentialType::kNoMatching},
-    {false, autofill::PasswordForm::Scheme::SCHEME_HTML, true, true, true,
-     false, HttpCredentialType::kConflicting},
-    {false, autofill::PasswordForm::Scheme::SCHEME_HTML, true, true, true, true,
+    {false, autofill::PasswordForm::Scheme::kHtml, false, true, true, true,
+     HttpCredentialType::kNoMatching},
+    {false, autofill::PasswordForm::Scheme::kHtml, true, false, true, true,
+     HttpCredentialType::kNoMatching},
+    {false, autofill::PasswordForm::Scheme::kHtml, true, true, false, true,
+     HttpCredentialType::kNoMatching},
+    {false, autofill::PasswordForm::Scheme::kHtml, true, true, true, false,
+     HttpCredentialType::kConflicting},
+    {false, autofill::PasswordForm::Scheme::kHtml, true, true, true, true,
      HttpCredentialType::kEquivalent},
 
-    {true, autofill::PasswordForm::Scheme::SCHEME_BASIC, false, true, true,
-     true, HttpCredentialType::kNoMatching},
-    {true, autofill::PasswordForm::Scheme::SCHEME_BASIC, true, false, true,
-     true, HttpCredentialType::kNoMatching},
-    {true, autofill::PasswordForm::Scheme::SCHEME_BASIC, true, true, false,
-     true, HttpCredentialType::kNoMatching},
-    {true, autofill::PasswordForm::Scheme::SCHEME_BASIC, true, true, true,
-     false, HttpCredentialType::kConflicting},
-    {true, autofill::PasswordForm::Scheme::SCHEME_BASIC, true, true, true, true,
+    {true, autofill::PasswordForm::Scheme::kBasic, false, true, true, true,
+     HttpCredentialType::kNoMatching},
+    {true, autofill::PasswordForm::Scheme::kBasic, true, false, true, true,
+     HttpCredentialType::kNoMatching},
+    {true, autofill::PasswordForm::Scheme::kBasic, true, true, false, true,
+     HttpCredentialType::kNoMatching},
+    {true, autofill::PasswordForm::Scheme::kBasic, true, true, true, false,
+     HttpCredentialType::kConflicting},
+    {true, autofill::PasswordForm::Scheme::kBasic, true, true, true, true,
      HttpCredentialType::kEquivalent},
 
-    {false, autofill::PasswordForm::Scheme::SCHEME_BASIC, false, true, true,
-     true, HttpCredentialType::kNoMatching},
-    {false, autofill::PasswordForm::Scheme::SCHEME_BASIC, true, false, true,
-     true, HttpCredentialType::kNoMatching},
-    {false, autofill::PasswordForm::Scheme::SCHEME_BASIC, true, true, false,
-     true, HttpCredentialType::kNoMatching},
-    {false, autofill::PasswordForm::Scheme::SCHEME_BASIC, true, true, true,
-     false, HttpCredentialType::kConflicting},
-    {false, autofill::PasswordForm::Scheme::SCHEME_BASIC, true, true, true,
-     true, HttpCredentialType::kEquivalent}};
+    {false, autofill::PasswordForm::Scheme::kBasic, false, true, true, true,
+     HttpCredentialType::kNoMatching},
+    {false, autofill::PasswordForm::Scheme::kBasic, true, false, true, true,
+     HttpCredentialType::kNoMatching},
+    {false, autofill::PasswordForm::Scheme::kBasic, true, true, false, true,
+     HttpCredentialType::kNoMatching},
+    {false, autofill::PasswordForm::Scheme::kBasic, true, true, true, false,
+     HttpCredentialType::kConflicting},
+    {false, autofill::PasswordForm::Scheme::kBasic, true, true, true, true,
+     HttpCredentialType::kEquivalent}};
 
 }  // namespace
 
@@ -166,9 +166,9 @@
   https_form.scheme = test.http_form_scheme;
   if (!test.same_scheme) {
     https_form.scheme =
-        (http_form.scheme == autofill::PasswordForm::Scheme::SCHEME_BASIC
-             ? autofill::PasswordForm::Scheme::SCHEME_HTML
-             : autofill::PasswordForm::Scheme::SCHEME_BASIC);
+        (http_form.scheme == autofill::PasswordForm::Scheme::kBasic
+             ? autofill::PasswordForm::Scheme::kHtml
+             : autofill::PasswordForm::Scheme::kBasic);
   }
   store_->AddLogin(https_form);
 
diff --git a/components/password_manager/core/browser/http_password_store_migrator.cc b/components/password_manager/core/browser/http_password_store_migrator.cc
index b20b4bbf..a357313 100644
--- a/components/password_manager/core/browser/http_password_store_migrator.cc
+++ b/components/password_manager/core/browser/http_password_store_migrator.cc
@@ -47,7 +47,7 @@
   GURL::Replacements rep;
   rep.SetSchemeStr(url::kHttpScheme);
   GURL http_origin = https_origin.ReplaceComponents(rep);
-  PasswordStore::FormDigest form(autofill::PasswordForm::SCHEME_HTML,
+  PasswordStore::FormDigest form(autofill::PasswordForm::Scheme::kHtml,
                                  http_origin.GetOrigin().spec(), http_origin);
   http_origin_domain_ = http_origin.GetOrigin();
   client_->GetPasswordStore()->GetLogins(form, this);
@@ -79,7 +79,8 @@
   if (!http_form.action.SchemeIs(url::kHttpsScheme))
     https_form.action = https_form.origin;
   https_form.form_data = autofill::FormData();
-  https_form.generation_upload_status = autofill::PasswordForm::NO_SIGNAL_SENT;
+  https_form.generation_upload_status =
+      autofill::PasswordForm::GenerationUploadStatus::kNoSignalSent;
   https_form.skip_zero_click = false;
   return https_form;
 }
diff --git a/components/password_manager/core/browser/http_password_store_migrator_unittest.cc b/components/password_manager/core/browser/http_password_store_migrator_unittest.cc
index 13e0f5d0..4597043 100644
--- a/components/password_manager/core/browser/http_password_store_migrator_unittest.cc
+++ b/components/password_manager/core/browser/http_password_store_migrator_unittest.cc
@@ -272,17 +272,17 @@
     PasswordForm http_html_form;
     http_html_form.origin = kOrigins[origin_has_paths];
     http_html_form.signon_realm = "http://example.org/";
-    http_html_form.scheme = PasswordForm::Scheme::SCHEME_HTML;
+    http_html_form.scheme = PasswordForm::Scheme::kHtml;
 
     PasswordForm non_html_empty_realm_form;
     non_html_empty_realm_form.origin = kOrigins[origin_has_paths];
     non_html_empty_realm_form.signon_realm = "http://example.org/";
-    non_html_empty_realm_form.scheme = PasswordForm::Scheme::SCHEME_BASIC;
+    non_html_empty_realm_form.scheme = PasswordForm::Scheme::kBasic;
 
     PasswordForm non_html_form;
     non_html_form.origin = kOrigins[origin_has_paths];
     non_html_form.signon_realm = "http://example.org/realm";
-    non_html_form.scheme = PasswordForm::Scheme::SCHEME_BASIC;
+    non_html_form.scheme = PasswordForm::Scheme::kBasic;
 
     EXPECT_EQ(HttpPasswordStoreMigrator::MigrateHttpFormToHttps(http_html_form)
                   .signon_realm,
diff --git a/components/password_manager/core/browser/login_database.cc b/components/password_manager/core/browser/login_database.cc
index ff564c0..1401a59 100644
--- a/components/password_manager/core/browser/login_database.cc
+++ b/components/password_manager/core/browser/login_database.cc
@@ -168,8 +168,8 @@
   s->BindInt(COLUMN_PREFERRED, form.preferred);
   s->BindInt64(COLUMN_DATE_CREATED, form.date_created.ToInternalValue());
   s->BindInt(COLUMN_BLACKLISTED_BY_USER, form.blacklisted_by_user);
-  s->BindInt(COLUMN_SCHEME, form.scheme);
-  s->BindInt(COLUMN_PASSWORD_TYPE, form.type);
+  s->BindInt(COLUMN_SCHEME, static_cast<int>(form.scheme));
+  s->BindInt(COLUMN_PASSWORD_TYPE, static_cast<int>(form.type));
   s->BindInt(COLUMN_TIMES_USED, form.times_used);
   base::Pickle form_data_pickle;
   autofill::SerializeFormData(form.form_data, &form_data_pickle);
@@ -185,7 +185,8 @@
                     ? std::string()
                     : form.federation_origin.Serialize());
   s->BindInt(COLUMN_SKIP_ZERO_CLICK, form.skip_zero_click);
-  s->BindInt(COLUMN_GENERATION_UPLOAD_STATUS, form.generation_upload_status);
+  s->BindInt(COLUMN_GENERATION_UPLOAD_STATUS,
+             static_cast<int>(form.generation_upload_status));
   base::Pickle usernames_pickle =
       SerializeValueElementPairs(form.other_possible_usernames);
   s->BindBlob(COLUMN_POSSIBLE_USERNAME_PAIRS, usernames_pickle.data(),
@@ -778,7 +779,7 @@
     int accounts_per_site = s.ColumnInt(3);
     if (blacklisted) {
       ++blacklisted_sites;
-    } else if (password_type == PasswordForm::TYPE_GENERATED) {
+    } else if (password_type == PasswordForm::Type::kGenerated) {
       total_generated_accounts += accounts_per_site;
       LogAccountStat(
           base::StringPrintf("PasswordManager.AccountsPerSite.AutoGenerated.%s",
@@ -823,7 +824,7 @@
     PasswordForm::Type type =
         static_cast<PasswordForm::Type>(usage_statement.ColumnInt(0));
 
-    if (type == PasswordForm::TYPE_GENERATED) {
+    if (type == PasswordForm::Type::kGenerated) {
       LogTimesUsedStat(base::StringPrintf(
                            "PasswordManager.TimesPasswordUsed.AutoGenerated.%s",
                            custom_passphrase.c_str()),
@@ -1062,8 +1063,8 @@
   s.BindInt(next_param++, form.preferred);
   s.BindInt64(next_param++, form.date_created.ToInternalValue());
   s.BindInt(next_param++, form.blacklisted_by_user);
-  s.BindInt(next_param++, form.scheme);
-  s.BindInt(next_param++, form.type);
+  s.BindInt(next_param++, static_cast<int>(form.scheme));
+  s.BindInt(next_param++, static_cast<int>(form.type));
   s.BindInt(next_param++, form.times_used);
   base::Pickle form_data_pickle;
   autofill::SerializeFormData(form.form_data, &form_data_pickle);
@@ -1076,7 +1077,7 @@
                                  ? std::string()
                                  : form.federation_origin.Serialize());
   s.BindInt(next_param++, form.skip_zero_click);
-  s.BindInt(next_param++, form.generation_upload_status);
+  s.BindInt(next_param++, static_cast<int>(form.generation_upload_status));
   base::Pickle username_pickle =
       SerializeValueElementPairs(form.other_possible_usernames);
   s.BindBlob(next_param++, username_pickle.data(), username_pickle.size());
@@ -1309,12 +1310,11 @@
       base::Time::FromInternalValue(s.ColumnInt64(COLUMN_DATE_CREATED));
   form->blacklisted_by_user = (s.ColumnInt(COLUMN_BLACKLISTED_BY_USER) > 0);
   int scheme_int = s.ColumnInt(COLUMN_SCHEME);
-  DCHECK_LE(0, scheme_int);
-  DCHECK_GE(PasswordForm::SCHEME_LAST, scheme_int);
   form->scheme = static_cast<PasswordForm::Scheme>(scheme_int);
+  DCHECK(autofill::mojom::IsKnownEnumValue(form->scheme));
   int type_int = s.ColumnInt(COLUMN_PASSWORD_TYPE);
-  DCHECK(type_int >= 0 && type_int <= PasswordForm::TYPE_LAST) << type_int;
   form->type = static_cast<PasswordForm::Type>(type_int);
+  DCHECK(autofill::mojom::IsKnownEnumValue(form->type));
   if (s.ColumnByteLength(COLUMN_POSSIBLE_USERNAME_PAIRS)) {
     base::Pickle pickle(
         static_cast<const char*>(s.ColumnBlob(COLUMN_POSSIBLE_USERNAME_PAIRS)),
@@ -1343,11 +1343,10 @@
   form->skip_zero_click = (s.ColumnInt(COLUMN_SKIP_ZERO_CLICK) > 0);
   int generation_upload_status_int =
       s.ColumnInt(COLUMN_GENERATION_UPLOAD_STATUS);
-  DCHECK(generation_upload_status_int >= 0 &&
-         generation_upload_status_int <= PasswordForm::UNKNOWN_STATUS);
   form->generation_upload_status =
       static_cast<PasswordForm::GenerationUploadStatus>(
           generation_upload_status_int);
+  DCHECK(autofill::mojom::IsKnownEnumValue(form->generation_upload_status));
   return ENCRYPTION_RESULT_SUCCESS;
 }
 
@@ -1360,9 +1359,10 @@
   const GURL signon_realm(form.signon_realm);
   std::string registered_domain = GetRegistryControlledDomain(signon_realm);
   const bool should_PSL_matching_apply =
-      form.scheme == PasswordForm::SCHEME_HTML &&
+      form.scheme == PasswordForm::Scheme::kHtml &&
       ShouldPSLDomainMatchingApply(registered_domain);
-  const bool should_federated_apply = form.scheme == PasswordForm::SCHEME_HTML;
+  const bool should_federated_apply =
+      form.scheme == PasswordForm::Scheme::kHtml;
   DCHECK(!get_statement_.empty());
   DCHECK(!get_statement_psl_.empty());
   DCHECK(!get_statement_federated_.empty());
diff --git a/components/password_manager/core/browser/login_database_ios_unittest.cc b/components/password_manager/core/browser/login_database_ios_unittest.cc
index 5119971..c9cf4b51 100644
--- a/components/password_manager/core/browser/login_database_ios_unittest.cc
+++ b/components/password_manager/core/browser/login_database_ios_unittest.cc
@@ -172,7 +172,7 @@
                                         base::Time::FromDoubleT(250),
                                         /*changes=*/nullptr);
 
-  PasswordStore::FormDigest form = {PasswordForm::SCHEME_HTML,
+  PasswordStore::FormDigest form = {PasswordForm::Scheme::kHtml,
                                     "http://www.example.com", GURL()};
   std::vector<std::unique_ptr<PasswordForm>> logins;
   EXPECT_TRUE(login_db_->GetLogins(form, &logins));
diff --git a/components/password_manager/core/browser/login_database_unittest.cc b/components/password_manager/core/browser/login_database_unittest.cc
index f272765a8..22831e3 100644
--- a/components/password_manager/core/browser/login_database_unittest.cc
+++ b/components/password_manager/core/browser/login_database_unittest.cc
@@ -77,7 +77,7 @@
   form->submit_element = ASCIIToUTF16("signIn");
   form->signon_realm = "http://www.google.com/";
   form->preferred = false;
-  form->scheme = PasswordForm::SCHEME_HTML;
+  form->scheme = PasswordForm::Scheme::kHtml;
   form->times_used = 1;
   form->form_data.name = ASCIIToUTF16("form_name");
   form->date_synced = base::Time::Now();
@@ -159,18 +159,18 @@
   return arg.origin.spec() == "https://accounts.google.com/ServiceLogin" &&
          arg.action.spec() == "https://accounts.google.com/ServiceLoginAuth" &&
          arg.username_value == ASCIIToUTF16("theerikchen") &&
-         arg.scheme == PasswordForm::SCHEME_HTML;
+         arg.scheme == PasswordForm::Scheme::kHtml;
 }
 
 MATCHER(IsGoogle2Account, "") {
   return arg.origin.spec() == "https://accounts.google.com/ServiceLogin" &&
          arg.action.spec() == "https://accounts.google.com/ServiceLoginAuth" &&
          arg.username_value == ASCIIToUTF16("theerikchen2") &&
-         arg.scheme == PasswordForm::SCHEME_HTML;
+         arg.scheme == PasswordForm::Scheme::kHtml;
 }
 
 MATCHER(IsBasicAuthAccount, "") {
-  return arg.scheme == PasswordForm::SCHEME_BASIC;
+  return arg.scheme == PasswordForm::Scheme::kBasic;
 }
 
 }  // namespace
@@ -216,7 +216,7 @@
     html_form.password_element = ASCIIToUTF16("password");
     html_form.submit_element = ASCIIToUTF16("");
     html_form.signon_realm = "http://example.com/";
-    html_form.scheme = PasswordForm::SCHEME_HTML;
+    html_form.scheme = PasswordForm::Scheme::kHtml;
     html_form.date_created = now;
 
     // Add them and make sure they are there.
@@ -461,7 +461,7 @@
   form.submit_element = ASCIIToUTF16("");
   form.signon_realm = "https://foo.com/";
   form.preferred = false;
-  form.scheme = PasswordForm::SCHEME_HTML;
+  form.scheme = PasswordForm::Scheme::kHtml;
 
   // Add it and make sure it is there.
   EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
@@ -506,7 +506,7 @@
   form.password_value = ASCIIToUTF16("test");
   form.signon_realm = "https://foo.com/";
   form.preferred = false;
-  form.scheme = PasswordForm::SCHEME_HTML;
+  form.scheme = PasswordForm::Scheme::kHtml;
 
   // We go to the mobile site.
   PasswordForm form2(form);
@@ -514,7 +514,7 @@
   form2.action = GURL("https://mobile.foo.com/login");
   form2.signon_realm = "federation://mobile.foo.com/accounts.google.com";
   form2.username_value = ASCIIToUTF16("test1@gmail.com");
-  form2.type = PasswordForm::TYPE_API;
+  form2.type = PasswordForm::Type::kApi;
   form2.federation_origin =
       url::Origin::Create(GURL("https://accounts.google.com/"));
 
@@ -525,8 +525,9 @@
   EXPECT_EQ(2U, result.size());
 
   // Match against desktop.
-  PasswordStore::FormDigest form_request = {
-      PasswordForm::SCHEME_HTML, "https://foo.com/", GURL("https://foo.com/")};
+  PasswordStore::FormDigest form_request = {PasswordForm::Scheme::kHtml,
+                                            "https://foo.com/",
+                                            GURL("https://foo.com/")};
   EXPECT_TRUE(db().GetLogins(form_request, &result));
   // Both forms are matched, only form2 is a PSL match.
   form.is_public_suffix_match = false;
@@ -550,8 +551,8 @@
   form.federation_origin =
       url::Origin::Create(GURL("https://accounts.google.com/"));
   form.username_value = ASCIIToUTF16("test@gmail.com");
-  form.type = PasswordForm::TYPE_API;
-  form.scheme = PasswordForm::SCHEME_HTML;
+  form.type = PasswordForm::Type::kApi;
+  form.scheme = PasswordForm::Scheme::kHtml;
 
   PasswordForm form_with_port(form);
   form_with_port.origin = GURL("http://localhost:8080/");
@@ -561,7 +562,7 @@
   EXPECT_EQ(AddChangeForForm(form_with_port), db().AddLogin(form_with_port));
 
   // Match localhost with and without port.
-  PasswordStore::FormDigest form_request(PasswordForm::SCHEME_HTML,
+  PasswordStore::FormDigest form_request(PasswordForm::Scheme::kHtml,
                                          "http://localhost/",
                                          GURL("http://localhost/"));
   std::vector<std::unique_ptr<PasswordForm>> result;
@@ -575,25 +576,25 @@
 }
 
 TEST_F(LoginDatabaseTest, TestPublicSuffixDisabledForNonHTMLForms) {
-  TestNonHTMLFormPSLMatching(PasswordForm::SCHEME_BASIC);
-  TestNonHTMLFormPSLMatching(PasswordForm::SCHEME_DIGEST);
-  TestNonHTMLFormPSLMatching(PasswordForm::SCHEME_OTHER);
+  TestNonHTMLFormPSLMatching(PasswordForm::Scheme::kBasic);
+  TestNonHTMLFormPSLMatching(PasswordForm::Scheme::kDigest);
+  TestNonHTMLFormPSLMatching(PasswordForm::Scheme::kOther);
 }
 
 TEST_F(LoginDatabaseTest, TestIPAddressMatches_HTML) {
-  TestRetrievingIPAddress(PasswordForm::SCHEME_HTML);
+  TestRetrievingIPAddress(PasswordForm::Scheme::kHtml);
 }
 
 TEST_F(LoginDatabaseTest, TestIPAddressMatches_basic) {
-  TestRetrievingIPAddress(PasswordForm::SCHEME_BASIC);
+  TestRetrievingIPAddress(PasswordForm::Scheme::kBasic);
 }
 
 TEST_F(LoginDatabaseTest, TestIPAddressMatches_digest) {
-  TestRetrievingIPAddress(PasswordForm::SCHEME_DIGEST);
+  TestRetrievingIPAddress(PasswordForm::Scheme::kDigest);
 }
 
 TEST_F(LoginDatabaseTest, TestIPAddressMatches_other) {
-  TestRetrievingIPAddress(PasswordForm::SCHEME_OTHER);
+  TestRetrievingIPAddress(PasswordForm::Scheme::kOther);
 }
 
 TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingShouldMatchingApply) {
@@ -614,7 +615,7 @@
   form.submit_element = ASCIIToUTF16("");
   form.signon_realm = "https://accounts.google.com/";
   form.preferred = false;
-  form.scheme = PasswordForm::SCHEME_HTML;
+  form.scheme = PasswordForm::Scheme::kHtml;
 
   // Add it and make sure it is there.
   EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
@@ -628,7 +629,7 @@
   result.clear();
 
   // We go to a different site on the same domain where feature is not needed.
-  PasswordStore::FormDigest form2 = {PasswordForm::SCHEME_HTML,
+  PasswordStore::FormDigest form2 = {PasswordForm::Scheme::kHtml,
                                      "https://some.other.google.com/",
                                      GURL("https://some.other.google.com/")};
 
@@ -652,7 +653,7 @@
   form.password_value = ASCIIToUTF16("test");
   form.signon_realm = "https://accounts.google.com/";
   form.preferred = false;
-  form.scheme = PasswordForm::SCHEME_HTML;
+  form.scheme = PasswordForm::Scheme::kHtml;
 
   // We go to a different site on the same domain where PSL is disabled.
   PasswordForm form2(form);
@@ -660,7 +661,7 @@
   form2.action = GURL("https://some.other.google.com/login");
   form2.signon_realm = "federation://some.other.google.com/accounts.google.com";
   form2.username_value = ASCIIToUTF16("test1@gmail.com");
-  form2.type = PasswordForm::TYPE_API;
+  form2.type = PasswordForm::Type::kApi;
   form2.federation_origin =
       url::Origin::Create(GURL("https://accounts.google.com/"));
 
@@ -671,7 +672,7 @@
   EXPECT_EQ(2U, result.size());
 
   // Match against the first one.
-  PasswordStore::FormDigest form_request = {PasswordForm::SCHEME_HTML,
+  PasswordStore::FormDigest form_request = {PasswordForm::Scheme::kHtml,
                                             form.signon_realm, form.origin};
   EXPECT_TRUE(db().GetLogins(form_request, &result));
   EXPECT_THAT(result, testing::ElementsAre(Pointee(form)));
@@ -693,14 +694,14 @@
   form.action = GURL("https://psl.example.com/login");
   form.signon_realm = "federation://psl.example.com/accounts.google.com";
   form.username_value = ASCIIToUTF16("test1@gmail.com");
-  form.type = PasswordForm::TYPE_API;
+  form.type = PasswordForm::Type::kApi;
   form.federation_origin =
       url::Origin::Create(GURL("https://accounts.google.com/"));
-  form.scheme = PasswordForm::SCHEME_HTML;
+  form.scheme = PasswordForm::Scheme::kHtml;
   EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
 
   // Match against.
-  PasswordStore::FormDigest form_request = {PasswordForm::SCHEME_HTML,
+  PasswordStore::FormDigest form_request = {PasswordForm::Scheme::kHtml,
                                             "https://example.com/",
                                             GURL("https://example.com/login")};
   std::vector<std::unique_ptr<PasswordForm>> result;
@@ -730,7 +731,7 @@
   form.submit_element = ASCIIToUTF16("");
   form.signon_realm = "https://foo.com/";
   form.preferred = false;
-  form.scheme = PasswordForm::SCHEME_HTML;
+  form.scheme = PasswordForm::Scheme::kHtml;
 
   // Add it and make sure it is there.
   EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
@@ -765,7 +766,7 @@
   form.submit_element = ASCIIToUTF16("");
   form.signon_realm = "https://baz.com/";
   form.preferred = false;
-  form.scheme = PasswordForm::SCHEME_HTML;
+  form.scheme = PasswordForm::Scheme::kHtml;
 
   // Add it and make sure it is there.
   EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
@@ -813,7 +814,7 @@
   form.submit_element = ASCIIToUTF16("");
   form.signon_realm = "http://foo.com/";
   form.preferred = false;
-  form.scheme = PasswordForm::SCHEME_HTML;
+  form.scheme = PasswordForm::Scheme::kHtml;
 
   // Add it and make sure it is there.
   EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
@@ -1120,7 +1121,7 @@
   form.signon_realm = "http://www.google.com/";
   form.preferred = true;
   form.blacklisted_by_user = true;
-  form.scheme = PasswordForm::SCHEME_HTML;
+  form.scheme = PasswordForm::Scheme::kHtml;
   form.date_synced = base::Time::Now();
   form.display_name = ASCIIToUTF16("Mr. Smith");
   form.icon_url = GURL("https://accounts.google.com/Icon");
@@ -1180,7 +1181,7 @@
   incomplete_form.password_value = ASCIIToUTF16("my_password");
   incomplete_form.preferred = true;
   incomplete_form.blacklisted_by_user = false;
-  incomplete_form.scheme = PasswordForm::SCHEME_HTML;
+  incomplete_form.scheme = PasswordForm::Scheme::kHtml;
   EXPECT_EQ(AddChangeForForm(incomplete_form), db().AddLogin(incomplete_form));
 
   // A form on some website. It should trigger a match with the stored one.
@@ -1245,7 +1246,7 @@
   incomplete_form.password_value = ASCIIToUTF16("my_password");
   incomplete_form.preferred = true;
   incomplete_form.blacklisted_by_user = false;
-  incomplete_form.scheme = PasswordForm::SCHEME_HTML;
+  incomplete_form.scheme = PasswordForm::Scheme::kHtml;
   EXPECT_EQ(AddChangeForForm(incomplete_form), db().AddLogin(incomplete_form));
 
   // Save a complete version of the previous form. Both forms could exist if
@@ -1291,7 +1292,7 @@
   form.password_value = ASCIIToUTF16("my_password");
   form.preferred = true;
   form.blacklisted_by_user = false;
-  form.scheme = PasswordForm::SCHEME_HTML;
+  form.scheme = PasswordForm::Scheme::kHtml;
   EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
 
   // Add almost the same form again.
@@ -1311,7 +1312,7 @@
   form.password_value = ASCIIToUTF16("my_password");
   form.preferred = true;
   form.blacklisted_by_user = false;
-  form.scheme = PasswordForm::SCHEME_HTML;
+  form.scheme = PasswordForm::Scheme::kHtml;
   EXPECT_EQ(PasswordStoreChangeList(), db().AddLogin(form));
 
   // |signon_realm| shouldn't be empty.
@@ -1328,7 +1329,7 @@
   form.password_value = ASCIIToUTF16("my_password");
   form.preferred = true;
   form.blacklisted_by_user = false;
-  form.scheme = PasswordForm::SCHEME_HTML;
+  form.scheme = PasswordForm::Scheme::kHtml;
   EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form));
 
   form.action = GURL("http://accounts.google.com/login");
@@ -1341,8 +1342,8 @@
   form.date_synced = base::Time::Now();
   form.date_created = base::Time::Now() - base::TimeDelta::FromDays(1);
   form.blacklisted_by_user = true;
-  form.scheme = PasswordForm::SCHEME_BASIC;
-  form.type = PasswordForm::TYPE_GENERATED;
+  form.scheme = PasswordForm::Scheme::kBasic;
+  form.type = PasswordForm::Type::kGenerated;
   form.display_name = ASCIIToUTF16("Mr. Smith");
   form.icon_url = GURL("https://accounts.google.com/Icon");
   form.federation_origin =
@@ -1368,7 +1369,7 @@
   form.password_value = ASCIIToUTF16("my_password");
   form.preferred = true;
   form.blacklisted_by_user = false;
-  form.scheme = PasswordForm::SCHEME_HTML;
+  form.scheme = PasswordForm::Scheme::kHtml;
   // The form isn't in the database.
   EXPECT_FALSE(db().RemoveLogin(form, /*changes=*/nullptr));
 
@@ -1396,22 +1397,22 @@
   EXPECT_EQ(AddChangeForForm(password_form), db().AddLogin(password_form));
 
   password_form.username_value = ASCIIToUTF16("test3@gmail.com");
-  password_form.type = PasswordForm::TYPE_GENERATED;
+  password_form.type = PasswordForm::Type::kGenerated;
   password_form.times_used = 2;
   EXPECT_EQ(AddChangeForForm(password_form), db().AddLogin(password_form));
 
   password_form.origin = GURL("ftp://third.example.com/");
   password_form.signon_realm = "ftp://third.example.com/";
   password_form.times_used = 4;
-  password_form.scheme = PasswordForm::SCHEME_OTHER;
+  password_form.scheme = PasswordForm::Scheme::kOther;
   EXPECT_EQ(AddChangeForForm(password_form), db().AddLogin(password_form));
 
   password_form.origin = GURL("http://fourth.example.com/");
   password_form.signon_realm = "http://fourth.example.com/";
-  password_form.type = PasswordForm::TYPE_MANUAL;
+  password_form.type = PasswordForm::Type::kManual;
   password_form.username_value = ASCIIToUTF16("");
   password_form.times_used = 10;
-  password_form.scheme = PasswordForm::SCHEME_HTML;
+  password_form.scheme = PasswordForm::Scheme::kHtml;
   EXPECT_EQ(AddChangeForForm(password_form), db().AddLogin(password_form));
 
   password_form.origin = GURL("https://fifth.example.com/");
@@ -1630,7 +1631,7 @@
 
   // -- Not HTML form based logins or blacklisted logins. Should be ignored.
   PasswordForm ignored_form;
-  ignored_form.scheme = PasswordForm::SCHEME_HTML;
+  ignored_form.scheme = PasswordForm::Scheme::kHtml;
   ignored_form.signon_realm = "http://example.org/";
   ignored_form.origin = GURL("http://example.org/blacklist");
   ignored_form.blacklisted_by_user = true;
@@ -1638,19 +1639,19 @@
   ignored_form.password_value = ASCIIToUTF16("password_y");
   EXPECT_EQ(AddChangeForForm(ignored_form), db().AddLogin(ignored_form));
 
-  ignored_form.scheme = PasswordForm::SCHEME_BASIC;
+  ignored_form.scheme = PasswordForm::Scheme::kBasic;
   ignored_form.signon_realm = "http://example.org/HTTP Auth Realm";
   ignored_form.origin = GURL("http://example.org/");
   ignored_form.blacklisted_by_user = false;
   EXPECT_EQ(AddChangeForForm(ignored_form), db().AddLogin(ignored_form));
 
-  ignored_form.scheme = PasswordForm::SCHEME_HTML;
+  ignored_form.scheme = PasswordForm::Scheme::kHtml;
   ignored_form.signon_realm = "android://hash@com.example/";
   ignored_form.origin = GURL();
   ignored_form.blacklisted_by_user = false;
   EXPECT_EQ(AddChangeForForm(ignored_form), db().AddLogin(ignored_form));
 
-  ignored_form.scheme = PasswordForm::SCHEME_HTML;
+  ignored_form.scheme = PasswordForm::Scheme::kHtml;
   ignored_form.signon_realm = "federation://example.com/federation.com";
   ignored_form.origin = GURL("https://example.com/");
   ignored_form.blacklisted_by_user = false;
diff --git a/components/password_manager/core/browser/new_password_form_manager.cc b/components/password_manager/core/browser/new_password_form_manager.cc
index 4bc4e08..1e121a3 100644
--- a/components/password_manager/core/browser/new_password_form_manager.cc
+++ b/components/password_manager/core/browser/new_password_form_manager.cc
@@ -261,11 +261,11 @@
 
   // TODO(https://crbug.com/831123): Implement indicator event metrics.
   if (password_overridden_ &&
-      pending_credentials_.type == PasswordForm::TYPE_GENERATED &&
+      pending_credentials_.type == PasswordForm::Type::kGenerated &&
       !HasGeneratedPassword()) {
     metrics_util::LogPasswordGenerationSubmissionEvent(
         metrics_util::PASSWORD_OVERRIDDEN);
-    pending_credentials_.type = PasswordForm::TYPE_MANUAL;
+    pending_credentials_.type = PasswordForm::Type::kManual;
   }
 
   if (is_new_login_) {
@@ -280,7 +280,7 @@
   }
 
   if (pending_credentials_.times_used == 1 &&
-      pending_credentials_.type == PasswordForm::TYPE_GENERATED) {
+      pending_credentials_.type == PasswordForm::Type::kGenerated) {
     // This also includes PSL matched credentials.
     metrics_util::LogPasswordGenerationSubmissionEvent(
         metrics_util::PASSWORD_USED);
@@ -397,7 +397,7 @@
     } else {
       new_blacklisted_->origin = observed_form_.url;
       new_blacklisted_->signon_realm = GetSignonRealm(observed_form_.url);
-      new_blacklisted_->scheme = PasswordForm::SCHEME_HTML;
+      new_blacklisted_->scheme = PasswordForm::Scheme::kHtml;
     }
     blacklisted_matches_.push_back(new_blacklisted_.get());
   }
@@ -565,7 +565,7 @@
   std::vector<const PasswordForm*> matches;
   PasswordForm::Scheme observed_form_scheme =
       observed_http_auth_digest_ ? observed_http_auth_digest_->scheme
-                                 : PasswordForm::SCHEME_HTML;
+                                 : PasswordForm::Scheme::kHtml;
   for (const auto* match : form_fetcher_->GetNonFederatedMatches()) {
     if (match->scheme == observed_form_scheme)
       matches.push_back(match);
@@ -893,7 +893,7 @@
   // If we're dealing with an API-driven provisionally saved form, then take
   // the server provided values. We don't do this for non-API forms, as
   // those will never have those members set.
-  if (parsed_submitted_form_->type == PasswordForm::TYPE_API) {
+  if (parsed_submitted_form_->type == PasswordForm::Type::kApi) {
     pending_credentials_.skip_zero_click =
         parsed_submitted_form_->skip_zero_click;
     pending_credentials_.display_name = parsed_submitted_form_->display_name;
@@ -907,7 +907,7 @@
   }
 
   if (HasGeneratedPassword())
-    pending_credentials_.type = PasswordForm::TYPE_GENERATED;
+    pending_credentials_.type = PasswordForm::Type::kGenerated;
 }
 
 void NewPasswordFormManager::CreatePendingCredentialsForNewCredentials(
@@ -1074,7 +1074,7 @@
       form_fetcher_->GetNonFederatedMatches();
   PasswordForm::Scheme observed_form_scheme =
       observed_http_auth_digest_ ? observed_http_auth_digest_->scheme
-                                 : PasswordForm::SCHEME_HTML;
+                                 : PasswordForm::Scheme::kHtml;
   base::EraseIf(result, [observed_form_scheme](const auto* form) {
     return form->scheme != observed_form_scheme;
   });
diff --git a/components/password_manager/core/browser/new_password_form_manager_unittest.cc b/components/password_manager/core/browser/new_password_form_manager_unittest.cc
index 80baf81..196465d 100644
--- a/components/password_manager/core/browser/new_password_form_manager_unittest.cc
+++ b/components/password_manager/core/browser/new_password_form_manager_unittest.cc
@@ -309,7 +309,7 @@
     saved_match_.password_value = ASCIIToUTF16("test1");
     saved_match_.password_element = ASCIIToUTF16("field2");
     saved_match_.is_public_suffix_match = false;
-    saved_match_.scheme = PasswordForm::SCHEME_HTML;
+    saved_match_.scheme = PasswordForm::Scheme::kHtml;
 
     psl_saved_match_ = saved_match_;
     psl_saved_match_.origin = psl_origin;
@@ -1866,7 +1866,7 @@
     SCOPED_TRACE(testing::Message("html_credentials_saved=")
                  << html_credentials_saved);
     PasswordForm http_auth_form = parsed_observed_form_;
-    http_auth_form.scheme = PasswordForm::SCHEME_BASIC;
+    http_auth_form.scheme = PasswordForm::Scheme::kBasic;
 
     // Check that no filling because no http auth credentials are stored.
     EXPECT_CALL(driver_, FillPasswordForm(_)).Times(0);
@@ -1902,7 +1902,7 @@
 TEST_F(NewPasswordFormManagerTest, HTTPAuthAlreadySaved) {
   TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
   PasswordForm http_auth_form = parsed_observed_form_;
-  http_auth_form.scheme = PasswordForm::SCHEME_BASIC;
+  http_auth_form.scheme = PasswordForm::Scheme::kBasic;
 
   CreateFormManagerForHttpAuthForm(http_auth_form);
 
@@ -1923,7 +1923,7 @@
 TEST_F(NewPasswordFormManagerTest, HTTPAuthPasswordOverridden) {
   TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
   PasswordForm http_auth_form = parsed_observed_form_;
-  http_auth_form.scheme = PasswordForm::SCHEME_BASIC;
+  http_auth_form.scheme = PasswordForm::Scheme::kBasic;
 
   CreateFormManagerForHttpAuthForm(http_auth_form);
   MockFormSaver& form_saver = MockFormSaver::Get(form_manager_.get());
@@ -1962,7 +1962,7 @@
 TEST_F(NewPasswordFormManagerTest, BlacklistHttpAuthCredentials) {
   PasswordForm http_auth_form = parsed_observed_form_;
   http_auth_form.signon_realm += "my-auth-realm";
-  http_auth_form.scheme = PasswordForm::SCHEME_BASIC;
+  http_auth_form.scheme = PasswordForm::Scheme::kBasic;
 
   CreateFormManagerForHttpAuthForm(http_auth_form);
   MockFormSaver& form_saver = MockFormSaver::Get(form_manager_.get());
diff --git a/components/password_manager/core/browser/password_form_filling.cc b/components/password_manager/core/browser/password_form_filling.cc
index 68c2b5b..9262fd7 100644
--- a/components/password_manager/core/browser/password_form_filling.cc
+++ b/components/password_manager/core/browser/password_form_filling.cc
@@ -52,7 +52,7 @@
               const std::vector<const PasswordForm*>& federated_matches,
               const PasswordForm& preferred_match,
               bool wait_for_username) {
-  DCHECK_EQ(PasswordForm::SCHEME_HTML, preferred_match.scheme);
+  DCHECK_EQ(PasswordForm::Scheme::kHtml, preferred_match.scheme);
 
   std::unique_ptr<BrowserSavePasswordProgressLogger> logger;
   if (password_manager_util::IsLoggingActive(&client)) {
@@ -82,7 +82,7 @@
     const std::map<base::string16, const PasswordForm*>& best_matches,
     const PasswordForm& preferred_match,
     bool wait_for_username) {
-  DCHECK_EQ(PasswordForm::SCHEME_HTML, preferred_match.scheme);
+  DCHECK_EQ(PasswordForm::Scheme::kHtml, preferred_match.scheme);
 
   std::unique_ptr<BrowserSavePasswordProgressLogger> logger;
   if (password_manager_util::IsLoggingActive(&client)) {
@@ -110,7 +110,7 @@
     const PasswordForm* preferred_match,
     PasswordFormMetricsRecorder* metrics_recorder) {
   DCHECK(driver);
-  DCHECK_EQ(PasswordForm::SCHEME_HTML, observed_form.scheme);
+  DCHECK_EQ(PasswordForm::Scheme::kHtml, observed_form.scheme);
 
   const bool new_parsing_enabled =
       base::FeatureList::IsEnabled(features::kNewPasswordFormParsing);
diff --git a/components/password_manager/core/browser/password_form_manager.cc b/components/password_manager/core/browser/password_form_manager.cc
index eb3846a..cde9727 100644
--- a/components/password_manager/core/browser/password_form_manager.cc
+++ b/components/password_manager/core/browser/password_form_manager.cc
@@ -134,7 +134,7 @@
   // Non-HTML forms should not need any interaction with the renderer, and hence
   // no driver. Note that cloned PasswordFormManager instances can have HTML
   // forms without drivers as well.
-  DCHECK((observed_form.scheme == PasswordForm::SCHEME_HTML) ||
+  DCHECK((observed_form.scheme == PasswordForm::Scheme::kHtml) ||
          (driver == nullptr))
       << observed_form.scheme;
   if (driver)
@@ -176,8 +176,8 @@
     const PasswordForm& form,
     const password_manager::PasswordManagerDriver* driver) const {
   // Non-HTML form case.
-  if (observed_form_.scheme != PasswordForm::SCHEME_HTML ||
-      form.scheme != PasswordForm::SCHEME_HTML) {
+  if (observed_form_.scheme != PasswordForm::Scheme::kHtml ||
+      form.scheme != PasswordForm::Scheme::kHtml) {
     const bool forms_match = observed_form_.signon_realm == form.signon_realm &&
                              observed_form_.scheme == form.scheme;
     return forms_match ? RESULT_COMPLETE_MATCH : RESULT_NO_MATCH;
@@ -291,17 +291,17 @@
       submitted_form_->submission_event);
 
   if (password_overridden_ &&
-      pending_credentials_.type == PasswordForm::TYPE_GENERATED &&
+      pending_credentials_.type == PasswordForm::Type::kGenerated &&
       !HasGeneratedPassword()) {
     metrics_util::LogPasswordGenerationSubmissionEvent(
         metrics_util::PASSWORD_OVERRIDDEN);
-    pending_credentials_.type = PasswordForm::TYPE_MANUAL;
+    pending_credentials_.type = PasswordForm::Type::kManual;
   }
 
   if (is_new_login_) {
     UMA_HISTOGRAM_BOOLEAN(
         "PasswordManager.NewlySavedPasswordIsGenerated",
-        pending_credentials_.type == PasswordForm::TYPE_GENERATED);
+        pending_credentials_.type == PasswordForm::Type::kGenerated);
     password_form_manager_helpers::SanitizePossibleUsernames(
         &pending_credentials_);
     pending_credentials_.date_created = base::Time::Now();
@@ -314,7 +314,7 @@
   }
 
   if (pending_credentials_.times_used == 1 &&
-      pending_credentials_.type == PasswordForm::TYPE_GENERATED) {
+      pending_credentials_.type == PasswordForm::Type::kGenerated) {
     // This also includes PSL matched credentials.
     metrics_util::LogPasswordGenerationSubmissionEvent(
         metrics_util::PASSWORD_USED);
@@ -520,13 +520,13 @@
 
   for (auto const& driver : drivers_)
     ProcessFrameInternal(driver);
-  if (observed_form_.scheme != PasswordForm::SCHEME_HTML)
+  if (observed_form_.scheme != PasswordForm::Scheme::kHtml)
     ProcessLoginPrompt();
 }
 
 void PasswordFormManager::ProcessFrame(
     const base::WeakPtr<PasswordManagerDriver>& driver) {
-  DCHECK_EQ(PasswordForm::SCHEME_HTML, observed_form_.scheme);
+  DCHECK_EQ(PasswordForm::Scheme::kHtml, observed_form_.scheme);
 
   // Don't keep processing the same form.
   if (autofills_left_ <= 0)
@@ -560,7 +560,7 @@
 }
 
 void PasswordFormManager::ProcessLoginPrompt() {
-  DCHECK_NE(PasswordForm::SCHEME_HTML, observed_form_.scheme);
+  DCHECK_NE(PasswordForm::Scheme::kHtml, observed_form_.scheme);
   if (!preferred_match_) {
     DCHECK(best_matches_.empty());
     metrics_recorder_->RecordFillEvent(
@@ -671,7 +671,7 @@
       is_new_login_ = false;
     }
   } else if (!best_matches_.empty() &&
-             submitted_form_->type != autofill::PasswordForm::TYPE_API &&
+             submitted_form_->type != autofill::PasswordForm::Type::kApi &&
              submitted_form_->username_value.empty()) {
     // This branch deals with the case that the submitted form has no username
     // element and needs to decide whether to offer to update any credentials.
@@ -739,7 +739,7 @@
   // If we're dealing with an API-driven provisionally saved form, then take
   // the server provided values. We don't do this for non-API forms, as
   // those will never have those members set.
-  if (submitted_form_->type == autofill::PasswordForm::TYPE_API) {
+  if (submitted_form_->type == autofill::PasswordForm::Type::kApi) {
     pending_credentials_.skip_zero_click = submitted_form_->skip_zero_click;
     pending_credentials_.display_name = submitted_form_->display_name;
     pending_credentials_.federation_origin = submitted_form_->federation_origin;
@@ -751,7 +751,7 @@
   }
 
   if (HasGeneratedPassword())
-    pending_credentials_.type = PasswordForm::TYPE_GENERATED;
+    pending_credentials_.type = PasswordForm::Type::kGenerated;
 }
 
 const PasswordForm* PasswordFormManager::FindBestMatchForUpdatePassword(
@@ -788,7 +788,7 @@
 
   // Match Credential API forms only by username. Stop here if nothing was found
   // above.
-  if (submitted_form->type == autofill::PasswordForm::TYPE_API)
+  if (submitted_form->type == autofill::PasswordForm::Type::kApi)
     return nullptr;
 
   // Verify that the submitted form has no username and no "new password"
diff --git a/components/password_manager/core/browser/password_form_manager_unittest.cc b/components/password_manager/core/browser/password_form_manager_unittest.cc
index ee56fc750..e412d60 100644
--- a/components/password_manager/core/browser/password_form_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_form_manager_unittest.cc
@@ -1813,9 +1813,9 @@
 }
 
 TEST_F(PasswordFormManagerTest, NonHTMLFormsDoNotMatchHTMLForms) {
-  ASSERT_EQ(PasswordForm::SCHEME_HTML, observed_form()->scheme);
+  ASSERT_EQ(PasswordForm::Scheme::kHtml, observed_form()->scheme);
   PasswordForm non_html_form(*observed_form());
-  non_html_form.scheme = PasswordForm::SCHEME_DIGEST;
+  non_html_form.scheme = PasswordForm::Scheme::kDigest;
   EXPECT_EQ(PasswordFormManager::RESULT_NO_MATCH,
             form_manager()->DoesManage(non_html_form, nullptr));
 
@@ -2037,26 +2037,31 @@
   // Form data is different than saved form data, account creation signal should
   // be sent.
   autofill::ServerFieldType field_type = autofill::ACCOUNT_CREATION_PASSWORD;
-  AccountCreationUploadTest(observed_form_data, 0, PasswordForm::NO_SIGNAL_SENT,
+  AccountCreationUploadTest(observed_form_data, 0,
+                            PasswordForm::GenerationUploadStatus::kNoSignalSent,
                             &field_type);
 
   // Non-zero times used will not upload since we only upload a positive signal
   // at most once.
-  AccountCreationUploadTest(observed_form_data, 1, PasswordForm::NO_SIGNAL_SENT,
+  AccountCreationUploadTest(observed_form_data, 1,
+                            PasswordForm::GenerationUploadStatus::kNoSignalSent,
                             nullptr);
 
   // Same form data as saved match and POSITIVE_SIGNAL_SENT means there should
   // be a negative autofill ping sent.
   field_type = autofill::NOT_ACCOUNT_CREATION_PASSWORD;
-  AccountCreationUploadTest(saved_match()->form_data, 2,
-                            PasswordForm::POSITIVE_SIGNAL_SENT, &field_type);
+  AccountCreationUploadTest(
+      saved_match()->form_data, 2,
+      PasswordForm::GenerationUploadStatus::kPositiveSignalSent, &field_type);
 
   // For any other GenerationUploadStatus, no autofill upload should occur
   // if the observed form data matches the saved form data.
   AccountCreationUploadTest(saved_match()->form_data, 3,
-                            PasswordForm::NO_SIGNAL_SENT, nullptr);
-  AccountCreationUploadTest(saved_match()->form_data, 3,
-                            PasswordForm::NEGATIVE_SIGNAL_SENT, nullptr);
+                            PasswordForm::GenerationUploadStatus::kNoSignalSent,
+                            nullptr);
+  AccountCreationUploadTest(
+      saved_match()->form_data, 3,
+      PasswordForm::GenerationUploadStatus::kNegativeSignalSent, nullptr);
 }
 
 TEST_F(PasswordFormManagerTest, CorrectlySavePasswordWithoutUsernameFields) {
@@ -2121,7 +2126,7 @@
   form.preferred = false;
 
   PasswordForm generated_form = form;
-  generated_form.type = PasswordForm::TYPE_GENERATED;
+  generated_form.type = PasswordForm::Type::kGenerated;
   generated_form.password_value = ASCIIToUTF16("password2");
   generated_form.preferred = true;
 
@@ -2696,7 +2701,7 @@
 
 TEST_F(PasswordFormManagerTest, GenerationStatusChangedWithPassword) {
   PasswordForm generated_form = *observed_form();
-  generated_form.type = PasswordForm::TYPE_GENERATED;
+  generated_form.type = PasswordForm::Type::kGenerated;
   generated_form.username_value = ASCIIToUTF16("username");
   generated_form.password_value = ASCIIToUTF16("password2");
   generated_form.preferred = true;
@@ -2713,14 +2718,14 @@
       .WillOnce(testing::SaveArg<0>(&new_credentials));
   form_manager()->Save();
 
-  EXPECT_EQ(PasswordForm::TYPE_MANUAL, new_credentials.type);
+  EXPECT_EQ(PasswordForm::Type::kManual, new_credentials.type);
 }
 
 TEST_F(PasswordFormManagerTest, GenerationStatusNotUpdatedIfPasswordUnchanged) {
   base::HistogramTester histogram_tester;
 
   PasswordForm generated_form = *observed_form();
-  generated_form.type = PasswordForm::TYPE_GENERATED;
+  generated_form.type = PasswordForm::Type::kGenerated;
   generated_form.username_value = ASCIIToUTF16("username");
   generated_form.password_value = ASCIIToUTF16("password2");
   generated_form.preferred = true;
@@ -2736,7 +2741,7 @@
       .WillOnce(testing::SaveArg<0>(&new_credentials));
   form_manager()->Save();
 
-  EXPECT_EQ(PasswordForm::TYPE_GENERATED, new_credentials.type);
+  EXPECT_EQ(PasswordForm::Type::kGenerated, new_credentials.type);
   histogram_tester.ExpectBucketCount("PasswordGeneration.SubmissionEvent",
                                      metrics_util::PASSWORD_USED, 1);
 
@@ -2754,7 +2759,7 @@
   base::HistogramTester histogram_tester;
 
   PasswordForm generated_form = *observed_form();
-  generated_form.type = PasswordForm::TYPE_GENERATED;
+  generated_form.type = PasswordForm::Type::kGenerated;
   generated_form.username_value = ASCIIToUTF16("username");
   generated_form.password_value = ASCIIToUTF16("password2");
   generated_form.preferred = true;
@@ -2771,7 +2776,7 @@
       .WillOnce(testing::SaveArg<0>(&new_credentials));
   form_manager()->Save();
 
-  EXPECT_EQ(PasswordForm::TYPE_MANUAL, new_credentials.type);
+  EXPECT_EQ(PasswordForm::Type::kManual, new_credentials.type);
   EXPECT_EQ(ASCIIToUTF16("another_password"), new_credentials.password_value);
   histogram_tester.ExpectBucketCount("PasswordGeneration.SubmissionEvent",
                                      metrics_util::PASSWORD_OVERRIDDEN, 1);
@@ -3339,9 +3344,9 @@
 TEST_F(PasswordFormManagerTest, TestSavingAPIFormsWithSamePassword) {
   // Turn |observed_form| and |saved_match| to API created forms.
   observed_form()->username_element.clear();
-  observed_form()->type = autofill::PasswordForm::TYPE_API;
+  observed_form()->type = autofill::PasswordForm::Type::kApi;
   saved_match()->username_element.clear();
-  saved_match()->type = autofill::PasswordForm::TYPE_API;
+  saved_match()->type = autofill::PasswordForm::Type::kApi;
 
   FakeFormFetcher fetcher;
   fetcher.Fetch();
@@ -3373,7 +3378,7 @@
             new_credentials.username_value);
   EXPECT_EQ(saved_match()->password_value, new_credentials.password_value);
   EXPECT_EQ(base::string16(), new_credentials.username_element);
-  EXPECT_EQ(autofill::PasswordForm::TYPE_API, new_credentials.type);
+  EXPECT_EQ(autofill::PasswordForm::Type::kApi, new_credentials.type);
 }
 
 TEST_F(PasswordFormManagerTest, SkipZeroClickIntact) {
@@ -3440,8 +3445,9 @@
 // For all combinations of PasswordForm schemes, test that OnFetchCompleted
 // filters out forms with schemes not matching the observed form.
 TEST_F(PasswordFormManagerTest, RemoveResultsWithWrongScheme_ObservingHTML) {
-  for (int correct = 0; correct <= PasswordForm::SCHEME_LAST; ++correct) {
-    for (int wrong = 0; wrong <= PasswordForm::SCHEME_LAST; ++wrong) {
+  constexpr int kMaxValue = static_cast<int>(PasswordForm::Scheme::kMaxValue);
+  for (int correct = 0; correct <= kMaxValue; ++correct) {
+    for (int wrong = 0; wrong <= kMaxValue; ++wrong) {
       if (correct == wrong)
         continue;
 
@@ -3458,8 +3464,8 @@
       fetcher.Fetch();
       PasswordFormManager form_manager(
           password_manager(), client(),
-          (kCorrectScheme == PasswordForm::SCHEME_HTML ? client()->driver()
-                                                       : nullptr),
+          (kCorrectScheme == PasswordForm::Scheme::kHtml ? client()->driver()
+                                                         : nullptr),
           observed, std::make_unique<NiceMock<MockFormSaver>>(), &fetcher);
       form_manager.Init(nullptr);
 
@@ -3880,7 +3886,7 @@
 // into forms and HTTP Basic auth.
 TEST_F(PasswordFormManagerTest, TestUkmForFilling) {
   PasswordForm scheme_basic_form = *observed_form();
-  scheme_basic_form.scheme = PasswordForm::SCHEME_BASIC;
+  scheme_basic_form.scheme = PasswordForm::Scheme::kBasic;
 
   const struct {
     // Whether the login is doing HTTP Basic Auth instead of form based login.
diff --git a/components/password_manager/core/browser/password_generation_state_unittest.cc b/components/password_manager/core/browser/password_generation_state_unittest.cc
index 42e69e32..98d7eda7 100644
--- a/components/password_manager/core/browser/password_generation_state_unittest.cc
+++ b/components/password_manager/core/browser/password_generation_state_unittest.cc
@@ -57,7 +57,7 @@
   form.username_value = ASCIIToUTF16("MyName");
   form.password_value = ASCIIToUTF16("Strong password");
   form.preferred = true;
-  form.type = autofill::PasswordForm::TYPE_GENERATED;
+  form.type = autofill::PasswordForm::Type::kGenerated;
   return form;
 }
 
diff --git a/components/password_manager/core/browser/password_manager.cc b/components/password_manager/core/browser/password_manager.cc
index 827c47e..dbc9344 100644
--- a/components/password_manager/core/browser/password_manager.cc
+++ b/components/password_manager/core/browser/password_manager.cc
@@ -1098,7 +1098,7 @@
 
   // If we see the login form again, then the login failed.
   if (submitted_manager->GetPendingCredentials().scheme ==
-      PasswordForm::SCHEME_HTML) {
+      PasswordForm::Scheme::kHtml) {
     for (const PasswordForm& form : all_visible_forms_) {
       if (IsPasswordFormReappeared(
               form, submitted_manager->GetPendingCredentials())) {
diff --git a/components/password_manager/core/browser/password_manager_util.cc b/components/password_manager/core/browser/password_manager_util.cc
index 6ffae88d..6ca5bc1 100644
--- a/components/password_manager/core/browser/password_manager_util.cc
+++ b/components/password_manager/core/browser/password_manager_util.cc
@@ -113,14 +113,14 @@
   // Remove username-only credentials which are not federated.
   base::EraseIf(*android_credentials,
                 [](const std::unique_ptr<PasswordForm>& form) {
-                  return form->scheme == PasswordForm::SCHEME_USERNAME_ONLY &&
+                  return form->scheme == PasswordForm::Scheme::kUsernameOnly &&
                          form->federation_origin.opaque();
                 });
 
   // Set "skip_zero_click" on federated credentials.
   std::for_each(android_credentials->begin(), android_credentials->end(),
                 [](const std::unique_ptr<PasswordForm>& form) {
-                  if (form->scheme == PasswordForm::SCHEME_USERNAME_ONLY)
+                  if (form->scheme == PasswordForm::Scheme::kUsernameOnly)
                     form->skip_zero_click = true;
                 });
 }
@@ -291,7 +291,7 @@
 
   // Next attempt is to find a match by password value. It should not be tried
   // when the username was actually detected.
-  if (submitted_form.type == PasswordForm::TYPE_API ||
+  if (submitted_form.type == PasswordForm::Type::kApi ||
       !submitted_form.username_value.empty())
     return nullptr;
 
diff --git a/components/password_manager/core/browser/password_manager_util_unittest.cc b/components/password_manager/core/browser/password_manager_util_unittest.cc
index f67f80f1..ecb6a44 100644
--- a/components/password_manager/core/browser/password_manager_util_unittest.cc
+++ b/components/password_manager/core/browser/password_manager_util_unittest.cc
@@ -39,7 +39,7 @@
 
 autofill::PasswordForm GetTestAndroidCredential() {
   autofill::PasswordForm form;
-  form.scheme = autofill::PasswordForm::SCHEME_HTML;
+  form.scheme = autofill::PasswordForm::Scheme::kHtml;
   form.origin = GURL(kTestAndroidRealm);
   form.signon_realm = kTestAndroidRealm;
   form.username_value = base::ASCIIToUTF16(kTestUsername);
@@ -49,7 +49,7 @@
 
 autofill::PasswordForm GetTestCredential() {
   autofill::PasswordForm form;
-  form.scheme = autofill::PasswordForm::SCHEME_HTML;
+  form.scheme = autofill::PasswordForm::Scheme::kHtml;
   form.origin = GURL(kTestURL);
   form.signon_realm = form.origin.GetOrigin().spec();
   form.username_value = base::ASCIIToUTF16(kTestUsername);
@@ -59,7 +59,7 @@
 
 autofill::PasswordForm GetTestProxyCredential() {
   autofill::PasswordForm form;
-  form.scheme = autofill::PasswordForm::SCHEME_BASIC;
+  form.scheme = autofill::PasswordForm::Scheme::kBasic;
   form.origin = GURL(kTestProxyOrigin);
   form.signon_realm = kTestProxySignonRealm;
   form.username_value = base::ASCIIToUTF16(kTestUsername);
@@ -93,7 +93,7 @@
       std::make_unique<autofill::PasswordForm>(GetTestAndroidCredential()));
 
   autofill::PasswordForm username_only;
-  username_only.scheme = autofill::PasswordForm::SCHEME_USERNAME_ONLY;
+  username_only.scheme = autofill::PasswordForm::Scheme::kUsernameOnly;
   username_only.signon_realm = kTestAndroidRealm;
   username_only.username_value = base::ASCIIToUTF16(kTestUsername2);
   forms.push_back(std::make_unique<autofill::PasswordForm>(username_only));
@@ -338,7 +338,7 @@
   autofill::PasswordForm stored = GetTestCredential();
   autofill::PasswordForm parsed = GetTestCredential();
   parsed.username_value.clear();
-  parsed.type = PasswordForm::TYPE_API;
+  parsed.type = PasswordForm::Type::kApi;
 
   // In case of the Credential Management API we know for sure that the site
   // meant empty username. Don't try any other heuristics.
@@ -370,7 +370,7 @@
   autofill::PasswordForm blacklisted_credential = MakeNormalizedBlacklistedForm(
       password_manager::PasswordStore::FormDigest(GetTestAndroidCredential()));
   EXPECT_TRUE(blacklisted_credential.blacklisted_by_user);
-  EXPECT_EQ(PasswordForm::SCHEME_HTML, blacklisted_credential.scheme);
+  EXPECT_EQ(PasswordForm::Scheme::kHtml, blacklisted_credential.scheme);
   EXPECT_EQ(kTestAndroidRealm, blacklisted_credential.signon_realm);
   EXPECT_EQ(GURL(kTestAndroidRealm), blacklisted_credential.origin);
 }
@@ -379,7 +379,7 @@
   autofill::PasswordForm blacklisted_credential = MakeNormalizedBlacklistedForm(
       password_manager::PasswordStore::FormDigest(GetTestCredential()));
   EXPECT_TRUE(blacklisted_credential.blacklisted_by_user);
-  EXPECT_EQ(PasswordForm::SCHEME_HTML, blacklisted_credential.scheme);
+  EXPECT_EQ(PasswordForm::Scheme::kHtml, blacklisted_credential.scheme);
   EXPECT_EQ(GURL(kTestURL).GetOrigin().spec(),
             blacklisted_credential.signon_realm);
   EXPECT_EQ(GURL(kTestURL).GetOrigin(), blacklisted_credential.origin);
@@ -389,7 +389,7 @@
   autofill::PasswordForm blacklisted_credential = MakeNormalizedBlacklistedForm(
       password_manager::PasswordStore::FormDigest(GetTestProxyCredential()));
   EXPECT_TRUE(blacklisted_credential.blacklisted_by_user);
-  EXPECT_EQ(PasswordForm::SCHEME_BASIC, blacklisted_credential.scheme);
+  EXPECT_EQ(PasswordForm::Scheme::kBasic, blacklisted_credential.scheme);
   EXPECT_EQ(kTestProxySignonRealm, blacklisted_credential.signon_realm);
   EXPECT_EQ(GURL(kTestProxyOrigin), blacklisted_credential.origin);
 }
diff --git a/components/password_manager/core/browser/password_store.cc b/components/password_manager/core/browser/password_store.cc
index ab51371..42fa7d6b 100644
--- a/components/password_manager/core/browser/password_store.cc
+++ b/components/password_manager/core/browser/password_store.cc
@@ -98,7 +98,7 @@
       origin(form.origin) {}
 
 PasswordStore::FormDigest::FormDigest(const autofill::FormData& form)
-    : scheme(PasswordForm::SCHEME_HTML),
+    : scheme(PasswordForm::Scheme::kHtml),
       signon_realm(form.url.GetOrigin().spec()),
       origin(form.url) {}
 
@@ -228,7 +228,7 @@
   // security feature to help minimize damage that can be done by XSS attacks.
   // TODO(mdm): actually delete them at some point, say M24 or so.
   base::Time cutoff;  // the null time
-  if (form.scheme == PasswordForm::SCHEME_HTML &&
+  if (form.scheme == PasswordForm::Scheme::kHtml &&
       (form.signon_realm == "http://www.google.com" ||
        form.signon_realm == "http://www.google.com/" ||
        form.signon_realm == "https://www.google.com" ||
@@ -862,7 +862,7 @@
   std::vector<std::unique_ptr<PasswordForm>> results(FillMatchingLogins(form));
   for (const std::string& realm : additional_android_realms) {
     std::vector<std::unique_ptr<PasswordForm>> more_results(
-        FillMatchingLogins({PasswordForm::SCHEME_HTML, realm, GURL()}));
+        FillMatchingLogins({PasswordForm::Scheme::kHtml, realm, GURL()}));
     for (auto& result : more_results)
       result->is_affiliation_based_match = true;
     password_manager_util::TrimUsernameOnlyCredentials(&more_results);
@@ -939,7 +939,7 @@
   PasswordStoreChangeList all_changes;
   for (const std::string& affiliated_web_realm : affiliated_web_realms) {
     std::vector<std::unique_ptr<PasswordForm>> web_logins(FillMatchingLogins(
-        {PasswordForm::SCHEME_HTML, affiliated_web_realm, GURL()}));
+        {PasswordForm::Scheme::kHtml, affiliated_web_realm, GURL()}));
     for (auto& web_login : web_logins) {
       // Do not update HTTP logins, logins saved under insecure conditions, and
       // non-HTML login forms; PSL matches; logins with a different username;
diff --git a/components/password_manager/core/browser/password_store_default_unittest.cc b/components/password_manager/core/browser/password_store_default_unittest.cc
index 6d94b7a..d1347db 100644
--- a/components/password_manager/core/browser/password_store_default_unittest.cc
+++ b/components/password_manager/core/browser/password_store_default_unittest.cc
@@ -62,7 +62,7 @@
 };
 
 PasswordFormData CreateTestPasswordFormData() {
-  PasswordFormData data = {PasswordForm::SCHEME_HTML,
+  PasswordFormData data = {PasswordForm::Scheme::kHtml,
                            "http://bar.example.com",
                            "http://bar.example.com/origin",
                            "http://bar.example.com/action",
@@ -168,7 +168,7 @@
 
   // Some non-ASCII password form data.
   static const PasswordFormData form_data[] = {
-      {PasswordForm::SCHEME_HTML, "http://foo.example.com",
+      {PasswordForm::Scheme::kHtml, "http://foo.example.com",
        "http://foo.example.com/origin", "http://foo.example.com/action",
        L"มีสีสัน", L"お元気ですか?", L"盆栽", L"أحب كرة", L"£éä국수çà", true, 1},
   };
diff --git a/components/password_manager/core/browser/password_store_origin_unittest.h b/components/password_manager/core/browser/password_store_origin_unittest.h
index 80ea3ae..3c8c2fd1 100644
--- a/components/password_manager/core/browser/password_store_origin_unittest.h
+++ b/components/password_manager/core/browser/password_store_origin_unittest.h
@@ -30,7 +30,7 @@
 namespace password_manager {
 
 PasswordFormData CreateTestPasswordFormDataByOrigin(const char* origin_url) {
-  PasswordFormData data = {PasswordForm::SCHEME_HTML,
+  PasswordFormData data = {PasswordForm::Scheme::kHtml,
                            origin_url,
                            origin_url,
                            "login_element",
diff --git a/components/password_manager/core/browser/password_store_unittest.cc b/components/password_manager/core/browser/password_store_unittest.cc
index 62efd98..41cc43c 100644
--- a/components/password_manager/core/browser/password_store_unittest.cc
+++ b/components/password_manager/core/browser/password_store_unittest.cc
@@ -154,29 +154,29 @@
   static const PasswordFormData form_data[] = {
       // A form on https://www.google.com/ older than the cutoff. Will be
       // ignored.
-      {PasswordForm::SCHEME_HTML, "https://www.google.com",
+      {PasswordForm::Scheme::kHtml, "https://www.google.com",
        "https://www.google.com/origin", "https://www.google.com/action",
        L"submit_element", L"username_element", L"password_element",
        L"username_value_1", L"", true, cutoff - 1},
       // A form on https://www.google.com/ older than the cutoff. Will be
       // ignored.
-      {PasswordForm::SCHEME_HTML, "https://www.google.com",
+      {PasswordForm::Scheme::kHtml, "https://www.google.com",
        "https://www.google.com/origin", "https://www.google.com/action",
        L"submit_element", L"username_element", L"password_element",
        L"username_value_2", L"", true, cutoff - 1},
       // A form on https://www.google.com/ newer than the cutoff.
-      {PasswordForm::SCHEME_HTML, "https://www.google.com",
+      {PasswordForm::Scheme::kHtml, "https://www.google.com",
        "https://www.google.com/origin", "https://www.google.com/action",
        L"submit_element", L"username_element", L"password_element",
        L"username_value_3", L"", true, cutoff + 1},
       // A form on https://accounts.google.com/ older than the cutoff.
-      {PasswordForm::SCHEME_HTML, "https://accounts.google.com",
+      {PasswordForm::Scheme::kHtml, "https://accounts.google.com",
        "https://accounts.google.com/origin",
        "https://accounts.google.com/action", L"submit_element",
        L"username_element", L"password_element", L"username_value", L"", true,
        cutoff - 1},
       // A form on http://bar.example.com/ older than the cutoff.
-      {PasswordForm::SCHEME_HTML, "http://bar.example.com",
+      {PasswordForm::Scheme::kHtml, "http://bar.example.com",
        "http://bar.example.com/origin", "http://bar.example.com/action",
        L"submit_element", L"username_element", L"password_element",
        L"username_value", L"", true, cutoff - 1},
@@ -194,21 +194,21 @@
   // any login forms on www.google.com to save, but we technically allow them.
   // We should not get back the older saved password though.
   const PasswordStore::FormDigest www_google = {
-      PasswordForm::SCHEME_HTML, "https://www.google.com", GURL()};
+      PasswordForm::Scheme::kHtml, "https://www.google.com", GURL()};
   std::vector<std::unique_ptr<PasswordForm>> www_google_expected;
   www_google_expected.push_back(std::make_unique<PasswordForm>(*all_forms[2]));
 
   // We should still get the accounts.google.com login even though it's older
   // than our cutoff - this is the new location of all Google login forms.
   const PasswordStore::FormDigest accounts_google = {
-      PasswordForm::SCHEME_HTML, "https://accounts.google.com", GURL()};
+      PasswordForm::Scheme::kHtml, "https://accounts.google.com", GURL()};
   std::vector<std::unique_ptr<PasswordForm>> accounts_google_expected;
   accounts_google_expected.push_back(
       std::make_unique<PasswordForm>(*all_forms[3]));
 
   // Same thing for a generic saved login.
   const PasswordStore::FormDigest bar_example = {
-      PasswordForm::SCHEME_HTML, "http://bar.example.com", GURL()};
+      PasswordForm::Scheme::kHtml, "http://bar.example.com", GURL()};
   std::vector<std::unique_ptr<PasswordForm>> bar_example_expected;
   bar_example_expected.push_back(std::make_unique<PasswordForm>(*all_forms[4]));
 
@@ -258,14 +258,14 @@
   /* clang-format off */
   static const PasswordFormData kTestCredentials[] = {
       // The old credential.
-      {PasswordForm::SCHEME_HTML,
+      {PasswordForm::Scheme::kHtml,
        kTestWebRealm1,
        kTestWebOrigin1,
        "", L"", L"username_element_1",  L"password_element_1",
        L"username_value_1",
        L"", true, 1},
       // The new credential with different values for all primary key fields.
-      {PasswordForm::SCHEME_HTML,
+      {PasswordForm::Scheme::kHtml,
        kTestWebRealm2,
        kTestWebOrigin2,
        "", L"", L"username_element_2",  L"password_element_2",
@@ -317,7 +317,7 @@
 TEST_F(PasswordStoreTest, RemoveLoginsCreatedBetweenCallbackIsCalled) {
   /* clang-format off */
   static const PasswordFormData kTestCredential =
-      {PasswordForm::SCHEME_HTML,
+      {PasswordForm::Scheme::kHtml,
        kTestWebRealm1,
        kTestWebOrigin1,
        "", L"", L"username_element_1",  L"password_element_1",
@@ -356,21 +356,21 @@
   /* clang-format off */
   static const PasswordFormData kTestCredentials[] = {
       // Credential that is an exact match of the observed form.
-      {PasswordForm::SCHEME_HTML,
+      {PasswordForm::Scheme::kHtml,
        kTestWebRealm1,
        kTestWebOrigin1,
        "", L"", L"",  L"",
        L"username_value_1",
        L"", true, 1},
       // Credential that is a PSL match of the observed form.
-      {PasswordForm::SCHEME_HTML,
+      {PasswordForm::Scheme::kHtml,
        kTestPSLMatchingWebRealm,
        kTestPSLMatchingWebOrigin,
        "", L"", L"",  L"",
        L"username_value_2",
        L"", true, 1},
       // Credential for an unrelated Android application.
-      {PasswordForm::SCHEME_HTML,
+      {PasswordForm::Scheme::kHtml,
        kTestUnrelatedAndroidRealm,
        "", "", L"", L"", L"",
        L"username_value_3",
@@ -388,7 +388,7 @@
   }
 
   PasswordStore::FormDigest observed_form = {
-      PasswordForm::SCHEME_HTML, kTestWebRealm1, GURL(kTestWebOrigin1)};
+      PasswordForm::Scheme::kHtml, kTestWebRealm1, GURL(kTestWebOrigin1)};
 
   std::vector<std::unique_ptr<PasswordForm>> expected_results;
   expected_results.push_back(
@@ -427,13 +427,13 @@
   } kTestCredentials[] = {
       // Credential that is an exact match of the observed form.
       {
-          {PasswordForm::SCHEME_HTML, kTestWebRealm1, kTestWebOrigin1, "", L"",
-           L"", L"", L"username_value_1", L"", true, 1},
+          {PasswordForm::Scheme::kHtml, kTestWebRealm1, kTestWebOrigin1, "",
+           L"", L"", L"", L"username_value_1", L"", true, 1},
           false,
       },
       // Credential that is a PSL match of the observed form.
       {
-          {PasswordForm::SCHEME_HTML, kTestPSLMatchingWebRealm,
+          {PasswordForm::Scheme::kHtml, kTestPSLMatchingWebRealm,
            kTestPSLMatchingWebOrigin, "", L"", L"", L"", L"username_value_2",
            L"", true, 1},
           false,
@@ -441,38 +441,38 @@
       // Credential for an Android application affiliated with the realm of the
       // observed from.
       {
-          {PasswordForm::SCHEME_HTML, kTestAndroidRealm1, "", "", L"", L"", L"",
-           L"username_value_3", L"", true, 1},
+          {PasswordForm::Scheme::kHtml, kTestAndroidRealm1, "", "", L"", L"",
+           L"", L"username_value_3", L"", true, 1},
           false,
       },
       // Second credential for the same Android application.
       {
-          {PasswordForm::SCHEME_HTML, kTestAndroidRealm1, "", "", L"", L"", L"",
-           L"username_value_3b", L"", true, 1},
+          {PasswordForm::Scheme::kHtml, kTestAndroidRealm1, "", "", L"", L"",
+           L"", L"username_value_3b", L"", true, 1},
           false,
       },
       // Third credential for the same application which is username-only.
       {
-          {PasswordForm::SCHEME_USERNAME_ONLY, kTestAndroidRealm1, "", "", L"",
+          {PasswordForm::Scheme::kUsernameOnly, kTestAndroidRealm1, "", "", L"",
            L"", L"", L"username_value_3c", L"", true, 1},
           false,
       },
       // Credential for another Android application affiliated with the realm
       // of the observed from.
       {
-          {PasswordForm::SCHEME_HTML, kTestAndroidRealm2, "", "", L"", L"", L"",
-           L"username_value_4", L"", true, 1},
+          {PasswordForm::Scheme::kHtml, kTestAndroidRealm2, "", "", L"", L"",
+           L"", L"username_value_4", L"", true, 1},
           false,
       },
       // Federated credential for this second Android application.
       {
-          {PasswordForm::SCHEME_HTML, kTestAndroidRealm2, "", "", L"", L"", L"",
-           L"username_value_4b", L"", true, 1},
+          {PasswordForm::Scheme::kHtml, kTestAndroidRealm2, "", "", L"", L"",
+           L"", L"username_value_4b", L"", true, 1},
           true,
       },
       // Credential for an unrelated Android application.
       {
-          {PasswordForm::SCHEME_HTML, kTestUnrelatedAndroidRealm, "", "", L"",
+          {PasswordForm::Scheme::kHtml, kTestUnrelatedAndroidRealm, "", "", L"",
            L"", L"", L"username_value_5", L"", true, 1},
           false,
       }};
@@ -489,7 +489,7 @@
   }
 
   PasswordStore::FormDigest observed_form = {
-      PasswordForm::SCHEME_HTML, kTestWebRealm1, GURL(kTestWebOrigin1)};
+      PasswordForm::Scheme::kHtml, kTestWebRealm1, GURL(kTestWebOrigin1)};
 
   std::vector<std::unique_ptr<PasswordForm>> expected_results;
   expected_results.push_back(
@@ -548,7 +548,7 @@
       // The credential for the Android application that will be updated
       // explicitly so it can be tested if the changes are correctly propagated
       // to affiliated Web credentials.
-      {PasswordForm::SCHEME_HTML,
+      {PasswordForm::Scheme::kHtml,
        kTestAndroidRealm1,
        "", "", L"", L"", L"",
        kTestUsername,
@@ -558,7 +558,7 @@
       // automatically propagated to.
 
       // Credential for an affiliated web site with the same username.
-      {PasswordForm::SCHEME_HTML,
+      {PasswordForm::Scheme::kHtml,
        kTestWebRealm1,
        kTestWebOrigin1,
        "", L"", L"",  L"",
@@ -567,7 +567,7 @@
       // Credential for another affiliated web site with the same username.
       // Although the password is different than the current/old password for
       // the Android application, it should be updated regardless.
-      {PasswordForm::SCHEME_HTML,
+      {PasswordForm::Scheme::kHtml,
        kTestWebRealm2,
        kTestWebOrigin2,
        "", L"", L"",  L"",
@@ -579,21 +579,21 @@
 
       // Credential for another affiliated web site, but one that already has
       // the new password.
-      {PasswordForm::SCHEME_HTML,
+      {PasswordForm::Scheme::kHtml,
        kTestWebRealm3,
        kTestWebOrigin3,
        "", L"", L"",  L"",
        kTestUsername,
        kTestNewPassword, true, 1},
       // Credential for the HTTP version of an affiliated web site.
-      {PasswordForm::SCHEME_HTML,
+      {PasswordForm::Scheme::kHtml,
        kTestInsecureWebRealm,
        kTestInsecureWebOrigin,
        "", L"", L"",  L"",
        kTestUsername,
        kTestOldPassword, true, 1},
       // Credential for an affiliated web site, but with a different username.
-      {PasswordForm::SCHEME_HTML,
+      {PasswordForm::Scheme::kHtml,
        kTestWebRealm1,
        kTestWebOrigin1,
        "", L"", L"",  L"",
@@ -601,34 +601,34 @@
        kTestOldPassword, true, 1},
       // Credential for a web site that is a PSL match to a web sites affiliated
       // with the Android application.
-      {PasswordForm::SCHEME_HTML,
+      {PasswordForm::Scheme::kHtml,
        kTestPSLMatchingWebRealm,
        kTestPSLMatchingWebOrigin,
        "poisoned", L"poisoned", L"",  L"",
        kTestUsername,
        kTestOldPassword, true, 1},
       // Credential for an unrelated web site.
-      {PasswordForm::SCHEME_HTML,
+      {PasswordForm::Scheme::kHtml,
        kTestUnrelatedWebRealm,
        kTestUnrelatedWebOrigin,
        "", L"", L"",  L"",
        kTestUsername,
        kTestOldPassword, true, 1},
       // Credential for an affiliated Android application.
-      {PasswordForm::SCHEME_HTML,
+      {PasswordForm::Scheme::kHtml,
        kTestAndroidRealm2,
        "", "", L"", L"", L"",
        kTestUsername,
        kTestOldPassword, true, 1},
       // Credential for an unrelated Android application.
-      {PasswordForm::SCHEME_HTML,
+      {PasswordForm::Scheme::kHtml,
        kTestUnrelatedAndroidRealm,
        "", "", L"", L"", L"",
        kTestUsername,
        kTestOldPassword, true, 1},
       // Credential for an affiliated web site with the same username, but one
       // that was updated at the same time via Sync as the Android credential.
-      {PasswordForm::SCHEME_HTML,
+      {PasswordForm::Scheme::kHtml,
        kTestWebRealm5,
        kTestWebOrigin5,
        "", L"", L"",  L"",
@@ -727,20 +727,20 @@
 
 TEST_F(PasswordStoreTest, GetAllLogins) {
   static constexpr PasswordFormData kTestCredentials[] = {
-      {PasswordForm::SCHEME_HTML, kTestAndroidRealm1, "", "", L"", L"", L"",
+      {PasswordForm::Scheme::kHtml, kTestAndroidRealm1, "", "", L"", L"", L"",
        L"username_value_1", L"", true, 1},
-      {PasswordForm::SCHEME_HTML, kTestAndroidRealm2, "", "", L"", L"", L"",
+      {PasswordForm::Scheme::kHtml, kTestAndroidRealm2, "", "", L"", L"", L"",
        L"username_value_2", L"", true, 1},
-      {PasswordForm::SCHEME_HTML, kTestAndroidRealm3, "", "", L"", L"", L"",
+      {PasswordForm::Scheme::kHtml, kTestAndroidRealm3, "", "", L"", L"", L"",
        L"username_value_3", L"", true, 1},
-      {PasswordForm::SCHEME_HTML, kTestWebRealm1, kTestWebOrigin1, "", L"", L"",
-       L"", L"username_value_4", L"", true, 1},
+      {PasswordForm::Scheme::kHtml, kTestWebRealm1, kTestWebOrigin1, "", L"",
+       L"", L"", L"username_value_4", L"", true, 1},
       // A PasswordFormData with nullptr as the username_value will be converted
       // in a blacklisted PasswordForm in FillPasswordFormWithData().
-      {PasswordForm::SCHEME_HTML, kTestWebRealm2, kTestWebOrigin2, "", L"", L"",
-       L"", nullptr, L"", true, 1},
-      {PasswordForm::SCHEME_HTML, kTestWebRealm3, kTestWebOrigin3, "", L"", L"",
-       L"", nullptr, L"", true, 1}};
+      {PasswordForm::Scheme::kHtml, kTestWebRealm2, kTestWebOrigin2, "", L"",
+       L"", L"", nullptr, L"", true, 1},
+      {PasswordForm::Scheme::kHtml, kTestWebRealm3, kTestWebOrigin3, "", L"",
+       L"", L"", nullptr, L"", true, 1}};
 
   auto store = base::MakeRefCounted<PasswordStoreDefault>(
       std::make_unique<LoginDatabase>(test_login_db_file_path()));
@@ -767,20 +767,20 @@
 
 TEST_F(PasswordStoreTest, GetAllLoginsWithAffiliationAndBrandingInformation) {
   static constexpr PasswordFormData kTestCredentials[] = {
-      {PasswordForm::SCHEME_HTML, kTestAndroidRealm1, "", "", L"", L"", L"",
+      {PasswordForm::Scheme::kHtml, kTestAndroidRealm1, "", "", L"", L"", L"",
        L"username_value_1", L"", true, 1},
-      {PasswordForm::SCHEME_HTML, kTestAndroidRealm2, "", "", L"", L"", L"",
+      {PasswordForm::Scheme::kHtml, kTestAndroidRealm2, "", "", L"", L"", L"",
        L"username_value_2", L"", true, 1},
-      {PasswordForm::SCHEME_HTML, kTestAndroidRealm3, "", "", L"", L"", L"",
+      {PasswordForm::Scheme::kHtml, kTestAndroidRealm3, "", "", L"", L"", L"",
        L"username_value_3", L"", true, 1},
-      {PasswordForm::SCHEME_HTML, kTestWebRealm1, kTestWebOrigin1, "", L"", L"",
-       L"", L"username_value_4", L"", true, 1},
+      {PasswordForm::Scheme::kHtml, kTestWebRealm1, kTestWebOrigin1, "", L"",
+       L"", L"", L"username_value_4", L"", true, 1},
       // A PasswordFormData with nullptr as the username_value will be converted
       // in a blacklisted PasswordForm in FillPasswordFormWithData().
-      {PasswordForm::SCHEME_HTML, kTestWebRealm2, kTestWebOrigin2, "", L"", L"",
-       L"", nullptr, L"", true, 1},
-      {PasswordForm::SCHEME_HTML, kTestWebRealm3, kTestWebOrigin3, "", L"", L"",
-       L"", nullptr, L"", true, 1}};
+      {PasswordForm::Scheme::kHtml, kTestWebRealm2, kTestWebOrigin2, "", L"",
+       L"", L"", nullptr, L"", true, 1},
+      {PasswordForm::Scheme::kHtml, kTestWebRealm3, kTestWebOrigin3, "", L"",
+       L"", L"", nullptr, L"", true, 1}};
 
   auto store = base::MakeRefCounted<PasswordStoreDefault>(
       std::make_unique<LoginDatabase>(test_login_db_file_path()));
@@ -834,9 +834,9 @@
 #if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
 TEST_F(PasswordStoreTest, CheckPasswordReuse) {
   static constexpr PasswordFormData kTestCredentials[] = {
-      {PasswordForm::SCHEME_HTML, "https://www.google.com",
+      {PasswordForm::Scheme::kHtml, "https://www.google.com",
        "https://www.google.com", "", L"", L"", L"", L"", L"password", true, 1},
-      {PasswordForm::SCHEME_HTML, "https://facebook.com",
+      {PasswordForm::Scheme::kHtml, "https://facebook.com",
        "https://facebook.com", "", L"", L"", L"", L"", L"topsecret", true, 1}};
 
   scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
diff --git a/components/password_manager/core/browser/psl_matching_helper.cc b/components/password_manager/core/browser/psl_matching_helper.cc
index d660f23..3ac27eb 100644
--- a/components/password_manager/core/browser/psl_matching_helper.cc
+++ b/components/password_manager/core/browser/psl_matching_helper.cc
@@ -60,8 +60,8 @@
     return MatchResult::EXACT_MATCH;
 
   // PSL and federated matches only apply to HTML forms.
-  if (form_digest.scheme != PasswordForm::SCHEME_HTML ||
-      form.scheme != PasswordForm::SCHEME_HTML)
+  if (form_digest.scheme != PasswordForm::Scheme::kHtml ||
+      form.scheme != PasswordForm::Scheme::kHtml)
     return MatchResult::NO_MATCH;
 
   const bool allow_psl_match = ShouldPSLDomainMatchingApply(
diff --git a/components/password_manager/core/browser/psl_matching_helper_unittest.cc b/components/password_manager/core/browser/psl_matching_helper_unittest.cc
index 82bffd01..8fff5b5 100644
--- a/components/password_manager/core/browser/psl_matching_helper_unittest.cc
+++ b/components/password_manager/core/browser/psl_matching_helper_unittest.cc
@@ -68,7 +68,7 @@
     form.origin = GURL(data.form_origin);
     form.signon_realm = form.origin.GetOrigin().spec();
     PasswordStore::FormDigest digest(
-        autofill::PasswordForm::SCHEME_HTML,
+        autofill::PasswordForm::Scheme::kHtml,
         GURL(data.digest_origin).GetOrigin().spec(), GURL(data.digest_origin));
 
     EXPECT_EQ(data.match_result, GetMatchResult(form, digest))
@@ -119,7 +119,7 @@
     form.origin = GURL(data.form_origin);
     form.signon_realm = form.origin.GetOrigin().spec();
     PasswordStore::FormDigest digest(
-        autofill::PasswordForm::SCHEME_HTML,
+        autofill::PasswordForm::Scheme::kHtml,
         GURL(data.digest_origin).GetOrigin().spec(), GURL(data.digest_origin));
 
     EXPECT_EQ(data.match_result, GetMatchResult(form, digest))
@@ -183,7 +183,7 @@
                         form.federation_origin.host();
 
     PasswordStore::FormDigest digest(
-        autofill::PasswordForm::SCHEME_HTML,
+        autofill::PasswordForm::Scheme::kHtml,
         GURL(data.digest_origin).GetOrigin().spec(), GURL(data.digest_origin));
 
     EXPECT_EQ(data.match_result, GetMatchResult(form, digest))
@@ -254,7 +254,7 @@
                         form.federation_origin.host();
 
     PasswordStore::FormDigest digest(
-        autofill::PasswordForm::SCHEME_HTML,
+        autofill::PasswordForm::Scheme::kHtml,
         GURL(data.digest_origin).GetOrigin().spec(), GURL(data.digest_origin));
 
     EXPECT_EQ(data.match_result, GetMatchResult(form, digest))
diff --git a/components/password_manager/core/browser/sync/password_sync_bridge.cc b/components/password_manager/core/browser/sync/password_sync_bridge.cc
index e8f2f85..c2b8029 100644
--- a/components/password_manager/core/browser/sync/password_sync_bridge.cc
+++ b/components/password_manager/core/browser/sync/password_sync_bridge.cc
@@ -32,7 +32,7 @@
   sync_pb::PasswordSpecifics specifics;
   sync_pb::PasswordSpecificsData* password_data =
       specifics.mutable_client_only_encrypted_data();
-  password_data->set_scheme(password_form.scheme);
+  password_data->set_scheme(static_cast<int>(password_form.scheme));
   password_data->set_signon_realm(password_form.signon_realm);
   password_data->set_origin(password_form.origin.spec());
   password_data->set_action(password_form.action.spec());
@@ -48,7 +48,7 @@
   password_data->set_date_created(
       password_form.date_created.ToDeltaSinceWindowsEpoch().InMicroseconds());
   password_data->set_blacklisted(password_form.blacklisted_by_user);
-  password_data->set_type(password_form.type);
+  password_data->set_type(static_cast<int>(password_form.type));
   password_data->set_times_used(password_form.times_used);
   password_data->set_display_name(
       base::UTF16ToUTF8(password_form.display_name));
@@ -119,32 +119,32 @@
 bool AreLocalAndRemotePasswordsEqual(
     const sync_pb::PasswordSpecificsData& password_specifics,
     const autofill::PasswordForm& password_form) {
-  return (password_form.scheme == password_specifics.scheme() &&
-          password_form.signon_realm == password_specifics.signon_realm() &&
-          password_form.origin.spec() == password_specifics.origin() &&
-          password_form.action.spec() == password_specifics.action() &&
-          base::UTF16ToUTF8(password_form.username_element) ==
-              password_specifics.username_element() &&
-          base::UTF16ToUTF8(password_form.password_element) ==
-              password_specifics.password_element() &&
-          base::UTF16ToUTF8(password_form.username_value) ==
-              password_specifics.username_value() &&
-          base::UTF16ToUTF8(password_form.password_value) ==
-              password_specifics.password_value() &&
-          password_form.preferred == password_specifics.preferred() &&
-          password_form.date_created ==
-              base::Time::FromDeltaSinceWindowsEpoch(
-                  base::TimeDelta::FromMicroseconds(
-                      password_specifics.date_created())) &&
-          password_form.blacklisted_by_user ==
-              password_specifics.blacklisted() &&
-          password_form.type == password_specifics.type() &&
-          password_form.times_used == password_specifics.times_used() &&
-          base::UTF16ToUTF8(password_form.display_name) ==
-              password_specifics.display_name() &&
-          password_form.icon_url.spec() == password_specifics.avatar_url() &&
-          url::Origin::Create(GURL(password_specifics.federation_url()))
-                  .Serialize() == password_form.federation_origin.Serialize());
+  return (
+      static_cast<int>(password_form.scheme) == password_specifics.scheme() &&
+      password_form.signon_realm == password_specifics.signon_realm() &&
+      password_form.origin.spec() == password_specifics.origin() &&
+      password_form.action.spec() == password_specifics.action() &&
+      base::UTF16ToUTF8(password_form.username_element) ==
+          password_specifics.username_element() &&
+      base::UTF16ToUTF8(password_form.password_element) ==
+          password_specifics.password_element() &&
+      base::UTF16ToUTF8(password_form.username_value) ==
+          password_specifics.username_value() &&
+      base::UTF16ToUTF8(password_form.password_value) ==
+          password_specifics.password_value() &&
+      password_form.preferred == password_specifics.preferred() &&
+      password_form.date_created ==
+          base::Time::FromDeltaSinceWindowsEpoch(
+              base::TimeDelta::FromMicroseconds(
+                  password_specifics.date_created())) &&
+      password_form.blacklisted_by_user == password_specifics.blacklisted() &&
+      static_cast<int>(password_form.type) == password_specifics.type() &&
+      password_form.times_used == password_specifics.times_used() &&
+      base::UTF16ToUTF8(password_form.display_name) ==
+          password_specifics.display_name() &&
+      password_form.icon_url.spec() == password_specifics.avatar_url() &&
+      url::Origin::Create(GURL(password_specifics.federation_url()))
+              .Serialize() == password_form.federation_origin.Serialize());
 }
 
 bool ShouldRecoverPasswordsDuringMerge() {
diff --git a/components/password_manager/core/browser/sync/password_syncable_service.cc b/components/password_manager/core/browser/sync/password_syncable_service.cc
index 12438fb..f55a7a3 100644
--- a/components/password_manager/core/browser/sync/password_syncable_service.cc
+++ b/components/password_manager/core/browser/sync/password_syncable_service.cc
@@ -43,30 +43,30 @@
 bool AreLocalAndSyncPasswordsEqual(
     const sync_pb::PasswordSpecificsData& password_specifics,
     const autofill::PasswordForm& password_form) {
-  return (password_form.scheme == password_specifics.scheme() &&
-          password_form.signon_realm == password_specifics.signon_realm() &&
-          password_form.origin.spec() == password_specifics.origin() &&
-          password_form.action.spec() == password_specifics.action() &&
-          base::UTF16ToUTF8(password_form.username_element) ==
-              password_specifics.username_element() &&
-          base::UTF16ToUTF8(password_form.password_element) ==
-              password_specifics.password_element() &&
-          base::UTF16ToUTF8(password_form.username_value) ==
-              password_specifics.username_value() &&
-          base::UTF16ToUTF8(password_form.password_value) ==
-              password_specifics.password_value() &&
-          password_form.preferred == password_specifics.preferred() &&
-          password_form.date_created.ToInternalValue() ==
-              password_specifics.date_created() &&
-          password_form.blacklisted_by_user ==
-              password_specifics.blacklisted() &&
-          password_form.type == password_specifics.type() &&
-          password_form.times_used == password_specifics.times_used() &&
-          base::UTF16ToUTF8(password_form.display_name) ==
-              password_specifics.display_name() &&
-          password_form.icon_url.spec() == password_specifics.avatar_url() &&
-          url::Origin::Create(GURL(password_specifics.federation_url()))
-                  .Serialize() == password_form.federation_origin.Serialize());
+  return (
+      static_cast<int>(password_form.scheme) == password_specifics.scheme() &&
+      password_form.signon_realm == password_specifics.signon_realm() &&
+      password_form.origin.spec() == password_specifics.origin() &&
+      password_form.action.spec() == password_specifics.action() &&
+      base::UTF16ToUTF8(password_form.username_element) ==
+          password_specifics.username_element() &&
+      base::UTF16ToUTF8(password_form.password_element) ==
+          password_specifics.password_element() &&
+      base::UTF16ToUTF8(password_form.username_value) ==
+          password_specifics.username_value() &&
+      base::UTF16ToUTF8(password_form.password_value) ==
+          password_specifics.password_value() &&
+      password_form.preferred == password_specifics.preferred() &&
+      password_form.date_created.ToInternalValue() ==
+          password_specifics.date_created() &&
+      password_form.blacklisted_by_user == password_specifics.blacklisted() &&
+      static_cast<int>(password_form.type) == password_specifics.type() &&
+      password_form.times_used == password_specifics.times_used() &&
+      base::UTF16ToUTF8(password_form.display_name) ==
+          password_specifics.display_name() &&
+      password_form.icon_url.spec() == password_specifics.avatar_url() &&
+      url::Origin::Create(GURL(password_specifics.federation_url()))
+              .Serialize() == password_form.federation_origin.Serialize());
 }
 
 syncer::SyncChange::SyncChangeType GetSyncChangeType(
@@ -456,10 +456,12 @@
   sync_pb::EntitySpecifics password_data;
   sync_pb::PasswordSpecificsData* password_specifics =
       password_data.mutable_password()->mutable_client_only_encrypted_data();
+#define CopyEnumField(field) \
+  password_specifics->set_##field(static_cast<int>(password_form.field))
 #define CopyField(field) password_specifics->set_##field(password_form.field)
 #define CopyStringField(field) \
   password_specifics->set_##field(base::UTF16ToUTF8(password_form.field))
-  CopyField(scheme);
+  CopyEnumField(scheme);
   CopyField(signon_realm);
   password_specifics->set_origin(password_form.origin.spec());
   password_specifics->set_action(password_form.action.spec());
@@ -471,7 +473,7 @@
   password_specifics->set_date_created(
       password_form.date_created.ToInternalValue());
   password_specifics->set_blacklisted(password_form.blacklisted_by_user);
-  CopyField(type);
+  CopyEnumField(type);
   CopyField(times_used);
   CopyStringField(display_name);
   password_specifics->set_avatar_url(password_form.icon_url.spec());
@@ -481,6 +483,7 @@
           : password_form.federation_origin.Serialize());
 #undef CopyStringField
 #undef CopyField
+#undef CopyEnumField
 
   std::string tag = MakePasswordSyncTag(*password_specifics);
   return syncer::SyncData::CreateLocalData(tag, tag, password_data);
diff --git a/components/password_manager/core/browser/sync/password_syncable_service_unittest.cc b/components/password_manager/core/browser/sync/password_syncable_service_unittest.cc
index 16c11cf7..0f0db98 100644
--- a/components/password_manager/core/browser/sync/password_syncable_service_unittest.cc
+++ b/components/password_manager/core/browser/sync/password_syncable_service_unittest.cc
@@ -55,7 +55,7 @@
 
 // PasswordForm values for tests.
 constexpr autofill::PasswordForm::Type kArbitraryType =
-    autofill::PasswordForm::TYPE_GENERATED;
+    autofill::PasswordForm::Type::kGenerated;
 constexpr char kIconUrl[] = "https://fb.com/Icon";
 constexpr char kDisplayName[] = "Agent Smith";
 constexpr char kFederationUrl[] = "https://fb.com/";
@@ -134,7 +134,8 @@
   sync_pb::PasswordSpecificsData* password_specifics =
       password_data.mutable_password()->mutable_client_only_encrypted_data();
   password_specifics->set_signon_realm(signon_realm);
-  password_specifics->set_type(autofill::PasswordForm::TYPE_GENERATED);
+  password_specifics->set_type(
+      static_cast<int>(autofill::PasswordForm::Type::kGenerated));
   password_specifics->set_times_used(3);
   password_specifics->set_display_name("Mr. X");
   password_specifics->set_avatar_url("https://accounts.google.com/Icon");
@@ -724,7 +725,7 @@
 // Sync representation is matching the expectations.
 TEST_F(PasswordSyncableServiceTest, SerializeNonEmptyPasswordForm) {
   autofill::PasswordForm form;
-  form.scheme = autofill::PasswordForm::SCHEME_USERNAME_ONLY;
+  form.scheme = autofill::PasswordForm::Scheme::kUsernameOnly;
   form.signon_realm = "http://google.com/";
   form.origin = GURL("https://google.com/origin");
   form.action = GURL("https://google.com/action");
@@ -735,7 +736,7 @@
   form.preferred = true;
   form.date_created = base::Time::FromInternalValue(100);
   form.blacklisted_by_user = true;
-  form.type = autofill::PasswordForm::TYPE_LAST;
+  form.type = autofill::PasswordForm::Type::kMaxValue;
   form.times_used = 11;
   form.display_name = base::ASCIIToUTF16("Great Peter");
   form.icon_url = GURL("https://google.com/icon");
@@ -744,7 +745,8 @@
   syncer::SyncData data = SyncDataFromPassword(form);
   const sync_pb::PasswordSpecificsData& specifics = GetPasswordSpecifics(data);
   EXPECT_TRUE(specifics.has_scheme());
-  EXPECT_EQ(autofill::PasswordForm::SCHEME_USERNAME_ONLY, specifics.scheme());
+  EXPECT_EQ(static_cast<int>(autofill::PasswordForm::Scheme::kUsernameOnly),
+            specifics.scheme());
   EXPECT_TRUE(specifics.has_signon_realm());
   EXPECT_EQ("http://google.com/", specifics.signon_realm());
   EXPECT_TRUE(specifics.has_origin());
@@ -766,7 +768,8 @@
   EXPECT_TRUE(specifics.has_blacklisted());
   EXPECT_TRUE(specifics.blacklisted());
   EXPECT_TRUE(specifics.has_type());
-  EXPECT_EQ(autofill::PasswordForm::TYPE_LAST, specifics.type());
+  EXPECT_EQ(static_cast<int>(autofill::PasswordForm::Type::kMaxValue),
+            specifics.type());
   EXPECT_TRUE(specifics.has_times_used());
   EXPECT_EQ(11, specifics.times_used());
   EXPECT_TRUE(specifics.has_display_name());
diff --git a/components/password_manager/core/browser/test_password_store.cc b/components/password_manager/core/browser/test_password_store.cc
index fdefa9e..74906fa 100644
--- a/components/password_manager/core/browser/test_password_store.cc
+++ b/components/password_manager/core/browser/test_password_store.cc
@@ -112,13 +112,13 @@
     const bool realm_psl_matches =
         IsPublicSuffixDomainMatch(elements.first, form.signon_realm);
     if (realm_matches || realm_psl_matches ||
-        (form.scheme == autofill::PasswordForm::SCHEME_HTML &&
+        (form.scheme == autofill::PasswordForm::Scheme::kHtml &&
          password_manager::IsFederatedRealm(elements.first, form.origin))) {
       const bool is_psl = !realm_matches && realm_psl_matches;
       for (const auto& stored_form : elements.second) {
         // Repeat the condition above with an additional check for origin.
         if (realm_matches || realm_psl_matches ||
-            (form.scheme == autofill::PasswordForm::SCHEME_HTML &&
+            (form.scheme == autofill::PasswordForm::Scheme::kHtml &&
              stored_form.origin.GetOrigin() == form.origin.GetOrigin() &&
              password_manager::IsFederatedRealm(stored_form.signon_realm,
                                                 form.origin))) {
diff --git a/components/password_manager/core/browser/votes_uploader.cc b/components/password_manager/core/browser/votes_uploader.cc
index 6f1b45b..3b2fd59 100644
--- a/components/password_manager/core/browser/votes_uploader.cc
+++ b/components/password_manager/core/browser/votes_uploader.cc
@@ -216,18 +216,20 @@
       if (UploadPasswordVote(*pending, submitted_form,
                              autofill::ACCOUNT_CREATION_PASSWORD,
                              observed_structure.FormSignatureAsStr())) {
-        pending->generation_upload_status = PasswordForm::POSITIVE_SIGNAL_SENT;
+        pending->generation_upload_status =
+            PasswordForm::GenerationUploadStatus::kPositiveSignalSent;
       }
     }
   } else if (pending->generation_upload_status ==
-             PasswordForm::POSITIVE_SIGNAL_SENT) {
+             PasswordForm::GenerationUploadStatus::kPositiveSignalSent) {
     // A signal was sent that this was an account creation form, but the
     // credential is now being used on the same form again. This cancels out
     // the previous vote.
     if (UploadPasswordVote(*pending, submitted_form,
                            autofill::NOT_ACCOUNT_CREATION_PASSWORD,
                            std::string())) {
-      pending->generation_upload_status = PasswordForm::NEGATIVE_SIGNAL_SENT;
+      pending->generation_upload_status =
+          PasswordForm::GenerationUploadStatus::kNegativeSignalSent;
     }
   } else if (generation_popup_was_shown_) {
     // Even if there is no autofill vote to be sent, send the vote about the
diff --git a/components/password_manager/core/common/credential_manager_types.cc b/components/password_manager/core/common/credential_manager_types.cc
index f5fa75f..676ed66 100644
--- a/components/password_manager/core/common/credential_manager_types.cc
+++ b/components/password_manager/core/common/credential_manager_types.cc
@@ -77,8 +77,8 @@
   form->origin = origin;
   form->password_value = info.password.value_or(base::string16());
   form->username_value = info.id.value_or(base::string16());
-  form->scheme = autofill::PasswordForm::SCHEME_HTML;
-  form->type = autofill::PasswordForm::TYPE_API;
+  form->scheme = autofill::PasswordForm::Scheme::kHtml;
+  form->type = autofill::PasswordForm::Type::kApi;
 
   form->signon_realm =
       info.type == CredentialType::CREDENTIAL_TYPE_PASSWORD
@@ -91,8 +91,8 @@
     const GURL& origin) {
   std::unique_ptr<autofill::PasswordForm> form(new autofill::PasswordForm);
   form->origin = origin;
-  form->scheme = autofill::PasswordForm::SCHEME_HTML;
-  form->type = autofill::PasswordForm::TYPE_API;
+  form->scheme = autofill::PasswordForm::Scheme::kHtml;
+  form->type = autofill::PasswordForm::Type::kApi;
   form->signon_realm = origin.GetOrigin().spec();
   return form;
 }
diff --git a/components/password_manager/core/common/credential_manager_types_unittest.cc b/components/password_manager/core/common/credential_manager_types_unittest.cc
index 54dc23d..93d1868 100644
--- a/components/password_manager/core/common/credential_manager_types_unittest.cc
+++ b/components/password_manager/core/common/credential_manager_types_unittest.cc
@@ -48,11 +48,11 @@
   form = CreatePasswordFormFromCredentialInfo(info, origin_);
   ASSERT_NE(nullptr, form.get());
 
-  EXPECT_EQ(autofill::PasswordForm::TYPE_API, form->type);
+  EXPECT_EQ(autofill::PasswordForm::Type::kApi, form->type);
   EXPECT_EQ(info.icon, form->icon_url);
   EXPECT_EQ(info.name, form->display_name);
   EXPECT_EQ(origin_, form->origin);
-  EXPECT_EQ(autofill::PasswordForm::SCHEME_HTML, form->scheme);
+  EXPECT_EQ(autofill::PasswordForm::Scheme::kHtml, form->scheme);
 
   // Federated credentials have empty passwords, non-empty federation_origins,
   // and funky signon realms.
@@ -77,7 +77,7 @@
   EXPECT_EQ(info.icon, form->icon_url);
   EXPECT_EQ(info.name, form->display_name);
   EXPECT_EQ(origin_, form->origin);
-  EXPECT_EQ(autofill::PasswordForm::SCHEME_HTML, form->scheme);
+  EXPECT_EQ(autofill::PasswordForm::Scheme::kHtml, form->scheme);
 
   // Local credentials have empty federation_origins, non-empty passwords, and
   // a signon realm that matches the origin.
@@ -94,7 +94,7 @@
   EXPECT_EQ(GURL(), form->icon_url);
   EXPECT_EQ(base::string16(), form->display_name);
   EXPECT_EQ(origin_, form->origin);
-  EXPECT_EQ(autofill::PasswordForm::SCHEME_HTML, form->scheme);
+  EXPECT_EQ(autofill::PasswordForm::Scheme::kHtml, form->scheme);
   EXPECT_TRUE(form->federation_origin.opaque());
   EXPECT_EQ(base::string16(), form->password_value);
   EXPECT_EQ(origin_.spec(), form->signon_realm);
diff --git a/components/policy/proto/chrome_device_policy.proto b/components/policy/proto/chrome_device_policy.proto
index 98449e0..e9197c5 100644
--- a/components/policy/proto/chrome_device_policy.proto
+++ b/components/policy/proto/chrome_device_policy.proto
@@ -265,14 +265,6 @@
     // including network credentials during the rollback process.
     // If that is not possible, rolls back with a full powerwash.
     ROLLBACK_AND_RESTORE_IF_POSSIBLE = 3;
-    // If |target_version_prefix| specifies an older version than the currently
-    // installed Chrome OS version and it's possible to carry over device-level
-    // configuration such as network credentials during the rollback process
-    // and skipping OOBE after the rollback, the device rolls back to a Chrome
-    // OS version starting with |target_version_prefix|.
-    // If this is not possible, the device will stay on the current version
-    // (same as ROLLBACK_DISABLED).
-    ROLLBACK_ONLY_IF_RESTORE_POSSIBLE = 4;
   }
 
   // Specifies what should happen if |target_version_prefix| specifies an older
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 96d7269..878949d 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -7501,7 +7501,7 @@
       'type': 'int-enum',
       'schema': {
         'type': 'integer',
-        'enum': [ 1, 2, 3, 4 ],
+        'enum': [ 1, 2, 3 ],
       },
       'items': [
         {
@@ -7518,13 +7518,7 @@
           'name': 'RollbackAndRestoreIfPossible',
           'value': 3,
           'caption': '''Roll back and stay on target version if OS version is newer than target. Try to carry over device-level configuration (including network credentials) through the rollback process, if possible, but do the rollback with full powerwash even if restoring the data is not possible (because the target version doesn't support restoring data or because of a backward-incompatible change).
-          Supported on <ph name="PRODUCT_OS_NAME">$2<ex>Google Chrome OS</ex></ph> version 70 and higher. For older clients, this value means that rollback is disabled.''',
-        },
-        {
-          'name': 'RollbackOnlyIfRestorePossible',
-          'value': 4,
-          'caption': '''Roll back and stay on target version if OS version is newer than target and it's possible to carry over device-level configuration (including network credentials) through rollback, also skipping OOBE after rollback. Don't do or abort rollback if that's not possible (because the target version doesn't support restoring data or because of a backward-incompatible change).
-          Supported on <ph name="PRODUCT_OS_NAME">$2<ex>Google Chrome OS</ex></ph> version 70 and higher. For older clients, this value means that rollback is disabled.''',
+          Supported on <ph name="PRODUCT_OS_NAME">$2<ex>Google Chrome OS</ex></ph> version 75 and higher. For older clients, this value means that rollback is disabled.''',
         },
       ],
       'supported_on': ['chrome_os:67-'],
diff --git a/components/printing/browser/printer_capabilities.cc b/components/printing/browser/printer_capabilities.cc
index dd0d081..d31931e 100644
--- a/components/printing/browser/printer_capabilities.cc
+++ b/components/printing/browser/printer_capabilities.cc
@@ -118,26 +118,6 @@
 }
 #endif
 
-std::pair<std::string, std::string> GetPrinterNameAndDescription(
-    const PrinterBasicInfo& printer) {
-#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
-  // On Mac, |printer.printer_description| specifies the printer name and
-  // |printer.printer_name| specifies the device name / printer queue name.
-  // Chrome OS emulates the Mac behavior.
-  const std::string& real_name = printer.printer_description;
-  std::string real_description;
-  const auto it = printer.options.find(kDriverNameTagName);
-  if (it != printer.options.end())
-    real_description = it->second;
-  return std::make_pair(real_name, real_description);
-#elif defined(OS_WIN)
-  return std::make_pair(GetUserFriendlyName(printer.printer_name),
-                        printer.printer_description);
-#else
-  return std::make_pair(printer.printer_name, printer.printer_description);
-#endif
-}
-
 base::Value GetSettingsOnBlockingPool(
     const std::string& device_name,
     const PrinterBasicInfo& basic_info,
@@ -148,15 +128,12 @@
   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
                                                 base::BlockingType::MAY_BLOCK);
 
-  const auto printer_name_description =
-      GetPrinterNameAndDescription(basic_info);
-
   base::Value printer_info(base::Value::Type::DICTIONARY);
   printer_info.SetKey(kSettingDeviceName, base::Value(device_name));
   printer_info.SetKey(kSettingPrinterName,
-                      base::Value(printer_name_description.first));
+                      base::Value(basic_info.display_name));
   printer_info.SetKey(kSettingPrinterDescription,
-                      base::Value(printer_name_description.second));
+                      base::Value(basic_info.printer_description));
   printer_info.SetKey(
       kCUPSEnterprisePrinter,
       base::Value(
diff --git a/components/ukm/app_source_url_recorder.h b/components/ukm/app_source_url_recorder.h
index b9cf11a6..0675b76 100644
--- a/components/ukm/app_source_url_recorder.h
+++ b/components/ukm/app_source_url_recorder.h
@@ -34,7 +34,7 @@
   // Get a UKM SourceId for an Arc app.
   static SourceId GetSourceIdForArc(const std::string& package_name);
 
-  // Get a UKM SourceId for a PWA.
+  // Get a UKM SourceId for a PWA or bookmark app.
   static SourceId GetSourceIdForPWA(const GURL& url);
 
   // For internal use only.
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 74760af..ce8477d 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -1123,6 +1123,8 @@
     "keyboard_lock/keyboard_lock_metrics.h",
     "keyboard_lock/keyboard_lock_service_impl.cc",
     "keyboard_lock/keyboard_lock_service_impl.h",
+    "loader/cross_origin_read_blocking_checker.cc",
+    "loader/cross_origin_read_blocking_checker.h",
     "loader/cross_site_document_resource_handler.cc",
     "loader/cross_site_document_resource_handler.h",
     "loader/data_pipe_to_source_stream.cc",
diff --git a/content/browser/accessibility/accessibility_auralinux_browsertest.cc b/content/browser/accessibility/accessibility_auralinux_browsertest.cc
index c23ff421..d45f32d 100644
--- a/content/browser/accessibility/accessibility_auralinux_browsertest.cc
+++ b/content/browser/accessibility/accessibility_auralinux_browsertest.cc
@@ -244,36 +244,6 @@
   g_object_unref(atk_text);
 }
 
-IN_PROC_BROWSER_TEST_F(AccessibilityAuraLinuxBrowserTest,
-                       TestAtkTextGetTextCrash) {
-  LoadInitialAccessibilityTreeFromHtml(
-      R"HTML(<!DOCTYPE html>
-      <html>
-      <body>
-        <ul><li>Text</li></ul>
-      </body>
-      </html>)HTML");
-
-  // Retrieve the AtkObject interface for the document node.
-  AtkObject* document = GetRendererAccessible();
-  EXPECT_EQ(1, atk_object_get_n_accessible_children(document));
-  AtkObject* list = atk_object_ref_accessible_child(document, 0);
-
-  EXPECT_TRUE(ATK_IS_TEXT(list));
-
-  // There should be no crash when atk_text_get_text_at_offset returns an
-  // empty value.
-  int start_offset = -1, end_offset = -1;
-  gchar* text = atk_text_get_text_at_offset(ATK_TEXT(list), 0,
-                                            ATK_TEXT_BOUNDARY_WORD_START,
-                                            &start_offset, &end_offset);
-  ASSERT_EQ(text, nullptr);
-  ASSERT_EQ(start_offset, -1);
-  ASSERT_EQ(end_offset, -1);
-
-  g_object_unref(list);
-}
-
 #if defined(ATK_CHECK_VERSION) && ATK_CHECK_VERSION(2, 30, 0)
 #define ATK_230
 #endif
@@ -754,24 +724,40 @@
       R"HTML(<!DOCTYPE html>
       <html>
       <body>
-        <li>Text</li>
+        <li>Text 1</li>
+        <li>Text 2</li>
+        <li>Text 3</li>
       </body>
       </html>)HTML");
 
   // Retrieve the AtkObject interface for the document node.
   AtkObject* document = GetRendererAccessible();
-  EXPECT_EQ(1, atk_object_get_n_accessible_children(document));
-  AtkObject* list_item = atk_object_ref_accessible_child(document, 0);
+  EXPECT_EQ(3, atk_object_get_n_accessible_children(document));
+  AtkObject* list_item_1 = atk_object_ref_accessible_child(document, 0);
+  AtkObject* list_item_2 = atk_object_ref_accessible_child(document, 1);
 
-  EXPECT_TRUE(ATK_IS_TEXT(list_item));
+  EXPECT_TRUE(ATK_IS_TEXT(list_item_1));
 
-  // The text of the list item should include the list marker and the text of
-  // the item itself.
-  gchar* text = atk_text_get_text(ATK_TEXT(list_item), 0, -1);
-  ASSERT_STREQ(text, "\xE2\x80\xA2 Text");
+  const base::string16 string16_embed(
+      1, ui::AXPlatformNodeAuraLinux::kEmbeddedCharacter);
+  std::string expected_string = base::UTF16ToUTF8(string16_embed) + "Text 1";
+
+  // The text of the list item should include the list marker as an embedded
+  // object.
+  gchar* text = atk_text_get_text(ATK_TEXT(list_item_1), 0, -1);
+  ASSERT_STREQ(text, expected_string.c_str());
+  g_free(text);
+  text = atk_text_get_text_at_offset(
+      ATK_TEXT(list_item_2), 0, ATK_TEXT_BOUNDARY_WORD_START, nullptr, nullptr);
+  ASSERT_STREQ(text, base::UTF16ToUTF8(string16_embed).c_str());
   g_free(text);
 
-  g_object_unref(list_item);
+  text = atk_text_get_text_at_offset(
+      ATK_TEXT(list_item_2), 1, ATK_TEXT_BOUNDARY_WORD_START, nullptr, nullptr);
+  ASSERT_STREQ(text, "Text ");
+  g_free(text);
+
+  g_object_unref(list_item_1);
 }
 
 IN_PROC_BROWSER_TEST_F(AccessibilityAuraLinuxBrowserTest,
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc
index b168e862..cc2cf75 100644
--- a/content/browser/accessibility/browser_accessibility.cc
+++ b/content/browser/accessibility/browser_accessibility.cc
@@ -39,6 +39,27 @@
 
 BrowserAccessibility::~BrowserAccessibility() {}
 
+namespace {
+
+int GetBoundaryTextOffsetInsideBaseAnchor(
+    ui::TextBoundaryDirection direction,
+    const BrowserAccessibilityPosition::AXPositionInstance& base,
+    const BrowserAccessibilityPosition::AXPositionInstance& position) {
+  if (base->GetAnchor() == position->GetAnchor())
+    return position->text_offset();
+
+  // If the position is outside the anchor of the base position, then return
+  // the first or last position in the same direction.
+  switch (direction) {
+    case ui::BACKWARDS_DIRECTION:
+      return base->CreatePositionAtStartOfAnchor()->text_offset();
+    case ui::FORWARDS_DIRECTION:
+      return base->CreatePositionAtEndOfAnchor()->text_offset();
+  }
+}
+
+}  // namespace
+
 void BrowserAccessibility::Init(BrowserAccessibilityManager* manager,
                                 ui::AXNode* node) {
   manager_ = manager;
@@ -1229,15 +1250,15 @@
           CreatePositionAt(static_cast<int>(offset), affinity);
       switch (direction) {
         case ui::BACKWARDS_DIRECTION:
-          return position
-              ->CreatePreviousWordStartPosition(
-                  ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary)
-              ->text_offset();
+          return GetBoundaryTextOffsetInsideBaseAnchor(
+              direction, position,
+              position->CreatePreviousWordStartPosition(
+                  ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary));
         case ui::FORWARDS_DIRECTION:
-          return position
-              ->CreateNextWordStartPosition(
-                  ui::AXBoundaryBehavior::StopAtAnchorBoundary)
-              ->text_offset();
+          return GetBoundaryTextOffsetInsideBaseAnchor(
+              direction, position,
+              position->CreateNextWordStartPosition(
+                  ui::AXBoundaryBehavior::StopAtAnchorBoundary));
       }
     }
     case ui::AXTextBoundary::kWordStartOrEnd: {
@@ -1245,15 +1266,15 @@
           CreatePositionAt(static_cast<int>(offset), affinity);
       switch (direction) {
         case ui::BACKWARDS_DIRECTION:
-          return position
-              ->CreatePreviousWordStartPosition(
-                  ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary)
-              ->text_offset();
+          return GetBoundaryTextOffsetInsideBaseAnchor(
+              direction, position,
+              position->CreatePreviousWordStartPosition(
+                  ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary));
         case ui::FORWARDS_DIRECTION:
-          return position
-              ->CreateNextWordEndPosition(
-                  ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary)
-              ->text_offset();
+          return GetBoundaryTextOffsetInsideBaseAnchor(
+              direction, position,
+              position->CreateNextWordEndPosition(
+                  ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary));
       }
     }
     case ui::AXTextBoundary::kLineStart: {
@@ -1261,15 +1282,15 @@
           CreatePositionAt(static_cast<int>(offset), affinity);
       switch (direction) {
         case ui::BACKWARDS_DIRECTION:
-          return position
-              ->CreatePreviousLineStartPosition(
-                  ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary)
-              ->text_offset();
+          return GetBoundaryTextOffsetInsideBaseAnchor(
+              direction, position,
+              position->CreatePreviousLineStartPosition(
+                  ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary));
         case ui::FORWARDS_DIRECTION:
-          return position
-              ->CreateNextLineStartPosition(
-                  ui::AXBoundaryBehavior::StopAtAnchorBoundary)
-              ->text_offset();
+          return GetBoundaryTextOffsetInsideBaseAnchor(
+              direction, position,
+              position->CreateNextLineStartPosition(
+                  ui::AXBoundaryBehavior::StopAtAnchorBoundary));
       }
     }
     default:
diff --git a/content/browser/loader/cross_origin_read_blocking_checker.cc b/content/browser/loader/cross_origin_read_blocking_checker.cc
new file mode 100644
index 0000000..3aee65b7
--- /dev/null
+++ b/content/browser/loader/cross_origin_read_blocking_checker.cc
@@ -0,0 +1,122 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/loader/cross_origin_read_blocking_checker.h"
+
+#include "base/callback.h"
+#include "net/base/io_buffer.h"
+#include "net/base/mime_sniffer.h"
+#include "services/network/cross_origin_read_blocking.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/resource_response.h"
+#include "storage/browser/blob/blob_data_handle.h"
+#include "storage/browser/blob/blob_reader.h"
+#include "url/origin.h"
+
+namespace content {
+
+CrossOriginReadBlockingChecker::CrossOriginReadBlockingChecker(
+    const network::ResourceRequest& request,
+    const network::ResourceResponseHead& response,
+    const url::Origin& request_initiator_site_lock,
+    const storage::BlobDataHandle& blob_data_handle,
+    base::OnceCallback<void(Result)> callback)
+    : callback_(std::move(callback)) {
+  DCHECK(!callback_.is_null());
+  network::CrossOriginReadBlocking::LogAction(
+      network::CrossOriginReadBlocking::Action::kResponseStarted);
+  corb_analyzer_ =
+      std::make_unique<network::CrossOriginReadBlocking::ResponseAnalyzer>(
+          request.url, request.request_initiator, response,
+          request_initiator_site_lock, request.fetch_request_mode);
+  if (corb_analyzer_->ShouldBlock()) {
+    OnBlocked();
+    return;
+  }
+  if (corb_analyzer_->needs_sniffing()) {
+    StartSniffing(blob_data_handle);
+    return;
+  }
+  DCHECK(corb_analyzer_->ShouldAllow());
+  OnAllowed();
+}
+
+CrossOriginReadBlockingChecker::~CrossOriginReadBlockingChecker() = default;
+
+int CrossOriginReadBlockingChecker::GetNetError() {
+  DCHECK(blob_reader_);
+  return blob_reader_->net_error();
+}
+
+void CrossOriginReadBlockingChecker::OnAllowed() {
+  corb_analyzer_->LogAllowedResponse();
+  std::move(callback_).Run(Result::kAllowed);
+}
+
+void CrossOriginReadBlockingChecker::OnBlocked() {
+  corb_analyzer_->LogBlockedResponse();
+  std::move(callback_).Run(corb_analyzer_->ShouldReportBlockedResponse()
+                               ? Result::kBlocked_ShouldReport
+                               : Result::kBlocked_ShouldNotReport);
+}
+
+void CrossOriginReadBlockingChecker::OnNetError() {
+  std::move(callback_).Run(Result::kNetError);
+}
+
+void CrossOriginReadBlockingChecker::StartSniffing(
+    const storage::BlobDataHandle& blob_data_handle) {
+  blob_reader_ = blob_data_handle.CreateReader();
+  const storage::BlobReader::Status size_status = blob_reader_->CalculateSize(
+      base::BindOnce(&CrossOriginReadBlockingChecker::DidCalculateSize,
+                     base::Unretained(this)));
+  switch (size_status) {
+    case storage::BlobReader::Status::NET_ERROR:
+      OnNetError();
+      return;
+    case storage::BlobReader::Status::IO_PENDING:
+      return;
+    case storage::BlobReader::Status::DONE:
+      DidCalculateSize(net::OK);
+      return;
+  }
+}
+
+void CrossOriginReadBlockingChecker::DidCalculateSize(int result) {
+  size_t buf_size = net::kMaxBytesToSniff;
+  if (buf_size > blob_reader_->total_size())
+    buf_size = blob_reader_->total_size();
+  buffer_ = base::MakeRefCounted<net::IOBufferWithSize>(buf_size);
+  int bytes_read;
+  const storage::BlobReader::Status status = blob_reader_->Read(
+      buffer_.get(), buf_size, &bytes_read,
+      base::BindOnce(&CrossOriginReadBlockingChecker::OnReadComplete,
+                     base::Unretained(this)));
+  switch (status) {
+    case storage::BlobReader::Status::NET_ERROR:
+      OnNetError();
+      return;
+    case storage::BlobReader::Status::IO_PENDING:
+      return;
+    case storage::BlobReader::Status::DONE:
+      OnReadComplete(bytes_read);
+      return;
+  }
+}
+
+void CrossOriginReadBlockingChecker::OnReadComplete(int bytes_read) {
+  if (bytes_read != buffer_->size()) {
+    OnNetError();
+    return;
+  }
+  base::StringPiece data(buffer_->data(), bytes_read);
+  corb_analyzer_->SniffResponseBody(data, 0);
+  if (corb_analyzer_->ShouldBlock()) {
+    OnBlocked();
+    return;
+  }
+  OnAllowed();
+}
+
+}  // namespace content
diff --git a/content/browser/loader/cross_origin_read_blocking_checker.h b/content/browser/loader/cross_origin_read_blocking_checker.h
new file mode 100644
index 0000000..f72a8cb
--- /dev/null
+++ b/content/browser/loader/cross_origin_read_blocking_checker.h
@@ -0,0 +1,74 @@
+// 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 CONTENT_BROWSER_LOADER_CROSS_ORIGIN_READ_BLOCKING_CHECKER_H_
+#define CONTENT_BROWSER_LOADER_CROSS_ORIGIN_READ_BLOCKING_CHECKER_H_
+
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "services/network/cross_origin_read_blocking.h"
+
+namespace net {
+class IOBufferWithSize;
+}  // namespace net
+
+namespace network {
+struct ResourceRequest;
+struct ResourceResponseHead;
+}  // namespace network
+
+namespace storage {
+class BlobDataHandle;
+class BlobReader;
+}  // namespace storage
+
+namespace url {
+class Origin;
+}  // namespace url
+
+namespace content {
+
+// This class checks whether we should block the response or not using
+// CrossOriginReadBlocking::ResponseAnalyzer.
+class CrossOriginReadBlockingChecker {
+ public:
+  enum class Result {
+    kAllowed,
+    kBlocked_ShouldReport,
+    kBlocked_ShouldNotReport,
+    kNetError
+  };
+  CrossOriginReadBlockingChecker(
+      const network::ResourceRequest& request,
+      const network::ResourceResponseHead& response,
+      const url::Origin& request_initiator_site_lock,
+      const storage::BlobDataHandle& blob_data_handle,
+      base::OnceCallback<void(Result)> callback);
+  ~CrossOriginReadBlockingChecker();
+
+  int GetNetError();
+
+ private:
+  void OnAllowed();
+  void OnBlocked();
+  void OnNetError();
+
+  void StartSniffing(const storage::BlobDataHandle& blob_data_handle);
+
+  void DidCalculateSize(int result);
+
+  void OnReadComplete(int bytes_read);
+
+  base::OnceCallback<void(Result)> callback_;
+  std::unique_ptr<network::CrossOriginReadBlocking::ResponseAnalyzer>
+      corb_analyzer_;
+  std::unique_ptr<storage::BlobReader> blob_reader_;
+  scoped_refptr<net::IOBufferWithSize> buffer_;
+
+  DISALLOW_COPY_AND_ASSIGN(CrossOriginReadBlockingChecker);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_LOADER_CROSS_ORIGIN_READ_BLOCKING_CHECKER_H_
diff --git a/content/browser/loader/cross_site_document_resource_handler.cc b/content/browser/loader/cross_site_document_resource_handler.cc
index 2151c5b9..d514c10 100644
--- a/content/browser/loader/cross_site_document_resource_handler.cc
+++ b/content/browser/loader/cross_site_document_resource_handler.cc
@@ -236,8 +236,8 @@
   // Enforce the Cross-Origin-Resource-Policy (CORP) header.
   if (network::CrossOriginResourcePolicy::kBlock ==
       network::CrossOriginResourcePolicy::Verify(
-          *request(), *response, fetch_request_mode_,
-          kNonNetworkServiceInitiatorLock)) {
+          request()->url(), request()->initiator(), response->head,
+          fetch_request_mode_, kNonNetworkServiceInitiatorLock)) {
     blocked_read_completed_ = true;
     blocked_by_cross_origin_resource_policy_ = true;
     controller->Cancel();
@@ -256,8 +256,8 @@
   // Enforce the Cross-Origin-Resource-Policy (CORP) header.
   if (network::CrossOriginResourcePolicy::kBlock ==
       network::CrossOriginResourcePolicy::Verify(
-          *request(), *response, fetch_request_mode_,
-          kNonNetworkServiceInitiatorLock)) {
+          request()->url(), request()->initiator(), response->head,
+          fetch_request_mode_, kNonNetworkServiceInitiatorLock)) {
     blocked_read_completed_ = true;
     blocked_by_cross_origin_resource_policy_ = true;
     controller->Cancel();
@@ -510,7 +510,7 @@
     if (analyzer_->ShouldReportBlockedResponse())
       info->set_should_report_corb_blocking(true);
     network::CrossOriginReadBlocking::SanitizeBlockedResponse(
-        pending_response_start_);
+        &pending_response_start_->head);
 
     // Pass an empty/blocked body onto the next handler.  size of the two
     // buffers is the same (see OnWillRead).  After the next statement,
@@ -637,8 +637,8 @@
   // Delegate most decisions to CrossOriginReadBlocking::ResponseAnalyzer.
   analyzer_ =
       std::make_unique<network::CrossOriginReadBlocking::ResponseAnalyzer>(
-          *request(), response, kNonNetworkServiceInitiatorLock,
-          fetch_request_mode_);
+          request()->url(), request()->initiator(), response.head,
+          kNonNetworkServiceInitiatorLock, fetch_request_mode_);
   if (analyzer_->ShouldAllow())
     return false;
 
diff --git a/content/browser/loader/prefetched_signed_exchange_cache.cc b/content/browser/loader/prefetched_signed_exchange_cache.cc
index 2564bdd..d1056e3 100644
--- a/content/browser/loader/prefetched_signed_exchange_cache.cc
+++ b/content/browser/loader/prefetched_signed_exchange_cache.cc
@@ -6,6 +6,7 @@
 
 #include "base/feature_list.h"
 #include "base/strings/stringprintf.h"
+#include "content/browser/loader/cross_origin_read_blocking_checker.h"
 #include "content/browser/loader/navigation_loader_interceptor.h"
 #include "content/browser/navigation_subresource_loader_params.h"
 #include "content/browser/web_package/signed_exchange_utils.h"
@@ -120,25 +121,40 @@
   InnerResponseURLLoader(
       const network::ResourceRequest& request,
       const network::ResourceResponseHead& inner_response,
+      const url::Origin& request_initiator_site_lock,
       std::unique_ptr<const storage::BlobDataHandle> blob_data_handle,
       const network::URLLoaderCompletionStatus& completion_status,
       network::mojom::URLLoaderClientPtr client,
       bool is_navigation_request)
-      : blob_data_handle_(std::move(blob_data_handle)),
+      : response_(inner_response),
+        blob_data_handle_(std::move(blob_data_handle)),
         completion_status_(completion_status),
         client_(std::move(client)),
         weak_factory_(this) {
-    DCHECK(inner_response.headers);
+    DCHECK(response_.headers);
     DCHECK(request.request_initiator);
+
+    UpdateRequestResponseStartTime(&response_);
+    response_.encoded_data_length = 0;
+    if (is_navigation_request) {
+      client_->OnReceiveResponse(response_);
+      // When Network Service is not enabled, we need to wait
+      // ProceedWithResponse for navigation request. See
+      // https://crbug.com/791049.
+      if (base::FeatureList::IsEnabled(network::features::kNetworkService))
+        SendResponseBody();
+      return;
+    }
+
     if (network::cors::ShouldCheckCors(request.url, request.request_initiator,
                                        request.fetch_request_mode)) {
       const auto error_status = network::cors::CheckAccess(
-          request.url, inner_response.headers->response_code(),
+          request.url, response_.headers->response_code(),
           GetHeaderString(
-              inner_response,
+              response_,
               network::cors::header_names::kAccessControlAllowOrigin),
           GetHeaderString(
-              inner_response,
+              response_,
               network::cors::header_names::kAccessControlAllowCredentials),
           request.fetch_credentials_mode, *request.request_initiator);
       if (error_status) {
@@ -147,18 +163,11 @@
       }
     }
 
-    network::ResourceResponseHead response = inner_response;
-    UpdateRequestResponseStartTime(&response);
-    response.encoded_data_length = 0;
-    client_->OnReceiveResponse(response);
-    // When Network Service is not enabled, we need to wait ProceedWithResponse
-    // for navigation request.
-    // See https://crbug.com/791049.
-    if (is_navigation_request &&
-        !base::FeatureList::IsEnabled(network::features::kNetworkService)) {
-      return;
-    }
-    SendResponseBody();
+    corb_checker_ = std::make_unique<CrossOriginReadBlockingChecker>(
+        request, response_, request_initiator_site_lock, *blob_data_handle_,
+        base::BindOnce(
+            &InnerResponseURLLoader::OnCrossOriginReadBlockingCheckComplete,
+            base::Unretained(this)));
   }
   ~InnerResponseURLLoader() override {}
 
@@ -173,6 +182,47 @@
     return header_value;
   }
 
+  void OnCrossOriginReadBlockingCheckComplete(
+      CrossOriginReadBlockingChecker::Result result) {
+    switch (result) {
+      case CrossOriginReadBlockingChecker::Result::kAllowed:
+        client_->OnReceiveResponse(response_);
+        SendResponseBody();
+        return;
+      case CrossOriginReadBlockingChecker::Result::kNetError:
+        client_->OnComplete(
+            network::URLLoaderCompletionStatus(corb_checker_->GetNetError()));
+        return;
+      case CrossOriginReadBlockingChecker::Result::kBlocked_ShouldReport:
+        break;
+      case CrossOriginReadBlockingChecker::Result::kBlocked_ShouldNotReport:
+        break;
+    }
+
+    // Send sanitized response.
+    network::CrossOriginReadBlocking::SanitizeBlockedResponse(&response_);
+    client_->OnReceiveResponse(response_);
+
+    // Send an empty response's body.
+    mojo::ScopedDataPipeProducerHandle pipe_producer_handle;
+    mojo::ScopedDataPipeConsumerHandle pipe_consumer_handle;
+    MojoResult rv = mojo::CreateDataPipe(nullptr, &pipe_producer_handle,
+                                         &pipe_consumer_handle);
+    if (rv != MOJO_RESULT_OK) {
+      client_->OnComplete(
+          network::URLLoaderCompletionStatus(net::ERR_INSUFFICIENT_RESOURCES));
+      return;
+    }
+    client_->OnStartLoadingResponseBody(std::move(pipe_consumer_handle));
+
+    // Send a dummy OnComplete message.
+    network::URLLoaderCompletionStatus status =
+        network::URLLoaderCompletionStatus(net::OK);
+    status.should_report_corb_blocking =
+        result == CrossOriginReadBlockingChecker::Result::kBlocked_ShouldReport;
+    client_->OnComplete(status);
+  }
+
   // network::mojom::URLLoader overrides:
   void FollowRedirect(const std::vector<std::string>& removed_headers,
                       const net::HttpRequestHeaders& modified_headers,
@@ -236,9 +286,11 @@
     client_->OnComplete(status);
   }
 
+  network::ResourceResponseHead response_;
   std::unique_ptr<const storage::BlobDataHandle> blob_data_handle_;
   const network::URLLoaderCompletionStatus completion_status_;
   network::mojom::URLLoaderClientPtr client_;
+  std::unique_ptr<CrossOriginReadBlockingChecker> corb_checker_;
 
   base::WeakPtrFactory<InnerResponseURLLoader> weak_factory_;
 
@@ -252,8 +304,10 @@
  public:
   SubresourceSignedExchangeURLLoaderFactory(
       network::mojom::URLLoaderFactoryRequest request,
-      std::unique_ptr<const PrefetchedSignedExchangeCache::Entry> entry)
-      : entry_(std::move(entry)) {
+      std::unique_ptr<const PrefetchedSignedExchangeCache::Entry> entry,
+      const url::Origin& request_initiator_site_lock)
+      : entry_(std::move(entry)),
+        request_initiator_site_lock_(request_initiator_site_lock) {
     bindings_.AddBinding(this, std::move(request));
     bindings_.set_connection_error_handler(base::BindRepeating(
         &SubresourceSignedExchangeURLLoaderFactory::OnConnectionError,
@@ -271,13 +325,14 @@
                             const net::MutableNetworkTrafficAnnotationTag&
                                 traffic_annotation) override {
     DCHECK_EQ(request.url, entry_->inner_url());
-    mojo::MakeStrongBinding(std::make_unique<InnerResponseURLLoader>(
-                                request, *entry_->inner_response(),
-                                std::make_unique<const storage::BlobDataHandle>(
-                                    *entry_->blob_data_handle()),
-                                *entry_->completion_status(), std::move(client),
-                                false /* is_navigation_request */),
-                            std::move(loader));
+    mojo::MakeStrongBinding(
+        std::make_unique<InnerResponseURLLoader>(
+            request, *entry_->inner_response(), request_initiator_site_lock_,
+            std::make_unique<const storage::BlobDataHandle>(
+                *entry_->blob_data_handle()),
+            *entry_->completion_status(), std::move(client),
+            false /* is_navigation_request */),
+        std::move(loader));
   }
   void Clone(network::mojom::URLLoaderFactoryRequest request) override {
     bindings_.AddBinding(this, std::move(request));
@@ -291,6 +346,7 @@
   }
 
   std::unique_ptr<const PrefetchedSignedExchangeCache::Entry> entry_;
+  const url::Origin request_initiator_site_lock_;
   mojo::BindingSet<network::mojom::URLLoaderFactory> bindings_;
 
   DISALLOW_COPY_AND_ASSIGN(SubresourceSignedExchangeURLLoaderFactory);
@@ -372,6 +428,7 @@
     mojo::MakeStrongBinding(
         std::make_unique<InnerResponseURLLoader>(
             resource_request, *exchange_->inner_response(),
+            url::Origin::Create(exchange_->inner_url()),
             std::make_unique<const storage::BlobDataHandle>(
                 *exchange_->blob_data_handle()),
             *exchange_->completion_status(), std::move(client),
@@ -478,15 +535,18 @@
   if (it == exchanges_.end())
     return nullptr;
   return std::make_unique<PrefetchedNavigationLoaderInterceptor>(
-      it->second->Clone(), GetInfoListForNavigation(outer_url));
+      it->second->Clone(),
+      GetInfoListForNavigation(outer_url, it->second->inner_url()));
 }
 
 std::vector<PrefetchedSignedExchangeInfo>
 PrefetchedSignedExchangeCache::GetInfoListForNavigation(
-    const GURL& outer_url) const {
+    const GURL& outer_url,
+    const GURL& inner_url) const {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   std::vector<PrefetchedSignedExchangeInfo> info_list;
   const url::Origin outer_url_origin = url::Origin::Create(outer_url);
+  const url::Origin inner_url_origin = url::Origin::Create(inner_url);
 
   for (const auto& exchanges_it : exchanges_) {
     const std::unique_ptr<const Entry>& exchange = exchanges_it.second;
@@ -498,7 +558,8 @@
     }
     network::mojom::URLLoaderFactoryPtrInfo loader_factory_info;
     new SubresourceSignedExchangeURLLoaderFactory(
-        mojo::MakeRequest(&loader_factory_info), exchange->Clone());
+        mojo::MakeRequest(&loader_factory_info), exchange->Clone(),
+        inner_url_origin);
     info_list.emplace_back(
         exchange->outer_url(), *exchange->header_integrity(),
         exchange->inner_url(), *exchange->inner_response(),
diff --git a/content/browser/loader/prefetched_signed_exchange_cache.h b/content/browser/loader/prefetched_signed_exchange_cache.h
index 68e83cb..c6856dc 100644
--- a/content/browser/loader/prefetched_signed_exchange_cache.h
+++ b/content/browser/loader/prefetched_signed_exchange_cache.h
@@ -110,7 +110,8 @@
 
   ~PrefetchedSignedExchangeCache();
   std::vector<PrefetchedSignedExchangeInfo> GetInfoListForNavigation(
-      const GURL& outer_url) const;
+      const GURL& outer_url,
+      const GURL& inner_url) const;
 
   EntryMap exchanges_;
 
diff --git a/content/browser/loader/resource_loader.cc b/content/browser/loader/resource_loader.cc
index 7e9106b3..6bd5b8d 100644
--- a/content/browser/loader/resource_loader.cc
+++ b/content/browser/loader/resource_loader.cc
@@ -90,6 +90,9 @@
   response->head.network_accessed = response_info.network_accessed;
   response->head.async_revalidation_requested =
       response_info.async_revalidation_requested;
+  response->head.was_in_prefetch_cache =
+      !(request->load_flags() & net::LOAD_PREFETCH) &&
+      response_info.unused_since_prefetch;
   if (info->ShouldReportRawHeaders()) {
     response->head.raw_request_response_info =
         network::BuildRawRequestResponseInfo(*request, raw_request_headers,
diff --git a/content/browser/media/system_media_controls_notifier.cc b/content/browser/media/system_media_controls_notifier.cc
index 2d701e2..c86ab6d5 100644
--- a/content/browser/media/system_media_controls_notifier.cc
+++ b/content/browser/media/system_media_controls_notifier.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <utility>
 
+#include "content/public/browser/content_browser_client.h"
 #include "services/media_session/public/mojom/constants.mojom.h"
 #include "services/media_session/public/mojom/media_session.mojom.h"
 #include "services/service_manager/public/cpp/connector.h"
@@ -16,6 +17,9 @@
 
 using ABI::Windows::Media::MediaPlaybackStatus;
 
+const int kMinImageSize = 71;
+const int kDesiredImageSize = 150;
+
 SystemMediaControlsNotifier::SystemMediaControlsNotifier(
     service_manager::Connector* connector)
     : connector_(connector) {}
@@ -46,19 +50,28 @@
 
   // Observe the active media controller for changes to playback state and
   // supported actions.
-  media_session::mojom::MediaControllerObserverPtr media_controller_observer;
+  media_session::mojom::MediaControllerObserverPtr
+      media_controller_observer_ptr;
   media_controller_observer_binding_.Bind(
-      mojo::MakeRequest(&media_controller_observer));
-  media_controller_ptr_->AddObserver(std::move(media_controller_observer));
+      mojo::MakeRequest(&media_controller_observer_ptr));
+  media_controller_ptr_->AddObserver(std::move(media_controller_observer_ptr));
+
+  // Observe the active media controller for changes to provided artwork.
+  media_session::mojom::MediaControllerImageObserverPtr image_observer_ptr;
+  media_controller_image_observer_binding_.Bind(
+      mojo::MakeRequest(&image_observer_ptr));
+  media_controller_ptr_->ObserveImages(
+      media_session::mojom::MediaSessionImageType::kArtwork, kMinImageSize,
+      kDesiredImageSize, std::move(image_observer_ptr));
 }
 
 void SystemMediaControlsNotifier::MediaSessionInfoChanged(
-    media_session::mojom::MediaSessionInfoPtr session_info) {
+    media_session::mojom::MediaSessionInfoPtr session_info_ptr) {
   DCHECK(service_);
 
-  session_info_ = std::move(session_info);
-  if (session_info_) {
-    if (session_info_->playback_state ==
+  session_info_ptr_ = std::move(session_info_ptr);
+  if (session_info_ptr_) {
+    if (session_info_ptr_->playback_state ==
         media_session::mojom::MediaPlaybackState::kPlaying) {
       service_->SetPlaybackStatus(
           MediaPlaybackStatus::MediaPlaybackStatus_Playing);
@@ -69,6 +82,58 @@
   } else {
     service_->SetPlaybackStatus(
         MediaPlaybackStatus::MediaPlaybackStatus_Stopped);
+
+    // These steps reference the Media Session Standard
+    // https://wicg.github.io/mediasession/#metadata
+    // 5.3.1 If the active media session is null, unset the media metadata
+    // presented to the platform, and terminate these steps.
+    service_->ClearMetadata();
+  }
+}
+
+void SystemMediaControlsNotifier::MediaSessionMetadataChanged(
+    const base::Optional<media_session::MediaMetadata>& metadata) {
+  DCHECK(service_);
+
+  if (metadata.has_value()) {
+    // 5.3.3 Update the media metadata presented to the platform to match the
+    // metadata for the active media session.
+    // If no title was provided, the title of the tab will be in the title
+    // property.
+    service_->SetTitle(metadata->title);
+
+    // If no artist was provided, then the source URL will be in the artist
+    // property.
+    service_->SetArtist(metadata->artist);
+    service_->UpdateDisplay();
+  } else {
+    // 5.3.2 If the metadata of the active media session is an empty metadata,
+    // unset the media metadata presented to the platform.
+    service_->ClearMetadata();
+  }
+}
+
+void SystemMediaControlsNotifier::MediaControllerImageChanged(
+    media_session::mojom::MediaSessionImageType type,
+    const SkBitmap& bitmap) {
+  DCHECK(service_);
+
+  if (!bitmap.empty()) {
+    // 5.3.4.4.3 If the image format is supported, use the image as the artwork
+    // for display in the platform UI. Otherwise the fetch image algorithm fails
+    // and terminates.
+    service_->SetThumbnail(bitmap);
+  } else {
+    // 5.3.4.2 If metadata's artwork is empty, terminate these steps.
+    // If no images are fetched in the fetch image algorithm, the user agent
+    // may have fallback behavior such as displaying a default image as artwork.
+    // We display the application icon if no artwork is provided.
+    base::Optional<gfx::ImageSkia> icon =
+        GetContentClient()->browser()->GetProductLogo();
+    if (icon.has_value())
+      service_->SetThumbnail(*icon->bitmap());
+    else
+      service_->ClearThumbnail();
   }
 }
 
diff --git a/content/browser/media/system_media_controls_notifier.h b/content/browser/media/system_media_controls_notifier.h
index ed7bc8e..7f41acb 100644
--- a/content/browser/media/system_media_controls_notifier.h
+++ b/content/browser/media/system_media_controls_notifier.h
@@ -27,7 +27,8 @@
 // metadata. It observes changes to the active Media Session and updates the
 // SMTC accordingly.
 class CONTENT_EXPORT SystemMediaControlsNotifier
-    : public media_session::mojom::MediaControllerObserver {
+    : public media_session::mojom::MediaControllerObserver,
+      public media_session::mojom::MediaControllerImageObserver {
  public:
   explicit SystemMediaControlsNotifier(service_manager::Connector* connector);
   ~SystemMediaControlsNotifier() override;
@@ -38,13 +39,18 @@
   void MediaSessionInfoChanged(
       media_session::mojom::MediaSessionInfoPtr session_info) override;
   void MediaSessionMetadataChanged(
-      const base::Optional<media_session::MediaMetadata>& metadata) override {}
+      const base::Optional<media_session::MediaMetadata>& metadata) override;
   void MediaSessionActionsChanged(
       const std::vector<media_session::mojom::MediaSessionAction>& actions)
       override {}
   void MediaSessionChanged(
       const base::Optional<base::UnguessableToken>& request_id) override {}
 
+  // media_session::mojom::MediaControllerImageObserver implementation.
+  void MediaControllerImageChanged(
+      ::media_session::mojom::MediaSessionImageType type,
+      const SkBitmap& bitmap) override;
+
   void SetSystemMediaControlsServiceForTesting(
       system_media_controls::SystemMediaControlsService* service) {
     service_ = service;
@@ -59,11 +65,13 @@
 
   // Tracks current media session state/metadata.
   media_session::mojom::MediaControllerPtr media_controller_ptr_;
-  media_session::mojom::MediaSessionInfoPtr session_info_;
+  media_session::mojom::MediaSessionInfoPtr session_info_ptr_;
 
   // Used to receive updates to the active media controller.
   mojo::Binding<media_session::mojom::MediaControllerObserver>
       media_controller_observer_binding_{this};
+  mojo::Binding<media_session::mojom::MediaControllerImageObserver>
+      media_controller_image_observer_binding_{this};
 
   DISALLOW_COPY_AND_ASSIGN(SystemMediaControlsNotifier);
 };
diff --git a/content/browser/media/system_media_controls_notifier_unittest.cc b/content/browser/media/system_media_controls_notifier_unittest.cc
index ab90552..e6c39a6 100644
--- a/content/browser/media/system_media_controls_notifier_unittest.cc
+++ b/content/browser/media/system_media_controls_notifier_unittest.cc
@@ -18,6 +18,7 @@
 using media_session::mojom::MediaPlaybackState;
 using media_session::mojom::MediaSessionInfo;
 using media_session::mojom::MediaSessionInfoPtr;
+using testing::_;
 using testing::Expectation;
 
 class SystemMediaControlsNotifierTest : public testing::Test {
@@ -48,6 +49,29 @@
 
   void SimulateStopped() { notifier_->MediaSessionInfoChanged(nullptr); }
 
+  void SimulateMetadataChanged(bool empty,
+                               base::string16 title,
+                               base::string16 artist) {
+    if (!empty) {
+      media_session::MediaMetadata metadata;
+      metadata.title = title;
+      metadata.artist = artist;
+      notifier_->MediaSessionMetadataChanged(
+          base::Optional<media_session::MediaMetadata>(metadata));
+    } else {
+      notifier_->MediaSessionMetadataChanged(base::nullopt);
+    }
+  }
+
+  void SimulateImageChanged() {
+    // Need a non-empty SkBitmap so MediaControllerImageChanged doesn't try to
+    // get the icon from ChromeContentBrowserClient.
+    SkBitmap bitmap;
+    bitmap.allocN32Pixels(1, 1);
+    notifier_->MediaControllerImageChanged(
+        media_session::mojom::MediaSessionImageType::kArtwork, bitmap);
+  }
+
   SystemMediaControlsNotifier& notifier() { return *notifier_; }
   system_media_controls::testing::MockSystemMediaControlsService&
   mock_system_media_controls_service() {
@@ -71,14 +95,43 @@
           mock_system_media_controls_service(),
           SetPlaybackStatus(MediaPlaybackStatus::MediaPlaybackStatus_Paused))
           .After(playing);
-  EXPECT_CALL(
-      mock_system_media_controls_service(),
-      SetPlaybackStatus(MediaPlaybackStatus::MediaPlaybackStatus_Stopped))
-      .After(paused);
+  Expectation stopped =
+      EXPECT_CALL(
+          mock_system_media_controls_service(),
+          SetPlaybackStatus(MediaPlaybackStatus::MediaPlaybackStatus_Stopped))
+          .After(paused);
+  EXPECT_CALL(mock_system_media_controls_service(), ClearMetadata())
+      .After(stopped);
 
   SimulatePlaying();
   SimulatePaused();
   SimulateStopped();
 }
 
+TEST_F(SystemMediaControlsNotifierTest, ProperlyUpdatesMetadata) {
+  base::string16 title = L"title";
+  base::string16 artist = L"artist";
+
+  EXPECT_CALL(mock_system_media_controls_service(), SetTitle(title));
+  EXPECT_CALL(mock_system_media_controls_service(), SetArtist(artist));
+  EXPECT_CALL(mock_system_media_controls_service(), ClearMetadata()).Times(0);
+  EXPECT_CALL(mock_system_media_controls_service(), UpdateDisplay());
+
+  SimulateMetadataChanged(false, title, artist);
+}
+
+TEST_F(SystemMediaControlsNotifierTest, ProperlyUpdatesNullMetadata) {
+  EXPECT_CALL(mock_system_media_controls_service(), SetTitle(_)).Times(0);
+  EXPECT_CALL(mock_system_media_controls_service(), SetArtist(_)).Times(0);
+  EXPECT_CALL(mock_system_media_controls_service(), ClearMetadata());
+
+  SimulateMetadataChanged(true, L"", L"");
+}
+
+TEST_F(SystemMediaControlsNotifierTest, ProperlyUpdatesImage) {
+  EXPECT_CALL(mock_system_media_controls_service(), SetThumbnail(_));
+
+  SimulateImageChanged();
+}
+
 }  // namespace content
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc
index 081307b..81e1aae 100644
--- a/content/browser/service_worker/service_worker_browsertest.cc
+++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -1477,7 +1477,7 @@
   FetchOnRegisteredWorker(kPath, &result, &response1, &blob_data_handle);
   ASSERT_EQ(ServiceWorkerFetchDispatcher::FetchEventResult::kGotResponse,
             result);
-  EXPECT_EQ(std::string(), *response1->cache_storage_cache_name);
+  EXPECT_FALSE(response1->cache_storage_cache_name.has_value());
   EXPECT_EQ(network::mojom::FetchResponseSource::kNetwork,
             response1->response_source);
 
@@ -1508,7 +1508,7 @@
   FetchOnRegisteredWorker(kPath, &result, &response1, &blob_data_handle);
   ASSERT_EQ(ServiceWorkerFetchDispatcher::FetchEventResult::kGotResponse,
             result);
-  EXPECT_EQ(std::string(), *response1->cache_storage_cache_name);
+  EXPECT_FALSE(response1->cache_storage_cache_name.has_value());
   EXPECT_EQ(network::mojom::FetchResponseSource::kNetwork,
             response1->response_source);
 
diff --git a/content/browser/web_package/signed_exchange_subresource_prefetch_browsertest.cc b/content/browser/web_package/signed_exchange_subresource_prefetch_browsertest.cc
index 8442067..f8b60715 100644
--- a/content/browser/web_package/signed_exchange_subresource_prefetch_browsertest.cc
+++ b/content/browser/web_package/signed_exchange_subresource_prefetch_browsertest.cc
@@ -5,12 +5,17 @@
 #include <string>
 #include <vector>
 
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/task_runner.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/test_timeouts.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
@@ -22,12 +27,14 @@
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_features.h"
+#include "content/public/common/content_paths.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test.h"
 #include "content/public/test/content_browser_test_utils.h"
 #include "content/shell/browser/shell.h"
 #include "net/base/features.h"
 #include "net/dns/mock_host_resolver.h"
+#include "services/network/cross_origin_read_blocking.h"
 #include "services/network/public/cpp/features.h"
 #include "storage/browser/blob/blob_storage_context.h"
 
@@ -120,6 +127,132 @@
             blob_context));
   }
 
+  // Test that CORB logic works well with prefetched signed exchange
+  // subresources. This test loads a main SXG which signed by
+  // "publisher.example.com", and loads a SXG subresource using a <script> tag.
+  //
+  // When |cross_origin| is set, the SXG subresource is signed by
+  // "crossorigin.example.com", otherwise sined by "publisher.example.com".
+  // |content| is the inner body content of the SXG subresource.
+  // |mime_type| is the MIME tyepe of the inner response of the SXG subresource.
+  // When |has_nosniff| is set, the inner response header of the SXG subresource
+  // has "x-content-type-options: nosniff" header.
+  // |expected_title| is the expected title after loading the SXG page. If the
+  // content load should not be blocked, this should be the title which is set
+  // by executing |content|, otherwise this should be "original title".
+  // |expected_action| is the expected CrossOriginReadBlocking::Action which is
+  // recorded in the histogram.
+  void RunCrossOriginReadBlockingTest(
+      bool cross_origin,
+      const std::string& content,
+      const std::string& mime_type,
+      bool has_nosniff,
+      const std::string& expected_title,
+      network::CrossOriginReadBlocking::Action expected_action) {
+    int script_sxg_fetch_count = 0;
+    int script_fetch_count = 0;
+    const char* prefetch_path = "/prefetch.html";
+    const char* target_sxg_path = "/target.sxg";
+    const char* target_path = "/target.html";
+    const char* script_sxg_path = "/script_js.sxg";
+    const char* script_path = "/script.js";
+
+    base::RunLoop script_sxg_prefetch_waiter;
+    RegisterRequestMonitor(embedded_test_server(), script_sxg_path,
+                           &script_sxg_fetch_count,
+                           &script_sxg_prefetch_waiter);
+    base::RunLoop script_prefetch_waiter;
+    RegisterRequestMonitor(embedded_test_server(), script_path,
+                           &script_fetch_count, &script_prefetch_waiter);
+    RegisterRequestHandler(embedded_test_server());
+    ASSERT_TRUE(embedded_test_server()->Start());
+
+    const GURL target_sxg_url = embedded_test_server()->GetURL(target_sxg_path);
+    const GURL target_url =
+        embedded_test_server()->GetURL("publisher.example.com", target_path);
+    const GURL script_sxg_url = embedded_test_server()->GetURL(script_sxg_path);
+    const GURL script_url = embedded_test_server()->GetURL(
+        cross_origin ? "crossorigin.example.com" : "publisher.example.com",
+        script_path);
+
+    const net::SHA256HashValue target_header_integrity = {{0x01}};
+    const net::SHA256HashValue script_header_integrity = {{0x02}};
+    const std::string script_header_integrity_string =
+        GetHeaderIntegrityString(script_header_integrity);
+
+    const std::string outer_link_header = base::StringPrintf(
+        "<%s>;"
+        "rel=\"alternate\";"
+        "type=\"application/signed-exchange;v=b3\";"
+        "anchor=\"%s\"",
+        script_sxg_url.spec().c_str(), script_url.spec().c_str());
+    const std::string inner_link_headers = base::StringPrintf(
+        "Link: "
+        "<%s>;rel=\"allowed-alt-sxg\";header-integrity=\"%s\","
+        "<%s>;rel=\"preload\";as=\"script\"",
+        script_url.spec().c_str(), script_header_integrity_string.c_str(),
+        script_url.spec().c_str());
+
+    RegisterResponse(
+        prefetch_path,
+        ResponseEntry(base::StringPrintf(
+            "<body><link rel='prefetch' href='%s'></body>", target_sxg_path)));
+    RegisterResponse(
+        script_path,
+        ResponseEntry("document.title=\"from server\";", "text/javascript"));
+    RegisterResponse(
+        target_sxg_path,
+        ResponseEntry(base::StringPrintf(
+                          "<head><script src=\"%s\"></script><title>original "
+                          "title</title>"
+                          "</head>",
+                          script_url.spec().c_str()),
+                      "application/signed-exchange;v=b3",
+                      {{"x-content-type-options", "nosniff"},
+                       {"link", outer_link_header}}));
+    RegisterResponse(script_sxg_path,
+                     ResponseEntry(content, "application/signed-exchange;v=b3",
+                                   {{"x-content-type-options", "nosniff"}}));
+    std::vector<std::string> script_inner_response_headers;
+    if (has_nosniff) {
+      script_inner_response_headers.emplace_back(
+          "x-content-type-options: nosniff");
+    }
+    MockSignedExchangeHandlerFactory factory(
+        {MockSignedExchangeHandlerParams(
+             target_sxg_url, SignedExchangeLoadResult::kSuccess, net::OK,
+             target_url, "text/html", {inner_link_headers},
+             target_header_integrity),
+         MockSignedExchangeHandlerParams(
+             script_sxg_url, SignedExchangeLoadResult::kSuccess, net::OK,
+             script_url, mime_type, script_inner_response_headers,
+             script_header_integrity)});
+    ScopedSignedExchangeHandlerFactory scoped_factory(&factory);
+
+    NavigateToURL(shell(), embedded_test_server()->GetURL(prefetch_path));
+    script_sxg_prefetch_waiter.Run();
+    EXPECT_EQ(1, script_sxg_fetch_count);
+    EXPECT_EQ(0, script_fetch_count);
+
+    WaitUntilLoaded(target_sxg_url);
+    WaitUntilLoaded(script_sxg_url);
+
+    EXPECT_EQ(2u, GetCachedExchanges().size());
+
+    {
+      base::HistogramTester histograms;
+      NavigateToURLAndWaitTitle(target_sxg_url, expected_title);
+      histograms.ExpectBucketCount(
+          "SiteIsolation.XSD.Browser.Action",
+          network::CrossOriginReadBlocking::Action::kResponseStarted, 1);
+      histograms.ExpectBucketCount("SiteIsolation.XSD.Browser.Action",
+                                   expected_action, 1);
+    }
+
+    EXPECT_EQ(1, script_sxg_fetch_count);
+    EXPECT_EQ(0, script_fetch_count);
+  }
+
  private:
   static void SetBlobLimitsOnIO(
       scoped_refptr<ChromeBlobStorageContext> context) {
@@ -476,6 +609,157 @@
 }
 
 IN_PROC_BROWSER_TEST_P(SignedExchangeSubresourcePrefetchBrowserTest,
+                       PrefetchAlternativeSubresourceSXG_ImageSrcsetAndSizes) {
+  int image1_sxg_fetch_count = 0;
+  int image1_fetch_count = 0;
+  int image2_sxg_fetch_count = 0;
+  int image2_fetch_count = 0;
+  const char* prefetch_path = "/prefetch.html";
+  const char* target_sxg_path = "/target.sxg";
+  const char* target_path = "/target.html";
+  const char* image1_sxg_path = "/image1_png.sxg";
+  const char* image1_path = "/image1.png";
+  const char* image2_sxg_path = "/image2_png.sxg";
+  const char* image2_path = "/image2.png";
+
+  base::RunLoop image1_sxg_prefetch_waiter;
+  RegisterRequestMonitor(embedded_test_server(), image1_sxg_path,
+                         &image1_sxg_fetch_count, &image1_sxg_prefetch_waiter);
+  base::RunLoop image1_prefetch_waiter;
+  RegisterRequestMonitor(embedded_test_server(), image1_path,
+                         &image1_fetch_count, &image1_prefetch_waiter);
+  base::RunLoop image2_sxg_prefetch_waiter;
+  RegisterRequestMonitor(embedded_test_server(), image2_sxg_path,
+                         &image2_sxg_fetch_count, &image2_sxg_prefetch_waiter);
+  base::RunLoop image2_prefetch_waiter;
+  RegisterRequestMonitor(embedded_test_server(), image2_path,
+                         &image2_fetch_count, &image2_prefetch_waiter);
+  RegisterRequestHandler(embedded_test_server());
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  const GURL target_sxg_url = embedded_test_server()->GetURL(target_sxg_path);
+  const GURL target_url = embedded_test_server()->GetURL(target_path);
+  const GURL image1_sxg_url = embedded_test_server()->GetURL(image1_sxg_path);
+  const GURL image1_url = embedded_test_server()->GetURL(image1_path);
+  const GURL image2_sxg_url = embedded_test_server()->GetURL(image2_sxg_path);
+  const GURL image2_url = embedded_test_server()->GetURL(image2_path);
+
+  std::string image_contents;
+  {
+    base::ScopedAllowBlockingForTesting allow_blocking;
+    base::FilePath path;
+    ASSERT_TRUE(base::PathService::Get(content::DIR_TEST_DATA, &path));
+    path = path.AppendASCII("loader/empty16x16.png");
+    ASSERT_TRUE(base::PathExists(path));
+    ASSERT_TRUE(base::ReadFileToString(path, &image_contents));
+  }
+
+  const net::SHA256HashValue target_header_integrity = {{0x01}};
+  const net::SHA256HashValue image1_header_integrity = {{0x02}};
+  const net::SHA256HashValue image2_header_integrity = {{0x03}};
+  const std::string image1_header_integrity_string =
+      GetHeaderIntegrityString(image1_header_integrity);
+  const std::string image2_header_integrity_string =
+      GetHeaderIntegrityString(image2_header_integrity);
+
+  const std::string outer_link_header = base::StringPrintf(
+      "<%s>;"
+      "rel=\"alternate\";"
+      "type=\"application/signed-exchange;v=b3\";"
+      "anchor=\"%s\","
+      "<%s>;"
+      "rel=\"alternate\";"
+      "type=\"application/signed-exchange;v=b3\";"
+      "anchor=\"%s\"",
+      image1_sxg_url.spec().c_str(), image1_url.spec().c_str(),
+      image2_sxg_url.spec().c_str(), image2_url.spec().c_str());
+  const std::string inner_link_headers = base::StringPrintf(
+      "Link: "
+      "<%s>;rel=\"allowed-alt-sxg\";header-integrity=\"%s\","
+      "<%s>;rel=\"allowed-alt-sxg\";header-integrity=\"%s\","
+      "<%s>;rel=\"preload\";as=\"image\";"
+      // imagesrcset says the size of image1 is 320, and the size of image2 is
+      // 160.
+      "imagesrcset=\"%s 320w, %s 160w\";"
+      // imagesizes says the size of the image is 320. So image1 is selected.
+      "imagesizes=\"320px\"",
+      image1_url.spec().c_str(), image1_header_integrity_string.c_str(),
+      image2_url.spec().c_str(), image2_header_integrity_string.c_str(),
+      image2_url.spec().c_str(), image1_url.spec().c_str(),
+      image2_url.spec().c_str());
+
+  RegisterResponse(
+      prefetch_path,
+      ResponseEntry(base::StringPrintf(
+          "<body><link rel='prefetch' href='%s'></body>", target_sxg_path)));
+  RegisterResponse(image1_path, ResponseEntry(image_contents, "image/png"));
+  RegisterResponse(image2_path, ResponseEntry(image_contents, "image/png"));
+  RegisterResponse(
+      target_sxg_path,
+      // We mock the SignedExchangeHandler, so just return a HTML
+      // content as "application/signed-exchange;v=b3".
+      ResponseEntry(base::StringPrintf(
+                        "<head>"
+                        "<title>Prefetch Target (SXG)</title>"
+                        "</head>"
+                        "<img src=\"%s\" onload=\"document.title='done'\">",
+                        image1_url.spec().c_str()),
+                    "application/signed-exchange;v=b3",
+                    {{"x-content-type-options", "nosniff"},
+                     {"link", outer_link_header}}));
+  RegisterResponse(
+      image1_sxg_path,
+      // We mock the SignedExchangeHandler, so just return a JS
+      // content as "application/signed-exchange;v=b3".
+      ResponseEntry(image_contents, "application/signed-exchange;v=b3",
+                    {{"x-content-type-options", "nosniff"}}));
+  MockSignedExchangeHandlerFactory factory(
+      {MockSignedExchangeHandlerParams(
+           target_sxg_url, SignedExchangeLoadResult::kSuccess, net::OK,
+           target_url, "text/html", {inner_link_headers},
+           target_header_integrity),
+       MockSignedExchangeHandlerParams(
+           image1_sxg_url, SignedExchangeLoadResult::kSuccess, net::OK,
+           image1_url, "image/png", {}, image1_header_integrity),
+       MockSignedExchangeHandlerParams(
+           image2_sxg_url, SignedExchangeLoadResult::kSuccess, net::OK,
+           image2_url, "image/png", {}, image2_header_integrity)});
+  ScopedSignedExchangeHandlerFactory scoped_factory(&factory);
+
+  NavigateToURL(shell(), embedded_test_server()->GetURL(prefetch_path));
+  image1_sxg_prefetch_waiter.Run();
+  EXPECT_EQ(1, image1_sxg_fetch_count);
+  EXPECT_EQ(0, image1_fetch_count);
+  EXPECT_EQ(0, image2_sxg_fetch_count);
+  EXPECT_EQ(0, image2_fetch_count);
+
+  WaitUntilLoaded(target_sxg_url);
+  WaitUntilLoaded(image1_sxg_url);
+
+  const auto cached_exchanges = GetCachedExchanges();
+  EXPECT_EQ(2u, cached_exchanges.size());
+
+  const auto target_it = cached_exchanges.find(target_sxg_url);
+  ASSERT_TRUE(target_it != cached_exchanges.end());
+  EXPECT_EQ(target_sxg_url, target_it->second->outer_url());
+  EXPECT_EQ(target_url, target_it->second->inner_url());
+  EXPECT_EQ(target_header_integrity, *target_it->second->header_integrity());
+
+  const auto image1_it = cached_exchanges.find(image1_sxg_url);
+  ASSERT_TRUE(image1_it != cached_exchanges.end());
+  EXPECT_EQ(image1_sxg_url, image1_it->second->outer_url());
+  EXPECT_EQ(image1_url, image1_it->second->inner_url());
+  EXPECT_EQ(image1_header_integrity, *image1_it->second->header_integrity());
+
+  NavigateToURLAndWaitTitle(target_sxg_url, "done");
+
+  EXPECT_EQ(1, image1_sxg_fetch_count);
+  EXPECT_EQ(0, image1_fetch_count);
+  EXPECT_EQ(0, image2_sxg_fetch_count);
+  EXPECT_EQ(0, image2_fetch_count);
+}
+
+IN_PROC_BROWSER_TEST_P(SignedExchangeSubresourcePrefetchBrowserTest,
                        PrefetchAlternativeSubresourceSXG_CrossOrigin) {
   int script_sxg_fetch_count = 0;
   int script_fetch_count = 0;
@@ -1400,6 +1684,38 @@
   }
 }
 
+IN_PROC_BROWSER_TEST_P(SignedExchangeSubresourcePrefetchBrowserTest,
+                       CrossOriginReadBlocking_AllowedAfterSniffing) {
+  RunCrossOriginReadBlockingTest(
+      true /* cross_origin */, "document.title=\"done\"", "text/javascript",
+      false /* has_nosniff */, "done",
+      network::CrossOriginReadBlocking::Action::kAllowedAfterSniffing);
+}
+
+IN_PROC_BROWSER_TEST_P(SignedExchangeSubresourcePrefetchBrowserTest,
+                       CrossOriginReadBlocking_BlockedAfterSniffing) {
+  RunCrossOriginReadBlockingTest(
+      true /* cross_origin */, "<!DOCTYPE html>hello;", "text/html",
+      false /* has_nosniff */, "original title",
+      network::CrossOriginReadBlocking::Action::kBlockedAfterSniffing);
+}
+
+IN_PROC_BROWSER_TEST_P(SignedExchangeSubresourcePrefetchBrowserTest,
+                       CrossOriginReadBlocking_AllowedWithoutSniffing) {
+  RunCrossOriginReadBlockingTest(
+      false /* cross_origin */, "document.title=\"done\"", "text/javascript",
+      true /* has_nosniff */, "done",
+      network::CrossOriginReadBlocking::Action::kAllowedWithoutSniffing);
+}
+
+IN_PROC_BROWSER_TEST_P(SignedExchangeSubresourcePrefetchBrowserTest,
+                       CrossOriginReadBlocking_BlockedWithoutSniffing) {
+  RunCrossOriginReadBlockingTest(
+      true /* cross_origin */, "<!DOCTYPE html>hello;", "text/html",
+      true /* has_nosniff */, "original title",
+      network::CrossOriginReadBlocking::Action::kBlockedWithoutSniffing);
+}
+
 INSTANTIATE_TEST_SUITE_P(
     SignedExchangeSubresourcePrefetchBrowserTest,
     SignedExchangeSubresourcePrefetchBrowserTest,
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index e81820e..3b583e59 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -392,10 +392,6 @@
   if (base::FeatureList::IsEnabled(features::kLazyImageVisibleLoadTimeMetrics))
     WebRuntimeFeatures::EnableLazyImageVisibleLoadTimeMetrics(true);
 
-  WebRuntimeFeatures::EnableRestrictDeviceSensorEventsToSecureContexts(
-      base::FeatureList::IsEnabled(
-          blink::features::kRestrictDeviceSensorEventsToSecureContexts));
-
   WebRuntimeFeatures::EnableRestrictLazyFrameLoadingToDataSaver(
       base::GetFieldTrialParamByFeatureAsBool(
           features::kLazyFrameLoading,
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index ce9d0ed..b0b6dd2 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -963,6 +963,10 @@
   return blink::UserAgentMetadata();
 }
 
+base::Optional<gfx::ImageSkia> ContentBrowserClient::GetProductLogo() const {
+  return base::nullopt;
+}
+
 bool ContentBrowserClient::IsBuiltinComponent(BrowserContext* browser_context,
                                               const url::Origin& origin) {
   return false;
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index 449941d..061fbe9 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -1535,6 +1535,10 @@
   // Returns user agent metadata. Content may cache this value.
   virtual blink::UserAgentMetadata GetUserAgentMetadata() const;
 
+  // Returns a 256x256 transparent background image of the product logo, i.e.
+  // the browser icon, if available.
+  virtual base::Optional<gfx::ImageSkia> GetProductLogo() const;
+
   // Returns whether |origin| should be considered a integral component similar
   // to native code, and as such whether its log messages should be recorded.
   virtual bool IsBuiltinComponent(BrowserContext* browser_context,
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index 8e55869..8ad2c14 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -464,8 +464,6 @@
     "seccomp_sandbox_status_android.h",
     "service_worker/controller_service_worker_connector.cc",
     "service_worker/controller_service_worker_connector.h",
-    "service_worker/controller_service_worker_impl.cc",
-    "service_worker/controller_service_worker_impl.h",
     "service_worker/embedded_worker_instance_client_impl.cc",
     "service_worker/embedded_worker_instance_client_impl.h",
     "service_worker/navigation_preload_request.cc",
@@ -484,12 +482,8 @@
     "service_worker/service_worker_provider_state_for_client.h",
     "service_worker/service_worker_subresource_loader.cc",
     "service_worker/service_worker_subresource_loader.h",
-    "service_worker/service_worker_timeout_timer.cc",
-    "service_worker/service_worker_timeout_timer.h",
     "service_worker/service_worker_type_converters.cc",
     "service_worker/service_worker_type_converters.h",
-    "service_worker/service_worker_type_util.cc",
-    "service_worker/service_worker_type_util.h",
     "service_worker/web_service_worker_provider_impl.cc",
     "service_worker/web_service_worker_provider_impl.h",
     "skia_benchmarking_extension.cc",
diff --git a/content/renderer/media/stream/media_stream_center.cc b/content/renderer/media/stream/media_stream_center.cc
index e3e3f58..47b1d41 100644
--- a/content/renderer/media/stream/media_stream_center.cc
+++ b/content/renderer/media/stream/media_stream_center.cc
@@ -226,13 +226,6 @@
   // kSampleFormatS16 is the format used for all audio input streams.
   settings.sample_size =
       media::SampleFormatToBitsPerChannel(media::kSampleFormatS16);
-
-  ProcessedLocalAudioSource* const processed_source =
-      ProcessedLocalAudioSource::From(source);
-  settings.volume = processed_source
-                        ? static_cast<double>(processed_source->Volume()) /
-                              processed_source->MaxVolume()
-                        : 1.0;
 }
 
 }  // namespace content
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 084bff7..f7e38abe 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -3054,16 +3054,6 @@
   pending_context_menus_.Remove(request_id);
 }
 
-void RenderFrameImpl::BindToFrame(blink::WebNavigationControl* frame) {
-  DCHECK(!frame_);
-
-  std::pair<FrameMap::iterator, bool> result =
-      g_frame_map.Get().emplace(frame, this);
-  CHECK(result.second) << "Inserting a duplicate item.";
-
-  frame_ = frame;
-}
-
 blink::WebPlugin* RenderFrameImpl::CreatePlugin(
     const WebPluginInfo& info,
     const blink::WebPluginParams& params,
@@ -3991,6 +3981,16 @@
 #endif
 }
 
+void RenderFrameImpl::BindToFrame(blink::WebNavigationControl* frame) {
+  DCHECK(!frame_);
+
+  std::pair<FrameMap::iterator, bool> result =
+      g_frame_map.Get().emplace(frame, this);
+  CHECK(result.second) << "Inserting a duplicate item.";
+
+  frame_ = frame;
+}
+
 blink::WebPlugin* RenderFrameImpl::CreatePlugin(
     const blink::WebPluginParams& params) {
   blink::WebPlugin* plugin = nullptr;
@@ -5275,10 +5275,6 @@
         old_extra_data->TakeNavigationResponseOverrideOwnership();
   }
 
-  // Set an empty HTTP origin header for non GET methods if none is currently
-  // present.
-  request.SetHttpOriginIfNeeded(WebSecurityOrigin::CreateUnique());
-
   WebDocument frame_document = frame_->GetDocument();
   if (!request.GetExtraData())
     request.SetExtraData(std::make_unique<RequestExtraData>());
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index a590b85..bafcf9a 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -464,7 +464,6 @@
   int ShowContextMenu(ContextMenuClient* client,
                       const ContextMenuParams& params) override;
   void CancelContextMenu(int request_id) override;
-  void BindToFrame(blink::WebNavigationControl* frame) override;
   blink::WebPlugin* CreatePlugin(
       const WebPluginInfo& info,
       const blink::WebPluginParams& params,
@@ -660,6 +659,7 @@
                         SerializeAsMHTMLCallback callback) override;
 
   // blink::WebLocalFrameClient implementation:
+  void BindToFrame(blink::WebNavigationControl* frame) override;
   blink::WebPlugin* CreatePlugin(const blink::WebPluginParams& params) override;
   blink::WebMediaPlayer* CreateMediaPlayer(
       const blink::WebMediaPlayerSource& source,
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc
index 67f40c5..32f5e253 100644
--- a/content/renderer/renderer_blink_platform_impl.cc
+++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -1050,6 +1050,13 @@
       worker);
 }
 
+bool RendererBlinkPlatformImpl::IsExcludedHeaderForServiceWorkerFetchEvent(
+    const blink::WebString& header_name) {
+  return GetContentClient()
+      ->renderer()
+      ->IsExcludedHeaderForServiceWorkerFetchEvent(header_name.Ascii());
+}
+
 //------------------------------------------------------------------------------
 
 void RendererBlinkPlatformImpl::RecordMetricsForBackgroundedRendererPurge() {
diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h
index 7b55027..ba77a97 100644
--- a/content/renderer/renderer_blink_platform_impl.h
+++ b/content/renderer/renderer_blink_platform_impl.h
@@ -199,6 +199,8 @@
   void DidStartWorkerThread() override;
   void WillStopWorkerThread() override;
   void WorkerContextCreated(const v8::Local<v8::Context>& worker) override;
+  bool IsExcludedHeaderForServiceWorkerFetchEvent(
+      const blink::WebString& header_name) override;
 
   void RecordMetricsForBackgroundedRendererPurge() override;
 
diff --git a/content/renderer/service_worker/controller_service_worker_impl.cc b/content/renderer/service_worker/controller_service_worker_impl.cc
deleted file mode 100644
index fdbc316..0000000
--- a/content/renderer/service_worker/controller_service_worker_impl.cc
+++ /dev/null
@@ -1,39 +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/renderer/service_worker/controller_service_worker_impl.h"
-
-#include "base/sequenced_task_runner.h"
-#include "content/renderer/service_worker/service_worker_context_client.h"
-
-namespace content {
-
-ControllerServiceWorkerImpl::ControllerServiceWorkerImpl(
-    blink::mojom::ControllerServiceWorkerRequest request,
-    base::WeakPtr<ServiceWorkerContextClient> context_client,
-    scoped_refptr<base::SequencedTaskRunner> task_runner)
-    : context_client_(std::move(context_client)),
-      task_runner_(std::move(task_runner)) {
-  bindings_.AddBinding(this, std::move(request), task_runner_);
-}
-
-ControllerServiceWorkerImpl::~ControllerServiceWorkerImpl() = default;
-
-void ControllerServiceWorkerImpl::Clone(
-    blink::mojom::ControllerServiceWorkerRequest request) {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
-  bindings_.AddBinding(this, std::move(request), task_runner_);
-}
-
-void ControllerServiceWorkerImpl::DispatchFetchEvent(
-    blink::mojom::DispatchFetchEventParamsPtr params,
-    blink::mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
-    DispatchFetchEventCallback callback) {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
-  DCHECK(context_client_);
-  context_client_->DispatchOrQueueFetchEvent(
-      std::move(params), std::move(response_callback), std::move(callback));
-}
-
-}  // namespace content
diff --git a/content/renderer/service_worker/controller_service_worker_impl.h b/content/renderer/service_worker/controller_service_worker_impl.h
deleted file mode 100644
index d2e56d8..0000000
--- a/content/renderer/service_worker/controller_service_worker_impl.h
+++ /dev/null
@@ -1,68 +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_RENDERER_SERVICE_WORKER_CONTROLLER_SERVICE_WORKER_IMPL_H_
-#define CONTENT_RENDERER_SERVICE_WORKER_CONTROLLER_SERVICE_WORKER_IMPL_H_
-
-#include <utility>
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
-#include "third_party/blink/public/mojom/service_worker/controller_service_worker.mojom.h"
-
-namespace base {
-class SequencedTaskRunner;
-}
-
-namespace content {
-
-class ServiceWorkerContextClient;
-
-// An instance of this class is created on the service worker thread
-// when ServiceWorkerContextClient's WorkerContextData is created.
-// This implements blink::mojom::ControllerServiceWorker and its Mojo endpoint
-// is connected by each controllee and also by the ServiceWorkerProviderHost
-// in the browser process.
-// Subresource requests made by the controllees are sent to this class as
-// Fetch events via the Mojo endpoints.
-//
-// TODO(kinuko): Implement self-killing timer, that does something similar to
-// what ServiceWorkerVersion::StopWorkerIfIdle did in the browser process in
-// the non-S13n codepath.
-class ControllerServiceWorkerImpl
-    : public blink::mojom::ControllerServiceWorker {
- public:
-  // |context_client|'s weak pointer is the one that is bound to the worker
-  // thread. (It should actually outlive this instance, but allow us to make
-  // sure the thread safety)
-  ControllerServiceWorkerImpl(
-      blink::mojom::ControllerServiceWorkerRequest request,
-      base::WeakPtr<ServiceWorkerContextClient> context_client,
-      scoped_refptr<base::SequencedTaskRunner> task_runner);
-  ~ControllerServiceWorkerImpl() override;
-
-  // blink::mojom::ControllerServiceWorker:
-  void DispatchFetchEvent(
-      blink::mojom::DispatchFetchEventParamsPtr params,
-      blink::mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
-      DispatchFetchEventCallback callback) override;
-  void Clone(blink::mojom::ControllerServiceWorkerRequest request) override;
-
- private:
-  // Connected by the ServiceWorkerProviderHost in the browser process
-  // and by the controllees.
-  mojo::BindingSet<blink::mojom::ControllerServiceWorker> bindings_;
-
-  // This should never be null because |context_client_| owns |this|.
-  // TODO(falken): Make this a raw pointer.
-  base::WeakPtr<ServiceWorkerContextClient> context_client_;
-
-  scoped_refptr<base::SequencedTaskRunner> task_runner_;
-
-  DISALLOW_COPY_AND_ASSIGN(ControllerServiceWorkerImpl);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_SERVICE_WORKER_CONTROLLER_SERVICE_WORKER_IMPL_H_
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index 086f4a00..4446b64 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -35,14 +35,11 @@
 #include "content/renderer/loader/web_url_request_util.h"
 #include "content/renderer/render_thread_impl.h"
 #include "content/renderer/renderer_blink_platform_impl.h"
-#include "content/renderer/service_worker/controller_service_worker_impl.h"
 #include "content/renderer/service_worker/embedded_worker_instance_client_impl.h"
 #include "content/renderer/service_worker/navigation_preload_request.h"
 #include "content/renderer/service_worker/service_worker_fetch_context_impl.h"
 #include "content/renderer/service_worker/service_worker_network_provider_for_service_worker.h"
-#include "content/renderer/service_worker/service_worker_timeout_timer.h"
 #include "content/renderer/service_worker/service_worker_type_converters.h"
-#include "content/renderer/service_worker/service_worker_type_util.h"
 #include "net/base/net_errors.h"
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
@@ -58,15 +55,7 @@
 #include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
 #include "third_party/blink/public/platform/interface_provider.h"
-#include "third_party/blink/public/platform/modules/background_fetch/web_background_fetch_registration.h"
-#include "third_party/blink/public/platform/modules/notifications/web_notification_data.h"
-#include "third_party/blink/public/platform/modules/payments/web_payment_handler_response.h"
-#include "third_party/blink/public/platform/modules/payments/web_payment_request_event_data.h"
-#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_clients_info.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_error.h"
-#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_request.h"
-#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_response.h"
-#include "third_party/blink/public/platform/notification_data_conversions.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/url_conversion.h"
 #include "third_party/blink/public/platform/web_blob_registry.h"
@@ -88,211 +77,19 @@
 constexpr char kServiceWorkerContextClientScope[] =
     "ServiceWorkerContextClient";
 
-class StreamHandleListener
-    : public blink::WebServiceWorkerStreamHandle::Listener {
- public:
-  StreamHandleListener(
-      blink::mojom::ServiceWorkerStreamCallbackPtr callback_ptr,
-      std::unique_ptr<ServiceWorkerTimeoutTimer::StayAwakeToken> token)
-      : callback_ptr_(std::move(callback_ptr)), token_(std::move(token)) {}
-
-  ~StreamHandleListener() override {}
-
-  void OnAborted() override {
-    callback_ptr_->OnAborted();
-    token_.reset();
-  }
-
-  void OnCompleted() override {
-    callback_ptr_->OnCompleted();
-    token_.reset();
-  }
-
- private:
-  blink::mojom::ServiceWorkerStreamCallbackPtr callback_ptr_;
-  std::unique_ptr<ServiceWorkerTimeoutTimer::StayAwakeToken> token_;
-};
-
-blink::WebServiceWorkerClientInfo ToWebServiceWorkerClientInfo(
-    blink::mojom::ServiceWorkerClientInfoPtr client_info) {
-  DCHECK(!client_info->client_uuid.empty());
-
-  blink::WebServiceWorkerClientInfo web_client_info;
-
-  web_client_info.uuid = blink::WebString::FromASCII(client_info->client_uuid);
-  web_client_info.page_hidden = client_info->page_hidden;
-  web_client_info.is_focused = client_info->is_focused;
-  web_client_info.url = client_info->url;
-  web_client_info.frame_type = client_info->frame_type;
-  web_client_info.client_type = client_info->client_type;
-
-  return web_client_info;
-}
-
-// Converts a blink::mojom::BackgroundFetchRegistrationPtr object to
-// a blink::WebBackgroundFetchRegistration object.
-blink::WebBackgroundFetchRegistration ToWebBackgroundFetchRegistration(
-    blink::mojom::BackgroundFetchRegistrationPtr registration) {
-  return blink::WebBackgroundFetchRegistration(
-      blink::WebString::FromUTF8(registration->registration_data->developer_id),
-      registration->registration_data->upload_total,
-      registration->registration_data->uploaded,
-      registration->registration_data->download_total,
-      registration->registration_data->downloaded,
-      registration->registration_data->result,
-      registration->registration_data->failure_reason,
-      mojo::ScopedMessagePipeHandle(
-          registration->registration_interface.PassHandle()),
-      registration->registration_interface.version());
-}
-
-// This is complementary to ConvertWebKitPriorityToNetPriority, defined in
-// web_url_loader_impl.cc.
-WebURLRequest::Priority ConvertNetPriorityToWebKitPriority(
-    const net::RequestPriority priority) {
-  switch (priority) {
-    case net::HIGHEST:
-      return WebURLRequest::Priority::kVeryHigh;
-    case net::MEDIUM:
-      return WebURLRequest::Priority::kHigh;
-    case net::LOW:
-      return WebURLRequest::Priority::kMedium;
-    case net::LOWEST:
-      return WebURLRequest::Priority::kLow;
-    case net::IDLE:
-      return WebURLRequest::Priority::kVeryLow;
-    case net::THROTTLED:
-      NOTREACHED();
-      return WebURLRequest::Priority::kVeryLow;
-  }
-
-  NOTREACHED();
-  return WebURLRequest::Priority::kVeryLow;
-}
-
-// Finds an event callback keyed by |event_id| from |map|, and runs the callback
-// with |args|. Returns true if the callback was found and called, otherwise
-// returns false.
-template <typename MapType, class... Args>
-bool RunEventCallback(MapType* map,
-                      ServiceWorkerTimeoutTimer* timer,
-                      int event_id,
-                      Args... args) {
-  auto iter = map->find(event_id);
-  // The event may have been aborted.
-  if (iter == map->end())
-    return false;
-  std::move(iter->second).Run(args...);
-  map->erase(iter);
-  timer->EndEvent(event_id);
-  return true;
-}
-
-// Creates a callback which takes an |event_id| and |status|, which calls the
-// given event's callback with the given status and removes it from |map|.
-template <typename MapType, typename... Args>
-ServiceWorkerTimeoutTimer::AbortCallback CreateAbortCallback(MapType* map,
-                                                             Args... args) {
-  return base::BindOnce(
-      [](MapType* map, Args... args, int event_id,
-         blink::mojom::ServiceWorkerEventStatus status) {
-        auto iter = map->find(event_id);
-        DCHECK(iter != map->end());
-        std::move(iter->second).Run(status, std::forward<Args>(args)...);
-        map->erase(iter);
-      },
-      map, std::forward<Args>(args)...);
-}
-
-bool IsExcludedHeaderForServiceWorkerFetchEvent(
-    const std::string& header_name) {
-  // Excluding Sec-Fetch-... headers as suggested in
-  // https://crbug.com/949997#c4.
-  if (base::StartsWith(header_name, "sec-fetch-",
-                       base::CompareCase::INSENSITIVE_ASCII)) {
-    return true;
-  }
-
-  if (GetContentClient()
-          ->renderer()
-          ->IsExcludedHeaderForServiceWorkerFetchEvent(header_name)) {
-    return true;
-  }
-
-  return false;
-}
-
 }  // namespace
 
 // Holds data that needs to be bound to the worker context on the
 // worker thread.
 struct ServiceWorkerContextClient::WorkerContextData {
   explicit WorkerContextData(ServiceWorkerContextClient* owner)
-      : service_worker_binding(owner),
-        weak_factory(owner),
-        proxy_weak_factory(owner->proxy_) {}
+      : weak_factory(owner), proxy_weak_factory(owner->proxy_) {}
 
   ~WorkerContextData() { DCHECK(thread_checker.CalledOnValidThread()); }
 
-  mojo::Binding<blink::mojom::ServiceWorker> service_worker_binding;
-
-  // Maps for inflight event callbacks.
-  // These are mapped from an event id issued from ServiceWorkerTimeoutTimer to
-  // the Mojo callback to notify the end of the event.
-  std::map<int, DispatchInstallEventCallback> install_event_callbacks;
-  std::map<int, DispatchActivateEventCallback> activate_event_callbacks;
-  std::map<int, DispatchBackgroundFetchAbortEventCallback>
-      background_fetch_abort_event_callbacks;
-  std::map<int, DispatchBackgroundFetchClickEventCallback>
-      background_fetch_click_event_callbacks;
-  std::map<int, DispatchBackgroundFetchFailEventCallback>
-      background_fetch_fail_event_callbacks;
-  std::map<int, DispatchBackgroundFetchSuccessEventCallback>
-      background_fetched_event_callbacks;
-  std::map<int, DispatchSyncEventCallback> sync_event_callbacks;
-  std::map<int, DispatchPeriodicSyncEventCallback>
-      periodic_sync_event_callbacks;
-  std::map<int, payments::mojom::PaymentHandlerResponseCallbackPtr>
-      abort_payment_result_callbacks;
-  std::map<int, DispatchCanMakePaymentEventCallback>
-      abort_payment_event_callbacks;
-  std::map<int, DispatchCanMakePaymentEventCallback>
-      can_make_payment_event_callbacks;
-  std::map<int, DispatchPaymentRequestEventCallback>
-      payment_request_event_callbacks;
-  std::map<int, DispatchNotificationClickEventCallback>
-      notification_click_event_callbacks;
-  std::map<int, DispatchNotificationCloseEventCallback>
-      notification_close_event_callbacks;
-  std::map<int, DispatchPushEventCallback> push_event_callbacks;
-  std::map<int, DispatchFetchEventCallback> fetch_event_callbacks;
-  std::map<int, DispatchCookieChangeEventCallback>
-      cookie_change_event_callbacks;
-  std::map<int, DispatchExtendableMessageEventCallback> message_event_callbacks;
-
-  // Maps for response callbacks.
-  // These are mapped from an event id to the Mojo interface pointer which is
-  // passed from the relevant DispatchSomeEvent() method.
-  std::map<int, payments::mojom::PaymentHandlerResponseCallbackPtr>
-      can_make_payment_result_callbacks;
-  std::map<int, payments::mojom::PaymentHandlerResponseCallbackPtr>
-      payment_response_callbacks;
-  std::map<int, blink::mojom::ServiceWorkerFetchResponseCallbackPtr>
-      fetch_response_callbacks;
-
   // Inflight navigation preload requests.
   base::IDMap<std::unique_ptr<NavigationPreloadRequest>> preload_requests;
 
-  // Timer triggered when the service worker considers it should be stopped or
-  // an event should be aborted.
-  std::unique_ptr<ServiceWorkerTimeoutTimer> timeout_timer;
-
-  // |controller_impl| should be destroyed before |timeout_timer| since the
-  // pipe needs to be disconnected before callbacks passed by
-  // DispatchSomeEvent() get destructed, which may be stored in |timeout_timer|
-  // as parameters of pending tasks added after a termination request.
-  std::unique_ptr<ControllerServiceWorkerImpl> controller_impl;
-
   base::ThreadChecker thread_checker;
   base::WeakPtrFactory<ServiceWorkerContextClient> weak_factory;
   base::WeakPtrFactory<blink::WebServiceWorkerContextProxy> proxy_weak_factory;
@@ -462,25 +259,11 @@
   context_ = std::make_unique<WorkerContextData>(this);
 
   DCHECK(pending_service_worker_request_.is_pending());
+  proxy_->BindServiceWorker(pending_service_worker_request_.PassMessagePipe());
+
   DCHECK(pending_controller_request_.is_pending());
-  DCHECK(!context_->service_worker_binding.is_bound());
-  DCHECK(!context_->controller_impl);
-  context_->service_worker_binding.Bind(
-      std::move(pending_service_worker_request_), worker_task_runner_);
-
-  auto weak_ptr = GetWeakPtr();
-  // Intentionally dereferences the weak ptr in order to
-  // ensure the WeakPtrFactory is bound to this thread (the worker thread).
-  weak_ptr = weak_ptr->GetWeakPtr();
-  context_->controller_impl = std::make_unique<ControllerServiceWorkerImpl>(
-      std::move(pending_controller_request_), std::move(weak_ptr),
-      worker_task_runner_);
-
-  // Create the idle timer. At this point the timer is not started. It will be
-  // started after the WorkerStarted message is sent.
-  context_->timeout_timer =
-      std::make_unique<ServiceWorkerTimeoutTimer>(base::BindRepeating(
-          &ServiceWorkerContextClient::OnIdleTimeout, base::Unretained(this)));
+  proxy_->BindControllerServiceWorker(
+      pending_controller_request_.PassMessagePipe());
 }
 
 void ServiceWorkerContextClient::WillEvaluateScript() {
@@ -595,463 +378,6 @@
                                blink::WebStringToGURL(source_url));
 }
 
-void ServiceWorkerContextClient::DidHandleActivateEvent(
-    int request_id,
-    blink::mojom::ServiceWorkerEventStatus status) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  if (!context_)
-    return;
-  TRACE_EVENT_WITH_FLOW1("ServiceWorker",
-                         "ServiceWorkerContextClient::DidHandleActivateEvent",
-                         TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                                             TRACE_ID_LOCAL(request_id)),
-                         TRACE_EVENT_FLAG_FLOW_IN, "status",
-                         ServiceWorkerUtils::MojoEnumToString(status));
-  RunEventCallback(&context_->activate_event_callbacks,
-                   context_->timeout_timer.get(), request_id, status);
-}
-
-void ServiceWorkerContextClient::DidHandleBackgroundFetchAbortEvent(
-    int request_id,
-    blink::mojom::ServiceWorkerEventStatus status) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  if (!context_)
-    return;
-  TRACE_EVENT_WITH_FLOW1(
-      "ServiceWorker",
-      "ServiceWorkerContextClient::DidHandleBackgroundFetchAbortEvent",
-      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                          TRACE_ID_LOCAL(request_id)),
-      TRACE_EVENT_FLAG_FLOW_IN, "status",
-      ServiceWorkerUtils::MojoEnumToString(status));
-  RunEventCallback(&context_->background_fetch_abort_event_callbacks,
-                   context_->timeout_timer.get(), request_id, status);
-}
-
-void ServiceWorkerContextClient::DidHandleBackgroundFetchClickEvent(
-    int request_id,
-    blink::mojom::ServiceWorkerEventStatus status) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  if (!context_)
-    return;
-  TRACE_EVENT_WITH_FLOW1(
-      "ServiceWorker",
-      "ServiceWorkerContextClient::DidHandleBackgroundFetchClickEvent",
-      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                          TRACE_ID_LOCAL(request_id)),
-      TRACE_EVENT_FLAG_FLOW_IN, "status",
-      ServiceWorkerUtils::MojoEnumToString(status));
-  RunEventCallback(&context_->background_fetch_click_event_callbacks,
-                   context_->timeout_timer.get(), request_id, status);
-}
-
-void ServiceWorkerContextClient::DidHandleBackgroundFetchFailEvent(
-    int request_id,
-    blink::mojom::ServiceWorkerEventStatus status) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  if (!context_)
-    return;
-  TRACE_EVENT_WITH_FLOW1(
-      "ServiceWorker",
-      "ServiceWorkerContextClient::DidHandleBackgroundFetchFailEvent",
-      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                          TRACE_ID_LOCAL(request_id)),
-      TRACE_EVENT_FLAG_FLOW_IN, "status",
-      ServiceWorkerUtils::MojoEnumToString(status));
-  RunEventCallback(&context_->background_fetch_fail_event_callbacks,
-                   context_->timeout_timer.get(), request_id, status);
-}
-
-void ServiceWorkerContextClient::DidHandleBackgroundFetchSuccessEvent(
-    int request_id,
-    blink::mojom::ServiceWorkerEventStatus status) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  if (!context_)
-    return;
-  TRACE_EVENT_WITH_FLOW1(
-      "ServiceWorker",
-      "ServiceWorkerContextClient::DidHandleBackgroundFetchSuccessEvent",
-      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                          TRACE_ID_LOCAL(request_id)),
-      TRACE_EVENT_FLAG_FLOW_IN, "status",
-      ServiceWorkerUtils::MojoEnumToString(status));
-  RunEventCallback(&context_->background_fetched_event_callbacks,
-                   context_->timeout_timer.get(), request_id, status);
-}
-
-void ServiceWorkerContextClient::DidHandleCookieChangeEvent(
-    int request_id,
-    blink::mojom::ServiceWorkerEventStatus status) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  if (!context_)
-    return;
-  TRACE_EVENT_WITH_FLOW1(
-      "ServiceWorker", "ServiceWorkerContextClient::DidHandleCookieChangeEvent",
-      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                          TRACE_ID_LOCAL(request_id)),
-      TRACE_EVENT_FLAG_FLOW_IN, "status",
-      ServiceWorkerUtils::MojoEnumToString(status));
-  RunEventCallback(&context_->cookie_change_event_callbacks,
-                   context_->timeout_timer.get(), request_id, status);
-}
-
-void ServiceWorkerContextClient::DidHandleExtendableMessageEvent(
-    int request_id,
-    blink::mojom::ServiceWorkerEventStatus status) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  if (!context_)
-    return;
-  TRACE_EVENT_WITH_FLOW1(
-      "ServiceWorker",
-      "ServiceWorkerContextClient::DidHandleExtendableMessageEvent",
-      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                          TRACE_ID_LOCAL(request_id)),
-      TRACE_EVENT_FLAG_FLOW_IN, "status",
-      ServiceWorkerUtils::MojoEnumToString(status));
-  RunEventCallback(&context_->message_event_callbacks,
-                   context_->timeout_timer.get(), request_id, status);
-}
-
-void ServiceWorkerContextClient::DidHandleInstallEvent(
-    int event_id,
-    blink::mojom::ServiceWorkerEventStatus status) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  proxy_->SetFetchHandlerExistence(proxy_->HasFetchEventHandler()
-                                       ? FetchHandlerExistence::EXISTS
-                                       : FetchHandlerExistence::DOES_NOT_EXIST);
-  if (!context_)
-    return;
-  TRACE_EVENT_WITH_FLOW1("ServiceWorker",
-                         "ServiceWorkerContextClient::DidHandleInstallEvent",
-                         TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                                             TRACE_ID_LOCAL(event_id)),
-                         TRACE_EVENT_FLAG_FLOW_IN, "status",
-                         ServiceWorkerUtils::MojoEnumToString(status));
-  RunEventCallback(&context_->install_event_callbacks,
-                   context_->timeout_timer.get(), event_id, status,
-                   proxy_->HasFetchEventHandler());
-}
-
-void ServiceWorkerContextClient::RespondToFetchEventWithNoResponse(
-    int fetch_event_id,
-    base::TimeTicks event_dispatch_time,
-    base::TimeTicks respond_with_settled_time) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  if (!context_)
-    return;
-  TRACE_EVENT_WITH_FLOW0(
-      "ServiceWorker",
-      "ServiceWorkerContextClient::RespondToFetchEventWithNoResponse",
-      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                          TRACE_ID_LOCAL(fetch_event_id)),
-      TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
-  DCHECK(base::ContainsKey(context_->fetch_response_callbacks, fetch_event_id));
-  const blink::mojom::ServiceWorkerFetchResponseCallbackPtr& response_callback =
-      context_->fetch_response_callbacks[fetch_event_id];
-
-  auto timing = blink::mojom::ServiceWorkerFetchEventTiming::New();
-  timing->dispatch_event_time = event_dispatch_time;
-  timing->respond_with_settled_time = respond_with_settled_time;
-
-  response_callback->OnFallback(std::move(timing));
-  context_->fetch_response_callbacks.erase(fetch_event_id);
-}
-
-void ServiceWorkerContextClient::RespondToFetchEvent(
-    int fetch_event_id,
-    const blink::WebServiceWorkerResponse& web_response,
-    base::TimeTicks event_dispatch_time,
-    base::TimeTicks respond_with_settled_time) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  if (!context_)
-    return;
-  TRACE_EVENT_WITH_FLOW0(
-      "ServiceWorker", "ServiceWorkerContextClient::RespondToFetchEvent",
-      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                          TRACE_ID_LOCAL(fetch_event_id)),
-      TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
-  DCHECK(base::ContainsKey(context_->fetch_response_callbacks, fetch_event_id));
-
-  blink::mojom::FetchAPIResponsePtr response(
-      GetFetchAPIResponseFromWebResponse(web_response));
-  const blink::mojom::ServiceWorkerFetchResponseCallbackPtr& response_callback =
-      context_->fetch_response_callbacks[fetch_event_id];
-
-  auto timing = blink::mojom::ServiceWorkerFetchEventTiming::New();
-  timing->dispatch_event_time = event_dispatch_time;
-  timing->respond_with_settled_time = respond_with_settled_time;
-
-  response_callback->OnResponse(std::move(response), std::move(timing));
-  context_->fetch_response_callbacks.erase(fetch_event_id);
-}
-
-void ServiceWorkerContextClient::RespondToFetchEventWithResponseStream(
-    int fetch_event_id,
-    const blink::WebServiceWorkerResponse& web_response,
-    blink::WebServiceWorkerStreamHandle* web_body_as_stream,
-    base::TimeTicks event_dispatch_time,
-    base::TimeTicks respond_with_settled_time) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  if (!context_)
-    return;
-  TRACE_EVENT_WITH_FLOW0(
-      "ServiceWorker",
-      "ServiceWorkerContextClient::RespondToFetchEventWithResponseStream",
-      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                          TRACE_ID_LOCAL(fetch_event_id)),
-      TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
-  DCHECK(base::ContainsKey(context_->fetch_response_callbacks, fetch_event_id));
-  blink::mojom::FetchAPIResponsePtr response(
-      GetFetchAPIResponseFromWebResponse(web_response));
-  const blink::mojom::ServiceWorkerFetchResponseCallbackPtr& response_callback =
-      context_->fetch_response_callbacks[fetch_event_id];
-  blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream =
-      blink::mojom::ServiceWorkerStreamHandle::New();
-  blink::mojom::ServiceWorkerStreamCallbackPtr callback_ptr;
-  body_as_stream->callback_request = mojo::MakeRequest(&callback_ptr);
-  body_as_stream->stream = web_body_as_stream->DrainStreamDataPipe();
-  DCHECK(body_as_stream->stream.is_valid());
-
-  web_body_as_stream->SetListener(std::make_unique<StreamHandleListener>(
-      std::move(callback_ptr),
-      context_->timeout_timer->CreateStayAwakeToken()));
-
-  auto timing = blink::mojom::ServiceWorkerFetchEventTiming::New();
-  timing->dispatch_event_time = event_dispatch_time;
-  timing->respond_with_settled_time = respond_with_settled_time;
-
-  response_callback->OnResponseStream(
-      std::move(response), std::move(body_as_stream), std::move(timing));
-  context_->fetch_response_callbacks.erase(fetch_event_id);
-}
-
-void ServiceWorkerContextClient::DidHandleFetchEvent(
-    int event_id,
-    blink::mojom::ServiceWorkerEventStatus status) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  if (!context_)
-    return;
-  // This TRACE_EVENT is used for perf benchmark to confirm if all of fetch
-  // events have completed. (crbug.com/736697)
-  TRACE_EVENT_WITH_FLOW1("ServiceWorker",
-                         "ServiceWorkerContextClient::DidHandleFetchEvent",
-                         TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                                             TRACE_ID_LOCAL(event_id)),
-                         TRACE_EVENT_FLAG_FLOW_IN, "status",
-                         ServiceWorkerUtils::MojoEnumToString(status));
-  if (!RunEventCallback(&context_->fetch_event_callbacks,
-                        context_->timeout_timer.get(), event_id, status)) {
-    // The event may have been aborted. Its response callback also needs to be
-    // deleted.
-    context_->fetch_response_callbacks.erase(event_id);
-  } else {
-    // |fetch_response_callback| should be used before settling a promise for
-    // waitUntil().
-    DCHECK(!base::ContainsKey(context_->fetch_response_callbacks, event_id));
-  }
-}
-
-void ServiceWorkerContextClient::DidHandleNotificationClickEvent(
-    int request_id,
-    blink::mojom::ServiceWorkerEventStatus status) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  if (!context_)
-    return;
-  TRACE_EVENT_WITH_FLOW1(
-      "ServiceWorker",
-      "ServiceWorkerContextClient::DidHandleNotificationClickEvent",
-      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                          TRACE_ID_LOCAL(request_id)),
-      TRACE_EVENT_FLAG_FLOW_IN, "status",
-      ServiceWorkerUtils::MojoEnumToString(status));
-  RunEventCallback(&context_->notification_click_event_callbacks,
-                   context_->timeout_timer.get(), request_id, status);
-}
-
-void ServiceWorkerContextClient::DidHandleNotificationCloseEvent(
-    int request_id,
-    blink::mojom::ServiceWorkerEventStatus status) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  if (!context_)
-    return;
-  TRACE_EVENT_WITH_FLOW1(
-      "ServiceWorker",
-      "ServiceWorkerContextClient::DidHandleNotificationCloseEvent",
-      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                          TRACE_ID_LOCAL(request_id)),
-      TRACE_EVENT_FLAG_FLOW_IN, "status",
-      ServiceWorkerUtils::MojoEnumToString(status));
-  RunEventCallback(&context_->notification_close_event_callbacks,
-                   context_->timeout_timer.get(), request_id, status);
-}
-
-void ServiceWorkerContextClient::DidHandlePushEvent(
-    int request_id,
-    blink::mojom::ServiceWorkerEventStatus status) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  if (!context_)
-    return;
-  TRACE_EVENT_WITH_FLOW1("ServiceWorker",
-                         "ServiceWorkerContextClient::DidHandlePushEvent",
-                         TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                                             TRACE_ID_LOCAL(request_id)),
-                         TRACE_EVENT_FLAG_FLOW_IN, "status",
-                         ServiceWorkerUtils::MojoEnumToString(status));
-  RunEventCallback(&context_->push_event_callbacks,
-                   context_->timeout_timer.get(), request_id, status);
-}
-
-void ServiceWorkerContextClient::DidHandleSyncEvent(
-    int request_id,
-    blink::mojom::ServiceWorkerEventStatus status) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  if (!context_)
-    return;
-  TRACE_EVENT_WITH_FLOW1("ServiceWorker",
-                         "ServiceWorkerContextClient::DidHandleSyncEvent",
-                         TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                                             TRACE_ID_LOCAL(request_id)),
-                         TRACE_EVENT_FLAG_FLOW_IN, "status",
-                         ServiceWorkerUtils::MojoEnumToString(status));
-  RunEventCallback(&context_->sync_event_callbacks,
-                   context_->timeout_timer.get(), request_id, status);
-}
-
-void ServiceWorkerContextClient::DidHandlePeriodicSyncEvent(
-    int request_id,
-    blink::mojom::ServiceWorkerEventStatus status) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  if (!context_)
-    return;
-  TRACE_EVENT_WITH_FLOW1(
-      "ServiceWorker", "ServiceWorkerContextClient::DidHandlePeriodicSyncEvent",
-      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                          TRACE_ID_LOCAL(request_id)),
-      TRACE_EVENT_FLAG_FLOW_IN, "status",
-      ServiceWorkerUtils::MojoEnumToString(status));
-  RunEventCallback(&context_->periodic_sync_event_callbacks,
-                   context_->timeout_timer.get(), request_id, status);
-}
-
-void ServiceWorkerContextClient::RespondToAbortPaymentEvent(
-    int event_id,
-    bool payment_aborted) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  if (!context_)
-    return;
-  TRACE_EVENT_WITH_FLOW0(
-      "ServiceWorker", "ServiceWorkerContextClient::RespondToAbortPaymentEvent",
-      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                          TRACE_ID_LOCAL(event_id)),
-      TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
-  DCHECK(base::ContainsKey(context_->abort_payment_result_callbacks, event_id));
-  const payments::mojom::PaymentHandlerResponseCallbackPtr& result_callback =
-      context_->abort_payment_result_callbacks[event_id];
-  result_callback->OnResponseForAbortPayment(payment_aborted);
-  context_->abort_payment_result_callbacks.erase(event_id);
-}
-
-void ServiceWorkerContextClient::DidHandleAbortPaymentEvent(
-    int event_id,
-    blink::mojom::ServiceWorkerEventStatus status) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  if (!context_)
-    return;
-  TRACE_EVENT_WITH_FLOW1(
-      "ServiceWorker", "ServiceWorkerContextClient::DidHandleAbortPaymentEvent",
-      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                          TRACE_ID_LOCAL(event_id)),
-      TRACE_EVENT_FLAG_FLOW_IN, "status",
-      ServiceWorkerUtils::MojoEnumToString(status));
-  if (RunEventCallback(&context_->abort_payment_event_callbacks,
-                       context_->timeout_timer.get(), event_id, status)) {
-    context_->abort_payment_result_callbacks.erase(event_id);
-  }
-}
-
-void ServiceWorkerContextClient::RespondToCanMakePaymentEvent(
-    int event_id,
-    bool can_make_payment) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  if (!context_)
-    return;
-  TRACE_EVENT_WITH_FLOW0(
-      "ServiceWorker",
-      "ServiceWorkerContextClient::RespondToCanMakePaymentEvent",
-      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                          TRACE_ID_LOCAL(event_id)),
-      TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
-  DCHECK(
-      base::ContainsKey(context_->can_make_payment_result_callbacks, event_id));
-  const payments::mojom::PaymentHandlerResponseCallbackPtr& result_callback =
-      context_->can_make_payment_result_callbacks[event_id];
-  result_callback->OnResponseForCanMakePayment(can_make_payment);
-  context_->can_make_payment_result_callbacks.erase(event_id);
-}
-
-void ServiceWorkerContextClient::DidHandleCanMakePaymentEvent(
-    int event_id,
-    blink::mojom::ServiceWorkerEventStatus status) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  if (!context_)
-    return;
-  TRACE_EVENT_WITH_FLOW1(
-      "ServiceWorker",
-      "ServiceWorkerContextClient::DidHandleCanMakePaymentEvent",
-      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                          TRACE_ID_LOCAL(event_id)),
-      TRACE_EVENT_FLAG_FLOW_IN, "status",
-      ServiceWorkerUtils::MojoEnumToString(status));
-  if (RunEventCallback(&context_->can_make_payment_event_callbacks,
-                       context_->timeout_timer.get(), event_id, status)) {
-    context_->can_make_payment_result_callbacks.erase(event_id);
-  }
-}
-
-void ServiceWorkerContextClient::RespondToPaymentRequestEvent(
-    int payment_request_id,
-    const blink::WebPaymentHandlerResponse& web_response) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  if (!context_)
-    return;
-  TRACE_EVENT_WITH_FLOW0(
-      "ServiceWorker",
-      "ServiceWorkerContextClient::RespondToPaymentRequestEvent",
-      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                          TRACE_ID_LOCAL(payment_request_id)),
-      TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
-  DCHECK(base::ContainsKey(context_->payment_response_callbacks,
-                           payment_request_id));
-  const payments::mojom::PaymentHandlerResponseCallbackPtr& response_callback =
-      context_->payment_response_callbacks[payment_request_id];
-  payments::mojom::PaymentHandlerResponsePtr response =
-      payments::mojom::PaymentHandlerResponse::New();
-  response->method_name = web_response.method_name.Utf8();
-  response->stringified_details = web_response.stringified_details.Utf8();
-  response_callback->OnResponseForPaymentRequest(std::move(response));
-  context_->payment_response_callbacks.erase(payment_request_id);
-}
-
-void ServiceWorkerContextClient::DidHandlePaymentRequestEvent(
-    int payment_request_id,
-    blink::mojom::ServiceWorkerEventStatus status) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  if (!context_)
-    return;
-  TRACE_EVENT_WITH_FLOW1(
-      "ServiceWorker",
-      "ServiceWorkerContextClient::DidHandlePaymentRequestEvent",
-      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                          TRACE_ID_LOCAL(payment_request_id)),
-      TRACE_EVENT_FLAG_FLOW_IN, "status",
-      ServiceWorkerUtils::MojoEnumToString(status));
-  if (RunEventCallback(&context_->payment_request_event_callbacks,
-                       context_->timeout_timer.get(), payment_request_id,
-                       status)) {
-    context_->payment_response_callbacks.erase(payment_request_id);
-  }
-}
-
 std::unique_ptr<blink::WebServiceWorkerNetworkProvider>
 ServiceWorkerContextClient::CreateServiceWorkerNetworkProviderOnMainThread() {
   DCHECK(main_thread_task_runner_->RunsTasksInCurrentSequence());
@@ -1096,166 +422,6 @@
       std::move(preference_watcher_request_));
 }
 
-int ServiceWorkerContextClient::WillStartTask() {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  // This is called from the Blink's code running in the worker thread and we
-  // expect |context_| to still be alive.
-  DCHECK(context_);
-  DCHECK(context_->timeout_timer);
-  return context_->timeout_timer->StartEvent(base::DoNothing());
-}
-
-void ServiceWorkerContextClient::DidEndTask(int task_id) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  // This is called from the Blink's code running in the worker thread and we
-  // expect |context_| to still be alive.
-  DCHECK(context_);
-  DCHECK(context_->timeout_timer);
-  // Check if the task is still alive, since the timeout timer might have
-  // already timed it out (which calls the abort callback passed to StartEvent()
-  // but that does nothing, since we just check HasEvent() here instead of
-  // maintaining our own set of started events).
-  if (context_->timeout_timer->HasEvent(task_id))
-    context_->timeout_timer->EndEvent(task_id);
-}
-
-void ServiceWorkerContextClient::DispatchOrQueueFetchEvent(
-    blink::mojom::DispatchFetchEventParamsPtr params,
-    blink::mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
-    DispatchFetchEventCallback callback) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  // |context_| is valid because the Mojo binding is on |worker_task_runner_|.
-  DCHECK(context_);
-  TRACE_EVENT2("ServiceWorker",
-               "ServiceWorkerContextClient::DispatchOrQueueFetchEvent", "url",
-               params->request->url.spec(), "queued",
-               RequestedTermination() ? "true" : "false");
-  if (RequestedTermination()) {
-    context_->timeout_timer->PushPendingTask(base::BindOnce(
-        &ServiceWorkerContextClient::DispatchFetchEvent, GetWeakPtr(),
-        std::move(params), std::move(response_callback), std::move(callback)));
-    return;
-  }
-  DispatchFetchEvent(std::move(params), std::move(response_callback),
-                     std::move(callback));
-}
-
-void ServiceWorkerContextClient::DispatchSyncEvent(
-    const std::string& tag,
-    bool last_chance,
-    base::TimeDelta timeout,
-    DispatchSyncEventCallback callback) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  // |context_| is valid because the Mojo binding is on |worker_task_runner_|.
-  DCHECK(context_);
-  int request_id = context_->timeout_timer->StartEventWithCustomTimeout(
-      CreateAbortCallback(&context_->sync_event_callbacks), timeout);
-  context_->sync_event_callbacks.emplace(request_id, std::move(callback));
-  TRACE_EVENT_WITH_FLOW0("ServiceWorker",
-                         "ServiceWorkerContextClient::DispatchSyncEvent",
-                         TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                                             TRACE_ID_LOCAL(request_id)),
-                         TRACE_EVENT_FLAG_FLOW_OUT);
-
-  // TODO(jkarlin): Make this blink::WebString::FromUTF8Lenient once
-  // https://crrev.com/1768063002/ lands.
-  proxy_->DispatchSyncEvent(request_id, blink::WebString::FromUTF8(tag),
-                            last_chance);
-}
-
-void ServiceWorkerContextClient::DispatchPeriodicSyncEvent(
-    const std::string& tag,
-    base::TimeDelta timeout,
-    DispatchPeriodicSyncEventCallback callback) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  // |context_| is valid because the Mojo binding is on |worker_task_runner_|.
-  DCHECK(context_);
-
-  int request_id = context_->timeout_timer->StartEventWithCustomTimeout(
-      CreateAbortCallback(&context_->periodic_sync_event_callbacks), timeout);
-  context_->periodic_sync_event_callbacks.emplace(request_id,
-                                                  std::move(callback));
-  TRACE_EVENT_WITH_FLOW0(
-      "ServiceWorker", "ServiceWorkerContextClient::DispatchPeriodicSyncEvent",
-      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                          TRACE_ID_LOCAL(request_id)),
-      TRACE_EVENT_FLAG_FLOW_OUT);
-
-  proxy_->DispatchPeriodicSyncEvent(request_id,
-                                    blink::WebString::FromUTF8(tag));
-}
-
-void ServiceWorkerContextClient::DispatchAbortPaymentEvent(
-    payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
-    DispatchAbortPaymentEventCallback callback) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  // Valid because the Mojo binding is on |worker_task_runner_|.
-  DCHECK(context_);
-  int event_id = context_->timeout_timer->StartEvent(
-      CreateAbortCallback(&context_->abort_payment_event_callbacks));
-  context_->abort_payment_event_callbacks.emplace(event_id,
-                                                  std::move(callback));
-  context_->abort_payment_result_callbacks.emplace(
-      event_id, std::move(response_callback));
-  TRACE_EVENT_WITH_FLOW0(
-      "ServiceWorker", "ServiceWorkerContextClient::DispatchAbortPaymentEvent",
-      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                          TRACE_ID_LOCAL(event_id)),
-      TRACE_EVENT_FLAG_FLOW_OUT);
-  proxy_->DispatchAbortPaymentEvent(event_id);
-}
-
-void ServiceWorkerContextClient::DispatchCanMakePaymentEvent(
-    payments::mojom::CanMakePaymentEventDataPtr eventData,
-    payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
-    DispatchCanMakePaymentEventCallback callback) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  // Valid because the Mojo binding is on |worker_task_runner_|.
-  DCHECK(context_);
-  int event_id = context_->timeout_timer->StartEvent(
-      CreateAbortCallback(&context_->can_make_payment_event_callbacks));
-  context_->can_make_payment_event_callbacks.emplace(event_id,
-                                                     std::move(callback));
-  context_->can_make_payment_result_callbacks.emplace(
-      event_id, std::move(response_callback));
-  TRACE_EVENT_WITH_FLOW0(
-      "ServiceWorker",
-      "ServiceWorkerContextClient::DispatchCanMakePaymentEvent",
-      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                          TRACE_ID_LOCAL(event_id)),
-      TRACE_EVENT_FLAG_FLOW_OUT);
-
-  blink::WebCanMakePaymentEventData webEventData =
-      mojo::ConvertTo<blink::WebCanMakePaymentEventData>(std::move(eventData));
-  proxy_->DispatchCanMakePaymentEvent(event_id, webEventData);
-}
-
-void ServiceWorkerContextClient::DispatchPaymentRequestEvent(
-    payments::mojom::PaymentRequestEventDataPtr eventData,
-    payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
-    DispatchPaymentRequestEventCallback callback) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  // Valid because the Mojo binding is on |worker_task_runner_|.
-  DCHECK(context_);
-  int event_id = context_->timeout_timer->StartEvent(
-      CreateAbortCallback(&context_->payment_request_event_callbacks));
-  context_->payment_request_event_callbacks.emplace(event_id,
-                                                    std::move(callback));
-  context_->payment_response_callbacks.emplace(event_id,
-                                               std::move(response_callback));
-  TRACE_EVENT_WITH_FLOW0(
-      "ServiceWorker",
-      "ServiceWorkerContextClient::DispatchPaymentRequestEvent",
-      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                          TRACE_ID_LOCAL(event_id)),
-      TRACE_EVENT_FLAG_FLOW_OUT);
-
-  auto webEventData =
-      mojo::ConvertTo<std::unique_ptr<blink::WebPaymentRequestEventData>>(
-          std::move(eventData));
-  proxy_->DispatchPaymentRequestEvent(event_id, std::move(webEventData));
-}
-
 void ServiceWorkerContextClient::OnNavigationPreloadResponse(
     int fetch_event_id,
     std::unique_ptr<blink::WebURLResponse> response,
@@ -1307,64 +473,6 @@
   context_->preload_requests.Remove(fetch_event_id);
 }
 
-void ServiceWorkerContextClient::ToWebServiceWorkerRequestForFetchEvent(
-    blink::mojom::FetchAPIRequestPtr request,
-    const std::string& client_id,
-    blink::WebServiceWorkerRequest* web_request) {
-  DCHECK(web_request);
-  web_request->SetURL(blink::WebURL(request->url));
-  web_request->SetMethod(blink::WebString::FromUTF8(request->method));
-  for (const auto& pair : request->headers) {
-    const std::string& header_name = pair.first;
-    const std::string& header_value = pair.second;
-    if (!IsExcludedHeaderForServiceWorkerFetchEvent(header_name)) {
-      web_request->SetHeader(blink::WebString::FromUTF8(header_name),
-                             blink::WebString::FromUTF8(header_value));
-    }
-  }
-
-  // The body is provided in |request->body|.
-  DCHECK(!request->blob);
-  if (request->body) {
-    std::vector<blink::mojom::BlobPtrInfo> blob_ptrs;
-    if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
-      // We need this as GetBlobFromUUID is a sync IPC.
-      // TODO(kinuko): Remove the friend for ScopedAllowBaseSyncPrimitives
-      // in //base as well when we remove this code.
-      base::ScopedAllowBaseSyncPrimitives allow_sync_primitives;
-      blob_ptrs = GetBlobPtrsForRequestBody(*request->body);
-    }
-    blink::WebHTTPBody body = GetWebHTTPBodyForRequestBodyWithBlobPtrs(
-        *request->body, std::move(blob_ptrs));
-    body.SetUniqueBoundary();
-    web_request->SetBody(body);
-  }
-
-  if (request->referrer) {
-    web_request->SetReferrer(
-        blink::WebString::FromUTF8(request->referrer->url.spec()),
-        request->referrer->policy);
-  }
-  web_request->SetMode(request->mode);
-  web_request->SetIsMainResourceLoad(request->is_main_resource_load);
-  web_request->SetCredentialsMode(request->credentials_mode);
-  web_request->SetCacheMode(request->cache_mode);
-  web_request->SetRedirectMode(request->redirect_mode);
-  web_request->SetRequestContext(request->request_context_type);
-  web_request->SetFrameType(request->frame_type);
-  web_request->SetClientId(blink::WebString::FromUTF8(client_id));
-  web_request->SetIsReload(request->is_reload);
-  if (request->integrity) {
-    web_request->SetIntegrity(blink::WebString::FromUTF8(*request->integrity));
-  }
-  web_request->SetPriority(
-      ConvertNetPriorityToWebKitPriority(request->priority));
-  web_request->SetKeepalive(request->keepalive);
-  web_request->SetIsHistoryNavigation(request->is_history_navigation);
-  if (request->fetch_window_id)
-    web_request->SetWindowId(*request->fetch_window_id);
-}
-
 void ServiceWorkerContextClient::SendWorkerStarted(
     blink::mojom::ServiceWorkerStartStatus status) {
   DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
@@ -1395,415 +503,32 @@
       ->OnStarted(status, WorkerThread::GetCurrentId(),
                   std::move(start_timing_));
 
-  context_->timeout_timer->Start();
   TRACE_EVENT_NESTABLE_ASYNC_END0("ServiceWorker", "ServiceWorkerContextClient",
                                   this);
 }
 
-void ServiceWorkerContextClient::DispatchActivateEvent(
-    DispatchActivateEventCallback callback) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  // |context_| is valid because the Mojo binding is on |worker_task_runner_|.
-  DCHECK(context_);
-  int request_id = context_->timeout_timer->StartEvent(
-      CreateAbortCallback(&context_->activate_event_callbacks));
-  context_->activate_event_callbacks.emplace(request_id, std::move(callback));
-  TRACE_EVENT_WITH_FLOW0("ServiceWorker",
-                         "ServiceWorkerContextClient::DispatchActivateEvent",
-                         TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                                             TRACE_ID_LOCAL(request_id)),
-                         TRACE_EVENT_FLAG_FLOW_OUT);
-  proxy_->DispatchActivateEvent(request_id);
-}
-
-void ServiceWorkerContextClient::DispatchBackgroundFetchAbortEvent(
-    blink::mojom::BackgroundFetchRegistrationPtr registration,
-    DispatchBackgroundFetchAbortEventCallback callback) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  // |context_| is valid because the Mojo binding is on |worker_task_runner_|.
-  DCHECK(context_);
-  int request_id = context_->timeout_timer->StartEvent(
-      CreateAbortCallback(&context_->background_fetch_abort_event_callbacks));
-  context_->background_fetch_abort_event_callbacks.emplace(request_id,
-                                                           std::move(callback));
-  TRACE_EVENT_WITH_FLOW0(
-      "ServiceWorker",
-      "ServiceWorkerContextClient::DispatchBackgroundFetchAbortEvent",
-      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                          TRACE_ID_LOCAL(request_id)),
-      TRACE_EVENT_FLAG_FLOW_OUT);
-
-  proxy_->DispatchBackgroundFetchAbortEvent(
-      request_id, ToWebBackgroundFetchRegistration(std::move(registration)));
-}
-
-void ServiceWorkerContextClient::DispatchBackgroundFetchClickEvent(
-    blink::mojom::BackgroundFetchRegistrationPtr registration,
-    DispatchBackgroundFetchClickEventCallback callback) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  // |context_| is valid because the Mojo binding is on |worker_task_runner_|.
-  DCHECK(context_);
-  int request_id = context_->timeout_timer->StartEvent(
-      CreateAbortCallback(&context_->background_fetch_click_event_callbacks));
-  context_->background_fetch_click_event_callbacks.emplace(request_id,
-                                                           std::move(callback));
-  TRACE_EVENT_WITH_FLOW0(
-      "ServiceWorker",
-      "ServiceWorkerContextClient::DispatchBackgroundFetchClickEvent",
-      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                          TRACE_ID_LOCAL(request_id)),
-      TRACE_EVENT_FLAG_FLOW_OUT);
-
-  proxy_->DispatchBackgroundFetchClickEvent(
-      request_id, ToWebBackgroundFetchRegistration(std::move(registration)));
-}
-
-void ServiceWorkerContextClient::DispatchBackgroundFetchFailEvent(
-    blink::mojom::BackgroundFetchRegistrationPtr registration,
-    DispatchBackgroundFetchFailEventCallback callback) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  // |context_| is valid because the Mojo binding is on |worker_task_runner_|.
-  DCHECK(context_);
-  int request_id = context_->timeout_timer->StartEvent(
-      CreateAbortCallback(&context_->background_fetch_fail_event_callbacks));
-  context_->background_fetch_fail_event_callbacks.emplace(request_id,
-                                                          std::move(callback));
-  TRACE_EVENT_WITH_FLOW0(
-      "ServiceWorker",
-      "ServiceWorkerContextClient::DispatchBackgroundFetchFailEvent",
-      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                          TRACE_ID_LOCAL(request_id)),
-      TRACE_EVENT_FLAG_FLOW_OUT);
-
-  proxy_->DispatchBackgroundFetchFailEvent(
-      request_id, ToWebBackgroundFetchRegistration(std::move(registration)));
-}
-
-void ServiceWorkerContextClient::DispatchBackgroundFetchSuccessEvent(
-    blink::mojom::BackgroundFetchRegistrationPtr registration,
-    DispatchBackgroundFetchSuccessEventCallback callback) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  // |context_| is valid because the Mojo binding is on |worker_task_runner_|.
-  DCHECK(context_);
-  int request_id = context_->timeout_timer->StartEvent(
-      CreateAbortCallback(&context_->background_fetched_event_callbacks));
-  context_->background_fetched_event_callbacks.emplace(request_id,
-                                                       std::move(callback));
-  TRACE_EVENT_WITH_FLOW0(
-      "ServiceWorker",
-      "ServiceWorkerContextClient::DispatchBackgroundFetchSuccessEvent",
-      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                          TRACE_ID_LOCAL(request_id)),
-      TRACE_EVENT_FLAG_FLOW_OUT);
-
-  proxy_->DispatchBackgroundFetchSuccessEvent(
-      request_id, ToWebBackgroundFetchRegistration(std::move(registration)));
-}
-
-void ServiceWorkerContextClient::InitializeGlobalScope(
-    blink::mojom::ServiceWorkerHostAssociatedPtrInfo service_worker_host,
-    blink::mojom::ServiceWorkerRegistrationObjectInfoPtr registration_info,
-    FetchHandlerExistence fetch_handler_existence) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  // Connect to the blink::mojom::ServiceWorkerHost.
-  proxy_->BindServiceWorkerHost(service_worker_host.PassHandle());
-  // Set ServiceWorkerGlobalScope#registration.
-  DCHECK_NE(registration_info->registration_id,
-            blink::mojom::kInvalidServiceWorkerRegistrationId);
-  DCHECK(registration_info->host_ptr_info.is_valid());
-  DCHECK(registration_info->request.is_pending());
-  proxy_->SetRegistration(
-      registration_info.To<blink::WebServiceWorkerRegistrationObjectInfo>());
-  proxy_->SetFetchHandlerExistence(fetch_handler_existence);
-
-  proxy_->ReadyToEvaluateScript();
-}
-
-void ServiceWorkerContextClient::DispatchInstallEvent(
-    DispatchInstallEventCallback callback) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  // |context_| is valid because the Mojo binding is on |worker_task_runner_|.
-  DCHECK(context_);
-  int event_id = context_->timeout_timer->StartEvent(CreateAbortCallback(
-      &context_->install_event_callbacks, false /* has_fetch_handler */));
-  context_->install_event_callbacks.emplace(event_id, std::move(callback));
-  TRACE_EVENT_WITH_FLOW0("ServiceWorker",
-                         "ServiceWorkerContextClient::DispatchInstallEvent",
-                         TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                                             TRACE_ID_LOCAL(event_id)),
-                         TRACE_EVENT_FLAG_FLOW_OUT);
-
-  proxy_->DispatchInstallEvent(event_id);
-}
-
-void ServiceWorkerContextClient::DispatchExtendableMessageEvent(
-    blink::mojom::ExtendableMessageEventPtr event,
-    DispatchExtendableMessageEventCallback callback) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  // |context_| is valid because the Mojo binding is on |worker_task_runner_|.
-  DCHECK(context_);
-  int request_id = context_->timeout_timer->StartEvent(
-      CreateAbortCallback(&context_->message_event_callbacks));
-  context_->message_event_callbacks.emplace(request_id, std::move(callback));
-  TRACE_EVENT_WITH_FLOW0(
-      "ServiceWorker",
-      "ServiceWorkerContextClient::DispatchExtendableMessageEvent",
-      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                          TRACE_ID_LOCAL(request_id)),
-      TRACE_EVENT_FLAG_FLOW_OUT);
-
-  if (event->source_info_for_client) {
-    blink::WebServiceWorkerClientInfo web_client =
-        ToWebServiceWorkerClientInfo(std::move(event->source_info_for_client));
-    proxy_->DispatchExtendableMessageEvent(request_id,
-                                           std::move(event->message),
-                                           event->source_origin, web_client);
-    return;
-  }
-
-  DCHECK_NE(event->source_info_for_service_worker->version_id,
-            blink::mojom::kInvalidServiceWorkerVersionId);
-  proxy_->DispatchExtendableMessageEvent(
-      request_id, std::move(event->message), event->source_origin,
-      event->source_info_for_service_worker
-          .To<blink::WebServiceWorkerObjectInfo>());
-}
-
-void ServiceWorkerContextClient::
-    DispatchExtendableMessageEventWithCustomTimeout(
-        blink::mojom::ExtendableMessageEventPtr event,
-        base::TimeDelta timeout,
-        DispatchExtendableMessageEventCallback callback) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  // |context_| is valid because the Mojo binding is on |worker_task_runner_|.
-  DCHECK(context_);
-  int request_id = context_->timeout_timer->StartEventWithCustomTimeout(
-      CreateAbortCallback(&context_->message_event_callbacks), timeout);
-
-  context_->message_event_callbacks.emplace(request_id, std::move(callback));
-  TRACE_EVENT1("ServiceWorker",
-               "ServiceWorkerContextClient::"
-               "DispatchExtendableMessageEventWithCustomTimeout",
-               "request_id", request_id);
-
-  if (event->source_info_for_client) {
-    blink::WebServiceWorkerClientInfo web_client =
-        ToWebServiceWorkerClientInfo(std::move(event->source_info_for_client));
-    proxy_->DispatchExtendableMessageEvent(request_id,
-                                           std::move(event->message),
-                                           event->source_origin, web_client);
-    return;
-  }
-
-  DCHECK_NE(event->source_info_for_service_worker->version_id,
-            blink::mojom::kInvalidServiceWorkerVersionId);
-  proxy_->DispatchExtendableMessageEvent(
-      request_id, std::move(event->message), event->source_origin,
-      event->source_info_for_service_worker
-          .To<blink::WebServiceWorkerObjectInfo>());
-}
-
-void ServiceWorkerContextClient::DispatchFetchEvent(
-    blink::mojom::DispatchFetchEventParamsPtr params,
-    blink::mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
-    DispatchFetchEventCallback callback) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  DCHECK(context_);
-  int event_id = context_->timeout_timer->StartEvent(
-      CreateAbortCallback(&context_->fetch_event_callbacks));
-  context_->fetch_event_callbacks.emplace(event_id, std::move(callback));
-  context_->fetch_response_callbacks.emplace(event_id,
-                                             std::move(response_callback));
-
-  // This TRACE_EVENT is used for perf benchmark to confirm if all of fetch
-  // events have completed. (crbug.com/736697)
-  TRACE_EVENT_WITH_FLOW1(
-      "ServiceWorker", "ServiceWorkerContextClient::DispatchFetchEvent",
-      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                          TRACE_ID_LOCAL(event_id)),
-      TRACE_EVENT_FLAG_FLOW_OUT, "url", params->request->url.spec());
-
-  // Set up for navigation preload (FetchEvent#preloadResponse) if needed.
-  const bool navigation_preload_sent = !!params->preload_handle;
-  if (navigation_preload_sent) {
-    SetupNavigationPreload(event_id, params->request->url,
-                           std::move(params->preload_handle));
-  }
-
-  // Dispatch the event to the service worker execution context.
-  blink::WebServiceWorkerRequest web_request;
-  ToWebServiceWorkerRequestForFetchEvent(std::move(params->request),
-                                         params->client_id, &web_request);
-  proxy_->DispatchFetchEvent(event_id, web_request, navigation_preload_sent);
-}
-
-void ServiceWorkerContextClient::DispatchNotificationClickEvent(
-    const std::string& notification_id,
-    const blink::PlatformNotificationData& notification_data,
-    int action_index,
-    const base::Optional<base::string16>& reply,
-    DispatchNotificationClickEventCallback callback) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  DCHECK(context_);
-  int request_id = context_->timeout_timer->StartEvent(
-      CreateAbortCallback(&context_->notification_click_event_callbacks));
-  context_->notification_click_event_callbacks.emplace(request_id,
-                                                       std::move(callback));
-  TRACE_EVENT_WITH_FLOW0(
-      "ServiceWorker",
-      "ServiceWorkerContextClient::DispatchNotificationClickEvent",
-      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                          TRACE_ID_LOCAL(request_id)),
-      TRACE_EVENT_FLAG_FLOW_OUT);
-
-  blink::WebString web_reply;
-  if (reply)
-    web_reply = blink::WebString::FromUTF16(reply.value());
-
-  proxy_->DispatchNotificationClickEvent(
-      request_id, blink::WebString::FromUTF8(notification_id),
-      ToWebNotificationData(notification_data), action_index, web_reply);
-}
-
-void ServiceWorkerContextClient::DispatchNotificationCloseEvent(
-    const std::string& notification_id,
-    const blink::PlatformNotificationData& notification_data,
-    DispatchNotificationCloseEventCallback callback) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  DCHECK(context_);
-  int request_id = context_->timeout_timer->StartEvent(
-      CreateAbortCallback(&context_->notification_close_event_callbacks));
-  context_->notification_close_event_callbacks.emplace(request_id,
-                                                       std::move(callback));
-  TRACE_EVENT_WITH_FLOW0(
-      "ServiceWorker",
-      "ServiceWorkerContextClient::DispatchNotificationCloseEvent",
-      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                          TRACE_ID_LOCAL(request_id)),
-      TRACE_EVENT_FLAG_FLOW_OUT);
-  proxy_->DispatchNotificationCloseEvent(
-      request_id, blink::WebString::FromUTF8(notification_id),
-      ToWebNotificationData(notification_data));
-}
-
-void ServiceWorkerContextClient::DispatchPushEvent(
-    const base::Optional<std::string>& payload,
-    DispatchPushEventCallback callback) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  // |context_| is valid because the Mojo binding is on |worker_task_runner_|.
-  DCHECK(context_);
-  int request_id = context_->timeout_timer->StartEventWithCustomTimeout(
-      CreateAbortCallback(&context_->push_event_callbacks),
-      base::TimeDelta::FromSeconds(blink::mojom::kPushEventTimeoutSeconds));
-  context_->push_event_callbacks.emplace(request_id, std::move(callback));
-  TRACE_EVENT_WITH_FLOW0("ServiceWorker",
-                         "ServiceWorkerContextClient::DispatchPushEvent",
-                         TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                                             TRACE_ID_LOCAL(request_id)),
-                         TRACE_EVENT_FLAG_FLOW_OUT);
-
-  // Only set data to be a valid string if the payload had decrypted data.
-  blink::WebString data;
-  if (payload)
-    data = blink::WebString::FromUTF8(*payload);
-  proxy_->DispatchPushEvent(request_id, data);
-}
-
-void ServiceWorkerContextClient::DispatchCookieChangeEvent(
-    const net::CanonicalCookie& cookie,
-    ::network::mojom::CookieChangeCause cause,
-    DispatchCookieChangeEventCallback callback) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  // |context_| is valid because the Mojo binding is on |worker_task_runner_|.
-  DCHECK(context_);
-  int request_id = context_->timeout_timer->StartEvent(
-      CreateAbortCallback(&context_->cookie_change_event_callbacks));
-  context_->cookie_change_event_callbacks.emplace(request_id,
-                                                  std::move(callback));
-  TRACE_EVENT_WITH_FLOW0(
-      "ServiceWorker", "ServiceWorkerContextClient::DispatchCookieChangeEvent",
-      TRACE_ID_WITH_SCOPE(kServiceWorkerContextClientScope,
-                          TRACE_ID_LOCAL(request_id)),
-      TRACE_EVENT_FLAG_FLOW_OUT);
-
-  // After onion-souping, the conversion below will be done by mojo directly.
-  DCHECK(!cookie.IsHttpOnly());
-  base::Optional<blink::WebCanonicalCookie> web_cookie_opt =
-      blink::WebCanonicalCookie::Create(
-          blink::WebString::FromUTF8(cookie.Name()),
-          blink::WebString::FromUTF8(cookie.Value()),
-          blink::WebString::FromUTF8(cookie.Domain()),
-          blink::WebString::FromUTF8(cookie.Path()), cookie.CreationDate(),
-          cookie.ExpiryDate(), cookie.LastAccessDate(), cookie.IsSecure(),
-          false /* cookie.IsHttpOnly() */,
-          static_cast<network::mojom::CookieSameSite>(cookie.SameSite()),
-          static_cast<network::mojom::CookiePriority>(cookie.Priority()));
-  DCHECK(web_cookie_opt.has_value());
-
-  proxy_->DispatchCookieChangeEvent(request_id, web_cookie_opt.value(), cause);
-}
-
-void ServiceWorkerContextClient::Ping(PingCallback callback) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  std::move(callback).Run();
-}
-
-void ServiceWorkerContextClient::SetIdleTimerDelayToZero() {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  // |context_| is valid because the Mojo binding is on |worker_task_runner_|.
-  DCHECK(context_);
-  DCHECK(context_->timeout_timer);
-  context_->timeout_timer->SetIdleTimerDelayToZero();
-}
-
 void ServiceWorkerContextClient::SetupNavigationPreload(
     int fetch_event_id,
-    const GURL& url,
-    blink::mojom::FetchEventPreloadHandlePtr preload_handle) {
+    const blink::WebURL& url,
+    std::unique_ptr<blink::WebFetchEventPreloadHandle> preload_handle) {
   DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  // |context_| is valid because it's valid in our callsite.
   DCHECK(context_);
   auto preload_request = std::make_unique<NavigationPreloadRequest>(
-      this, fetch_event_id, url, std::move(preload_handle));
+      this, fetch_event_id, GURL(url),
+      blink::mojom::FetchEventPreloadHandle::New(
+          network::mojom::URLLoaderPtrInfo(
+              std::move(preload_handle->url_loader),
+              network::mojom::URLLoader::Version_),
+          network::mojom::URLLoaderClientRequest(
+              std::move(preload_handle->url_loader_client_request))));
   context_->preload_requests.AddWithID(std::move(preload_request),
                                        fetch_event_id);
 }
 
-void ServiceWorkerContextClient::OnIdleTimeout() {
+void ServiceWorkerContextClient::RequestTermination(
+    RequestTerminationCallback callback) {
   DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  // |context_| is valid because this is called by a timer owned by |context_|.
-  DCHECK(context_);
-  // RequestedTermination() returns true if ServiceWorkerTimeoutTimer agrees
-  // we should request the host to terminate this worker now.
-  DCHECK(RequestedTermination());
-  (*instance_host_)
-      ->RequestTermination(base::BindOnce(
-          &ServiceWorkerContextClient::OnRequestedTermination, GetWeakPtr()));
-}
-
-void ServiceWorkerContextClient::OnRequestedTermination(
-    bool will_be_terminated) {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  // |context_| is valid because the Mojo binding is on |worker_task_runner_|.
-  DCHECK(context_);
-  DCHECK(context_->timeout_timer);
-
-  // This worker will be terminated soon. Ignore the message.
-  if (will_be_terminated)
-    return;
-
-  // Dispatch a dummy event to run all of queued tasks. This updates the
-  // idle timer too.
-  const int event_id = context_->timeout_timer->StartEvent(base::DoNothing());
-  context_->timeout_timer->EndEvent(event_id);
-}
-
-bool ServiceWorkerContextClient::RequestedTermination() const {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  // |context_| is valid because it's valid at our callsites.
-  DCHECK(context_);
-  DCHECK(context_->timeout_timer);
-  return context_->timeout_timer->did_idle_timeout();
+  (*instance_host_)->RequestTermination(std::move(callback));
 }
 
 void ServiceWorkerContextClient::StopWorkerOnMainThread() {
@@ -1818,17 +543,4 @@
   return context_->weak_factory.GetWeakPtr();
 }
 
-void ServiceWorkerContextClient::SetTimeoutTimerForTesting(
-    std::unique_ptr<ServiceWorkerTimeoutTimer> timeout_timer) {
-  DCHECK(context_);
-  context_->timeout_timer = std::move(timeout_timer);
-}
-
-ServiceWorkerTimeoutTimer*
-ServiceWorkerContextClient::GetTimeoutTimerForTesting() {
-  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
-  DCHECK(context_);
-  return context_->timeout_timer.get();
-}
-
 }  // namespace content
diff --git a/content/renderer/service_worker/service_worker_context_client.h b/content/renderer/service_worker/service_worker_context_client.h
index 7d88bb58..74796a6 100644
--- a/content/renderer/service_worker/service_worker_context_client.h
+++ b/content/renderer/service_worker/service_worker_context_client.h
@@ -44,9 +44,7 @@
 }
 
 namespace blink {
-struct PlatformNotificationData;
 class WebServiceWorkerContextProxy;
-class WebServiceWorkerResponse;
 class WebURLResponse;
 }
 
@@ -54,7 +52,6 @@
 
 class EmbeddedWorkerInstanceClientImpl;
 class HostChildURLLoaderFactoryBundle;
-class ServiceWorkerTimeoutTimer;
 class WebWorkerFetchContext;
 
 // ServiceWorkerContextClient is a "client" of a service worker execution
@@ -67,8 +64,7 @@
 // noted (here or in base class documentation), all methods are called on the
 // worker thread.
 class CONTENT_EXPORT ServiceWorkerContextClient
-    : public blink::WebServiceWorkerContextClient,
-      public blink::mojom::ServiceWorker {
+    : public blink::WebServiceWorkerContextClient {
  public:
   // Called on the main thread.
   // - |is_starting_installed_worker| is true if the script is already installed
@@ -130,97 +126,16 @@
                             const blink::WebString& message,
                             int line_number,
                             const blink::WebString& source_url) override;
-  void DidHandleActivateEvent(
-      int request_id,
-      blink::mojom::ServiceWorkerEventStatus status) override;
-  void DidHandleBackgroundFetchAbortEvent(
-      int request_id,
-      blink::mojom::ServiceWorkerEventStatus status) override;
-  void DidHandleBackgroundFetchClickEvent(
-      int request_id,
-      blink::mojom::ServiceWorkerEventStatus status) override;
-  void DidHandleBackgroundFetchFailEvent(
-      int request_id,
-      blink::mojom::ServiceWorkerEventStatus status) override;
-  void DidHandleBackgroundFetchSuccessEvent(
-      int request_id,
-      blink::mojom::ServiceWorkerEventStatus status) override;
-  void DidHandleCookieChangeEvent(
-      int request_id,
-      blink::mojom::ServiceWorkerEventStatus status) override;
-  void DidHandleExtendableMessageEvent(
-      int request_id,
-      blink::mojom::ServiceWorkerEventStatus status) override;
-  void DidHandleInstallEvent(
-      int event_id,
-      blink::mojom::ServiceWorkerEventStatus status) override;
-  void RespondToFetchEventWithNoResponse(
-      int fetch_event_id,
-      base::TimeTicks event_dispatch_time,
-      base::TimeTicks respond_with_settled_time) override;
-  void RespondToFetchEvent(int fetch_event_id,
-                           const blink::WebServiceWorkerResponse& response,
-                           base::TimeTicks event_dispatch_time,
-                           base::TimeTicks respond_with_settled_time) override;
-  void RespondToFetchEventWithResponseStream(
-      int fetch_event_id,
-      const blink::WebServiceWorkerResponse& response,
-      blink::WebServiceWorkerStreamHandle* web_body_as_stream,
-      base::TimeTicks event_dispatch_time,
-      base::TimeTicks respond_with_settled_time) override;
-  void DidHandleFetchEvent(
-      int fetch_event_id,
-      blink::mojom::ServiceWorkerEventStatus status) override;
-  void DidHandleNotificationClickEvent(
-      int request_id,
-      blink::mojom::ServiceWorkerEventStatus status) override;
-  void DidHandleNotificationCloseEvent(
-      int request_id,
-      blink::mojom::ServiceWorkerEventStatus status) override;
-  void DidHandlePushEvent(
-      int request_id,
-      blink::mojom::ServiceWorkerEventStatus status) override;
-  void DidHandleSyncEvent(
-      int request_id,
-      blink::mojom::ServiceWorkerEventStatus status) override;
-  void DidHandlePeriodicSyncEvent(
-      int request_id,
-      blink::mojom::ServiceWorkerEventStatus status) override;
-  void RespondToAbortPaymentEvent(int event_id, bool payment_aborted) override;
-  void DidHandleAbortPaymentEvent(
-      int event_id,
-      blink::mojom::ServiceWorkerEventStatus status) override;
-  void RespondToCanMakePaymentEvent(int event_id,
-                                    bool can_make_payment) override;
-  void DidHandleCanMakePaymentEvent(
-      int event_id,
-      blink::mojom::ServiceWorkerEventStatus status) override;
-  void RespondToPaymentRequestEvent(
-      int payment_request_id,
-      const blink::WebPaymentHandlerResponse& response) override;
-  void DidHandlePaymentRequestEvent(
-      int payment_request_id,
-      blink::mojom::ServiceWorkerEventStatus status) override;
+  void SetupNavigationPreload(int fetch_event_id,
+                              const blink::WebURL& url,
+                              std::unique_ptr<blink::WebFetchEventPreloadHandle>
+                                  preload_handle) override;
+  void RequestTermination(RequestTerminationCallback callback) override;
   std::unique_ptr<blink::WebServiceWorkerNetworkProvider>
   CreateServiceWorkerNetworkProviderOnMainThread() override;
   scoped_refptr<blink::WebWorkerFetchContext>
   CreateServiceWorkerFetchContextOnMainThread(
       blink::WebServiceWorkerNetworkProvider*) override;
-  int WillStartTask() override;
-  void DidEndTask(int task_id) override;
-
-  // Dispatches the fetch event if the worker is running normally, and queues it
-  // instead if the worker has already requested to be terminated by the
-  // browser. If queued, the event will be dispatched once the worker resumes
-  // normal operation (if the browser decides not to terminate it, and instead
-  // starts another event), or else is dropped if the worker is terminated.
-  //
-  // This method needs to be used only if the event comes directly from a
-  // client, which means it is coming through the ControllerServiceWorkerImpl.
-  void DispatchOrQueueFetchEvent(
-      blink::mojom::DispatchFetchEventParamsPtr params,
-      blink::mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
-      DispatchFetchEventCallback callback);
 
   /////////////////////////////////////////////////////////////////////////////
   // The following are for use by NavigationPreloadRequest.
@@ -261,127 +176,13 @@
                            DispatchOrQueueFetchEvent_NotRequestedTermination);
   FRIEND_TEST_ALL_PREFIXES(ServiceWorkerContextClientTest, TaskInServiceWorker);
 
-  using FetchHandlerExistence = blink::mojom::FetchHandlerExistence;
-
-  static void ToWebServiceWorkerRequestForFetchEvent(
-      blink::mojom::FetchAPIRequestPtr request,
-      const std::string& client_id,
-      blink::WebServiceWorkerRequest* web_request);
-
   void SendWorkerStarted(blink::mojom::ServiceWorkerStartStatus status);
 
-  // Implements blink::mojom::ServiceWorker.
-  void InitializeGlobalScope(
-      blink::mojom::ServiceWorkerHostAssociatedPtrInfo service_worker_host,
-      blink::mojom::ServiceWorkerRegistrationObjectInfoPtr registration_info,
-      FetchHandlerExistence fetch_hander_existence) override;
-  void DispatchInstallEvent(
-      DispatchInstallEventCallback callback) override;
-  void DispatchActivateEvent(DispatchActivateEventCallback callback) override;
-  void DispatchBackgroundFetchAbortEvent(
-      blink::mojom::BackgroundFetchRegistrationPtr registration,
-      DispatchBackgroundFetchAbortEventCallback callback) override;
-  void DispatchBackgroundFetchClickEvent(
-      blink::mojom::BackgroundFetchRegistrationPtr registration,
-      DispatchBackgroundFetchClickEventCallback callback) override;
-  void DispatchBackgroundFetchFailEvent(
-      blink::mojom::BackgroundFetchRegistrationPtr registration,
-      DispatchBackgroundFetchFailEventCallback callback) override;
-  void DispatchBackgroundFetchSuccessEvent(
-      blink::mojom::BackgroundFetchRegistrationPtr registration,
-      DispatchBackgroundFetchSuccessEventCallback callback) override;
-  void DispatchExtendableMessageEvent(
-      blink::mojom::ExtendableMessageEventPtr event,
-      DispatchExtendableMessageEventCallback callback) override;
-  void DispatchExtendableMessageEventWithCustomTimeout(
-      blink::mojom::ExtendableMessageEventPtr event,
-      base::TimeDelta timeout,
-      DispatchExtendableMessageEventCallback callback) override;
-  void DispatchFetchEvent(
-      blink::mojom::DispatchFetchEventParamsPtr params,
-      blink::mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
-      DispatchFetchEventCallback callback) override;
-  void DispatchNotificationClickEvent(
-      const std::string& notification_id,
-      const blink::PlatformNotificationData& notification_data,
-      int action_index,
-      const base::Optional<base::string16>& reply,
-      DispatchNotificationClickEventCallback callback) override;
-  void DispatchNotificationCloseEvent(
-      const std::string& notification_id,
-      const blink::PlatformNotificationData& notification_data,
-      DispatchNotificationCloseEventCallback callback) override;
-  void DispatchPushEvent(const base::Optional<std::string>& payload,
-                         DispatchPushEventCallback callback) override;
-  void DispatchSyncEvent(const std::string& tag,
-                         bool last_chance,
-                         base::TimeDelta timeout,
-                         DispatchSyncEventCallback callback) override;
-  void DispatchPeriodicSyncEvent(
-      const std::string& tag,
-      base::TimeDelta timeout,
-      DispatchPeriodicSyncEventCallback callback) override;
-  void DispatchAbortPaymentEvent(
-      payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
-      DispatchAbortPaymentEventCallback callback) override;
-  void DispatchCanMakePaymentEvent(
-      payments::mojom::CanMakePaymentEventDataPtr event_data,
-      payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
-      DispatchCanMakePaymentEventCallback callback) override;
-  void DispatchPaymentRequestEvent(
-      payments::mojom::PaymentRequestEventDataPtr event_data,
-      payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
-      DispatchPaymentRequestEventCallback callback) override;
-  void DispatchCookieChangeEvent(
-      const net::CanonicalCookie& cookie,
-      ::network::mojom::CookieChangeCause cause,
-      DispatchCookieChangeEventCallback callback) override;
-  void Ping(PingCallback callback) override;
-  void SetIdleTimerDelayToZero() override;
-
-  void OnNotificationClickEvent(
-      int request_id,
-      const std::string& notification_id,
-      const blink::PlatformNotificationData& notification_data,
-      int action_index,
-      const base::NullableString16& reply);
-  void OnNotificationCloseEvent(
-      int request_id,
-      const std::string& notification_id,
-      const blink::PlatformNotificationData& notification_data);
-
-  void OnFocusClientResponse(
-      int request_id,
-      const blink::mojom::ServiceWorkerClientInfo& client);
-  void OnNavigateClientResponse(
-      int request_id,
-      const blink::mojom::ServiceWorkerClientInfo& client);
-  void OnNavigateClientError(int request_id, const GURL& url);
-
-  void SetupNavigationPreload(
-      int fetch_event_id,
-      const GURL& url,
-      blink::mojom::FetchEventPreloadHandlePtr preload_handle);
-
-  // Called by ServiceWorkerTimeoutTimer when a certain time has passed since
-  // the last task finished.
-  void OnIdleTimeout();
-
-  void OnRequestedTermination(bool will_be_terminated);
-
-  // Returns true if the worker has requested to be terminated by the browser
-  // process. It does this due to idle timeout.
-  bool RequestedTermination() const;
-
   // Stops the worker context. Called on the main thread.
   void StopWorkerOnMainThread();
 
   base::WeakPtr<ServiceWorkerContextClient> GetWeakPtr();
 
-  void SetTimeoutTimerForTesting(
-      std::unique_ptr<ServiceWorkerTimeoutTimer> timeout_timer);
-  ServiceWorkerTimeoutTimer* GetTimeoutTimerForTesting();
-
   const int64_t service_worker_version_id_;
   const GURL service_worker_scope_;
   const GURL script_url_;
diff --git a/content/renderer/service_worker/service_worker_context_client_unittest.cc b/content/renderer/service_worker/service_worker_context_client_unittest.cc
deleted file mode 100644
index 62d04c3..0000000
--- a/content/renderer/service_worker/service_worker_context_client_unittest.cc
+++ /dev/null
@@ -1,670 +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/renderer/service_worker/service_worker_context_client.h"
-
-#include <utility>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/test/scoped_feature_list.h"
-#include "base/test/test_mock_time_task_runner.h"
-#include "base/time/tick_clock.h"
-#include "base/time/time.h"
-#include "content/child/thread_safe_sender.h"
-#include "content/common/service_worker/service_worker_types.h"
-#include "content/public/common/content_client.h"
-#include "content/public/renderer/content_renderer_client.h"
-#include "content/renderer/service_worker/embedded_worker_instance_client_impl.h"
-#include "content/renderer/service_worker/service_worker_timeout_timer.h"
-#include "content/renderer/service_worker/service_worker_type_util.h"
-#include "content/renderer/worker/worker_thread_registry.h"
-#include "mojo/public/cpp/bindings/associated_binding_set.h"
-#include "mojo/public/cpp/bindings/associated_interface_ptr.h"
-#include "services/network/public/cpp/features.h"
-#include "services/network/public/cpp/resource_request.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/common/fetch/fetch_api_request_headers_map.h"
-#include "third_party/blink/public/common/messaging/message_port_channel.h"
-#include "third_party/blink/public/mojom/background_fetch/background_fetch.mojom.h"
-#include "third_party/blink/public/mojom/service_worker/embedded_worker.mojom.h"
-#include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
-#include "third_party/blink/public/platform/modules/notifications/web_notification_data.h"
-#include "third_party/blink/public/platform/modules/payments/web_payment_request_event_data.h"
-#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_clients_info.h"
-#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_error.h"
-#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_registration_object_info.h"
-#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_request.h"
-#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
-#include "third_party/blink/public/platform/web_string.h"
-#include "third_party/blink/public/platform/web_url_response.h"
-#include "third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h"
-#include "third_party/blink/public/web/web_embedded_worker.h"
-
-namespace content {
-
-namespace {
-
-// Pipes connected to the context client.
-struct ContextClientPipes {
-  // From the browser to EmbeddedWorkerInstanceClientImpl.
-  blink::mojom::EmbeddedWorkerInstanceClientPtr embedded_worker_instance_client;
-
-  // From the browser to ServiceWorkerContextClient.
-  blink::mojom::ServiceWorkerPtr service_worker;
-  blink::mojom::ControllerServiceWorkerPtr controller;
-  blink::mojom::ServiceWorkerRegistrationObjectAssociatedPtr registration;
-
-  // From ServiceWorkerContextClient to the browser.
-  blink::mojom::ServiceWorkerHostAssociatedRequest service_worker_host_request;
-  blink::mojom::EmbeddedWorkerInstanceHostAssociatedRequest
-      embedded_worker_host_request;
-  blink::mojom::ServiceWorkerRegistrationObjectHostAssociatedRequest
-      registration_host_request;
-};
-
-// A fake WebEmbeddedWorker. This is needed to ensure WorkerContextDestroyed()
-// is called on EmbeddedWorkerInstanceClientImpl so it can self-destruct.
-class FakeWebEmbeddedWorker : public blink::WebEmbeddedWorker {
- public:
-  explicit FakeWebEmbeddedWorker(ServiceWorkerContextClient* context_client)
-      : context_client_(context_client) {}
-
-  void StartWorkerContext(const blink::WebEmbeddedWorkerStartData&) override {}
-  void TerminateWorkerContext() override {
-    v8::Local<v8::Context> local;
-    context_client_->WillDestroyWorkerContext(local);
-    context_client_->WorkerContextDestroyed();
-  }
-  void ResumeAfterDownload() override {}
-  void AddMessageToConsole(const blink::WebConsoleMessage&) override {}
-  void BindDevToolsAgent(mojo::ScopedInterfaceEndpointHandle,
-                         mojo::ScopedInterfaceEndpointHandle) override {}
-
- private:
-  ServiceWorkerContextClient* context_client_;
-};
-
-class MockWebServiceWorkerContextProxy
-    : public blink::WebServiceWorkerContextProxy {
- public:
-  ~MockWebServiceWorkerContextProxy() override = default;
-
-  void BindServiceWorkerHost(
-      mojo::ScopedInterfaceEndpointHandle service_worker_host) override {}
-  void SetRegistration(
-      blink::WebServiceWorkerRegistrationObjectInfo info) override {
-    DCHECK(!registration_object_info_);
-    registration_object_info_ =
-        std::make_unique<blink::WebServiceWorkerRegistrationObjectInfo>(
-            std::move(info));
-  }
-  void SetFetchHandlerExistence(
-      FetchHandlerExistence fetch_handler_existence) override {
-    fetch_handler_existence_ = fetch_handler_existence;
-  }
-  void ReadyToEvaluateScript() override {}
-  bool HasFetchEventHandler() override { return false; }
-  void DispatchFetchEvent(int fetch_event_id,
-                          const blink::WebServiceWorkerRequest& web_request,
-                          bool navigation_preload_sent) override {
-    fetch_events_.emplace_back(fetch_event_id, web_request);
-  }
-
-  void DispatchActivateEvent(int event_id) override { NOTREACHED(); }
-  void DispatchBackgroundFetchAbortEvent(
-      int event_id,
-      blink::WebBackgroundFetchRegistration registration) override {
-    NOTREACHED();
-  }
-  void DispatchBackgroundFetchClickEvent(
-      int event_id,
-      blink::WebBackgroundFetchRegistration registration) override {
-    NOTREACHED();
-  }
-  void DispatchBackgroundFetchFailEvent(
-      int event_id,
-      blink::WebBackgroundFetchRegistration registration) override {
-    NOTREACHED();
-  }
-  void DispatchBackgroundFetchSuccessEvent(
-      int event_id,
-      blink::WebBackgroundFetchRegistration registration) override {
-    NOTREACHED();
-  }
-  void DispatchCookieChangeEvent(
-      int event_id,
-      const blink::WebCanonicalCookie& cookie,
-      ::network::mojom::CookieChangeCause change_cause) override {
-    NOTREACHED();
-  }
-  void DispatchExtendableMessageEvent(
-      int event_id,
-      blink::TransferableMessage message,
-      const blink::WebSecurityOrigin& source_origin,
-      const blink::WebServiceWorkerClientInfo&) override {
-    NOTREACHED();
-  }
-  void DispatchExtendableMessageEvent(
-      int event_id,
-      blink::TransferableMessage message,
-      const blink::WebSecurityOrigin& source_origin,
-      blink::WebServiceWorkerObjectInfo) override {
-    NOTREACHED();
-  }
-  void DispatchInstallEvent(int event_id) override { NOTREACHED(); }
-  void DispatchNotificationClickEvent(int event_id,
-                                      const blink::WebString& notification_id,
-                                      const blink::WebNotificationData&,
-                                      int action_index,
-                                      const blink::WebString& reply) override {
-    NOTREACHED();
-  }
-  void DispatchNotificationCloseEvent(
-      int event_id,
-      const blink::WebString& notification_id,
-      const blink::WebNotificationData&) override {
-    NOTREACHED();
-  }
-  void DispatchPushEvent(int event_id, const blink::WebString& data) override {
-    NOTREACHED();
-  }
-  void DispatchSyncEvent(int sync_event_id,
-                         const blink::WebString& tag,
-                         bool last_chance) override {
-    NOTREACHED();
-  }
-  void DispatchPeriodicSyncEvent(int sync_event_id,
-                                 const blink::WebString& tag) override {
-    NOTREACHED();
-  }
-  void DispatchAbortPaymentEvent(int event_id) override { NOTREACHED(); }
-  void DispatchCanMakePaymentEvent(
-      int event_id,
-      const blink::WebCanMakePaymentEventData&) override {
-    NOTREACHED();
-  }
-  void DispatchPaymentRequestEvent(
-      int event_id,
-      std::unique_ptr<blink::WebPaymentRequestEventData>) override {
-    NOTREACHED();
-  }
-  void OnNavigationPreloadResponse(
-      int fetch_event_id,
-      std::unique_ptr<blink::WebURLResponse>,
-      mojo::ScopedDataPipeConsumerHandle) override {
-    NOTREACHED();
-  }
-  void OnNavigationPreloadError(
-      int fetch_event_id,
-      std::unique_ptr<blink::WebServiceWorkerError>) override {
-    NOTREACHED();
-  }
-  void OnNavigationPreloadComplete(int fetch_event_id,
-                                   base::TimeTicks completion_time,
-                                   int64_t encoded_data_length,
-                                   int64_t encoded_body_length,
-                                   int64_t decoded_body_length) override {
-    NOTREACHED();
-  }
-
-  const std::vector<
-      std::pair<int /* event_id */, blink::WebServiceWorkerRequest>>&
-  fetch_events() const {
-    return fetch_events_;
-  }
-
-  FetchHandlerExistence fetch_handler_existence() const {
-    return fetch_handler_existence_;
-  }
-
- private:
-  std::unique_ptr<blink::WebServiceWorkerRegistrationObjectInfo>
-      registration_object_info_;
-  std::vector<std::pair<int /* event_id */, blink::WebServiceWorkerRequest>>
-      fetch_events_;
-  FetchHandlerExistence fetch_handler_existence_ =
-      FetchHandlerExistence::UNKNOWN;
-};
-
-base::RepeatingClosure CreateCallbackWithCalledFlag(bool* out_is_called) {
-  return base::BindRepeating([](bool* out_is_called) { *out_is_called = true; },
-                             out_is_called);
-}
-
-class MockServiceWorkerObjectHost
-    : public blink::mojom::ServiceWorkerObjectHost {
- public:
-  explicit MockServiceWorkerObjectHost(int64_t version_id)
-      : version_id_(version_id) {}
-  ~MockServiceWorkerObjectHost() override = default;
-
-  blink::mojom::ServiceWorkerObjectInfoPtr CreateObjectInfo() {
-    auto info = blink::mojom::ServiceWorkerObjectInfo::New();
-    info->version_id = version_id_;
-    bindings_.AddBinding(this, mojo::MakeRequest(&info->host_ptr_info));
-    info->request = mojo::MakeRequest(&remote_object_);
-    return info;
-  }
-
-  int GetBindingCount() const { return bindings_.size(); }
-
- private:
-  // Implements blink::mojom::ServiceWorkerObjectHost.
-  void PostMessageToServiceWorker(
-      ::blink::TransferableMessage message) override {
-    NOTREACHED();
-  }
-  void TerminateForTesting(TerminateForTestingCallback callback) override {
-    NOTREACHED();
-  }
-
-  const int64_t version_id_;
-  mojo::AssociatedBindingSet<blink::mojom::ServiceWorkerObjectHost> bindings_;
-  blink::mojom::ServiceWorkerObjectAssociatedPtr remote_object_;
-};
-
-}  // namespace
-
-class ServiceWorkerContextClientTest : public testing::Test {
- public:
-  ServiceWorkerContextClientTest() = default;
-
- protected:
-  using FetchHandlerExistence = blink::mojom::FetchHandlerExistence;
-
-  void SetUp() override {
-    task_runner_ = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
-    message_loop_.SetTaskRunner(task_runner_);
-    // Use this thread as the worker thread.
-    WorkerThreadRegistry::Instance()->DidStartCurrentWorkerThread();
-    old_client_ = SetRendererClientForTesting(&renderer_client_);
-  }
-
-  void TearDown() override {
-    // Unregister this thread from worker threads.
-    WorkerThreadRegistry::Instance()->WillStopCurrentWorkerThread();
-    task_runner_->RunUntilIdle();
-    SetRendererClientForTesting(old_client_);
-  }
-
-  void EnableServicification() {
-    feature_list_.InitAndEnableFeature(network::features::kNetworkService);
-  }
-
-  // Creates an ContextClient, whose pipes are connected to |out_pipes|, then
-  // simulates that the service worker thread has started with |proxy|.
-  //
-  // The client's lifetime is tied to
-  // |out_pipes->embedded_worker_instance_client|.
-  ServiceWorkerContextClient* CreateContextClient(
-      ContextClientPipes* out_pipes,
-      blink::WebServiceWorkerContextProxy* proxy,
-      FetchHandlerExistence fetch_handler_existence =
-          FetchHandlerExistence::DOES_NOT_EXIST) {
-    EmbeddedWorkerInstanceClientImpl* embedded_worker_instance_client =
-        new EmbeddedWorkerInstanceClientImpl(
-            mojo::MakeRequest(&out_pipes->embedded_worker_instance_client));
-
-    auto service_worker_request = mojo::MakeRequest(&out_pipes->service_worker);
-    auto controller_request = mojo::MakeRequest(&out_pipes->controller);
-    blink::mojom::EmbeddedWorkerInstanceHostAssociatedPtr
-        embedded_worker_host_ptr;
-    out_pipes->embedded_worker_host_request =
-        mojo::MakeRequestAssociatedWithDedicatedPipe(&embedded_worker_host_ptr);
-    const GURL kScope("https://example.com");
-    const GURL kScript("https://example.com/SW.js");
-    auto context_client = std::make_unique<ServiceWorkerContextClient>(
-        1 /* service_worker_version_id */, kScope, kScript,
-        false /* is_script_streaming */,
-        blink::mojom::RendererPreferences::New(),
-        std::move(service_worker_request), std::move(controller_request),
-        embedded_worker_host_ptr.PassInterface(),
-        blink::mojom::ServiceWorkerProviderInfoForStartWorker::New(),
-        embedded_worker_instance_client,
-        blink::mojom::EmbeddedWorkerStartTiming::New(),
-        nullptr /* preference_watcher_request */,
-        nullptr /* subresource_loaders */,
-        blink::scheduler::GetSingleThreadTaskRunnerForTesting());
-
-    auto* context_client_raw = context_client.get();
-
-    embedded_worker_instance_client->service_worker_context_client_ =
-        std::move(context_client);
-    context_client_raw->StartWorkerContext(
-        std::make_unique<FakeWebEmbeddedWorker>(context_client_raw),
-        blink::WebEmbeddedWorkerStartData());
-
-    // TODO(falken): We should mock a worker thread task runner instead of
-    // using GetSingleThreadTaskRunnerForTesting() again, since that's the
-    // runner we used to mock the main thread when constructing the context
-    // client above.
-    context_client_raw->WorkerContextStarted(
-        proxy, blink::scheduler::GetSingleThreadTaskRunnerForTesting());
-
-    blink::mojom::ServiceWorkerHostAssociatedPtrInfo service_worker_host;
-    out_pipes->service_worker_host_request =
-        mojo::MakeRequest(&service_worker_host);
-    auto registration_info =
-        blink::mojom::ServiceWorkerRegistrationObjectInfo::New();
-    registration_info->registration_id = 100;  // dummy
-    registration_info->scope = kScope;
-    registration_info->update_via_cache =
-        blink::mojom::ServiceWorkerUpdateViaCache::kAll;
-    out_pipes->registration_host_request =
-        mojo::MakeRequest(&registration_info->host_ptr_info);
-    registration_info->request = mojo::MakeRequest(&out_pipes->registration);
-    out_pipes->service_worker->InitializeGlobalScope(
-        std::move(service_worker_host), std::move(registration_info),
-        fetch_handler_existence);
-    task_runner()->RunUntilIdle();
-    return context_client_raw;
-  }
-
-  ServiceWorkerContextClient* CreateIdleContextClient(
-      ContextClientPipes* pipes,
-      MockWebServiceWorkerContextProxy* mock_proxy) {
-    ServiceWorkerContextClient* context_client =
-        CreateContextClient(pipes, mock_proxy);
-    context_client->DidEvaluateScript(true /* success */);
-    task_runner()->RunUntilIdle();
-    EXPECT_TRUE(mock_proxy->fetch_events().empty());
-    is_idle_ = false;
-    auto timer = std::make_unique<ServiceWorkerTimeoutTimer>(
-        CreateCallbackWithCalledFlag(&is_idle_),
-        task_runner()->GetMockTickClock());
-    timer->Start();
-    context_client->SetTimeoutTimerForTesting(std::move(timer));
-
-    // Ensure the idle state.
-    EXPECT_FALSE(context_client->RequestedTermination());
-    task_runner()->FastForwardBy(ServiceWorkerTimeoutTimer::kIdleDelay +
-                                 ServiceWorkerTimeoutTimer::kUpdateInterval +
-                                 base::TimeDelta::FromSeconds(1));
-    EXPECT_TRUE(context_client->RequestedTermination());
-
-    return context_client;
-  }
-
-  ServiceWorkerTimeoutTimer* GetTimeoutTimer(
-      ServiceWorkerContextClient* context_client) {
-    return context_client->GetTimeoutTimerForTesting();
-  }
-
-  scoped_refptr<base::TestMockTimeTaskRunner> task_runner() const {
-    return task_runner_;
-  }
-
- private:
-  base::MessageLoop message_loop_;
-  scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
-  base::test::ScopedFeatureList feature_list_;
-  bool is_idle_;
-  ContentRendererClient renderer_client_;
-  ContentRendererClient* old_client_;
-};
-
-TEST_F(ServiceWorkerContextClientTest, Ping) {
-  ContextClientPipes pipes;
-  MockWebServiceWorkerContextProxy mock_proxy;
-  CreateContextClient(&pipes, &mock_proxy);
-
-  bool is_called = false;
-  pipes.service_worker->Ping(CreateCallbackWithCalledFlag(&is_called));
-  task_runner()->RunUntilIdle();
-  EXPECT_TRUE(is_called);
-}
-
-TEST_F(ServiceWorkerContextClientTest, DispatchFetchEvent) {
-  ContextClientPipes pipes;
-  MockWebServiceWorkerContextProxy mock_proxy;
-  ServiceWorkerContextClient* context_client =
-      CreateContextClient(&pipes, &mock_proxy);
-  context_client->DidEvaluateScript(true /* success */);
-  task_runner()->RunUntilIdle();
-  EXPECT_TRUE(mock_proxy.fetch_events().empty());
-
-  const GURL expected_url("https://example.com/expected");
-  auto request = blink::mojom::FetchAPIRequest::New();
-  request->url = expected_url;
-  blink::mojom::ServiceWorkerFetchResponseCallbackPtr fetch_callback_ptr;
-  blink::mojom::ServiceWorkerFetchResponseCallbackRequest
-      fetch_callback_request = mojo::MakeRequest(&fetch_callback_ptr);
-  auto params = blink::mojom::DispatchFetchEventParams::New();
-  params->request = std::move(request);
-  pipes.service_worker->DispatchFetchEvent(
-      std::move(params), std::move(fetch_callback_ptr),
-      base::BindOnce([](blink::mojom::ServiceWorkerEventStatus) {}));
-  task_runner()->RunUntilIdle();
-
-  ASSERT_EQ(1u, mock_proxy.fetch_events().size());
-  EXPECT_EQ(expected_url,
-            static_cast<GURL>(mock_proxy.fetch_events()[0].second.Url()));
-}
-
-class HeaderContentRendererClient : public ContentRendererClient {
-  bool IsExcludedHeaderForServiceWorkerFetchEvent(
-      const std::string& header_name) override {
-    return header_name == "x-bye-bye";
-  }
-};
-
-TEST_F(ServiceWorkerContextClientTest, DispatchFetchEvent_Headers) {
-  HeaderContentRendererClient header_client;
-  auto* old_client = SetRendererClientForTesting(&header_client);
-
-  ContextClientPipes pipes;
-  MockWebServiceWorkerContextProxy mock_proxy;
-  ServiceWorkerContextClient* context_client =
-      CreateContextClient(&pipes, &mock_proxy);
-  context_client->DidEvaluateScript(true /* success */);
-  task_runner()->RunUntilIdle();
-  EXPECT_TRUE(mock_proxy.fetch_events().empty());
-
-  const GURL expected_url("https://example.com/expected");
-  auto request = blink::mojom::FetchAPIRequest::New();
-  request->url = expected_url;
-  request->headers.emplace("x-bye-bye", "excluded");
-  request->headers.emplace("x-hi-hi", "present");
-  blink::mojom::ServiceWorkerFetchResponseCallbackPtr fetch_callback_ptr;
-  blink::mojom::ServiceWorkerFetchResponseCallbackRequest
-      fetch_callback_request = mojo::MakeRequest(&fetch_callback_ptr);
-  auto params = blink::mojom::DispatchFetchEventParams::New();
-  params->request = std::move(request);
-  pipes.service_worker->DispatchFetchEvent(
-      std::move(params), std::move(fetch_callback_ptr),
-      base::BindOnce([](blink::mojom::ServiceWorkerEventStatus) {}));
-  task_runner()->RunUntilIdle();
-
-  ASSERT_EQ(1u, mock_proxy.fetch_events().size());
-  const blink::WebServiceWorkerRequest& received_request =
-      mock_proxy.fetch_events()[0].second;
-  blink::FetchAPIRequestHeadersMap header_map;
-  GetServiceWorkerHeaderMapFromWebRequest(received_request, &header_map);
-
-  EXPECT_EQ(expected_url, static_cast<GURL>(received_request.Url()));
-  EXPECT_TRUE(header_map.find(std::string("x-bye-bye")) == header_map.end());
-  auto iter = header_map.find(std::string("x-hi-hi"));
-  ASSERT_TRUE(iter != header_map.end());
-  EXPECT_EQ("present", iter->second);
-
-  SetRendererClientForTesting(old_client);
-}
-
-TEST_F(ServiceWorkerContextClientTest,
-       DispatchOrQueueFetchEvent_NotRequestedTermination) {
-  EnableServicification();
-  ContextClientPipes pipes;
-  MockWebServiceWorkerContextProxy mock_proxy;
-  ServiceWorkerContextClient* context_client =
-      CreateContextClient(&pipes, &mock_proxy);
-  context_client->DidEvaluateScript(true /* success */);
-  task_runner()->RunUntilIdle();
-  EXPECT_TRUE(mock_proxy.fetch_events().empty());
-
-  bool is_idle = false;
-  auto timer = std::make_unique<ServiceWorkerTimeoutTimer>(
-      CreateCallbackWithCalledFlag(&is_idle),
-      task_runner()->GetMockTickClock());
-  timer->Start();
-  context_client->SetTimeoutTimerForTesting(std::move(timer));
-
-  // The dispatched fetch event should be recorded by |mock_proxy|.
-  const GURL expected_url("https://example.com/expected");
-  blink::mojom::ServiceWorkerFetchResponseCallbackPtr fetch_callback_ptr;
-  blink::mojom::ServiceWorkerFetchResponseCallbackRequest
-      fetch_callback_request = mojo::MakeRequest(&fetch_callback_ptr);
-  auto request = blink::mojom::FetchAPIRequest::New();
-  request->url = expected_url;
-  auto params = blink::mojom::DispatchFetchEventParams::New();
-  params->request = std::move(request);
-  context_client->DispatchOrQueueFetchEvent(
-      std::move(params), std::move(fetch_callback_ptr),
-      base::BindOnce([](blink::mojom::ServiceWorkerEventStatus) {}));
-  task_runner()->RunUntilIdle();
-
-  EXPECT_FALSE(context_client->RequestedTermination());
-  ASSERT_EQ(1u, mock_proxy.fetch_events().size());
-  EXPECT_EQ(expected_url,
-            static_cast<GURL>(mock_proxy.fetch_events()[0].second.Url()));
-}
-
-TEST_F(ServiceWorkerContextClientTest,
-       DispatchOrQueueFetchEvent_RequestedTerminationAndDie) {
-  EnableServicification();
-  ContextClientPipes pipes;
-  MockWebServiceWorkerContextProxy mock_proxy;
-  CreateIdleContextClient(&pipes, &mock_proxy);
-
-  const GURL expected_url("https://example.com/expected");
-
-  // FetchEvent dispatched directly from the controlled clients through
-  // blink::mojom::ControllerServiceWorker should be queued in the idle state.
-  {
-    blink::mojom::ServiceWorkerFetchResponseCallbackPtr fetch_callback_ptr;
-    blink::mojom::ServiceWorkerFetchResponseCallbackRequest
-        fetch_callback_request = mojo::MakeRequest(&fetch_callback_ptr);
-    auto request = blink::mojom::FetchAPIRequest::New();
-    request->url = expected_url;
-    auto params = blink::mojom::DispatchFetchEventParams::New();
-    params->request = std::move(request);
-    pipes.controller->DispatchFetchEvent(
-        std::move(params), std::move(fetch_callback_ptr),
-        base::BindOnce([](blink::mojom::ServiceWorkerEventStatus) {}));
-    task_runner()->RunUntilIdle();
-  }
-  EXPECT_TRUE(mock_proxy.fetch_events().empty());
-
-  // Destruction of |context_client| should not hit any DCHECKs.
-  pipes.embedded_worker_instance_client.reset();
-  task_runner()->RunUntilIdle();
-}
-
-TEST_F(ServiceWorkerContextClientTest,
-       DispatchOrQueueFetchEvent_RequestedTerminationAndWakeUp) {
-  EnableServicification();
-  ContextClientPipes pipes;
-  MockWebServiceWorkerContextProxy mock_proxy;
-  ServiceWorkerContextClient* context_client =
-      CreateIdleContextClient(&pipes, &mock_proxy);
-
-  const GURL expected_url_1("https://example.com/expected_1");
-  const GURL expected_url_2("https://example.com/expected_2");
-  blink::mojom::ServiceWorkerFetchResponseCallbackRequest
-      fetch_callback_request_1;
-  blink::mojom::ServiceWorkerFetchResponseCallbackRequest
-      fetch_callback_request_2;
-
-  // FetchEvent dispatched directly from the controlled clients through
-  // blink::mojom::ControllerServiceWorker should be queued in the idle state.
-  {
-    blink::mojom::ServiceWorkerFetchResponseCallbackPtr fetch_callback_ptr;
-    fetch_callback_request_1 = mojo::MakeRequest(&fetch_callback_ptr);
-    auto request = blink::mojom::FetchAPIRequest::New();
-    request->url = expected_url_1;
-    auto params = blink::mojom::DispatchFetchEventParams::New();
-    params->request = std::move(request);
-    pipes.controller->DispatchFetchEvent(
-        std::move(params), std::move(fetch_callback_ptr),
-        base::BindOnce([](blink::mojom::ServiceWorkerEventStatus) {}));
-    task_runner()->RunUntilIdle();
-  }
-  EXPECT_TRUE(mock_proxy.fetch_events().empty());
-
-  // Another event dispatched to blink::mojom::ServiceWorker wakes up
-  // the context client.
-  {
-    blink::mojom::ServiceWorkerFetchResponseCallbackPtr fetch_callback_ptr;
-    fetch_callback_request_2 = mojo::MakeRequest(&fetch_callback_ptr);
-    auto request = blink::mojom::FetchAPIRequest::New();
-    request->url = expected_url_2;
-    auto params = blink::mojom::DispatchFetchEventParams::New();
-    params->request = std::move(request);
-    pipes.service_worker->DispatchFetchEvent(
-        std::move(params), std::move(fetch_callback_ptr),
-        base::BindOnce([](blink::mojom::ServiceWorkerEventStatus) {}));
-    task_runner()->RunUntilIdle();
-  }
-  EXPECT_FALSE(context_client->RequestedTermination());
-
-  // All events should fire. The order of events should be kept.
-  ASSERT_EQ(2u, mock_proxy.fetch_events().size());
-  EXPECT_EQ(expected_url_1,
-            static_cast<GURL>(mock_proxy.fetch_events()[0].second.Url()));
-  EXPECT_EQ(expected_url_2,
-            static_cast<GURL>(mock_proxy.fetch_events()[1].second.Url()));
-}
-
-TEST_F(ServiceWorkerContextClientTest, TaskInServiceWorker) {
-  EnableServicification();
-  ContextClientPipes pipes;
-  MockWebServiceWorkerContextProxy mock_proxy;
-  ServiceWorkerContextClient* context_client =
-      CreateIdleContextClient(&pipes, &mock_proxy);
-
-  int task_id = context_client->WillStartTask();
-  EXPECT_FALSE(context_client->RequestedTermination());
-  context_client->DidEndTask(task_id);
-  EXPECT_FALSE(context_client->RequestedTermination());
-
-  // Ensure the idle state.
-  task_runner()->FastForwardBy(ServiceWorkerTimeoutTimer::kIdleDelay +
-                               ServiceWorkerTimeoutTimer::kUpdateInterval +
-                               base::TimeDelta::FromSeconds(1));
-  EXPECT_TRUE(context_client->RequestedTermination());
-}
-
-// Tests timing out a task created by WillStartTask().
-TEST_F(ServiceWorkerContextClientTest, AbortedTaskInServiceWorker) {
-  EnableServicification();
-  ContextClientPipes pipes;
-  MockWebServiceWorkerContextProxy mock_proxy;
-  ServiceWorkerContextClient* context_client =
-      CreateIdleContextClient(&pipes, &mock_proxy);
-
-  // Make a task that times out.
-  int task_id = context_client->WillStartTask();
-  task_runner()->FastForwardBy(ServiceWorkerTimeoutTimer::kEventTimeout +
-                               ServiceWorkerTimeoutTimer::kUpdateInterval +
-                               base::TimeDelta::FromSeconds(1));
-
-  // The event should have been aborted.
-  ServiceWorkerTimeoutTimer* timeout_timer = GetTimeoutTimer(context_client);
-  EXPECT_FALSE(timeout_timer->HasEvent(task_id));
-
-  // Calling DidEndTask() shouldn't crash.
-  context_client->DidEndTask(task_id);
-}
-
-TEST_F(ServiceWorkerContextClientTest, InstalledFetchEventHandler) {
-  ContextClientPipes pipes;
-  MockWebServiceWorkerContextProxy mock_proxy;
-  CreateContextClient(&pipes, &mock_proxy, FetchHandlerExistence::EXISTS);
-  EXPECT_EQ(FetchHandlerExistence::EXISTS,
-            mock_proxy.fetch_handler_existence());
-}
-
-}  // namespace content
diff --git a/content/renderer/service_worker/service_worker_subresource_loader.cc b/content/renderer/service_worker/service_worker_subresource_loader.cc
index 329c232..b322662 100644
--- a/content/renderer/service_worker/service_worker_subresource_loader.cc
+++ b/content/renderer/service_worker/service_worker_subresource_loader.cc
@@ -35,7 +35,6 @@
 #include "third_party/blink/public/mojom/blob/blob.mojom.h"
 #include "third_party/blink/public/mojom/service_worker/dispatch_fetch_event_params.mojom.h"
 #include "third_party/blink/public/platform/interface_provider.h"
-#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_request.h"
 #include "third_party/blink/public/platform/web_http_body.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "ui/base/page_transition_types.h"
diff --git a/content/renderer/service_worker/service_worker_type_converters.cc b/content/renderer/service_worker/service_worker_type_converters.cc
index 8f42273..b7d30068 100644
--- a/content/renderer/service_worker/service_worker_type_converters.cc
+++ b/content/renderer/service_worker/service_worker_type_converters.cc
@@ -10,129 +10,6 @@
 
 namespace mojo {
 
-blink::WebCanMakePaymentEventData
-TypeConverter<blink::WebCanMakePaymentEventData,
-              payments::mojom::CanMakePaymentEventDataPtr>::
-    Convert(const payments::mojom::CanMakePaymentEventDataPtr& input) {
-  blink::WebCanMakePaymentEventData output;
-
-  output.top_origin = blink::WebString::FromUTF8(input->top_origin.spec());
-  output.payment_request_origin =
-      blink::WebString::FromUTF8(input->payment_request_origin.spec());
-
-  output.method_data =
-      blink::WebVector<blink::WebPaymentMethodData>(input->method_data.size());
-  for (size_t i = 0; i < input->method_data.size(); i++) {
-    output.method_data[i] = mojo::ConvertTo<blink::WebPaymentMethodData>(
-        std::move(input->method_data[i]));
-  }
-
-  output.modifiers = blink::WebVector<blink::WebPaymentDetailsModifier>(
-      input->modifiers.size());
-  for (size_t i = 0; i < input->modifiers.size(); i++) {
-    output.modifiers[i] =
-        mojo::ConvertTo<blink::WebPaymentDetailsModifier>(input->modifiers[i]);
-  }
-
-  return output;
-}
-
-std::unique_ptr<blink::WebPaymentRequestEventData>
-TypeConverter<std::unique_ptr<blink::WebPaymentRequestEventData>,
-              payments::mojom::PaymentRequestEventDataPtr>::
-    Convert(const payments::mojom::PaymentRequestEventDataPtr& input) {
-  auto output = std::make_unique<blink::WebPaymentRequestEventData>();
-
-  output->top_origin = blink::WebString::FromUTF8(input->top_origin.spec());
-  output->payment_request_origin =
-      blink::WebString::FromUTF8(input->payment_request_origin.spec());
-  output->payment_request_id =
-      blink::WebString::FromUTF8(input->payment_request_id);
-
-  output->method_data =
-      blink::WebVector<blink::WebPaymentMethodData>(input->method_data.size());
-  for (size_t i = 0; i < input->method_data.size(); i++) {
-    output->method_data[i] = mojo::ConvertTo<blink::WebPaymentMethodData>(
-        std::move(input->method_data[i]));
-  }
-
-  output->total =
-      mojo::ConvertTo<blink::WebPaymentCurrencyAmount>(input->total);
-
-  output->modifiers = blink::WebVector<blink::WebPaymentDetailsModifier>(
-      input->modifiers.size());
-  for (size_t i = 0; i < input->modifiers.size(); i++) {
-    output->modifiers[i] =
-        mojo::ConvertTo<blink::WebPaymentDetailsModifier>(input->modifiers[i]);
-  }
-
-  output->instrument_key = blink::WebString::FromUTF8(input->instrument_key);
-  output->payment_handler_host_handle =
-      input->payment_handler_host.PassHandle();
-
-  return output;
-}
-
-blink::WebPaymentMethodData
-TypeConverter<blink::WebPaymentMethodData,
-              payments::mojom::PaymentMethodDataPtr>::
-    Convert(const payments::mojom::PaymentMethodDataPtr& input) {
-  DCHECK(!input->supported_method.empty());
-  blink::WebPaymentMethodData output;
-  output.supported_method = blink::WebString::FromUTF8(input->supported_method);
-  output.stringified_data = blink::WebString::FromUTF8(input->stringified_data);
-
-  return output;
-}
-
-blink::WebPaymentItem
-TypeConverter<blink::WebPaymentItem, payments::mojom::PaymentItemPtr>::Convert(
-    const payments::mojom::PaymentItemPtr& input) {
-  blink::WebPaymentItem output;
-  output.label = blink::WebString::FromUTF8(input->label);
-  output.amount =
-      mojo::ConvertTo<blink::WebPaymentCurrencyAmount>(input->amount);
-  output.pending = input->pending;
-  return output;
-}
-
-blink::WebPaymentCurrencyAmount
-TypeConverter<blink::WebPaymentCurrencyAmount,
-              payments::mojom::PaymentCurrencyAmountPtr>::
-    Convert(const payments::mojom::PaymentCurrencyAmountPtr& input) {
-  blink::WebPaymentCurrencyAmount output;
-  output.currency = blink::WebString::FromUTF8(input->currency);
-  output.value = blink::WebString::FromUTF8(input->value);
-  return output;
-}
-
-blink::WebPaymentDetailsModifier
-TypeConverter<blink::WebPaymentDetailsModifier,
-              payments::mojom::PaymentDetailsModifierPtr>::
-    Convert(const payments::mojom::PaymentDetailsModifierPtr& input) {
-  DCHECK(!input->method_data->supported_method.empty());
-  blink::WebPaymentDetailsModifier output;
-
-  output.supported_method =
-      blink::WebString::FromUTF8(input->method_data->supported_method);
-
-  // The total is optional in a modifier.
-  if (input->total)
-    output.total = mojo::ConvertTo<blink::WebPaymentItem>(input->total);
-
-  output.additional_display_items = blink::WebVector<blink::WebPaymentItem>(
-      input->additional_display_items.size());
-  for (size_t i = 0; i < input->additional_display_items.size(); i++) {
-    output.additional_display_items[i] = mojo::ConvertTo<blink::WebPaymentItem>(
-        input->additional_display_items[i]);
-  }
-
-  output.stringified_data =
-      blink::WebString::FromUTF8(input->method_data->stringified_data);
-
-  return output;
-}
-
 blink::WebServiceWorkerObjectInfo
 TypeConverter<blink::WebServiceWorkerObjectInfo,
               blink::mojom::ServiceWorkerObjectInfoPtr>::
diff --git a/content/renderer/service_worker/service_worker_type_converters.h b/content/renderer/service_worker/service_worker_type_converters.h
index 80f74c2a..2fbf6a9 100644
--- a/content/renderer/service_worker/service_worker_type_converters.h
+++ b/content/renderer/service_worker/service_worker_type_converters.h
@@ -8,12 +8,9 @@
 #include <memory>
 
 #include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
-#include "third_party/blink/public/mojom/payments/payment_app.mojom.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
-#include "third_party/blink/public/platform/modules/payments/web_can_make_payment_event_data.h"
-#include "third_party/blink/public/platform/modules/payments/web_payment_request_event_data.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_object_info.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_registration_object_info.h"
 #include "third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h"
@@ -21,47 +18,6 @@
 namespace mojo {
 
 template <>
-struct TypeConverter<blink::WebCanMakePaymentEventData,
-                     payments::mojom::CanMakePaymentEventDataPtr> {
-  static blink::WebCanMakePaymentEventData Convert(
-      const payments::mojom::CanMakePaymentEventDataPtr& input);
-};
-
-template <>
-struct TypeConverter<std::unique_ptr<blink::WebPaymentRequestEventData>,
-                     payments::mojom::PaymentRequestEventDataPtr> {
-  static std::unique_ptr<blink::WebPaymentRequestEventData> Convert(
-      const payments::mojom::PaymentRequestEventDataPtr& input);
-};
-
-template <>
-struct TypeConverter<blink::WebPaymentMethodData,
-                     payments::mojom::PaymentMethodDataPtr> {
-  static blink::WebPaymentMethodData Convert(
-      const payments::mojom::PaymentMethodDataPtr& input);
-};
-
-template <>
-struct TypeConverter<blink::WebPaymentItem, payments::mojom::PaymentItemPtr> {
-  static blink::WebPaymentItem Convert(
-      const payments::mojom::PaymentItemPtr& input);
-};
-
-template <>
-struct TypeConverter<blink::WebPaymentCurrencyAmount,
-                     payments::mojom::PaymentCurrencyAmountPtr> {
-  static blink::WebPaymentCurrencyAmount Convert(
-      const payments::mojom::PaymentCurrencyAmountPtr& input);
-};
-
-template <>
-struct TypeConverter<blink::WebPaymentDetailsModifier,
-                     payments::mojom::PaymentDetailsModifierPtr> {
-  static blink::WebPaymentDetailsModifier Convert(
-      const payments::mojom::PaymentDetailsModifierPtr& input);
-};
-
-template <>
 struct TypeConverter<blink::WebServiceWorkerObjectInfo,
                      blink::mojom::ServiceWorkerObjectInfoPtr> {
   static blink::WebServiceWorkerObjectInfo Convert(
diff --git a/content/renderer/service_worker/service_worker_type_util.cc b/content/renderer/service_worker/service_worker_type_util.cc
deleted file mode 100644
index 431355a..0000000
--- a/content/renderer/service_worker/service_worker_type_util.cc
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/renderer/service_worker/service_worker_type_util.h"
-
-#include <memory>
-#include <string>
-
-#include "base/strings/utf_string_conversions.h"
-#include "content/common/service_worker/service_worker_types.h"
-#include "storage/common/blob_storage/blob_handle.h"
-#include "third_party/blink/public/common/fetch/fetch_api_request_headers_map.h"
-#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_request.h"
-#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_response.h"
-#include "third_party/blink/public/platform/web_http_header_visitor.h"
-#include "third_party/blink/public/platform/web_string.h"
-
-namespace content {
-
-namespace {
-
-template <typename T>
-class HeaderVisitor : public blink::WebHTTPHeaderVisitor {
- public:
-  explicit HeaderVisitor(T* headers) : headers_(headers) {}
-  ~HeaderVisitor() override {}
-
-  void VisitHeader(const blink::WebString& name,
-                   const blink::WebString& value) override {
-    // Headers are ISO Latin 1.
-    const std::string& header_name = name.Latin1();
-    const std::string& header_value = value.Latin1();
-    CHECK(header_name.find('\0') == std::string::npos);
-    CHECK(header_value.find('\0') == std::string::npos);
-    headers_->insert(typename T::value_type(header_name, header_value));
-  }
-
- private:
-  T* const headers_;
-};
-
-template <typename T>
-std::unique_ptr<HeaderVisitor<T>> MakeHeaderVisitor(T* headers) {
-  return std::make_unique<HeaderVisitor<T>>(headers);
-}
-
-std::vector<std::string> GetHeaderList(
-    const blink::WebVector<blink::WebString>& web_headers) {
-  auto result = std::vector<std::string>(web_headers.size());
-  std::transform(web_headers.begin(), web_headers.end(), result.begin(),
-                 [](const blink::WebString& s) { return s.Latin1(); });
-  return result;
-}
-
-std::vector<GURL> GetURLList(
-    const blink::WebVector<blink::WebURL>& web_url_list) {
-  std::vector<GURL> result = std::vector<GURL>(web_url_list.size());
-  std::transform(web_url_list.begin(), web_url_list.end(), result.begin(),
-                 [](const blink::WebURL& url) { return url; });
-  return result;
-}
-
-}  // namespace
-
-void GetServiceWorkerHeaderMapFromWebRequest(
-    const blink::WebServiceWorkerRequest& web_request,
-    blink::FetchAPIRequestHeadersMap* headers) {
-  DCHECK(headers);
-  DCHECK(headers->empty());
-  web_request.VisitHttpHeaderFields(MakeHeaderVisitor(headers).get());
-}
-
-blink::mojom::FetchAPIResponsePtr GetFetchAPIResponseFromWebResponse(
-    const blink::WebServiceWorkerResponse& web_response) {
-  blink::mojom::SerializedBlobPtr blob;
-  if (!web_response.BlobUUID().IsEmpty()) {
-    blob = blink::mojom::SerializedBlob::New();
-    blob->uuid = web_response.BlobUUID().Utf8();
-    blob->size = web_response.BlobSize();
-    auto blob_pipe = web_response.CloneBlobPtr();
-    DCHECK(blob_pipe.is_valid());
-    blob->blob = blink::mojom::BlobPtrInfo(std::move(blob_pipe),
-                                           blink::mojom::Blob::Version_);
-  }
-
-  blink::mojom::SerializedBlobPtr side_data_blob;
-  if (web_response.SideDataBlobSize() != 0) {
-    side_data_blob = blink::mojom::SerializedBlob::New();
-    side_data_blob->uuid = web_response.SideDataBlobUUID().Utf8();
-    side_data_blob->size = web_response.SideDataBlobSize();
-    auto side_data_blob_pipe = web_response.CloneSideDataBlobPtr();
-    DCHECK(side_data_blob_pipe.is_valid());
-    side_data_blob->blob = blink::mojom::BlobPtrInfo(
-        std::move(side_data_blob_pipe), blink::mojom::Blob::Version_);
-  }
-
-  base::flat_map<std::string, std::string> headers;
-  web_response.VisitHttpHeaderFields(MakeHeaderVisitor(&headers).get());
-
-  return blink::mojom::FetchAPIResponse::New(
-      GetURLList(web_response.UrlList()), web_response.Status(),
-      web_response.StatusText().Utf8(), web_response.ResponseType(),
-      web_response.ResponseSource(), headers, std::move(blob),
-      web_response.GetError(), web_response.ResponseTime(),
-      web_response.CacheStorageCacheName().Utf8(),
-      GetHeaderList(web_response.CorsExposedHeaderNames()),
-      std::move(side_data_blob));
-}
-
-}  // namespace content
diff --git a/content/renderer/service_worker/service_worker_type_util.h b/content/renderer/service_worker/service_worker_type_util.h
deleted file mode 100644
index 8d7c1467..0000000
--- a/content/renderer/service_worker/service_worker_type_util.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_TYPE_UTIL_H_
-#define CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_TYPE_UTIL_H_
-
-#include "content/common/service_worker/service_worker_types.h"
-#include "third_party/blink/public/common/fetch/fetch_api_request_headers_map.h"
-#include "third_party/blink/public/mojom/fetch/fetch_api_response.mojom.h"
-
-namespace blink {
-class WebServiceWorkerRequest;
-class WebServiceWorkerResponse;
-}
-
-namespace content {
-
-void CONTENT_EXPORT GetServiceWorkerHeaderMapFromWebRequest(
-    const blink::WebServiceWorkerRequest& web_request,
-    blink::FetchAPIRequestHeadersMap* headers);
-
-blink::mojom::FetchAPIResponsePtr GetFetchAPIResponseFromWebResponse(
-    const blink::WebServiceWorkerResponse& web_response);
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_TYPE_UTIL_H_
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 4cee1c1..e4c45f4 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1878,10 +1878,8 @@
     "../renderer/render_frame_metadata_observer_impl_unittest.cc",
     "../renderer/render_thread_impl_unittest.cc",
     "../renderer/render_widget_unittest.cc",
-    "../renderer/service_worker/service_worker_context_client_unittest.cc",
     "../renderer/service_worker/service_worker_provider_context_unittest.cc",
     "../renderer/service_worker/service_worker_subresource_loader_unittest.cc",
-    "../renderer/service_worker/service_worker_timeout_timer_unittest.cc",
     "../renderer/skia_benchmarking_extension_unittest.cc",
     "../renderer/v8_value_converter_impl_unittest.cc",
     "../renderer/worker/worker_thread_registry_unittest.cc",
diff --git a/device/fido/attestation_object.cc b/device/fido/attestation_object.cc
index 552223a..0bd40b7 100644
--- a/device/fido/attestation_object.cc
+++ b/device/fido/attestation_object.cc
@@ -63,27 +63,15 @@
       ->IsAttestationCertificateInappropriatelyIdentifying();
 }
 
-std::vector<uint8_t> AttestationObject::SerializeToCBOREncodedBytes() const {
+cbor::Value AsCBOR(const AttestationObject& object) {
   cbor::Value::MapValue map;
   map[cbor::Value(kFormatKey)] =
-      cbor::Value(attestation_statement_->format_name());
+      cbor::Value(object.attestation_statement().format_name());
   map[cbor::Value(kAuthDataKey)] =
-      cbor::Value(authenticator_data_.SerializeToByteArray());
+      cbor::Value(object.authenticator_data().SerializeToByteArray());
   map[cbor::Value(kAttestationStatementKey)] =
-      cbor::Value(attestation_statement_->GetAsCBORMap());
-  return cbor::Writer::Write(cbor::Value(std::move(map)))
-      .value_or(std::vector<uint8_t>());
-}
-
-std::vector<uint8_t> SerializeToCtapStyleCborEncodedBytes(
-    const AttestationObject& object) {
-  cbor::Value::MapValue map;
-  map.emplace(1, object.attestation_statement().format_name());
-  map.emplace(2, object.authenticator_data().SerializeToByteArray());
-  map.emplace(3, object.attestation_statement().GetAsCBORMap());
-  auto encoded_bytes = cbor::Writer::Write(cbor::Value(std::move(map)));
-  DCHECK(encoded_bytes);
-  return std::move(*encoded_bytes);
+      AsCBOR(object.attestation_statement());
+  return cbor::Value(std::move(map));
 }
 
 }  // namespace device
diff --git a/device/fido/attestation_object.h b/device/fido/attestation_object.h
index 2eba61f..b89b8a1 100644
--- a/device/fido/attestation_object.h
+++ b/device/fido/attestation_object.h
@@ -60,12 +60,6 @@
   // not indended to be trackable.)
   bool IsAttestationCertificateInappropriatelyIdentifying();
 
-  // Produces a WebAuthN style CBOR-encoded byte-array in the following format:
-  // {"authData": authenticator data bytes,
-  //  "fmt": attestation format name,
-  //  "attStmt": attestation statement bytes }
-  std::vector<uint8_t> SerializeToCBOREncodedBytes() const;
-
   const std::array<uint8_t, kRpIdHashLength>& rp_id_hash() const {
     return authenticator_data_.application_parameter();
   }
@@ -85,14 +79,13 @@
   DISALLOW_COPY_AND_ASSIGN(AttestationObject);
 };
 
-// Produces a CTAP style CBOR-encoded byte array that that conforms to the
-// format CTAP2 devices sends to the client as a response. More specifically:
-// {01: attestation format name,
-//  02: authenticator data bytes,
-//  03: attestation statement bytes }
+// Produces a WebAuthN style CBOR-encoded byte-array
+// in the following format, when written:
+// {"authData": authenticator data bytes,
+//  "fmt": attestation format name,
+//  "attStmt": attestation statement bytes }
 COMPONENT_EXPORT(DEVICE_FIDO)
-std::vector<uint8_t> SerializeToCtapStyleCborEncodedBytes(
-    const AttestationObject& object);
+cbor::Value AsCBOR(const AttestationObject&);
 
 }  // namespace device
 
diff --git a/device/fido/attestation_statement.cc b/device/fido/attestation_statement.cc
index 44bc680..6c99457 100644
--- a/device/fido/attestation_statement.cc
+++ b/device/fido/attestation_statement.cc
@@ -35,8 +35,12 @@
   return base::nullopt;
 }
 
-cbor::Value::MapValue NoneAttestationStatement::GetAsCBORMap() const {
-  return cbor::Value::MapValue();
+cbor::Value NoneAttestationStatement::AsCBOR() const {
+  return cbor::Value(cbor::Value::MapValue());
+}
+
+cbor::Value AsCBOR(const AttestationStatement& as) {
+  return as.AsCBOR();
 }
 
 }  // namespace device
diff --git a/device/fido/attestation_statement.h b/device/fido/attestation_statement.h
index 2119f430..709184e 100644
--- a/device/fido/attestation_statement.h
+++ b/device/fido/attestation_statement.h
@@ -31,7 +31,7 @@
   // https://www.w3.org/TR/2017/WD-webauthn-20170505/#defined-attestation-formats
   // This is not a CBOR-encoded byte array, but the map that will be
   // nested within another CBOR object and encoded then.
-  virtual cbor::Value::MapValue GetAsCBORMap() const = 0;
+  virtual cbor::Value AsCBOR() const = 0;
 
   // Returns true if the attestation is a "self" attestation, i.e. is just the
   // private key signing itself to show that it is fresh.
@@ -66,15 +66,18 @@
   NoneAttestationStatement();
   ~NoneAttestationStatement() override;
 
+  cbor::Value AsCBOR() const override;
   bool IsSelfAttestation() override;
   bool IsAttestationCertificateInappropriatelyIdentifying() override;
-  cbor::Value::MapValue GetAsCBORMap() const override;
   base::Optional<base::span<const uint8_t>> GetLeafCertificate() const override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(NoneAttestationStatement);
 };
 
+COMPONENT_EXPORT(DEVICE_FIDO)
+cbor::Value AsCBOR(const AttestationStatement&);
+
 }  // namespace device
 
 #endif  // DEVICE_FIDO_ATTESTATION_STATEMENT_H_
diff --git a/device/fido/attestation_statement_formats.cc b/device/fido/attestation_statement_formats.cc
index dfa057b..1b76d170 100644
--- a/device/fido/attestation_statement_formats.cc
+++ b/device/fido/attestation_statement_formats.cc
@@ -119,7 +119,7 @@
 
 FidoAttestationStatement::~FidoAttestationStatement() = default;
 
-cbor::Value::MapValue FidoAttestationStatement::GetAsCBORMap() const {
+cbor::Value FidoAttestationStatement::AsCBOR() const {
   cbor::Value::MapValue attestation_statement_map;
   attestation_statement_map[cbor::Value(kSignatureKey)] =
       cbor::Value(signature_);
@@ -132,7 +132,7 @@
   attestation_statement_map[cbor::Value(kX509CertKey)] =
       cbor::Value(std::move(certificate_array));
 
-  return attestation_statement_map;
+  return cbor::Value(std::move(attestation_statement_map));
 }
 
 bool FidoAttestationStatement::IsSelfAttestation() {
@@ -174,7 +174,7 @@
 
 PackedAttestationStatement::~PackedAttestationStatement() = default;
 
-cbor::Value::MapValue PackedAttestationStatement::GetAsCBORMap() const {
+cbor::Value PackedAttestationStatement::AsCBOR() const {
   cbor::Value::MapValue attestation_statement_map;
   // alg
   attestation_statement_map[cbor::Value(kAlgorithmKey)] =
@@ -191,7 +191,7 @@
     attestation_statement_map[cbor::Value(kX509CertKey)] =
         cbor::Value(std::move(certificate_array));
   }
-  return attestation_statement_map;
+  return cbor::Value(std::move(attestation_statement_map));
 }
 
 bool PackedAttestationStatement::IsSelfAttestation() {
diff --git a/device/fido/attestation_statement_formats.h b/device/fido/attestation_statement_formats.h
index 3bb9137..5bf0e1b 100644
--- a/device/fido/attestation_statement_formats.h
+++ b/device/fido/attestation_statement_formats.h
@@ -29,8 +29,7 @@
                            std::vector<std::vector<uint8_t>> x509_certificates);
   ~FidoAttestationStatement() override;
 
-  // AttestationStatement
-  cbor::Value::MapValue GetAsCBORMap() const override;
+  cbor::Value AsCBOR() const override;
   bool IsSelfAttestation() override;
   bool IsAttestationCertificateInappropriatelyIdentifying() override;
   base::Optional<base::span<const uint8_t>> GetLeafCertificate() const override;
@@ -56,8 +55,7 @@
       std::vector<std::vector<uint8_t>> x509_certificates);
   ~PackedAttestationStatement() override;
 
-  // AttestationStatement
-  cbor::Value::MapValue GetAsCBORMap() const override;
+  cbor::Value AsCBOR() const override;
   bool IsSelfAttestation() override;
   bool IsAttestationCertificateInappropriatelyIdentifying() override;
   base::Optional<base::span<const uint8_t>> GetLeafCertificate() const override;
diff --git a/device/fido/attestation_statement_formats_unittest.cc b/device/fido/attestation_statement_formats_unittest.cc
index 8db60906..f7f4d0b 100644
--- a/device/fido/attestation_statement_formats_unittest.cc
+++ b/device/fido/attestation_statement_formats_unittest.cc
@@ -83,21 +83,17 @@
 
 TEST(PackedAttestationStatementTest, CBOR) {
   EXPECT_THAT(
-      *cbor::Writer::Write(
-          cbor::Value(PackedAttestationStatement(
-                          CoseAlgorithmIdentifier::kCoseEs256,
-                          fido_parsing_utils::Materialize(kSignature),
-                          {fido_parsing_utils::Materialize(kCertificates)})
-                          .GetAsCBORMap())),
+      *cbor::Writer::Write(AsCBOR(PackedAttestationStatement(
+          CoseAlgorithmIdentifier::kCoseEs256,
+          fido_parsing_utils::Materialize(kSignature),
+          {fido_parsing_utils::Materialize(kCertificates)}))),
       testing::ElementsAreArray(test_data::kPackedAttestationStatementCBOR));
 }
 
 TEST(PackedAttestationStatementTest, CBOR_NoCerts) {
-  EXPECT_THAT(*cbor::Writer::Write(cbor::Value(
-                  PackedAttestationStatement(
-                      CoseAlgorithmIdentifier::kCoseEs256,
-                      fido_parsing_utils::Materialize(kSignature), {})
-                      .GetAsCBORMap())),
+  EXPECT_THAT(*cbor::Writer::Write(AsCBOR(PackedAttestationStatement(
+                  CoseAlgorithmIdentifier::kCoseEs256,
+                  fido_parsing_utils::Materialize(kSignature), {}))),
               testing::ElementsAreArray(
                   test_data::kPackedAttestationStatementCBORNoCerts));
 }
diff --git a/device/fido/authenticator_get_assertion_response.cc b/device/fido/authenticator_get_assertion_response.cc
index 72c3458..4c21776 100644
--- a/device/fido/authenticator_get_assertion_response.cc
+++ b/device/fido/authenticator_get_assertion_response.cc
@@ -101,15 +101,14 @@
     const AuthenticatorGetAssertionResponse& response) {
   cbor::Value::MapValue response_map;
   if (response.credential()) {
-    response_map.emplace(1, response.credential()->ConvertToCBOR());
+    response_map.emplace(1, AsCBOR(*response.credential()));
   }
 
   response_map.emplace(2, response.auth_data().SerializeToByteArray());
   response_map.emplace(3, response.signature());
 
   if (response.user_entity()) {
-    response_map.emplace(4, PublicKeyCredentialUserEntity::ConvertToCBOR(
-                                *response.user_entity()));
+    response_map.emplace(4, AsCBOR(*response.user_entity()));
   }
   if (response.num_credentials()) {
     response_map.emplace(5, response.num_credentials().value());
diff --git a/device/fido/authenticator_get_info_response.cc b/device/fido/authenticator_get_info_response.cc
index 3e6be2d..5769e94 100644
--- a/device/fido/authenticator_get_info_response.cc
+++ b/device/fido/authenticator_get_info_response.cc
@@ -54,7 +54,7 @@
     device_info_map.emplace(2, ToArrayValue(*response.extensions));
 
   device_info_map.emplace(3, response.aaguid);
-  device_info_map.emplace(4, ConvertToCBOR(response.options));
+  device_info_map.emplace(4, AsCBOR(response.options));
 
   if (response.max_msg_size) {
     device_info_map.emplace(5,
diff --git a/device/fido/authenticator_make_credential_response.cc b/device/fido/authenticator_make_credential_response.cc
index 2559a51..8022cb3e 100644
--- a/device/fido/authenticator_make_credential_response.cc
+++ b/device/fido/authenticator_make_credential_response.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "components/cbor/writer.h"
 #include "device/fido/attestation_object.h"
 #include "device/fido/attestation_statement_formats.h"
 #include "device/fido/attested_credential_data.h"
@@ -75,7 +76,8 @@
 
 std::vector<uint8_t>
 AuthenticatorMakeCredentialResponse::GetCBOREncodedAttestationObject() const {
-  return attestation_object_.SerializeToCBOREncodedBytes();
+  return cbor::Writer::Write(AsCBOR(attestation_object_))
+      .value_or(std::vector<uint8_t>());
 }
 
 void AuthenticatorMakeCredentialResponse::EraseAttestationStatement(
@@ -98,9 +100,16 @@
   return attestation_object_.rp_id_hash();
 }
 
-std::vector<uint8_t> GetSerializedCtapDeviceResponse(
+std::vector<uint8_t> AsCTAPStyleCBORBytes(
     const AuthenticatorMakeCredentialResponse& response) {
-  return SerializeToCtapStyleCborEncodedBytes(response.attestation_object());
+  const AttestationObject& object = response.attestation_object();
+  cbor::Value::MapValue map;
+  map.emplace(1, object.attestation_statement().format_name());
+  map.emplace(2, object.authenticator_data().SerializeToByteArray());
+  map.emplace(3, AsCBOR(object.attestation_statement()));
+  auto encoded_bytes = cbor::Writer::Write(cbor::Value(std::move(map)));
+  DCHECK(encoded_bytes);
+  return std::move(*encoded_bytes);
 }
 
 }  // namespace device
diff --git a/device/fido/authenticator_make_credential_response.h b/device/fido/authenticator_make_credential_response.h
index e55193dd8..050f3a4 100644
--- a/device/fido/authenticator_make_credential_response.h
+++ b/device/fido/authenticator_make_credential_response.h
@@ -81,8 +81,13 @@
   DISALLOW_COPY_AND_ASSIGN(AuthenticatorMakeCredentialResponse);
 };
 
+// Through cbor::Writer, produces a CTAP style CBOR-encoded byte array
+// that conforms to the format CTAP2 devices sends to the client as a response.
+// {01: attestation format name,
+//  02: authenticator data bytes,
+//  03: attestation statement bytes }
 COMPONENT_EXPORT(DEVICE_FIDO)
-std::vector<uint8_t> GetSerializedCtapDeviceResponse(
+std::vector<uint8_t> AsCTAPStyleCBORBytes(
     const AuthenticatorMakeCredentialResponse& response);
 
 }  // namespace device
diff --git a/device/fido/authenticator_supported_options.cc b/device/fido/authenticator_supported_options.cc
index 12253ed..562704e 100644
--- a/device/fido/authenticator_supported_options.cc
+++ b/device/fido/authenticator_supported_options.cc
@@ -17,7 +17,7 @@
     const AuthenticatorSupportedOptions& other) = default;
 AuthenticatorSupportedOptions::~AuthenticatorSupportedOptions() = default;
 
-cbor::Value ConvertToCBOR(const AuthenticatorSupportedOptions& options) {
+cbor::Value AsCBOR(const AuthenticatorSupportedOptions& options) {
   cbor::Value::MapValue option_map;
   option_map.emplace(kResidentKeyMapKey, options.supports_resident_key);
   option_map.emplace(kUserPresenceMapKey, options.supports_user_presence);
diff --git a/device/fido/authenticator_supported_options.h b/device/fido/authenticator_supported_options.h
index b0ba9137..6027c4d3 100644
--- a/device/fido/authenticator_supported_options.h
+++ b/device/fido/authenticator_supported_options.h
@@ -71,7 +71,7 @@
 };
 
 COMPONENT_EXPORT(DEVICE_FIDO)
-cbor::Value ConvertToCBOR(const AuthenticatorSupportedOptions& options);
+cbor::Value AsCBOR(const AuthenticatorSupportedOptions& options);
 
 }  // namespace device
 
diff --git a/device/fido/credential_management.cc b/device/fido/credential_management.cc
index ec848f22..ed56dc12 100644
--- a/device/fido/credential_management.cc
+++ b/device/fido/credential_management.cc
@@ -47,33 +47,6 @@
 CredentialManagementRequest::~CredentialManagementRequest() = default;
 
 // static
-std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
-CredentialManagementRequest::EncodeAsCBOR(
-    const CredentialManagementRequest& request) {
-  cbor::Value::MapValue request_map;
-  request_map.emplace(
-      static_cast<int>(CredentialManagementRequestKey::kSubCommand),
-      static_cast<int>(request.subcommand));
-  if (request.params) {
-    request_map.emplace(
-        static_cast<int>(CredentialManagementRequestKey::kSubCommandParams),
-        *request.params);
-  }
-  if (request.pin_auth) {
-    request_map.emplace(
-        static_cast<int>(CredentialManagementRequestKey::kPinProtocol),
-        static_cast<int>(pin::kProtocolVersion));
-    request_map.emplace(
-        static_cast<int>(CredentialManagementRequestKey::kPinAuth),
-        *request.pin_auth);
-  }
-  return {request.version == kPreview
-              ? CtapRequestCommand::kAuthenticatorCredentialManagementPreview
-              : CtapRequestCommand::kAuthenticatorCredentialManagement,
-          cbor::Value(std::move(request_map))};
-}
-
-// static
 CredentialManagementRequest CredentialManagementRequest::ForGetCredsMetadata(
     Version version,
     base::span<const uint8_t> pin_token) {
@@ -352,4 +325,29 @@
 AggregatedEnumerateCredentialsResponse::
     ~AggregatedEnumerateCredentialsResponse() = default;
 
+std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
+AsCTAPRequestValuePair(const CredentialManagementRequest& request) {
+  cbor::Value::MapValue request_map;
+  request_map.emplace(
+      static_cast<int>(CredentialManagementRequestKey::kSubCommand),
+      static_cast<int>(request.subcommand));
+  if (request.params) {
+    request_map.emplace(
+        static_cast<int>(CredentialManagementRequestKey::kSubCommandParams),
+        *request.params);
+  }
+  if (request.pin_auth) {
+    request_map.emplace(
+        static_cast<int>(CredentialManagementRequestKey::kPinProtocol),
+        static_cast<int>(pin::kProtocolVersion));
+    request_map.emplace(
+        static_cast<int>(CredentialManagementRequestKey::kPinAuth),
+        *request.pin_auth);
+  }
+  return {request.version == CredentialManagementRequest::kPreview
+              ? CtapRequestCommand::kAuthenticatorCredentialManagementPreview
+              : CtapRequestCommand::kAuthenticatorCredentialManagement,
+          cbor::Value(std::move(request_map))};
+}
+
 }  // namespace device
diff --git a/device/fido/credential_management.h b/device/fido/credential_management.h
index cda0cf4..7649e40 100644
--- a/device/fido/credential_management.h
+++ b/device/fido/credential_management.h
@@ -205,6 +205,9 @@
 
 using DeleteCredentialResponse = pin::EmptyResponse;
 
+std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
+AsCTAPRequestValuePair(const CredentialManagementRequest&);
+
 }  // namespace device
 
 #endif  // DEVICE_FIDO_CREDENTIAL_MANAGEMENT_H_
diff --git a/device/fido/ctap2_device_operation.h b/device/fido/ctap2_device_operation.h
index 3d9c1ad1..0dc6b90 100644
--- a/device/fido/ctap2_device_operation.h
+++ b/device/fido/ctap2_device_operation.h
@@ -76,7 +76,7 @@
 
   void Start() override {
     std::pair<CtapRequestCommand, base::Optional<cbor::Value>> request(
-        Request::EncodeAsCBOR(this->request()));
+        AsCTAPRequestValuePair(this->request()));
     std::vector<uint8_t> request_bytes;
 
     // TODO: it would be nice to see which device each request is going to, but
diff --git a/device/fido/ctap_get_assertion_request.cc b/device/fido/ctap_get_assertion_request.cc
index 2ee95ad..7d60cab 100644
--- a/device/fido/ctap_get_assertion_request.cc
+++ b/device/fido/ctap_get_assertion_request.cc
@@ -37,9 +37,8 @@
 
 CtapGetAssertionRequest::~CtapGetAssertionRequest() = default;
 
-// static
 std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
-CtapGetAssertionRequest::EncodeAsCBOR(const CtapGetAssertionRequest& request) {
+AsCTAPRequestValuePair(const CtapGetAssertionRequest& request) {
   cbor::Value::MapValue cbor_map;
   cbor_map[cbor::Value(1)] = cbor::Value(request.rp_id);
   cbor_map[cbor::Value(2)] = cbor::Value(request.client_data_hash);
@@ -47,7 +46,7 @@
   if (!request.allow_list.empty()) {
     cbor::Value::ArrayValue allow_list_array;
     for (const auto& descriptor : request.allow_list) {
-      allow_list_array.push_back(descriptor.ConvertToCBOR());
+      allow_list_array.push_back(AsCBOR(descriptor));
     }
     cbor_map[cbor::Value(3)] = cbor::Value(std::move(allow_list_array));
   }
@@ -81,9 +80,8 @@
                         cbor::Value(std::move(cbor_map)));
 }
 
-// static
 std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
-CtapGetNextAssertionRequest::EncodeAsCBOR(const CtapGetNextAssertionRequest&) {
+AsCTAPRequestValuePair(const CtapGetNextAssertionRequest&) {
   return std::make_pair(CtapRequestCommand::kAuthenticatorGetNextAssertion,
                         base::nullopt);
 }
diff --git a/device/fido/ctap_get_assertion_request.h b/device/fido/ctap_get_assertion_request.h
index 4a2c199..0e2ee2e 100644
--- a/device/fido/ctap_get_assertion_request.h
+++ b/device/fido/ctap_get_assertion_request.h
@@ -40,12 +40,6 @@
   CtapGetAssertionRequest& operator=(CtapGetAssertionRequest&& other);
   ~CtapGetAssertionRequest();
 
-  // Serializes GetAssertion request parameter into CBOR encoded map with
-  // integer keys and CBOR encoded values as defined by the CTAP spec.
-  // https://drafts.fidoalliance.org/fido-2/latest/fido-client-to-authenticator-protocol-v2.0-wd-20180305.html#authenticatorGetAssertion
-  static std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
-  EncodeAsCBOR(const CtapGetAssertionRequest& request);
-
   std::string rp_id;
   std::string client_data_json;
   std::array<uint8_t, kClientDataHashLength> client_data_hash;
@@ -65,11 +59,19 @@
 };
 
 struct CtapGetNextAssertionRequest {
- public:
-  static std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
-  EncodeAsCBOR(const CtapGetNextAssertionRequest&);
 };
 
+// Serializes GetAssertion request parameter into CBOR encoded map with
+// integer keys and CBOR encoded values as defined by the CTAP spec.
+// https://drafts.fidoalliance.org/fido-2/latest/fido-client-to-authenticator-protocol-v2.0-wd-20180305.html#authenticatorGetAssertion
+COMPONENT_EXPORT(DEVICE_FIDO)
+std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
+AsCTAPRequestValuePair(const CtapGetAssertionRequest&);
+
+COMPONENT_EXPORT(DEVICE_FIDO)
+std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
+AsCTAPRequestValuePair(const CtapGetNextAssertionRequest&);
+
 }  // namespace device
 
 #endif  // DEVICE_FIDO_CTAP_GET_ASSERTION_REQUEST_H_
diff --git a/device/fido/ctap_make_credential_request.cc b/device/fido/ctap_make_credential_request.cc
index 84c37ac..656371b 100644
--- a/device/fido/ctap_make_credential_request.cc
+++ b/device/fido/ctap_make_credential_request.cc
@@ -41,22 +41,17 @@
 
 CtapMakeCredentialRequest::~CtapMakeCredentialRequest() = default;
 
-// static
 std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
-CtapMakeCredentialRequest::EncodeAsCBOR(
-    const CtapMakeCredentialRequest& request) {
+AsCTAPRequestValuePair(const CtapMakeCredentialRequest& request) {
   cbor::Value::MapValue cbor_map;
   cbor_map[cbor::Value(1)] = cbor::Value(request.client_data_hash);
-  cbor_map[cbor::Value(2)] =
-      PublicKeyCredentialRpEntity::ConvertToCBOR(request.rp);
-  cbor_map[cbor::Value(3)] =
-      PublicKeyCredentialUserEntity::ConvertToCBOR(request.user);
-  cbor_map[cbor::Value(4)] =
-      request.public_key_credential_params.ConvertToCBOR();
+  cbor_map[cbor::Value(2)] = AsCBOR(request.rp);
+  cbor_map[cbor::Value(3)] = AsCBOR(request.user);
+  cbor_map[cbor::Value(4)] = AsCBOR(request.public_key_credential_params);
   if (request.exclude_list) {
     cbor::Value::ArrayValue exclude_list_array;
     for (const auto& descriptor : *request.exclude_list) {
-      exclude_list_array.push_back(descriptor.ConvertToCBOR());
+      exclude_list_array.push_back(AsCBOR(descriptor));
     }
     cbor_map[cbor::Value(5)] = cbor::Value(std::move(exclude_list_array));
   }
diff --git a/device/fido/ctap_make_credential_request.h b/device/fido/ctap_make_credential_request.h
index 387bbfac..5c118b7 100644
--- a/device/fido/ctap_make_credential_request.h
+++ b/device/fido/ctap_make_credential_request.h
@@ -45,12 +45,6 @@
   CtapMakeCredentialRequest& operator=(CtapMakeCredentialRequest&& that);
   ~CtapMakeCredentialRequest();
 
-  // Serializes MakeCredential request parameter into CBOR encoded map with
-  // integer keys and CBOR encoded values as defined by the CTAP spec.
-  // https://drafts.fidoalliance.org/fido-2/latest/fido-client-to-authenticator-protocol-v2.0-wd-20180305.html#authenticatorMakeCredential
-  static std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
-  EncodeAsCBOR(const CtapMakeCredentialRequest& request);
-
   std::string client_data_json;
   ClientDataHash client_data_hash;
   PublicKeyCredentialRpEntity rp;
@@ -84,6 +78,13 @@
   base::Optional<std::pair<CredProtect, bool>> cred_protect;
 };
 
+// Serializes MakeCredential request parameter into CBOR encoded map with
+// integer keys and CBOR encoded values as defined by the CTAP spec.
+// https://drafts.fidoalliance.org/fido-2/latest/fido-client-to-authenticator-protocol-v2.0-wd-20180305.html#authenticatorMakeCredential
+COMPONENT_EXPORT(DEVICE_FIDO)
+std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
+AsCTAPRequestValuePair(const CtapMakeCredentialRequest& request);
+
 }  // namespace device
 
 #endif  // DEVICE_FIDO_CTAP_MAKE_CREDENTIAL_REQUEST_H_
diff --git a/device/fido/ctap_request_unittest.cc b/device/fido/ctap_request_unittest.cc
index aa9ddfaf..253b1756 100644
--- a/device/fido/ctap_request_unittest.cc
+++ b/device/fido/ctap_request_unittest.cc
@@ -36,7 +36,7 @@
   make_credential_param.user_verification =
       UserVerificationRequirement::kRequired;
   auto serialized_data = MockFidoDevice::EncodeCBORRequest(
-      CtapMakeCredentialRequest::EncodeAsCBOR(make_credential_param));
+      AsCTAPRequestValuePair(make_credential_param));
   EXPECT_THAT(serialized_data, ::testing::ElementsAreArray(
                                    test_data::kCtapMakeCredentialRequest));
 }
@@ -67,7 +67,7 @@
   get_assertion_req.user_verification = UserVerificationRequirement::kRequired;
 
   auto serialized_data = MockFidoDevice::EncodeCBORRequest(
-      CtapGetAssertionRequest::EncodeAsCBOR(get_assertion_req));
+      AsCTAPRequestValuePair(get_assertion_req));
   EXPECT_THAT(serialized_data,
               ::testing::ElementsAreArray(
                   test_data::kTestComplexCtapGetAssertionRequest));
diff --git a/device/fido/ctap_response_unittest.cc b/device/fido/ctap_response_unittest.cc
index c3e607e5..6d4f149 100644
--- a/device/fido/ctap_response_unittest.cc
+++ b/device/fido/ctap_response_unittest.cc
@@ -438,8 +438,7 @@
       FidoAttestationStatement::CreateFromU2fRegisterResponse(
           test_data::kTestU2fRegisterResponse);
   ASSERT_TRUE(fido_attestation_statement);
-  auto cbor = cbor::Writer::Write(
-      cbor::Value(fido_attestation_statement->GetAsCBORMap()));
+  auto cbor = cbor::Writer::Write(AsCBOR(*fido_attestation_statement));
   ASSERT_TRUE(cbor);
   EXPECT_THAT(*cbor, ::testing::ElementsAreArray(
                          test_data::kU2fAttestationStatementCBOR));
@@ -500,7 +499,8 @@
 
   ASSERT_TRUE(attestation_object);
   EXPECT_EQ(GetTestAttestationObjectBytes(),
-            attestation_object->SerializeToCBOREncodedBytes());
+            cbor::Writer::Write(AsCBOR(*attestation_object))
+                .value_or(std::vector<uint8_t>()));
 }
 
 // Tests that U2F authenticator data is properly serialized.
@@ -703,7 +703,7 @@
           std::make_unique<OpaqueAttestationStatement>(
               "packed", cbor::Value(std::move(attestation_map)))));
   EXPECT_THAT(
-      GetSerializedCtapDeviceResponse(response),
+      AsCTAPStyleCBORBytes(response),
       ::testing::ElementsAreArray(
           base::make_span(test_data::kTestMakeCredentialResponse).subspan(1)));
 }
diff --git a/device/fido/get_assertion_handler_unittest.cc b/device/fido/get_assertion_handler_unittest.cc
index 6e1c769..d92722c 100644
--- a/device/fido/get_assertion_handler_unittest.cc
+++ b/device/fido/get_assertion_handler_unittest.cc
@@ -245,7 +245,7 @@
   auto device = MockFidoDevice::MakeCtapWithGetInfoExpectation(
       test_data::kTestGetInfoResponseWithoutUvSupport);
   device->ExpectRequestAndRespondWith(
-      MockFidoDevice::EncodeCBORRequest(CtapMakeCredentialRequest::EncodeAsCBOR(
+      MockFidoDevice::EncodeCBORRequest(AsCTAPRequestValuePair(
           MakeCredentialTask::GetTouchRequest(device.get()))),
       test_data::kTestMakeCredentialResponse);
 
diff --git a/device/fido/make_credential_handler_unittest.cc b/device/fido/make_credential_handler_unittest.cc
index c8e2511..70e8233c 100644
--- a/device/fido/make_credential_handler_unittest.cc
+++ b/device/fido/make_credential_handler_unittest.cc
@@ -242,7 +242,7 @@
   auto device = MockFidoDevice::MakeCtapWithGetInfoExpectation(
       test_data::kTestGetInfoResponseWithoutUvSupport);
   device->ExpectRequestAndRespondWith(
-      MockFidoDevice::EncodeCBORRequest(CtapMakeCredentialRequest::EncodeAsCBOR(
+      MockFidoDevice::EncodeCBORRequest(AsCTAPRequestValuePair(
           MakeCredentialTask::GetTouchRequest(device.get()))),
       test_data::kTestMakeCredentialResponse);
   discovery()->AddDevice(std::move(device));
@@ -329,7 +329,7 @@
   auto device = MockFidoDevice::MakeCtapWithGetInfoExpectation(
       test_data::kTestGetInfoResponseWithoutResidentKeySupport);
   device->ExpectRequestAndRespondWith(
-      MockFidoDevice::EncodeCBORRequest(CtapMakeCredentialRequest::EncodeAsCBOR(
+      MockFidoDevice::EncodeCBORRequest(AsCTAPRequestValuePair(
           MakeCredentialTask::GetTouchRequest(device.get()))),
       test_data::kTestMakeCredentialResponse);
 
diff --git a/device/fido/opaque_attestation_statement.cc b/device/fido/opaque_attestation_statement.cc
index 8edb742..bcfd0fa4 100644
--- a/device/fido/opaque_attestation_statement.cc
+++ b/device/fido/opaque_attestation_statement.cc
@@ -21,7 +21,7 @@
 OpaqueAttestationStatement::~OpaqueAttestationStatement() = default;
 
 // Returns the deep copied cbor map value of |attestation_statement_map_|.
-Value::MapValue OpaqueAttestationStatement::GetAsCBORMap() const {
+Value OpaqueAttestationStatement::AsCBOR() const {
   DCHECK(attestation_statement_map_.is_map());
   Value::MapValue new_map;
   new_map.reserve(attestation_statement_map_.GetMap().size());
@@ -29,7 +29,7 @@
     new_map.try_emplace(new_map.end(), map_it.first.Clone(),
                         map_it.second.Clone());
   }
-  return new_map;
+  return cbor::Value(std::move(new_map));
 }
 
 bool OpaqueAttestationStatement::IsSelfAttestation() {
diff --git a/device/fido/opaque_attestation_statement.h b/device/fido/opaque_attestation_statement.h
index 7f6cef0..55db16e 100644
--- a/device/fido/opaque_attestation_statement.h
+++ b/device/fido/opaque_attestation_statement.h
@@ -23,7 +23,7 @@
   ~OpaqueAttestationStatement() override;
 
   // AttestationStatement:
-  cbor::Value::MapValue GetAsCBORMap() const override;
+  cbor::Value AsCBOR() const override;
   bool IsSelfAttestation() override;
   bool IsAttestationCertificateInappropriatelyIdentifying() override;
   base::Optional<base::span<const uint8_t>> GetLeafCertificate() const override;
diff --git a/device/fido/pin.cc b/device/fido/pin.cc
index b09ea3d..36834a3 100644
--- a/device/fido/pin.cc
+++ b/device/fido/pin.cc
@@ -74,12 +74,6 @@
                         cbor::Value(std::move(map)));
 }
 
-// static
-std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
-RetriesRequest::EncodeAsCBOR(const RetriesRequest&) {
-  return EncodePINCommand(Subcommand::kGetRetries);
-}
-
 RetriesResponse::RetriesResponse() = default;
 
 // static
@@ -106,11 +100,6 @@
   return ret;
 }
 
-// static
-std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
-KeyAgreementRequest::EncodeAsCBOR(const KeyAgreementRequest&) {
-  return EncodePINCommand(Subcommand::kGetKeyAgreement);
-}
 
 KeyAgreementResponse::KeyAgreementResponse() = default;
 
@@ -285,36 +274,6 @@
   EVP_CIPHER_CTX_cleanup(&aes_ctx);
 }
 
-// static
-std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
-SetRequest::EncodeAsCBOR(const SetRequest& request) {
-  // See
-  // https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-client-to-authenticator-protocol-v2.0-rd-20180702.html#settingNewPin
-  uint8_t shared_key[SHA256_DIGEST_LENGTH];
-  auto cose_key = GenerateSharedKey(request.peer_key_, shared_key);
-
-  static_assert((sizeof(pin_) % AES_BLOCK_SIZE) == 0,
-                "pin_ is not a multiple of the AES block size");
-  uint8_t encrypted_pin[sizeof(pin_)];
-  Encrypt(shared_key, request.pin_, encrypted_pin);
-
-  std::vector<uint8_t> pin_auth =
-      MakePinAuth(base::make_span(shared_key, sizeof(shared_key)),
-                  base::make_span(encrypted_pin, sizeof(encrypted_pin)));
-
-  return EncodePINCommand(
-      Subcommand::kSetPIN,
-      [&cose_key, &encrypted_pin, &pin_auth](cbor::Value::MapValue* map) {
-        map->emplace(static_cast<int>(RequestKey::kKeyAgreement),
-                     std::move(cose_key));
-        map->emplace(
-            static_cast<int>(RequestKey::kNewPINEnc),
-            base::span<const uint8_t>(encrypted_pin, sizeof(encrypted_pin)));
-        map->emplace(static_cast<int>(RequestKey::kPINAuth),
-                     std::move(pin_auth));
-      });
-}
-
 ChangeRequest::ChangeRequest(const std::string& old_pin,
                              const std::string& new_pin,
                              const KeyAgreementResponse& peer_key)
@@ -344,90 +303,6 @@
   return ret;
 }
 
-// static
-std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
-ChangeRequest::EncodeAsCBOR(const ChangeRequest& request) {
-  // See
-  // https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-client-to-authenticator-protocol-v2.0-rd-20180702.html#changingExistingPin
-  uint8_t shared_key[SHA256_DIGEST_LENGTH];
-  auto cose_key = GenerateSharedKey(request.peer_key_, shared_key);
-
-  static_assert((sizeof(new_pin_) % AES_BLOCK_SIZE) == 0,
-                "new_pin_ is not a multiple of the AES block size");
-  uint8_t encrypted_pin[sizeof(new_pin_)];
-  Encrypt(shared_key, request.new_pin_, encrypted_pin);
-
-  static_assert((sizeof(old_pin_hash_) % AES_BLOCK_SIZE) == 0,
-                "old_pin_hash_ is not a multiple of the AES block size");
-  uint8_t old_pin_hash_enc[sizeof(old_pin_hash_)];
-  Encrypt(shared_key, request.old_pin_hash_, old_pin_hash_enc);
-
-  uint8_t ciphertexts_concat[sizeof(encrypted_pin) + sizeof(old_pin_hash_enc)];
-  memcpy(ciphertexts_concat, encrypted_pin, sizeof(encrypted_pin));
-  memcpy(ciphertexts_concat + sizeof(encrypted_pin), old_pin_hash_enc,
-         sizeof(old_pin_hash_enc));
-  std::vector<uint8_t> pin_auth = MakePinAuth(
-      base::make_span(shared_key, sizeof(shared_key)),
-      base::make_span(ciphertexts_concat, sizeof(ciphertexts_concat)));
-
-  return EncodePINCommand(
-      Subcommand::kChangePIN, [&cose_key, &encrypted_pin, &old_pin_hash_enc,
-                               &pin_auth](cbor::Value::MapValue* map) {
-        map->emplace(static_cast<int>(RequestKey::kKeyAgreement),
-                     std::move(cose_key));
-        map->emplace(static_cast<int>(RequestKey::kPINHashEnc),
-                     base::span<const uint8_t>(old_pin_hash_enc,
-                                               sizeof(old_pin_hash_enc)));
-        map->emplace(
-            static_cast<int>(RequestKey::kNewPINEnc),
-            base::span<const uint8_t>(encrypted_pin, sizeof(encrypted_pin)));
-        map->emplace(static_cast<int>(RequestKey::kPINAuth),
-                     std::move(pin_auth));
-      });
-}
-
-// static
-std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
-ResetRequest::EncodeAsCBOR(const ResetRequest&) {
-  return std::make_pair(CtapRequestCommand::kAuthenticatorReset, base::nullopt);
-}
-
-TokenRequest::TokenRequest(const std::string& pin,
-                           const KeyAgreementResponse& peer_key)
-    : cose_key_(GenerateSharedKey(peer_key, shared_key_.data())) {
-  DCHECK_EQ(static_cast<size_t>(SHA256_DIGEST_LENGTH), shared_key_.size());
-  uint8_t digest[SHA256_DIGEST_LENGTH];
-  SHA256(reinterpret_cast<const uint8_t*>(pin.data()), pin.size(), digest);
-  memcpy(pin_hash_, digest, sizeof(pin_hash_));
-}
-
-TokenRequest::~TokenRequest() = default;
-
-TokenRequest::TokenRequest(TokenRequest&& other) = default;
-
-const std::array<uint8_t, 32>& TokenRequest::shared_key() const {
-  return shared_key_;
-}
-
-// static
-std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
-TokenRequest::EncodeAsCBOR(const TokenRequest& request) {
-  static_assert((sizeof(pin_hash_) % AES_BLOCK_SIZE) == 0,
-                "pin_hash_ is not a multiple of the AES block size");
-  uint8_t encrypted_pin[sizeof(request.pin_hash_)];
-  Encrypt(request.shared_key_.data(), request.pin_hash_, encrypted_pin);
-
-  return EncodePINCommand(
-      Subcommand::kGetPINToken,
-      [&request, &encrypted_pin](cbor::Value::MapValue* map) {
-        map->emplace(static_cast<int>(RequestKey::kKeyAgreement),
-                     std::move(request.cose_key_));
-        map->emplace(
-            static_cast<int>(RequestKey::kPINHashEnc),
-            base::span<const uint8_t>(encrypted_pin, sizeof(encrypted_pin)));
-      });
-}
-
 TokenResponse::TokenResponse() = default;
 TokenResponse::~TokenResponse() = default;
 TokenResponse::TokenResponse(const TokenResponse&) = default;
@@ -480,5 +355,132 @@
   return MakePinAuth(token_, client_data_hash);
 }
 
+// static
+std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
+AsCTAPRequestValuePair(const RetriesRequest&) {
+  return EncodePINCommand(Subcommand::kGetRetries);
+}
+
+// static
+std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
+AsCTAPRequestValuePair(const KeyAgreementRequest&) {
+  return EncodePINCommand(Subcommand::kGetKeyAgreement);
+}
+
+// static
+std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
+AsCTAPRequestValuePair(const SetRequest& request) {
+  // See
+  // https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-client-to-authenticator-protocol-v2.0-rd-20180702.html#settingNewPin
+  uint8_t shared_key[SHA256_DIGEST_LENGTH];
+  auto cose_key = GenerateSharedKey(request.peer_key_, shared_key);
+
+  static_assert((sizeof(request.pin_) % AES_BLOCK_SIZE) == 0,
+                "pin_ is not a multiple of the AES block size");
+  uint8_t encrypted_pin[sizeof(request.pin_)];
+  Encrypt(shared_key, request.pin_, encrypted_pin);
+
+  std::vector<uint8_t> pin_auth =
+      MakePinAuth(base::make_span(shared_key, sizeof(shared_key)),
+                  base::make_span(encrypted_pin, sizeof(encrypted_pin)));
+
+  return EncodePINCommand(
+      Subcommand::kSetPIN,
+      [&cose_key, &encrypted_pin, &pin_auth](cbor::Value::MapValue* map) {
+        map->emplace(static_cast<int>(RequestKey::kKeyAgreement),
+                     std::move(cose_key));
+        map->emplace(
+            static_cast<int>(RequestKey::kNewPINEnc),
+            base::span<const uint8_t>(encrypted_pin, sizeof(encrypted_pin)));
+        map->emplace(static_cast<int>(RequestKey::kPINAuth),
+                     std::move(pin_auth));
+      });
+}
+
+// static
+std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
+AsCTAPRequestValuePair(const ChangeRequest& request) {
+  // See
+  // https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-client-to-authenticator-protocol-v2.0-rd-20180702.html#changingExistingPin
+  uint8_t shared_key[SHA256_DIGEST_LENGTH];
+  auto cose_key = GenerateSharedKey(request.peer_key_, shared_key);
+
+  static_assert((sizeof(request.new_pin_) % AES_BLOCK_SIZE) == 0,
+                "new_pin_ is not a multiple of the AES block size");
+  uint8_t encrypted_pin[sizeof(request.new_pin_)];
+  Encrypt(shared_key, request.new_pin_, encrypted_pin);
+
+  static_assert((sizeof(request.old_pin_hash_) % AES_BLOCK_SIZE) == 0,
+                "old_pin_hash_ is not a multiple of the AES block size");
+  uint8_t old_pin_hash_enc[sizeof(request.old_pin_hash_)];
+  Encrypt(shared_key, request.old_pin_hash_, old_pin_hash_enc);
+
+  uint8_t ciphertexts_concat[sizeof(encrypted_pin) + sizeof(old_pin_hash_enc)];
+  memcpy(ciphertexts_concat, encrypted_pin, sizeof(encrypted_pin));
+  memcpy(ciphertexts_concat + sizeof(encrypted_pin), old_pin_hash_enc,
+         sizeof(old_pin_hash_enc));
+  std::vector<uint8_t> pin_auth = MakePinAuth(
+      base::make_span(shared_key, sizeof(shared_key)),
+      base::make_span(ciphertexts_concat, sizeof(ciphertexts_concat)));
+
+  return EncodePINCommand(
+      Subcommand::kChangePIN, [&cose_key, &encrypted_pin, &old_pin_hash_enc,
+                               &pin_auth](cbor::Value::MapValue* map) {
+        map->emplace(static_cast<int>(RequestKey::kKeyAgreement),
+                     std::move(cose_key));
+        map->emplace(static_cast<int>(RequestKey::kPINHashEnc),
+                     base::span<const uint8_t>(old_pin_hash_enc,
+                                               sizeof(old_pin_hash_enc)));
+        map->emplace(
+            static_cast<int>(RequestKey::kNewPINEnc),
+            base::span<const uint8_t>(encrypted_pin, sizeof(encrypted_pin)));
+        map->emplace(static_cast<int>(RequestKey::kPINAuth),
+                     std::move(pin_auth));
+      });
+}
+
+// static
+std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
+AsCTAPRequestValuePair(const ResetRequest&) {
+  return std::make_pair(CtapRequestCommand::kAuthenticatorReset, base::nullopt);
+}
+
+TokenRequest::TokenRequest(const std::string& pin,
+                           const KeyAgreementResponse& peer_key)
+    : cose_key_(GenerateSharedKey(peer_key, shared_key_.data())) {
+  DCHECK_EQ(static_cast<size_t>(SHA256_DIGEST_LENGTH), shared_key_.size());
+  uint8_t digest[SHA256_DIGEST_LENGTH];
+  SHA256(reinterpret_cast<const uint8_t*>(pin.data()), pin.size(), digest);
+  memcpy(pin_hash_, digest, sizeof(pin_hash_));
+}
+
+TokenRequest::~TokenRequest() = default;
+
+TokenRequest::TokenRequest(TokenRequest&& other) = default;
+
+const std::array<uint8_t, 32>& TokenRequest::shared_key() const {
+  return shared_key_;
+}
+
+// static
+std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
+AsCTAPRequestValuePair(const TokenRequest& request) {
+  static_assert((sizeof(request.pin_hash_) % AES_BLOCK_SIZE) == 0,
+                "pin_hash_ is not a multiple of the AES block size");
+  uint8_t encrypted_pin[sizeof(request.pin_hash_)];
+  Encrypt(request.shared_key_.data(), request.pin_hash_, encrypted_pin);
+
+  return EncodePINCommand(
+      Subcommand::kGetPINToken,
+      [&request, &encrypted_pin](cbor::Value::MapValue* map) {
+        map->emplace(static_cast<int>(RequestKey::kKeyAgreement),
+                     std::move(request.cose_key_));
+        map->emplace(
+            static_cast<int>(RequestKey::kPINHashEnc),
+            base::span<const uint8_t>(encrypted_pin, sizeof(encrypted_pin)));
+      });
+}
+
 }  // namespace pin
+
 }  // namespace device
diff --git a/device/fido/pin.h b/device/fido/pin.h
index 29735b2..f71cb2c9 100644
--- a/device/fido/pin.h
+++ b/device/fido/pin.h
@@ -43,10 +43,7 @@
 
 // RetriesRequest asks an authenticator for the number of remaining PIN attempts
 // before the device is locked.
-struct RetriesRequest {
-  static std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
-  EncodeAsCBOR(const RetriesRequest&);
-};
+struct RetriesRequest {};
 
 // RetriesResponse reflects an authenticator's response to a |RetriesRequest|.
 struct RetriesResponse {
@@ -63,10 +60,7 @@
 
 // KeyAgreementRequest asks an authenticator for an ephemeral ECDH key for
 // encrypting PIN material in future requests.
-struct KeyAgreementRequest {
-  static std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
-  EncodeAsCBOR(const KeyAgreementRequest&);
-};
+struct KeyAgreementRequest {};
 
 // KeyAgreementResponse reflects an authenticator's response to a
 // |KeyAgreementRequest| and is also used as representation of the
@@ -92,8 +86,8 @@
   // IsValid(pin) must be true.
   SetRequest(const std::string& pin, const KeyAgreementResponse& peer_key);
 
-  static std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
-  EncodeAsCBOR(const SetRequest&);
+  friend std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
+  AsCTAPRequestValuePair(const SetRequest&);
 
  private:
   const KeyAgreementResponse peer_key_;
@@ -114,8 +108,8 @@
                 const std::string& new_pin,
                 const KeyAgreementResponse& peer_key);
 
-  static std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
-  EncodeAsCBOR(const ChangeRequest&);
+  friend std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
+  AsCTAPRequestValuePair(const ChangeRequest&);
 
  private:
   const KeyAgreementResponse peer_key_;
@@ -127,10 +121,7 @@
 // credentials and clear any configured PIN. This is not strictly a
 // PIN-related command, but is generally used to reset a PIN and so is
 // included here.
-struct ResetRequest {
-  static std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
-  EncodeAsCBOR(const ResetRequest&);
-};
+struct ResetRequest {};
 
 using ResetResponse = EmptyResponse;
 
@@ -148,8 +139,8 @@
   // This is needed to decrypt the response.
   const std::array<uint8_t, 32>& shared_key() const;
 
-  static std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
-  EncodeAsCBOR(const TokenRequest&);
+  friend std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
+  AsCTAPRequestValuePair(const TokenRequest&);
 
  private:
   std::array<uint8_t, 32> shared_key_;
@@ -182,7 +173,26 @@
   std::vector<uint8_t> token_;
 };
 
+std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
+AsCTAPRequestValuePair(const RetriesRequest&);
+
+std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
+AsCTAPRequestValuePair(const KeyAgreementRequest&);
+
+std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
+AsCTAPRequestValuePair(const SetRequest&);
+
+std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
+AsCTAPRequestValuePair(const ChangeRequest&);
+
+std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
+AsCTAPRequestValuePair(const ResetRequest&);
+
+std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
+AsCTAPRequestValuePair(const TokenRequest&);
+
 }  // namespace pin
+
 }  // namespace device
 
 #endif  // DEVICE_FIDO_PIN_H_
diff --git a/device/fido/public_key_credential_descriptor.cc b/device/fido/public_key_credential_descriptor.cc
index f0afd12..624e6fb 100644
--- a/device/fido/public_key_credential_descriptor.cc
+++ b/device/fido/public_key_credential_descriptor.cc
@@ -71,11 +71,11 @@
 
 PublicKeyCredentialDescriptor::~PublicKeyCredentialDescriptor() = default;
 
-cbor::Value PublicKeyCredentialDescriptor::ConvertToCBOR() const {
+cbor::Value AsCBOR(const PublicKeyCredentialDescriptor& desc) {
   cbor::Value::MapValue cbor_descriptor_map;
-  cbor_descriptor_map[cbor::Value(kCredentialIdKey)] = cbor::Value(id_);
+  cbor_descriptor_map[cbor::Value(kCredentialIdKey)] = cbor::Value(desc.id());
   cbor_descriptor_map[cbor::Value(kCredentialTypeKey)] =
-      cbor::Value(CredentialTypeToString(credential_type_));
+      cbor::Value(CredentialTypeToString(desc.credential_type()));
   return cbor::Value(std::move(cbor_descriptor_map));
 }
 
diff --git a/device/fido/public_key_credential_descriptor.h b/device/fido/public_key_credential_descriptor.h
index 1dde94a..3330f85e 100644
--- a/device/fido/public_key_credential_descriptor.h
+++ b/device/fido/public_key_credential_descriptor.h
@@ -41,8 +41,6 @@
       PublicKeyCredentialDescriptor&& other);
   ~PublicKeyCredentialDescriptor();
 
-  cbor::Value ConvertToCBOR() const;
-
   CredentialType credential_type() const { return credential_type_; }
   const std::vector<uint8_t>& id() const { return id_; }
   const base::flat_set<FidoTransportProtocol>& transports() const {
@@ -55,6 +53,8 @@
   base::flat_set<FidoTransportProtocol> transports_;
 };
 
+cbor::Value AsCBOR(const PublicKeyCredentialDescriptor&);
+
 }  // namespace device
 
 #endif  // DEVICE_FIDO_PUBLIC_KEY_CREDENTIAL_DESCRIPTOR_H_
diff --git a/device/fido/public_key_credential_params.cc b/device/fido/public_key_credential_params.cc
index 0ea270a8..2fea4ea 100644
--- a/device/fido/public_key_credential_params.cc
+++ b/device/fido/public_key_credential_params.cc
@@ -58,11 +58,11 @@
 
 PublicKeyCredentialParams::~PublicKeyCredentialParams() = default;
 
-cbor::Value PublicKeyCredentialParams::ConvertToCBOR() const {
+cbor::Value AsCBOR(const PublicKeyCredentialParams& params) {
   cbor::Value::ArrayValue credential_param_array;
-  credential_param_array.reserve(public_key_credential_params_.size());
+  credential_param_array.reserve(params.public_key_credential_params().size());
 
-  for (const auto& credential : public_key_credential_params_) {
+  for (const auto& credential : params.public_key_credential_params()) {
     cbor::Value::MapValue cbor_credential_map;
     cbor_credential_map.emplace(kCredentialTypeMapKey,
                                 CredentialTypeToString(credential.type));
diff --git a/device/fido/public_key_credential_params.h b/device/fido/public_key_credential_params.h
index cfb6f14..eee85192 100644
--- a/device/fido/public_key_credential_params.h
+++ b/device/fido/public_key_credential_params.h
@@ -39,7 +39,6 @@
   PublicKeyCredentialParams& operator=(PublicKeyCredentialParams&& other);
   ~PublicKeyCredentialParams();
 
-  cbor::Value ConvertToCBOR() const;
   const std::vector<CredentialInfo>& public_key_credential_params() const {
     return public_key_credential_params_;
   }
@@ -48,6 +47,8 @@
   std::vector<CredentialInfo> public_key_credential_params_;
 };
 
+cbor::Value AsCBOR(const PublicKeyCredentialParams&);
+
 }  // namespace device
 
 #endif  // DEVICE_FIDO_PUBLIC_KEY_CREDENTIAL_PARAMS_H_
diff --git a/device/fido/public_key_credential_rp_entity.cc b/device/fido/public_key_credential_rp_entity.cc
index cae203a..6fdcb4f 100644
--- a/device/fido/public_key_credential_rp_entity.cc
+++ b/device/fido/public_key_credential_rp_entity.cc
@@ -44,20 +44,6 @@
   return rp;
 }
 
-// static
-cbor::Value PublicKeyCredentialRpEntity::ConvertToCBOR(
-    const PublicKeyCredentialRpEntity& rp) {
-  cbor::Value::MapValue rp_map;
-  rp_map.emplace(kEntityIdMapKey, rp.id);
-  if (rp.name) {
-    rp_map.emplace(kEntityNameMapKey, *rp.name);
-  }
-  if (rp.icon_url) {
-    rp_map.emplace(kIconUrlMapKey, rp.icon_url->spec());
-  }
-  return cbor::Value(std::move(rp_map));
-}
-
 PublicKeyCredentialRpEntity::PublicKeyCredentialRpEntity(std::string rp_id)
     : id(std::move(rp_id)) {}
 
@@ -75,4 +61,16 @@
 
 PublicKeyCredentialRpEntity::~PublicKeyCredentialRpEntity() = default;
 
+cbor::Value AsCBOR(const PublicKeyCredentialRpEntity& entity) {
+  cbor::Value::MapValue rp_map;
+  rp_map.emplace(kEntityIdMapKey, entity.id);
+  if (entity.name)
+    rp_map.emplace(kEntityNameMapKey, *entity.name);
+
+  if (entity.icon_url)
+    rp_map.emplace(kIconUrlMapKey, entity.icon_url->spec());
+
+  return cbor::Value(std::move(rp_map));
+}
+
 }  // namespace device
diff --git a/device/fido/public_key_credential_rp_entity.h b/device/fido/public_key_credential_rp_entity.h
index e701357a..84def50 100644
--- a/device/fido/public_key_credential_rp_entity.h
+++ b/device/fido/public_key_credential_rp_entity.h
@@ -24,7 +24,6 @@
  public:
   static base::Optional<PublicKeyCredentialRpEntity> CreateFromCBORValue(
       const cbor::Value& cbor);
-  static cbor::Value ConvertToCBOR(const PublicKeyCredentialRpEntity&);
 
   explicit PublicKeyCredentialRpEntity(std::string rp_id);
   PublicKeyCredentialRpEntity(const PublicKeyCredentialRpEntity& other);
@@ -39,6 +38,8 @@
   base::Optional<GURL> icon_url;
 };
 
+cbor::Value AsCBOR(const PublicKeyCredentialRpEntity&);
+
 }  // namespace device
 
 #endif  // DEVICE_FIDO_PUBLIC_KEY_CREDENTIAL_RP_ENTITY_H_
diff --git a/device/fido/public_key_credential_user_entity.cc b/device/fido/public_key_credential_user_entity.cc
index 056b648349..a8bc02f 100644
--- a/device/fido/public_key_credential_user_entity.cc
+++ b/device/fido/public_key_credential_user_entity.cc
@@ -54,21 +54,6 @@
   return user;
 }
 
-// static
-cbor::Value PublicKeyCredentialUserEntity::ConvertToCBOR(
-    const PublicKeyCredentialUserEntity& user) {
-  cbor::Value::MapValue user_map;
-  user_map.emplace(kEntityIdMapKey, user.id);
-  if (user.name)
-    user_map.emplace(kEntityNameMapKey, *user.name);
-  // Empty icon URLs result in CTAP1_ERR_INVALID_LENGTH on some security keys.
-  if (user.icon_url && !user.icon_url->is_empty())
-    user_map.emplace(kIconUrlMapKey, user.icon_url->spec());
-  if (user.display_name)
-    user_map.emplace(kDisplayNameMapKey, *user.display_name);
-  return cbor::Value(std::move(user_map));
-}
-
 PublicKeyCredentialUserEntity::PublicKeyCredentialUserEntity(
     std::vector<uint8_t> in_id)
     : id(std::move(in_id)) {}
@@ -87,6 +72,17 @@
 
 PublicKeyCredentialUserEntity::~PublicKeyCredentialUserEntity() = default;
 
-
+cbor::Value AsCBOR(const PublicKeyCredentialUserEntity& user) {
+  cbor::Value::MapValue user_map;
+  user_map.emplace(kEntityIdMapKey, user.id);
+  if (user.name)
+    user_map.emplace(kEntityNameMapKey, *user.name);
+  // Empty icon URLs result in CTAP1_ERR_INVALID_LENGTH on some security keys.
+  if (user.icon_url && !user.icon_url->is_empty())
+    user_map.emplace(kIconUrlMapKey, user.icon_url->spec());
+  if (user.display_name)
+    user_map.emplace(kDisplayNameMapKey, *user.display_name);
+  return cbor::Value(std::move(user_map));
+}
 
 }  // namespace device
diff --git a/device/fido/public_key_credential_user_entity.h b/device/fido/public_key_credential_user_entity.h
index 58ccf068..c51f0fb 100644
--- a/device/fido/public_key_credential_user_entity.h
+++ b/device/fido/public_key_credential_user_entity.h
@@ -24,7 +24,6 @@
  public:
   static base::Optional<PublicKeyCredentialUserEntity> CreateFromCBORValue(
       const cbor::Value& cbor);
-  static cbor::Value ConvertToCBOR(const PublicKeyCredentialUserEntity& user);
 
   explicit PublicKeyCredentialUserEntity(std::vector<uint8_t> id);
   PublicKeyCredentialUserEntity(const PublicKeyCredentialUserEntity& other);
@@ -41,6 +40,8 @@
   base::Optional<GURL> icon_url;
 };
 
+cbor::Value AsCBOR(const PublicKeyCredentialUserEntity&);
+
 }  // namespace device
 
 #endif  // DEVICE_FIDO_PUBLIC_KEY_CREDENTIAL_USER_ENTITY_H_
diff --git a/device/fido/virtual_ctap2_device.cc b/device/fido/virtual_ctap2_device.cc
index be2c76b..9ea3018 100644
--- a/device/fido/virtual_ctap2_device.cc
+++ b/device/fido/virtual_ctap2_device.cc
@@ -234,7 +234,7 @@
           std::move(authenticator_data),
           std::make_unique<OpaqueAttestationStatement>(
               "packed", cbor::Value(std::move(attestation_map)))));
-  return GetSerializedCtapDeviceResponse(make_credential_response);
+  return AsCTAPStyleCBORBytes(make_credential_response);
 }
 
 bool IsMakeCredentialOptionMapFormatCorrect(
@@ -1322,13 +1322,11 @@
     cbor::Value::MapValue response_map;
     response_map.emplace(
         static_cast<int>(CredentialManagementResponseKey::kUser),
-        PublicKeyCredentialUserEntity::ConvertToCBOR(
-            *registration.second.user));
+        AsCBOR(*registration.second.user));
     response_map.emplace(
         static_cast<int>(CredentialManagementResponseKey::kCredentialID),
-        PublicKeyCredentialDescriptor(CredentialType::kPublicKey,
-                                      registration.first)
-            .ConvertToCBOR());
+        AsCBOR(PublicKeyCredentialDescriptor(CredentialType::kPublicKey,
+                                             registration.first)));
     std::string public_key;
     EC_KEY* ec_key =
         EVP_PKEY_get0_EC_KEY(registration.second.private_key->key());
@@ -1344,8 +1342,7 @@
 void VirtualCtap2Device::GetNextRP(cbor::Value::MapValue* response_map) {
   DCHECK(!mutable_state()->pending_rps.empty());
   response_map->emplace(static_cast<int>(CredentialManagementResponseKey::kRP),
-                        PublicKeyCredentialRpEntity::ConvertToCBOR(
-                            mutable_state()->pending_rps.front()));
+                        AsCBOR(mutable_state()->pending_rps.front()));
   response_map->emplace(
       static_cast<int>(CredentialManagementResponseKey::kRPIDHash),
       fido_parsing_utils::CreateSHA256Hash(
diff --git a/device/fido/win/type_conversions_unittest.cc b/device/fido/win/type_conversions_unittest.cc
index 443c0c03..3746415 100644
--- a/device/fido/win/type_conversions_unittest.cc
+++ b/device/fido/win/type_conversions_unittest.cc
@@ -120,9 +120,8 @@
     EXPECT_EQ(
         response->attestation_object().attestation_statement().format_name(),
         base::WideToUTF8(test.format));
-    EXPECT_EQ(cbor::Writer::Write(cbor::Value(response->attestation_object()
-                                                  .attestation_statement()
-                                                  .GetAsCBORMap())),
+    EXPECT_EQ(cbor::Writer::Write(AsCBOR(
+                  response->attestation_object().attestation_statement())),
               test.cbor_attestation_statement);
     EXPECT_EQ(response->transport_used(), test.expected_transport);
   }
diff --git a/device/vr/oculus/oculus_render_loop.cc b/device/vr/oculus/oculus_render_loop.cc
index 1d5ac27..12d3be2 100644
--- a/device/vr/oculus/oculus_render_loop.cc
+++ b/device/vr/oculus/oculus_render_loop.cc
@@ -139,7 +139,9 @@
   ovr_frame_index_ = 0;
 }
 
-void OculusRenderLoop::OnSessionStart() {}
+void OculusRenderLoop::OnSessionStart() {
+  LogViewerType(VrViewerType::OCULUS_UNKNOWN);
+}
 
 bool OculusRenderLoop::PreComposite() {
   // If our current swap chain has a different size than the recommended size
diff --git a/device/vr/openvr/openvr_device_provider.cc b/device/vr/openvr/openvr_device_provider.cc
index b9c969f..3b696aa 100644
--- a/device/vr/openvr/openvr_device_provider.cc
+++ b/device/vr/openvr/openvr_device_provider.cc
@@ -18,8 +18,7 @@
   XrRuntimeAvailable runtime = XrRuntimeAvailable::NONE;
   if (vr::VR_IsRuntimeInstalled())
     runtime = XrRuntimeAvailable::OPENVR;
-  UMA_HISTOGRAM_ENUMERATION("XR.RuntimeAvailable", runtime,
-                            XrRuntimeAvailable::COUNT);
+  UMA_HISTOGRAM_ENUMERATION("XR.RuntimeAvailable", runtime);
 }
 
 OpenVRDeviceProvider::OpenVRDeviceProvider() = default;
diff --git a/device/vr/openvr/openvr_render_loop.cc b/device/vr/openvr/openvr_render_loop.cc
index a3d9174a..e342bd1 100644
--- a/device/vr/openvr/openvr_render_loop.cc
+++ b/device/vr/openvr/openvr_render_loop.cc
@@ -4,7 +4,6 @@
 
 #include "device/vr/openvr/openvr_render_loop.h"
 
-#include "base/metrics/histogram_functions.h"
 #include "device/vr/openvr/openvr_api_wrapper.h"
 #include "device/vr/openvr/openvr_gamepad_helper.h"
 #include "device/vr/openvr/openvr_type_converters.h"
@@ -163,7 +162,7 @@
   else if (model == "Vive MV")
     type = VrViewerType::OPENVR_VIVE;
 
-  base::UmaHistogramSparse("VRViewerType", static_cast<int>(type));
+  LogViewerType(type);
 }
 
 mojom::XRGamepadDataPtr OpenVRRenderLoop::GetNextGamepadData() {
diff --git a/device/vr/public/mojom/vr_service.mojom b/device/vr/public/mojom/vr_service.mojom
index d914ba2..7b7478a 100644
--- a/device/vr/public/mojom/vr_service.mojom
+++ b/device/vr/public/mojom/vr_service.mojom
@@ -17,17 +17,18 @@
 // WebXR interfaces
 //
 
-// TODO: Use EnableIf to only define values on platforms that have
-// implementations.
+// TODO(https://crbug.com/966099): Use EnableIf to only define values on
+// platforms that have implementations.
+// XRDeviceId is used in metrics, so don't reorder.
 enum XRDeviceId {
-  LAYOUT_TEST_DEVICE_ID = 0, // Fake device used by layout tests.
-  GVR_DEVICE_ID = 1,
-  [EnableIf=enable_openvr] OPENVR_DEVICE_ID = 2,
-  [EnableIf=enable_oculus_vr] OCULUS_DEVICE_ID = 3,
-  ARCORE_DEVICE_ID = 4,
-  ORIENTATION_DEVICE_ID = 5,
-  FAKE_DEVICE_ID = 6, // Fake device used by unit tests.
-  [EnableIf=enable_windows_mr] WINDOWS_MIXED_REALITY_ID = 7,
+  WEB_TEST_DEVICE_ID = 0, // Fake device used by web_tests.
+  FAKE_DEVICE_ID = 1, // Fake device used in unit tests.
+  ORIENTATION_DEVICE_ID = 2,
+  GVR_DEVICE_ID = 3,
+  [EnableIf=enable_openvr] OPENVR_DEVICE_ID = 4,
+  [EnableIf=enable_oculus_vr] OCULUS_DEVICE_ID = 5,
+  [EnableIf=enable_windows_mr] WINDOWS_MIXED_REALITY_ID = 6,
+  ARCORE_DEVICE_ID = 7,
 };
 
 enum XRHandedness {
@@ -348,9 +349,7 @@
 interface XRDevice {
   // Request to initialize a session in the browser process. If successful, the
   // XRSession struct with the requisite interfaces will be returned.
-  RequestSession(
-    XRSessionOptions options,
-    bool triggered_by_displayactive) => (XRSession? session);
+  RequestSession(XRSessionOptions options) => (XRSession? session);
   SupportsSession(XRSessionOptions options) => (bool supports_session);
 
   // WebVR 1.1 functionality compatibility method. Returns VRDisplayInfo for an
diff --git a/device/vr/vr_device.h b/device/vr/vr_device.h
index abc3dff..742c445 100644
--- a/device/vr/vr_device.h
+++ b/device/vr/vr_device.h
@@ -24,7 +24,8 @@
   OPENVR_UNKNOWN = 20,
   OPENVR_VIVE = 21,
   OPENVR_RIFT_CV1 = 22,
-  VIEWER_TYPE_COUNT,
+  OCULUS_UNKNOWN = 40,                 // Going through Oculus APIs
+  WINDOWS_MIXED_REALITY_UNKNOWN = 60,  // Going through WMR APIs
 };
 
 // These values are persisted to logs. Entries should not be renumbered and
@@ -32,9 +33,11 @@
 enum class XrRuntimeAvailable {
   NONE = 0,
   OPENVR = 1,
-  COUNT,
+  kMaxValue = OPENVR,
 };
 
+void LogViewerType(VrViewerType);  // Implemented in vr_device_base.cc
+
 }  // namespace device
 
 #endif  // DEVICE_VR_VR_DEVICE_H
diff --git a/device/vr/vr_device_base.cc b/device/vr/vr_device_base.cc
index 8b20623..e88e257 100644
--- a/device/vr/vr_device_base.cc
+++ b/device/vr/vr_device_base.cc
@@ -4,6 +4,7 @@
 
 #include "device/vr/vr_device_base.h"
 
+#include "base/metrics/histogram_functions.h"
 #include "device/vr/vr_device_provider.h"
 #include "device/vr/vr_display_impl.h"
 
@@ -127,6 +128,10 @@
   std::move(callback).Run(std::move(session), std::move(controller));
 }
 
+void LogViewerType(VrViewerType type) {
+  base::UmaHistogramSparse("VRViewerType", static_cast<int>(type));
+}
+
 void VRDeviceBase::EndMagicWindowSession(VRDisplayImpl* session) {
   base::EraseIf(magic_window_sessions_,
                 [&](const std::unique_ptr<VRDisplayImpl>& item) {
diff --git a/device/vr/windows_mixed_reality/mixed_reality_renderloop.cc b/device/vr/windows_mixed_reality/mixed_reality_renderloop.cc
index 404e591..75434d62 100644
--- a/device/vr/windows_mixed_reality/mixed_reality_renderloop.cc
+++ b/device/vr/windows_mixed_reality/mixed_reality_renderloop.cc
@@ -384,10 +384,13 @@
 }
 
 void MixedRealityRenderLoop::OnSessionStart() {
+  LogViewerType(VrViewerType::WINDOWS_MIXED_REALITY_UNKNOWN);
+
   // Each session should start with new origins.
   origin_ = nullptr;
   attached_ = nullptr;
   last_origin_from_attached_ = base::nullopt;
+
   InitializeOrigin();
 
   ClearStageOrigin();
diff --git a/extensions/browser/guest_view/extensions_guest_view_message_filter.cc b/extensions/browser/guest_view/extensions_guest_view_message_filter.cc
index 77aac8f..a7e9ed1 100644
--- a/extensions/browser/guest_view/extensions_guest_view_message_filter.cc
+++ b/extensions/browser/guest_view/extensions_guest_view_message_filter.cc
@@ -140,6 +140,8 @@
   }
   auto* rfh =
       content::RenderFrameHost::FromID(render_process_id_, render_frame_id);
+  if (!rfh)
+    return;
   if (auto* mhve = MimeHandlerViewEmbedder::Get(rfh->GetFrameTreeNodeId()))
     mhve->ReadyToCreateMimeHandlerView(success);
 }
diff --git a/extensions/common/BUILD.gn b/extensions/common/BUILD.gn
index 93439e9a..feb42c8 100644
--- a/extensions/common/BUILD.gn
+++ b/extensions/common/BUILD.gn
@@ -383,8 +383,6 @@
     sources = [
       "api/declarative_net_request/test_utils.cc",
       "api/declarative_net_request/test_utils.h",
-      "file_test_util.cc",
-      "file_test_util.h",
     ]
 
     deps = [
diff --git a/extensions/common/file_test_util.cc b/extensions/common/file_test_util.cc
deleted file mode 100644
index f15c5f4..0000000
--- a/extensions/common/file_test_util.cc
+++ /dev/null
@@ -1,17 +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 "extensions/common/file_test_util.h"
-#include "base/files/file_util.h"
-
-namespace extensions {
-namespace file_test_util {
-
-bool WriteFile(const base::FilePath& path, base::StringPiece content) {
-  return base::WriteFile(path, content.data(), content.size()) ==
-         static_cast<int>(content.size());
-}
-
-}  // namespace file_test_util
-}  // namespace extensions
diff --git a/extensions/common/file_test_util.h b/extensions/common/file_test_util.h
deleted file mode 100644
index ecab05df..0000000
--- a/extensions/common/file_test_util.h
+++ /dev/null
@@ -1,23 +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 EXTENSIONS_COMMON_FILE_TEST_UTIL_H_
-#define EXTENSIONS_COMMON_FILE_TEST_UTIL_H_
-
-#include "base/strings/string_piece.h"
-
-namespace base {
-class FilePath;
-}
-
-namespace extensions {
-namespace file_test_util {
-
-// Writes |content| to |path|. Returns true if writing was successful,
-// verifying the number of bytes written equals the size of |content|.
-bool WriteFile(const base::FilePath& path, base::StringPiece content);
-
-}  // namespace file_test_util
-}  // namespace extensions
-
-#endif  // EXTENSIONS_COMMON_FILE_TEST_UTIL_H_
diff --git a/gpu/ipc/common/BUILD.gn b/gpu/ipc/common/BUILD.gn
index adf97c5..0e72647 100644
--- a/gpu/ipc/common/BUILD.gn
+++ b/gpu/ipc/common/BUILD.gn
@@ -3,7 +3,6 @@
 # found in the LICENSE file.
 
 import("//build/config/ui.gni")
-import("//gpu/vulkan/features.gni")
 import("//mojo/public/tools/bindings/mojom.gni")
 
 group("common") {
@@ -82,6 +81,8 @@
     "gpu_param_traits_macros.h",
     "memory_stats.cc",
     "memory_stats.h",
+    "vulkan_ycbcr_info.cc",
+    "vulkan_ycbcr_info.h",
   ]
 
   if (is_mac) {
@@ -249,8 +250,7 @@
     "//gpu/ipc/common",
     "//mojo/public/cpp/bindings:bindings",
   ]
-  if (enable_vulkan) {
+  if (is_android) {
     sources += [ "vulkan_ycbcr_info_mojom_traits.h" ]
-    deps += [ "//gpu/vulkan:vulkan" ]
   }
 }
diff --git a/gpu/ipc/common/typemaps.gni b/gpu/ipc/common/typemaps.gni
index 8316f13..cf81e70 100644
--- a/gpu/ipc/common/typemaps.gni
+++ b/gpu/ipc/common/typemaps.gni
@@ -2,8 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//gpu/vulkan/features.gni")
-
 typemaps = [
   "//gpu/ipc/common/capabilities.typemap",
   "//gpu/ipc/common/context_result.typemap",
@@ -16,8 +14,5 @@
   "//gpu/ipc/common/memory_stats.typemap",
   "//gpu/ipc/common/surface_handle.typemap",
   "//gpu/ipc/common/sync_token.typemap",
+  "//gpu/ipc/common/vulkan_ycbcr_info.typemap",
 ]
-
-if (enable_vulkan) {
-  typemaps += [ "//gpu/ipc/common/vulkan_ycbcr_info.typemap" ]
-}
diff --git a/gpu/vulkan/vulkan_ycbcr_info.cc b/gpu/ipc/common/vulkan_ycbcr_info.cc
similarity index 94%
rename from gpu/vulkan/vulkan_ycbcr_info.cc
rename to gpu/ipc/common/vulkan_ycbcr_info.cc
index c5834d90..ac0fbbe 100644
--- a/gpu/vulkan/vulkan_ycbcr_info.cc
+++ b/gpu/ipc/common/vulkan_ycbcr_info.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 "gpu/vulkan/vulkan_ycbcr_info.h"
+#include "gpu/ipc/common/vulkan_ycbcr_info.h"
 
 namespace gpu {
 
diff --git a/gpu/vulkan/vulkan_ycbcr_info.h b/gpu/ipc/common/vulkan_ycbcr_info.h
similarity index 90%
rename from gpu/vulkan/vulkan_ycbcr_info.h
rename to gpu/ipc/common/vulkan_ycbcr_info.h
index 643ffa5e..4ac1728 100644
--- a/gpu/vulkan/vulkan_ycbcr_info.h
+++ b/gpu/ipc/common/vulkan_ycbcr_info.h
@@ -2,17 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef GPU_VULKAN_VULKAN_YCBCR_INFO_H_
-#define GPU_VULKAN_VULKAN_YCBCR_INFO_H_
+#ifndef GPU_IPC_COMMON_VULKAN_YCBCR_INFO_H_
+#define GPU_IPC_COMMON_VULKAN_YCBCR_INFO_H_
 
 #include <stdint.h>
 
-#include "gpu/vulkan/vulkan_export.h"
+#include "gpu/gpu_export.h"
 
 namespace gpu {
 
 // Sampler Ycbcr conversion information.
-struct VULKAN_EXPORT VulkanYCbCrInfo {
+struct GPU_EXPORT VulkanYCbCrInfo {
   VulkanYCbCrInfo();
   VulkanYCbCrInfo(uint32_t suggested_ycbcr_model,
                   uint32_t suggested_ycbcr_range,
@@ -55,4 +55,4 @@
 
 }  // namespace gpu
 
-#endif  // GPU_VULKAN_VULKAN_YCBCR_INFO_H_
+#endif  // GPU_IPC_COMMON_VULKAN_YCBCR_INFO_H_
diff --git a/gpu/ipc/common/vulkan_ycbcr_info.mojom b/gpu/ipc/common/vulkan_ycbcr_info.mojom
index 692ad13..4c755cea 100644
--- a/gpu/ipc/common/vulkan_ycbcr_info.mojom
+++ b/gpu/ipc/common/vulkan_ycbcr_info.mojom
@@ -8,7 +8,7 @@
 // enums defined in the vulkan api which are passed as uint32/uint64 over ipc.
 // We use all of these values in an "opaque" way and don't consume it directly
 // in chrome.
-// See gpu/vulkan/vulkan_ycbcr_info.h.
+// See gpu/ipc/common/vulkan_ycbcr_info.h.
 struct VulkanYCbCrInfo {
   uint32 suggested_ycbcr_model;
   uint32 suggested_ycbcr_range;
diff --git a/gpu/ipc/common/vulkan_ycbcr_info.typemap b/gpu/ipc/common/vulkan_ycbcr_info.typemap
index 32b17b8..f7a4e24 100644
--- a/gpu/ipc/common/vulkan_ycbcr_info.typemap
+++ b/gpu/ipc/common/vulkan_ycbcr_info.typemap
@@ -3,6 +3,6 @@
 # found in the LICENSE file.
 
 mojom = "//gpu/ipc/common/vulkan_ycbcr_info.mojom"
-public_headers = [ "//gpu/vulkan/vulkan_ycbcr_info.h" ]
+public_headers = [ "//gpu/ipc/common/vulkan_ycbcr_info.h" ]
 traits_headers = [ "//gpu/ipc/common/vulkan_ycbcr_info_mojom_traits.h" ]
 type_mappings = [ "gpu.mojom.VulkanYCbCrInfo=::gpu::VulkanYCbCrInfo" ]
diff --git a/gpu/ipc/common/vulkan_ycbcr_info_mojom_traits.h b/gpu/ipc/common/vulkan_ycbcr_info_mojom_traits.h
index b33e894..88e8aa95 100644
--- a/gpu/ipc/common/vulkan_ycbcr_info_mojom_traits.h
+++ b/gpu/ipc/common/vulkan_ycbcr_info_mojom_traits.h
@@ -5,8 +5,8 @@
 #ifndef GPU_IPC_COMMON_VULKAN_YCBCR_INFO_MOJOM_TRAITS_H_
 #define GPU_IPC_COMMON_VULKAN_YCBCR_INFO_MOJOM_TRAITS_H_
 
+#include "gpu/ipc/common/vulkan_ycbcr_info.h"
 #include "gpu/ipc/common/vulkan_ycbcr_info.mojom-shared.h"
-#include "gpu/vulkan/vulkan_ycbcr_info.h"
 
 namespace mojo {
 
diff --git a/gpu/vulkan/BUILD.gn b/gpu/vulkan/BUILD.gn
index bb88be8..066ae742 100644
--- a/gpu/vulkan/BUILD.gn
+++ b/gpu/vulkan/BUILD.gn
@@ -50,8 +50,6 @@
       "vulkan_swap_chain.h",
       "vulkan_util.cc",
       "vulkan_util.h",
-      "vulkan_ycbcr_info.cc",
-      "vulkan_ycbcr_info.h",
     ]
 
     configs += [ "//build/config:precompiled_headers" ]
diff --git a/gpu/vulkan/android/BUILD.gn b/gpu/vulkan/android/BUILD.gn
index c9c4e59..b78a2ac 100644
--- a/gpu/vulkan/android/BUILD.gn
+++ b/gpu/vulkan/android/BUILD.gn
@@ -24,6 +24,7 @@
   defines = [ "IS_VULKAN_ANDROID_IMPL" ]
 
   deps = [
+    "//gpu/ipc/common:common",
     "//ui/gfx",
   ]
 
diff --git a/gpu/vulkan/android/vulkan_implementation_android.cc b/gpu/vulkan/android/vulkan_implementation_android.cc
index bbc80413..e3b427e 100644
--- a/gpu/vulkan/android/vulkan_implementation_android.cc
+++ b/gpu/vulkan/android/vulkan_implementation_android.cc
@@ -8,13 +8,13 @@
 #include "base/bind_helpers.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
+#include "gpu/ipc/common/vulkan_ycbcr_info.h"
 #include "gpu/vulkan/vulkan_device_queue.h"
 #include "gpu/vulkan/vulkan_function_pointers.h"
 #include "gpu/vulkan/vulkan_instance.h"
 #include "gpu/vulkan/vulkan_posix_util.h"
 #include "gpu/vulkan/vulkan_surface.h"
 #include "gpu/vulkan/vulkan_util.h"
-#include "gpu/vulkan/vulkan_ycbcr_info.h"
 #include "ui/gfx/gpu_fence.h"
 #include "ui/gfx/gpu_memory_buffer.h"
 
diff --git a/infra/config/cr-buildbucket.cfg b/infra/config/cr-buildbucket.cfg
index 5a23e730..73ee538 100644
--- a/infra/config/cr-buildbucket.cfg
+++ b/infra/config/cr-buildbucket.cfg
@@ -1113,7 +1113,7 @@
     builders {
       name: "android-kitkat-arm-rel"
       mixins: "android-ci"
-      dimensions: "os:Ubuntu-14.04"
+      dimensions: "os:Ubuntu-16.04"
     }
 
     builders {
@@ -3380,7 +3380,7 @@
       mixins: "android-try"
       mixins: "goma-j150"
       name: "android-kitkat-arm-rel"
-      dimensions: "os:Ubuntu-14.04"
+      dimensions: "os:Ubuntu-16.04"
     }
     builders {
       mixins: "android-try"
diff --git a/ios/chrome/browser/autofill/manual_fill/passwords_fetcher.mm b/ios/chrome/browser/autofill/manual_fill/passwords_fetcher.mm
index 4ee58f0..27eb3f40 100644
--- a/ios/chrome/browser/autofill/manual_fill/passwords_fetcher.mm
+++ b/ios/chrome/browser/autofill/manual_fill/passwords_fetcher.mm
@@ -87,7 +87,7 @@
       _passwordStore->GetAutofillableLogins(_savedPasswordsConsumer.get());
     } else {
       password_manager::PasswordStore::FormDigest digest = {
-          autofill::PasswordForm::SCHEME_HTML, std::string(), URL};
+          autofill::PasswordForm::Scheme::kHtml, std::string(), URL};
       digest.signon_realm = URL.spec();
       _passwordStore->GetLogins(digest, _savedPasswordsConsumer.get());
     }
diff --git a/ios/chrome/browser/autofill/manual_fill/passwords_fetcher_unittest.mm b/ios/chrome/browser/autofill/manual_fill/passwords_fetcher_unittest.mm
index 9d904ce..d3c93d75 100644
--- a/ios/chrome/browser/autofill/manual_fill/passwords_fetcher_unittest.mm
+++ b/ios/chrome/browser/autofill/manual_fill/passwords_fetcher_unittest.mm
@@ -86,7 +86,7 @@
     form.submit_element = base::ASCIIToUTF16("signIn");
     form.signon_realm = "http://www.example.com/";
     form.preferred = false;
-    form.scheme = autofill::PasswordForm::SCHEME_HTML;
+    form.scheme = autofill::PasswordForm::Scheme::kHtml;
     form.blacklisted_by_user = false;
     return form;
   }
@@ -106,7 +106,7 @@
     form->submit_element = base::ASCIIToUTF16("signIn");
     form->signon_realm = "http://www.example2.com/";
     form->preferred = false;
-    form->scheme = autofill::PasswordForm::SCHEME_HTML;
+    form->scheme = autofill::PasswordForm::Scheme::kHtml;
     form->blacklisted_by_user = false;
     GetPasswordStore()->AddLogin(*std::move(form));
   }
@@ -124,7 +124,7 @@
     form->submit_element = base::ASCIIToUTF16("signIn");
     form->signon_realm = "http://www.secret.test/";
     form->preferred = false;
-    form->scheme = autofill::PasswordForm::SCHEME_HTML;
+    form->scheme = autofill::PasswordForm::Scheme::kHtml;
     form->blacklisted_by_user = true;
     GetPasswordStore()->AddLogin(*std::move(form));
   }
diff --git a/ios/chrome/browser/passwords/credential_manager_egtest.mm b/ios/chrome/browser/passwords/credential_manager_egtest.mm
index bc75363..7ab718d 100644
--- a/ios/chrome/browser/passwords/credential_manager_egtest.mm
+++ b/ios/chrome/browser/passwords/credential_manager_egtest.mm
@@ -120,7 +120,7 @@
   passwordCredentialForm.origin =
       chrome_test_util::GetCurrentWebState()->GetLastCommittedURL().GetOrigin();
   passwordCredentialForm.signon_realm = passwordCredentialForm.origin.spec();
-  passwordCredentialForm.scheme = autofill::PasswordForm::SCHEME_HTML;
+  passwordCredentialForm.scheme = autofill::PasswordForm::Scheme::kHtml;
   passwordStore->AddLogin(passwordCredentialForm);
 }
 
diff --git a/ios/chrome/browser/passwords/credential_manager_unittest.mm b/ios/chrome/browser/passwords/credential_manager_unittest.mm
index d30954f..d7dda1b2 100644
--- a/ios/chrome/browser/passwords/credential_manager_unittest.mm
+++ b/ios/chrome/browser/passwords/credential_manager_unittest.mm
@@ -117,7 +117,7 @@
     password_credential_form_1_.password_value = base::ASCIIToUTF16("secret1");
     password_credential_form_1_.origin = GURL(kHttpsWebOrigin);
     password_credential_form_1_.signon_realm = kHttpsWebOrigin;
-    password_credential_form_1_.scheme = autofill::PasswordForm::SCHEME_HTML;
+    password_credential_form_1_.scheme = autofill::PasswordForm::Scheme::kHtml;
 
     password_credential_form_2_.username_value = base::ASCIIToUTF16("id2");
     password_credential_form_2_.display_name = base::ASCIIToUTF16("Name Two");
@@ -125,7 +125,7 @@
     password_credential_form_2_.password_value = base::ASCIIToUTF16("secret2");
     password_credential_form_2_.origin = GURL(kHttpsWebOrigin);
     password_credential_form_2_.signon_realm = kHttpsWebOrigin;
-    password_credential_form_2_.scheme = autofill::PasswordForm::SCHEME_HTML;
+    password_credential_form_2_.scheme = autofill::PasswordForm::Scheme::kHtml;
 
     federated_credential_form_.username_value = base::ASCIIToUTF16("id");
     federated_credential_form_.display_name = base::ASCIIToUTF16("name");
@@ -136,7 +136,7 @@
     federated_credential_form_.origin = GURL(kHttpsWebOrigin);
     federated_credential_form_.signon_realm =
         "federation://www.example.com/www.federation.com";
-    federated_credential_form_.scheme = autofill::PasswordForm::SCHEME_HTML;
+    federated_credential_form_.scheme = autofill::PasswordForm::Scheme::kHtml;
   }
 
   void TearDown() override {
diff --git a/ios/chrome/browser/passwords/password_controller_unittest.mm b/ios/chrome/browser/passwords/password_controller_unittest.mm
index 8af68ef..459fd193 100644
--- a/ios/chrome/browser/passwords/password_controller_unittest.mm
+++ b/ios/chrome/browser/passwords/password_controller_unittest.mm
@@ -131,7 +131,7 @@
                                 const char* username_value,
                                 const char* password_value) {
   PasswordForm form;
-  form.scheme = PasswordForm::SCHEME_HTML;
+  form.scheme = PasswordForm::Scheme::kHtml;
   form.origin = GURL(origin_url);
   form.signon_realm = origin_url;
   form.username_value = ASCIIToUTF16(username_value);
@@ -1206,7 +1206,7 @@
   bool* p_get_logins_called = &get_logins_called;
 
   password_manager::PasswordStore::FormDigest expected_form_digest(
-      autofill::PasswordForm::SCHEME_HTML, "https://chromium.test/",
+      autofill::PasswordForm::Scheme::kHtml, "https://chromium.test/",
       GURL("https://chromium.test/"));
   // TODO(crbug.com/949519): replace WillRepeatedly with WillOnce when the old
   // parser is gone.
diff --git a/ios/chrome/browser/ui/settings/password/passwords_table_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/password/passwords_table_view_controller_unittest.mm
index 13da8c07..c56adb8a 100644
--- a/ios/chrome/browser/ui/settings/password/passwords_table_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/settings/password/passwords_table_view_controller_unittest.mm
@@ -96,7 +96,7 @@
     form->submit_element = base::ASCIIToUTF16("signIn");
     form->signon_realm = "http://www.example.com/";
     form->preferred = false;
-    form->scheme = autofill::PasswordForm::SCHEME_HTML;
+    form->scheme = autofill::PasswordForm::Scheme::kHtml;
     form->blacklisted_by_user = false;
     AddPasswordForm(std::move(form));
   }
@@ -113,7 +113,7 @@
     form->submit_element = base::ASCIIToUTF16("signIn");
     form->signon_realm = "http://www.example2.com/";
     form->preferred = false;
-    form->scheme = autofill::PasswordForm::SCHEME_HTML;
+    form->scheme = autofill::PasswordForm::Scheme::kHtml;
     form->blacklisted_by_user = false;
     AddPasswordForm(std::move(form));
   }
@@ -131,7 +131,7 @@
     form->submit_element = base::ASCIIToUTF16("signIn");
     form->signon_realm = "http://www.secret.com/";
     form->preferred = false;
-    form->scheme = autofill::PasswordForm::SCHEME_HTML;
+    form->scheme = autofill::PasswordForm::Scheme::kHtml;
     form->blacklisted_by_user = true;
     AddPasswordForm(std::move(form));
   }
@@ -149,7 +149,7 @@
     form->submit_element = base::ASCIIToUTF16("signIn");
     form->signon_realm = "http://www.secret2.com/";
     form->preferred = false;
-    form->scheme = autofill::PasswordForm::SCHEME_HTML;
+    form->scheme = autofill::PasswordForm::Scheme::kHtml;
     form->blacklisted_by_user = true;
     AddPasswordForm(std::move(form));
   }
@@ -391,7 +391,7 @@
   form.password_value = base::ASCIIToUTF16("test");
   form.submit_element = base::ASCIIToUTF16("signIn");
   form.signon_realm = "http://www.example.com/";
-  form.scheme = autofill::PasswordForm::SCHEME_HTML;
+  form.scheme = autofill::PasswordForm::Scheme::kHtml;
   form.blacklisted_by_user = false;
 
   AddPasswordForm(std::make_unique<autofill::PasswordForm>(form));
diff --git a/ios/web/navigation/BUILD.gn b/ios/web/navigation/BUILD.gn
index 996a24a..559fd7e 100644
--- a/ios/web/navigation/BUILD.gn
+++ b/ios/web/navigation/BUILD.gn
@@ -26,6 +26,7 @@
     "//ios/web/public/download",
     "//ios/web/public/security",
     "//ios/web/public/session",
+    "//ios/web/security",
     "//ios/web/session",
     "//ios/web/web_state:user_interaction",
     "//ios/web/web_state:web_state_impl_header",
diff --git a/ios/web/navigation/crw_wk_navigation_handler.h b/ios/web/navigation/crw_wk_navigation_handler.h
index deb7aac..e638e3b 100644
--- a/ios/web/navigation/crw_wk_navigation_handler.h
+++ b/ios/web/navigation/crw_wk_navigation_handler.h
@@ -10,6 +10,7 @@
 
 #import <memory>
 
+#import "ios/web/security/cert_verification_error.h"
 #include "ui/base/page_transition_types.h"
 
 @class CRWWKNavigationHandler;
@@ -39,6 +40,11 @@
 - (web::UserInteractionState*)userInteractionStateForNavigationHandler:
     (CRWWKNavigationHandler*)navigationHandler;
 
+// Returns associated certificate verification errors.
+- (web::CertVerificationErrorsCacheType*)
+    certVerificationErrorsForNavigationHandler:
+        (CRWWKNavigationHandler*)navigationHandler;
+
 // Returns YES if WKWebView is halted.
 - (BOOL)navigationHandlerWebViewIsHalted:
     (CRWWKNavigationHandler*)navigationHandler;
@@ -90,6 +96,27 @@
             rendererInitiated:(BOOL)renderedInitiated
         placeholderNavigation:(BOOL)placeholderNavigation;
 
+// Notifies the delegate that load has been cancelled.
+- (void)navigationHandler:(CRWWKNavigationHandler*)navigationHandler
+     handleCancelledError:(NSError*)error
+            forNavigation:(WKNavigation*)navigation
+          provisionalLoad:(BOOL)provisionalLoad;
+
+// Notifies the delegate that load ends in an SSL error and certificate chain.
+- (void)navigationHandler:(CRWWKNavigationHandler*)navigationHandler
+       handleSSLCertError:(NSError*)error
+            forNavigation:(WKNavigation*)navigation;
+
+// Notifies the delegate that load ends in error.
+- (void)navigationHandler:(CRWWKNavigationHandler*)navigationHandler
+          handleLoadError:(NSError*)error
+            forNavigation:(WKNavigation*)navigation
+          provisionalLoad:(BOOL)provisionalLoad;
+
+// Instructs the delegate to clear the web frames list.
+- (void)navigationHandlerRemoveAllWebFrames:
+    (CRWWKNavigationHandler*)navigationHandler;
+
 @end
 
 // Handler class for WKNavigationDelegate, deals with navigation callbacks from
@@ -163,6 +190,15 @@
 // is moved into CRWWKNavigationHandler.
 - (void)commitPendingNavigationInfoInWebView:(WKWebView*)webView;
 
+// WKNavigation objects are used as a weak key to store web::NavigationContext.
+// WKWebView manages WKNavigation lifetime and destroys them after the
+// navigation is finished. However for window opening navigations WKWebView
+// passes null WKNavigation to WKNavigationDelegate callbacks and strong key is
+// used to store web::NavigationContext. Those "null" navigations have to be
+// cleaned up manually by calling this method.
+// TODO(crbug.com/956511): Make this private once refactor is done.
+- (void)forgetNullWKNavigation:(WKNavigation*)navigation;
+
 @end
 
 #endif  // IOS_WEB_NAVIGATION_CRW_WK_NAVIGATION_HANDLER_H_
diff --git a/ios/web/navigation/crw_wk_navigation_handler.mm b/ios/web/navigation/crw_wk_navigation_handler.mm
index d3e94b5..8cfd83b 100644
--- a/ios/web/navigation/crw_wk_navigation_handler.mm
+++ b/ios/web/navigation/crw_wk_navigation_handler.mm
@@ -15,6 +15,7 @@
 #import "ios/web/navigation/navigation_context_impl.h"
 #import "ios/web/navigation/navigation_manager_impl.h"
 #include "ios/web/navigation/navigation_manager_util.h"
+#import "ios/web/navigation/web_kit_constants.h"
 #import "ios/web/navigation/wk_back_forward_list_item_holder.h"
 #import "ios/web/navigation/wk_navigation_action_policy_util.h"
 #import "ios/web/navigation/wk_navigation_action_util.h"
@@ -23,6 +24,7 @@
 #import "ios/web/public/download/download_controller.h"
 #import "ios/web/public/url_scheme_util.h"
 #import "ios/web/public/web_client.h"
+#import "ios/web/security/wk_web_view_security_util.h"
 #import "ios/web/web_state/user_interaction_state.h"
 #import "ios/web/web_state/web_state_impl.h"
 #import "ios/web/web_view/wk_web_view_util.h"
@@ -39,7 +41,21 @@
 using web::wk_navigation_util::IsRestoreSessionUrl;
 using web::wk_navigation_util::IsWKInternalUrl;
 
-@interface CRWWKNavigationHandler ()
+@interface CRWWKNavigationHandler () {
+  // Used to poll for a SafeBrowsing warning being displayed. This is created in
+  // |decidePolicyForNavigationAction| and destroyed once any of the following
+  // happens: 1) a SafeBrowsing warning is detected; 2) any WKNavigationDelegate
+  // method is called; 3) |stopLoading| is called.
+  base::RepeatingTimer _safeBrowsingWarningDetectionTimer;
+
+  // Referrer for the current page; does not include the fragment.
+  NSString* _currentReferrerString;
+
+  // The WKNavigation captured when |stopLoading| was called. Used for reporting
+  // WebController.EmptyNavigationManagerCausedByStopLoading UMA metric which
+  // helps with diagnosing a navigation related crash (crbug.com/565457).
+  __weak WKNavigation* _stoppedWKNavigation;
+}
 
 // Returns the WebStateImpl from self.delegate.
 @property(nonatomic, readonly, assign) web::WebStateImpl* webStateImpl;
@@ -49,19 +65,13 @@
 // Returns the UserInteractionState from self.delegate.
 @property(nonatomic, readonly, assign)
     web::UserInteractionState* userInteractionState;
+// Returns the CertVerificationErrorsCacheType from self.delegate.
+@property(nonatomic, readonly, assign)
+    web::CertVerificationErrorsCacheType* certVerificationErrors;
 
 @end
 
-@implementation CRWWKNavigationHandler {
-  // Used to poll for a SafeBrowsing warning being displayed. This is created in
-  // |decidePolicyForNavigationAction| and destroyed once any of the following
-  // happens: 1) a SafeBrowsing warning is detected; 2) any WKNavigationDelegate
-  // method is called; 3) |stopLoading| is called.
-  base::RepeatingTimer _safeBrowsingWarningDetectionTimer;
-
-  // Referrer for the current page; does not include the fragment.
-  NSString* _currentReferrerString;
-}
+@implementation CRWWKNavigationHandler
 
 - (instancetype)init {
   if (self = [super init]) {
@@ -599,6 +609,74 @@
     didFailProvisionalNavigation:(WKNavigation*)navigation
                        withError:(NSError*)error {
   [self didReceiveWKNavigationDelegateCallback];
+
+  [self.navigationStates setState:web::WKNavigationState::PROVISIONALY_FAILED
+                    forNavigation:navigation];
+
+  // Ignore provisional navigation failure if a new navigation has been started,
+  // for example, if a page is reloaded after the start of the provisional
+  // load but before the load has been committed.
+  if (![[self.navigationStates lastAddedNavigation] isEqual:navigation]) {
+    return;
+  }
+
+  // TODO(crbug.com/570699): Remove this workaround once |stopLoading| does not
+  // discard pending navigation items.
+  if ((!self.webStateImpl ||
+       !self.webStateImpl->GetNavigationManagerImpl().GetVisibleItem()) &&
+      _stoppedWKNavigation &&
+      [error.domain isEqual:base::SysUTF8ToNSString(web::kWebKitErrorDomain)] &&
+      error.code == web::kWebKitErrorFrameLoadInterruptedByPolicyChange) {
+    // App is going to crash in this state (crbug.com/565457). Crash will occur
+    // on dereferencing visible navigation item, which is null. This scenario is
+    // possible after pending load was stopped for a child window. Early return
+    // to prevent the crash and report UMA metric to check if crash happening
+    // because the load was stopped.
+    UMA_HISTOGRAM_BOOLEAN(
+        "WebController.EmptyNavigationManagerCausedByStopLoading",
+        [_stoppedWKNavigation isEqual:navigation]);
+    return;
+  }
+
+  // Handle load cancellation for directly cancelled navigations without
+  // handling their potential errors. Otherwise, handle the error.
+  if (self.pendingNavigationInfo.cancelled) {
+    [self.delegate navigationHandler:self
+                handleCancelledError:error
+                       forNavigation:navigation
+                     provisionalLoad:YES];
+  } else if (error.code == NSURLErrorUnsupportedURL &&
+             self.webStateImpl->HasWebUI()) {
+    // This is a navigation to WebUI page.
+    DCHECK(web::GetWebClient()->IsAppSpecificURL(
+        net::GURLWithNSURL(error.userInfo[NSURLErrorFailingURLErrorKey])));
+  } else {
+    if (web::IsWKWebViewSSLCertError(error)) {
+      [self.delegate navigationHandler:self
+                    handleSSLCertError:error
+                         forNavigation:navigation];
+    } else {
+      [self.delegate navigationHandler:self
+                       handleLoadError:error
+                         forNavigation:navigation
+                       provisionalLoad:YES];
+    }
+  }
+
+  [self.delegate navigationHandlerRemoveAllWebFrames:self];
+  // This must be reset at the end, since code above may need information about
+  // the pending load.
+  self.pendingNavigationInfo = nil;
+  self.certVerificationErrors->Clear();
+  if (web::features::StorePendingItemInContext()) {
+    // Remove the navigation to immediately get rid of pending item.
+    if (web::WKNavigationState::NONE !=
+        [self.navigationStates stateForNavigation:navigation]) {
+      [self.navigationStates removeNavigation:navigation];
+    }
+  } else {
+    [self forgetNullWKNavigation:navigation];
+  }
 }
 
 - (void)webView:(WKWebView*)webView
@@ -643,6 +721,10 @@
   return [self.delegate userInteractionStateForNavigationHandler:self];
 }
 
+- (web::CertVerificationErrorsCacheType*)certVerificationErrors {
+  return [self.delegate certVerificationErrorsForNavigationHandler:self];
+}
+
 - (web::NavigationItemImpl*)currentNavItem {
   return self.navigationManagerImpl
              ? self.navigationManagerImpl->GetCurrentItemImpl()
@@ -919,6 +1001,7 @@
 #pragma mark - Public methods
 
 - (void)stopLoading {
+  _stoppedWKNavigation = [self.navigationStates lastAddedNavigation];
   self.pendingNavigationInfo.cancelled = YES;
   _safeBrowsingWarningDetectionTimer.Stop();
   [self loadCancelled];
@@ -1060,4 +1143,9 @@
                        web::ReferrerPolicyAlways);
 }
 
+- (void)forgetNullWKNavigation:(WKNavigation*)navigation {
+  if (!navigation)
+    [self.navigationStates removeNavigation:navigation];
+}
+
 @end
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index b453f93..42b01682 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -237,11 +237,6 @@
   // history navigations.
   BOOL _dispatchingSameDocumentHashChangeEvent;
 
-  // The WKNavigation captured when |stopLoading| was called. Used for reporting
-  // WebController.EmptyNavigationManagerCausedByStopLoading UMA metric which
-  // helps with diagnosing a navigation related crash (crbug.com/565457).
-  __weak WKNavigation* _stoppedWKNavigation;
-
   // Updates SSLStatus for current navigation item.
   CRWSSLStatusUpdater* _SSLStatusUpdater;
 
@@ -962,9 +957,6 @@
 }
 
 - (void)stopLoading {
-  _stoppedWKNavigation =
-      [self.navigationHandler.navigationStates lastAddedNavigation];
-
   base::RecordAction(base::UserMetricsAction("Stop"));
   // Discard the pending and transient entried before notifying the tab model
   // observers of the change via |-abortLoad|.
@@ -3553,70 +3545,6 @@
   [self.navigationHandler webView:webView
       didFailProvisionalNavigation:navigation
                          withError:error];
-
-  [self.navigationHandler.navigationStates
-           setState:web::WKNavigationState::PROVISIONALY_FAILED
-      forNavigation:navigation];
-
-  // Ignore provisional navigation failure if a new navigation has been started,
-  // for example, if a page is reloaded after the start of the provisional
-  // load but before the load has been committed.
-  if (![[self.navigationHandler.navigationStates lastAddedNavigation]
-          isEqual:navigation]) {
-    return;
-  }
-
-  // TODO(crbug.com/570699): Remove this workaround once |stopLoading| does not
-  // discard pending navigation items.
-  if ((!self.webStateImpl ||
-       !self.webStateImpl->GetNavigationManagerImpl().GetVisibleItem()) &&
-      _stoppedWKNavigation &&
-      [error.domain isEqual:base::SysUTF8ToNSString(web::kWebKitErrorDomain)] &&
-      error.code == web::kWebKitErrorFrameLoadInterruptedByPolicyChange) {
-    // App is going to crash in this state (crbug.com/565457). Crash will occur
-    // on dereferencing visible navigation item, which is null. This scenario is
-    // possible after pending load was stopped for a child window. Early return
-    // to prevent the crash and report UMA metric to check if crash happening
-    // because the load was stopped.
-    UMA_HISTOGRAM_BOOLEAN(
-        "WebController.EmptyNavigationManagerCausedByStopLoading",
-        [_stoppedWKNavigation isEqual:navigation]);
-    return;
-  }
-
-  // Handle load cancellation for directly cancelled navigations without
-  // handling their potential errors. Otherwise, handle the error.
-  if (self.navigationHandler.pendingNavigationInfo.cancelled) {
-    [self handleCancelledError:error
-                 forNavigation:navigation
-               provisionalLoad:YES];
-  } else if (error.code == NSURLErrorUnsupportedURL &&
-             self.webStateImpl->HasWebUI()) {
-    // This is a navigation to WebUI page.
-    DCHECK(web::GetWebClient()->IsAppSpecificURL(
-        net::GURLWithNSURL(error.userInfo[NSURLErrorFailingURLErrorKey])));
-  } else {
-    if (web::IsWKWebViewSSLCertError(error)) {
-      [self handleSSLCertError:error forNavigation:navigation];
-    } else {
-      [self handleLoadError:error forNavigation:navigation provisionalLoad:YES];
-    }
-  }
-
-  [self removeAllWebFrames];
-  // This must be reset at the end, since code above may need information about
-  // the pending load.
-  self.navigationHandler.pendingNavigationInfo = nil;
-  _certVerificationErrors->Clear();
-  if (web::features::StorePendingItemInContext()) {
-    // Remove the navigation to immediately get rid of pending item.
-    if (web::WKNavigationState::NONE != [self.navigationHandler.navigationStates
-                                            stateForNavigation:navigation]) {
-      [self.navigationHandler.navigationStates removeNavigation:navigation];
-    }
-  } else {
-    [self forgetNullWKNavigation:navigation];
-  }
 }
 
 - (void)webView:(WKWebView*)webView
@@ -3982,7 +3910,7 @@
       [self.navigationHandler.navigationStates removeNavigation:navigation];
     }
   } else {
-    [self forgetNullWKNavigation:navigation];
+    [self.navigationHandler forgetNullWKNavigation:navigation];
   }
 }
 
@@ -4001,7 +3929,7 @@
 
   [self removeAllWebFrames];
   _certVerificationErrors->Clear();
-  [self forgetNullWKNavigation:navigation];
+  [self.navigationHandler forgetNullWKNavigation:navigation];
 }
 
 - (void)webView:(WKWebView*)webView
@@ -4314,17 +4242,6 @@
   return MIMEType.compare(0, image.length(), image) == 0;
 }
 
-// WKNavigation objects are used as a weak key to store web::NavigationContext.
-// WKWebView manages WKNavigation lifetime and destroys them after the
-// navigation is finished. However for window opening navigations WKWebView
-// passes null WKNavigation to WKNavigationDelegate callbacks and strong key is
-// used to store web::NavigationContext. Those "null" navigations have to be
-// cleaned up manually by calling this method.
-- (void)forgetNullWKNavigation:(WKNavigation*)navigation {
-  if (!navigation)
-    [self.navigationHandler.navigationStates removeNavigation:navigation];
-}
-
 #pragma mark - CRWSSLStatusUpdaterDataSource
 
 - (void)SSLStatusUpdater:(CRWSSLStatusUpdater*)SSLStatusUpdater
@@ -4840,6 +4757,12 @@
   return &_userInteractionState;
 }
 
+- (web::CertVerificationErrorsCacheType*)
+    certVerificationErrorsForNavigationHandler:
+        (CRWWKNavigationHandler*)navigationHandler {
+  return _certVerificationErrors.get();
+}
+
 - (GURL)navigationHandlerDocumentURL:
     (CRWWKNavigationHandler*)navigationHandler {
   return _documentURL;
@@ -4896,6 +4819,34 @@
                    placeholderNavigation:placeholderNavigation];
 }
 
+- (void)navigationHandler:(CRWWKNavigationHandler*)navigationHandler
+     handleCancelledError:(NSError*)error
+            forNavigation:(WKNavigation*)navigation
+          provisionalLoad:(BOOL)provisionalLoad {
+  [self handleCancelledError:error
+               forNavigation:navigation
+             provisionalLoad:provisionalLoad];
+}
+
+- (void)navigationHandler:(CRWWKNavigationHandler*)navigationHandler
+       handleSSLCertError:(NSError*)error
+            forNavigation:(WKNavigation*)navigation {
+  [self handleSSLCertError:error forNavigation:navigation];
+}
+
+- (void)navigationHandler:(CRWWKNavigationHandler*)navigationHandler
+          handleLoadError:(NSError*)error
+            forNavigation:(WKNavigation*)navigation
+          provisionalLoad:(BOOL)provisionalLoad {
+  [self handleLoadError:error
+          forNavigation:navigation
+        provisionalLoad:provisionalLoad];
+}
+- (void)navigationHandlerRemoveAllWebFrames:
+    (CRWWKNavigationHandler*)navigationHandler {
+  [self removeAllWebFrames];
+}
+
 #pragma mark - Testing-Only Methods
 
 - (void)injectWebViewContentView:(CRWWebViewContentView*)webViewContentView {
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 830129d..5bf1e8c1 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -220,6 +220,8 @@
     "cert/internal/path_builder.h",
     "cert/internal/revocation_checker.cc",
     "cert/internal/revocation_checker.h",
+    "cert/internal/revocation_util.cc",
+    "cert/internal/revocation_util.h",
     "cert/internal/signature_algorithm.cc",
     "cert/internal/signature_algorithm.h",
     "cert/internal/simple_path_builder_delegate.cc",
@@ -4973,6 +4975,7 @@
     "cert/internal/path_builder_unittest.cc",
     "cert/internal/path_builder_verify_certificate_chain_unittest.cc",
     "cert/internal/revocation_checker_unittest.cc",
+    "cert/internal/revocation_util_unittest.cc",
     "cert/internal/signature_algorithm_unittest.cc",
     "cert/internal/simple_path_builder_delegate_unittest.cc",
     "cert/internal/test_helpers.cc",
diff --git a/net/cert/internal/ocsp.cc b/net/cert/internal/ocsp.cc
index 986bd7d..d10d1ac 100644
--- a/net/cert/internal/ocsp.cc
+++ b/net/cert/internal/ocsp.cc
@@ -13,10 +13,10 @@
 #include "net/cert/internal/cert_errors.h"
 #include "net/cert/internal/extended_key_usage.h"
 #include "net/cert/internal/parsed_certificate.h"
+#include "net/cert/internal/revocation_util.h"
 #include "net/cert/internal/verify_name_match.h"
 #include "net/cert/internal/verify_signed_data.h"
 #include "net/cert/x509_util.h"
-#include "net/der/encode_values.h"
 #include "third_party/boringssl/src/include/openssl/bytestring.h"
 #include "third_party/boringssl/src/include/openssl/digest.h"
 #include "third_party/boringssl/src/include/openssl/mem.h"
@@ -705,7 +705,11 @@
     // serial numbers. If an OCSP responder provides both an up to date
     // response and an expired response, the up to date response takes
     // precedence (PROVIDED > INVALID_DATE).
-    if (!CheckOCSPDateValid(single_response, verify_time, max_age)) {
+    if (!CheckRevocationDateValid(single_response.this_update,
+                                  single_response.has_next_update
+                                      ? &single_response.next_update
+                                      : nullptr,
+                                  verify_time, max_age)) {
       if (*response_details != OCSPVerifyResult::PROVIDED)
         *response_details = OCSPVerifyResult::INVALID_DATE;
       continue;
@@ -815,30 +819,6 @@
   return status;
 }
 
-bool CheckOCSPDateValid(const OCSPSingleResponse& response,
-                        const base::Time& verify_time,
-                        const base::TimeDelta& max_age) {
-  der::GeneralizedTime verify_time_der;
-  if (!der::EncodeTimeAsGeneralizedTime(verify_time, &verify_time_der))
-    return false;
-
-  if (response.this_update > verify_time_der)
-    return false;  // Response is not yet valid.
-
-  if (response.has_next_update && (response.next_update <= verify_time_der))
-    return false;  // Response is no longer valid.
-
-  der::GeneralizedTime earliest_this_update;
-  if (!der::EncodeTimeAsGeneralizedTime(verify_time - max_age,
-                                        &earliest_this_update)) {
-    return false;
-  }
-  if (response.this_update < earliest_this_update)
-    return false;  // Response is too old.
-
-  return true;
-}
-
 bool CreateOCSPRequest(const ParsedCertificate* cert,
                        const ParsedCertificate* issuer,
                        std::vector<uint8_t>* request_der) {
diff --git a/net/cert/internal/ocsp.h b/net/cert/internal/ocsp.h
index c530e5b..e8ab44e 100644
--- a/net/cert/internal/ocsp.h
+++ b/net/cert/internal/ocsp.h
@@ -313,15 +313,6 @@
     const base::TimeDelta& max_age,
     OCSPVerifyResult::ResponseStatus* response_details) WARN_UNUSED_RESULT;
 
-// Returns true if |response|, a valid OCSP response with a thisUpdate field and
-// potentially a nextUpdate field, is valid at |verify_time| and not older than
-// |max_age|. Expressed differently, returns true if |response.thisUpdate| <=
-// |verify_time| < response.nextUpdate, and |response.thisUpdate| >=
-// |verify_time| - |max_age|.
-NET_EXPORT_PRIVATE bool CheckOCSPDateValid(const OCSPSingleResponse& response,
-                                           const base::Time& verify_time,
-                                           const base::TimeDelta& max_age);
-
 // Creates a DER-encoded OCSPRequest for |cert|. The request is fairly basic:
 //  * No signature
 //  * No requestorName
diff --git a/net/cert/internal/ocsp_unittest.cc b/net/cert/internal/ocsp_unittest.cc
index 03d6d5e..1e9dc79 100644
--- a/net/cert/internal/ocsp_unittest.cc
+++ b/net/cert/internal/ocsp_unittest.cc
@@ -7,7 +7,6 @@
 #include "base/base64.h"
 #include "base/logging.h"
 #include "base/strings/string_util.h"
-#include "build/build_config.h"
 #include "net/cert/internal/test_helpers.h"
 #include "net/der/encode_values.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -171,133 +170,6 @@
             der::Input(&request_data));
 }
 
-TEST(OCSPDateTest, Valid) {
-  OCSPSingleResponse response;
-
-  base::Time now = base::Time::Now();
-  base::Time this_update = now - base::TimeDelta::FromHours(1);
-  ASSERT_TRUE(
-      der::EncodeTimeAsGeneralizedTime(this_update, &response.this_update));
-  response.has_next_update = false;
-  EXPECT_TRUE(CheckOCSPDateValid(response, now, kOCSPAgeOneWeek));
-
-  base::Time next_update = this_update + base::TimeDelta::FromDays(7);
-  ASSERT_TRUE(
-      der::EncodeTimeAsGeneralizedTime(next_update, &response.next_update));
-  response.has_next_update = true;
-  EXPECT_TRUE(CheckOCSPDateValid(response, now, kOCSPAgeOneWeek));
-}
-
-TEST(OCSPDateTest, ThisUpdateInTheFuture) {
-  OCSPSingleResponse response;
-
-  base::Time now = base::Time::Now();
-  base::Time this_update = now + base::TimeDelta::FromHours(1);
-  ASSERT_TRUE(
-      der::EncodeTimeAsGeneralizedTime(this_update, &response.this_update));
-  response.has_next_update = false;
-  EXPECT_FALSE(CheckOCSPDateValid(response, now, kOCSPAgeOneWeek));
-
-  base::Time next_update = this_update + base::TimeDelta::FromDays(7);
-  ASSERT_TRUE(
-      der::EncodeTimeAsGeneralizedTime(next_update, &response.next_update));
-  response.has_next_update = true;
-  EXPECT_FALSE(CheckOCSPDateValid(response, now, kOCSPAgeOneWeek));
-}
-
-TEST(OCSPDateTest, NextUpdatePassed) {
-  OCSPSingleResponse response;
-
-  base::Time now = base::Time::Now();
-  base::Time this_update = now - base::TimeDelta::FromDays(6);
-  ASSERT_TRUE(
-      der::EncodeTimeAsGeneralizedTime(this_update, &response.this_update));
-  response.has_next_update = false;
-  EXPECT_TRUE(CheckOCSPDateValid(response, now, kOCSPAgeOneWeek));
-
-  base::Time next_update = now - base::TimeDelta::FromHours(1);
-  ASSERT_TRUE(
-      der::EncodeTimeAsGeneralizedTime(next_update, &response.next_update));
-  response.has_next_update = true;
-  EXPECT_FALSE(CheckOCSPDateValid(response, now, kOCSPAgeOneWeek));
-}
-
-TEST(OCSPDateTest, NextUpdateBeforeThisUpdate) {
-  OCSPSingleResponse response;
-
-  base::Time now = base::Time::Now();
-  base::Time this_update = now - base::TimeDelta::FromDays(1);
-  ASSERT_TRUE(
-      der::EncodeTimeAsGeneralizedTime(this_update, &response.this_update));
-  response.has_next_update = false;
-  EXPECT_TRUE(CheckOCSPDateValid(response, now, kOCSPAgeOneWeek));
-
-  base::Time next_update = this_update - base::TimeDelta::FromDays(1);
-  ASSERT_TRUE(
-      der::EncodeTimeAsGeneralizedTime(next_update, &response.next_update));
-  response.has_next_update = true;
-  EXPECT_FALSE(CheckOCSPDateValid(response, now, kOCSPAgeOneWeek));
-}
-
-TEST(OCSPDateTest, ThisUpdateOlderThanMaxAge) {
-  OCSPSingleResponse response;
-
-  base::Time now = base::Time::Now();
-  base::Time this_update = now - kOCSPAgeOneWeek;
-  ASSERT_TRUE(
-      der::EncodeTimeAsGeneralizedTime(this_update, &response.this_update));
-  response.has_next_update = false;
-  EXPECT_TRUE(CheckOCSPDateValid(response, now, kOCSPAgeOneWeek));
-
-  base::Time next_update = now + base::TimeDelta::FromHours(1);
-  ASSERT_TRUE(
-      der::EncodeTimeAsGeneralizedTime(next_update, &response.next_update));
-  response.has_next_update = true;
-  EXPECT_TRUE(CheckOCSPDateValid(response, now, kOCSPAgeOneWeek));
-
-  ASSERT_TRUE(der::EncodeTimeAsGeneralizedTime(
-      this_update - base::TimeDelta::FromSeconds(1), &response.this_update));
-  response.has_next_update = false;
-  EXPECT_FALSE(CheckOCSPDateValid(response, now, kOCSPAgeOneWeek));
-  response.has_next_update = true;
-  EXPECT_FALSE(CheckOCSPDateValid(response, now, kOCSPAgeOneWeek));
-}
-
-TEST(OCSPDateTest, VerifyTimeFromBeforeWindowsEpoch) {
-  OCSPSingleResponse response;
-  base::Time windows_epoch;
-  base::Time verify_time = windows_epoch - base::TimeDelta::FromDays(1);
-
-  base::Time now = base::Time::Now();
-  base::Time this_update = now - base::TimeDelta::FromHours(1);
-  ASSERT_TRUE(
-      der::EncodeTimeAsGeneralizedTime(this_update, &response.this_update));
-  response.has_next_update = false;
-  EXPECT_FALSE(CheckOCSPDateValid(response, verify_time, kOCSPAgeOneWeek));
-
-  base::Time next_update = this_update + kOCSPAgeOneWeek;
-  ASSERT_TRUE(
-      der::EncodeTimeAsGeneralizedTime(next_update, &response.next_update));
-  response.has_next_update = true;
-  EXPECT_FALSE(CheckOCSPDateValid(response, verify_time, kOCSPAgeOneWeek));
-}
-
-TEST(OCSPDateTest, VerifyTimeMinusAgeFromBeforeWindowsEpoch) {
-  OCSPSingleResponse response;
-  base::Time windows_epoch;
-  base::Time verify_time = windows_epoch + base::TimeDelta::FromDays(1);
-
-  base::Time this_update = windows_epoch;
-  ASSERT_TRUE(
-      der::EncodeTimeAsGeneralizedTime(this_update, &response.this_update));
-  response.has_next_update = false;
-#if defined(OS_WIN)
-  EXPECT_FALSE(CheckOCSPDateValid(response, verify_time, kOCSPAgeOneWeek));
-#else
-  EXPECT_TRUE(CheckOCSPDateValid(response, verify_time, kOCSPAgeOneWeek));
-#endif
-}
-
 base::StringPiece kGetURLTestParams[] = {
     "http://www.example.com/", "http://www.example.com/path/",
     "http://www.example.com/path",
diff --git a/net/cert/internal/revocation_util.cc b/net/cert/internal/revocation_util.cc
new file mode 100644
index 0000000..786ec86
--- /dev/null
+++ b/net/cert/internal/revocation_util.cc
@@ -0,0 +1,38 @@
+// 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 "net/cert/internal/revocation_util.h"
+
+#include "base/time/time.h"
+#include "net/der/encode_values.h"
+#include "net/der/parse_values.h"
+
+namespace net {
+
+bool CheckRevocationDateValid(const der::GeneralizedTime& this_update,
+                              const der::GeneralizedTime* next_update,
+                              const base::Time& verify_time,
+                              const base::TimeDelta& max_age) {
+  der::GeneralizedTime verify_time_der;
+  if (!der::EncodeTimeAsGeneralizedTime(verify_time, &verify_time_der))
+    return false;
+
+  if (this_update > verify_time_der)
+    return false;  // Response is not yet valid.
+
+  if (next_update && (*next_update <= verify_time_der))
+    return false;  // Response is no longer valid.
+
+  der::GeneralizedTime earliest_this_update;
+  if (!der::EncodeTimeAsGeneralizedTime(verify_time - max_age,
+                                        &earliest_this_update)) {
+    return false;
+  }
+  if (this_update < earliest_this_update)
+    return false;  // Response is too old.
+
+  return true;
+}
+
+}  // namespace net
diff --git a/net/cert/internal/revocation_util.h b/net/cert/internal/revocation_util.h
new file mode 100644
index 0000000..26faaba
--- /dev/null
+++ b/net/cert/internal/revocation_util.h
@@ -0,0 +1,34 @@
+// 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 NET_CERT_INTERNAL_REVOCATION_UTIL_H_
+#define NET_CERT_INTERNAL_REVOCATION_UTIL_H_
+
+#include "base/optional.h"
+#include "net/base/net_export.h"
+
+namespace base {
+class Time;
+class TimeDelta;
+}  // namespace base
+
+namespace net {
+
+namespace der {
+struct GeneralizedTime;
+}
+
+// Returns true if a revocation status with |this_update| field and potentially
+// a |next_update| field, is valid at |verify_time| and not older than
+// |max_age|.  Expressed differently, returns true if |this_update <=
+// verify_time < next_update|, and |this_update >= verify_time - max_age|.
+NET_EXPORT_PRIVATE bool CheckRevocationDateValid(
+    const der::GeneralizedTime& this_update,
+    const der::GeneralizedTime* next_update,
+    const base::Time& verify_time,
+    const base::TimeDelta& max_age) WARN_UNUSED_RESULT;
+
+}  // namespace net
+
+#endif  // NET_CERT_INTERNAL_REVOCATION_UTIL_H_
diff --git a/net/cert/internal/revocation_util_unittest.cc b/net/cert/internal/revocation_util_unittest.cc
new file mode 100644
index 0000000..9b8fcbb
--- /dev/null
+++ b/net/cert/internal/revocation_util_unittest.cc
@@ -0,0 +1,150 @@
+// 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 "net/cert/internal/revocation_util.h"
+
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "net/der/encode_values.h"
+#include "net/der/parse_values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+namespace {
+
+constexpr base::TimeDelta kOneWeek = base::TimeDelta::FromDays(7);
+
+}  // namespace
+
+TEST(CheckRevocationDateTest, Valid) {
+  base::Time now = base::Time::Now();
+  base::Time this_update = now - base::TimeDelta::FromHours(1);
+  der::GeneralizedTime encoded_this_update;
+  ASSERT_TRUE(
+      der::EncodeTimeAsGeneralizedTime(this_update, &encoded_this_update));
+  EXPECT_TRUE(
+      CheckRevocationDateValid(encoded_this_update, nullptr, now, kOneWeek));
+
+  base::Time next_update = this_update + base::TimeDelta::FromDays(7);
+  der::GeneralizedTime encoded_next_update;
+  ASSERT_TRUE(
+      der::EncodeTimeAsGeneralizedTime(next_update, &encoded_next_update));
+  EXPECT_TRUE(CheckRevocationDateValid(encoded_this_update,
+                                       &encoded_next_update, now, kOneWeek));
+}
+
+TEST(CheckRevocationDateTest, ThisUpdateInTheFuture) {
+  base::Time now = base::Time::Now();
+  base::Time this_update = now + base::TimeDelta::FromHours(1);
+  der::GeneralizedTime encoded_this_update;
+  ASSERT_TRUE(
+      der::EncodeTimeAsGeneralizedTime(this_update, &encoded_this_update));
+  EXPECT_FALSE(
+      CheckRevocationDateValid(encoded_this_update, nullptr, now, kOneWeek));
+
+  base::Time next_update = this_update + base::TimeDelta::FromDays(7);
+  der::GeneralizedTime encoded_next_update;
+  ASSERT_TRUE(
+      der::EncodeTimeAsGeneralizedTime(next_update, &encoded_next_update));
+  EXPECT_FALSE(CheckRevocationDateValid(encoded_this_update,
+                                        &encoded_next_update, now, kOneWeek));
+}
+
+TEST(CheckRevocationDateTest, NextUpdatePassed) {
+  base::Time now = base::Time::Now();
+  base::Time this_update = now - base::TimeDelta::FromDays(6);
+  der::GeneralizedTime encoded_this_update;
+  ASSERT_TRUE(
+      der::EncodeTimeAsGeneralizedTime(this_update, &encoded_this_update));
+  EXPECT_TRUE(
+      CheckRevocationDateValid(encoded_this_update, nullptr, now, kOneWeek));
+
+  base::Time next_update = now - base::TimeDelta::FromHours(1);
+  der::GeneralizedTime encoded_next_update;
+  ASSERT_TRUE(
+      der::EncodeTimeAsGeneralizedTime(next_update, &encoded_next_update));
+  EXPECT_FALSE(CheckRevocationDateValid(encoded_this_update,
+                                        &encoded_next_update, now, kOneWeek));
+}
+
+TEST(CheckRevocationDateTest, NextUpdateBeforeThisUpdate) {
+  base::Time now = base::Time::Now();
+  base::Time this_update = now - base::TimeDelta::FromDays(1);
+  der::GeneralizedTime encoded_this_update;
+  ASSERT_TRUE(
+      der::EncodeTimeAsGeneralizedTime(this_update, &encoded_this_update));
+  EXPECT_TRUE(
+      CheckRevocationDateValid(encoded_this_update, nullptr, now, kOneWeek));
+
+  base::Time next_update = this_update - base::TimeDelta::FromDays(1);
+  der::GeneralizedTime encoded_next_update;
+  ASSERT_TRUE(
+      der::EncodeTimeAsGeneralizedTime(next_update, &encoded_next_update));
+  EXPECT_FALSE(CheckRevocationDateValid(encoded_this_update,
+                                        &encoded_next_update, now, kOneWeek));
+}
+
+TEST(CheckRevocationDateTest, ThisUpdateOlderThanMaxAge) {
+  base::Time now = base::Time::Now();
+  base::Time this_update = now - kOneWeek;
+  der::GeneralizedTime encoded_this_update;
+  ASSERT_TRUE(
+      der::EncodeTimeAsGeneralizedTime(this_update, &encoded_this_update));
+  EXPECT_TRUE(
+      CheckRevocationDateValid(encoded_this_update, nullptr, now, kOneWeek));
+
+  base::Time next_update = now + base::TimeDelta::FromHours(1);
+  der::GeneralizedTime encoded_next_update;
+  ASSERT_TRUE(
+      der::EncodeTimeAsGeneralizedTime(next_update, &encoded_next_update));
+  EXPECT_TRUE(CheckRevocationDateValid(encoded_this_update,
+                                       &encoded_next_update, now, kOneWeek));
+
+  ASSERT_TRUE(der::EncodeTimeAsGeneralizedTime(
+      this_update - base::TimeDelta::FromSeconds(1), &encoded_this_update));
+  EXPECT_FALSE(
+      CheckRevocationDateValid(encoded_this_update, nullptr, now, kOneWeek));
+  EXPECT_FALSE(CheckRevocationDateValid(encoded_this_update,
+                                        &encoded_next_update, now, kOneWeek));
+}
+
+TEST(CheckRevocationDateTest, VerifyTimeFromBeforeWindowsEpoch) {
+  base::Time windows_epoch;
+  base::Time verify_time = windows_epoch - base::TimeDelta::FromDays(1);
+
+  base::Time now = base::Time::Now();
+  base::Time this_update = now - base::TimeDelta::FromHours(1);
+  der::GeneralizedTime encoded_this_update;
+  ASSERT_TRUE(
+      der::EncodeTimeAsGeneralizedTime(this_update, &encoded_this_update));
+  EXPECT_FALSE(CheckRevocationDateValid(encoded_this_update, nullptr,
+                                        verify_time, kOneWeek));
+
+  base::Time next_update = this_update + kOneWeek;
+  der::GeneralizedTime encoded_next_update;
+  ASSERT_TRUE(
+      der::EncodeTimeAsGeneralizedTime(next_update, &encoded_next_update));
+  EXPECT_FALSE(CheckRevocationDateValid(
+      encoded_this_update, &encoded_next_update, verify_time, kOneWeek));
+}
+
+TEST(CheckRevocationDateTest, VerifyTimeMinusAgeFromBeforeWindowsEpoch) {
+  base::Time windows_epoch;
+  base::Time verify_time = windows_epoch + base::TimeDelta::FromDays(1);
+
+  base::Time this_update = windows_epoch;
+  der::GeneralizedTime encoded_this_update;
+  ASSERT_TRUE(
+      der::EncodeTimeAsGeneralizedTime(this_update, &encoded_this_update));
+#if defined(OS_WIN)
+  EXPECT_FALSE(CheckRevocationDateValid(encoded_this_update, nullptr,
+                                        verify_time, kOneWeek));
+#else
+  EXPECT_TRUE(CheckRevocationDateValid(encoded_this_update, nullptr,
+                                       verify_time, kOneWeek));
+#endif
+}
+
+}  // namespace net
diff --git a/printing/BUILD.gn b/printing/BUILD.gn
index 64fcd1c..50faec7 100644
--- a/printing/BUILD.gn
+++ b/printing/BUILD.gn
@@ -320,6 +320,12 @@
       sources += [ "backend/cups_ipp_util_unittest.cc" ]
     } else {
       sources += [ "backend/cups_helper_unittest.cc" ]
+      if (is_linux) {
+        sources += [ "backend/print_backend_cups_linux_unittest.cc" ]
+      }
+      if (is_mac) {
+        sources += [ "backend/print_backend_cups_mac_unittest.cc" ]
+      }
     }
   }
 }
diff --git a/printing/backend/print_backend.h b/printing/backend/print_backend.h
index a01e8bd..b78c2dd6 100644
--- a/printing/backend/print_backend.h
+++ b/printing/backend/print_backend.h
@@ -22,15 +22,18 @@
 // This is the interface for platform-specific code for a print backend
 namespace printing {
 
-// Note: There are raw values. The |printer_name| and |printer_description|
-// require further interpretation on Windows, Mac and Chrome OS. See existing
-// callers for examples.
 struct PRINTING_EXPORT PrinterBasicInfo {
   PrinterBasicInfo();
   PrinterBasicInfo(const PrinterBasicInfo& other);
   ~PrinterBasicInfo();
 
+  // The name of the printer as understood by OS.
   std::string printer_name;
+
+  // The name of the printer as shown in Print Preview.
+  // For Windows SetGetDisplayNameFunction() can be used to set the setter of
+  // this field.
+  std::string display_name;
   std::string printer_description;
   int printer_status = 0;
   int is_default = false;
diff --git a/printing/backend/print_backend_cups.cc b/printing/backend/print_backend_cups.cc
index 8016c15..e3a9d22 100644
--- a/printing/backend/print_backend_cups.cc
+++ b/printing/backend/print_backend_cups.cc
@@ -18,6 +18,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/synchronization/lock.h"
 #include "base/values.h"
+#include "build/build_config.h"
 #include "printing/backend/cups_helper.h"
 #include "printing/backend/print_backend_consts.h"
 #include "url/gurl.h"
@@ -30,8 +31,19 @@
 const char kCUPSPrinterStateOpt[] = "printer-state";
 const char kCUPSPrinterTypeOpt[] = "printer-type";
 
-bool PrinterBasicInfoFromCUPS(const cups_dest_t& printer,
-                              PrinterBasicInfo* printer_info) {
+}  // namespace
+
+PrintBackendCUPS::PrintBackendCUPS(const GURL& print_server_url,
+                                   http_encryption_t encryption,
+                                   bool blocking)
+    : print_server_url_(print_server_url),
+      cups_encryption_(encryption),
+      blocking_(blocking) {}
+
+// static
+bool PrintBackendCUPS::PrinterBasicInfoFromCUPS(
+    const cups_dest_t& printer,
+    PrinterBasicInfo* printer_info) {
   // CUPS can have 'printers' that are actually scanners. (not MFC)
   // At least on Mac. Check for scanners and skip them.
   const char* type_str =
@@ -47,8 +59,6 @@
 
   const char* info =
       cupsGetOption(kCUPSPrinterInfoOpt, printer.num_options, printer.options);
-  if (info)
-    printer_info->printer_description = info;
 
   const char* state =
       cupsGetOption(kCUPSPrinterStateOpt, printer.num_options, printer.options);
@@ -65,18 +75,24 @@
     printer_info->options[printer.options[opt_index].name] =
         printer.options[opt_index].value;
   }
+
+#if defined(OS_MACOSX)
+  // On Mac, "printer-info" option specifies the printer name and
+  // "printer-make-and-model" specifies the printer description.
+  if (info)
+    printer_info->display_name = info;
+  if (drv_info)
+    printer_info->printer_description = drv_info;
+#else
+  // On Linux destination name specifies the printer name and "printer-info"
+  // specifies the printer description.
+  printer_info->display_name = printer.name;
+  if (info)
+    printer_info->printer_description = info;
+#endif
   return true;
 }
 
-}  // namespace
-
-PrintBackendCUPS::PrintBackendCUPS(const GURL& print_server_url,
-                                   http_encryption_t encryption,
-                                   bool blocking)
-    : print_server_url_(print_server_url),
-      cups_encryption_(encryption),
-      blocking_(blocking) {}
-
 bool PrintBackendCUPS::EnumeratePrinters(PrinterList* printer_list) {
   DCHECK(printer_list);
   printer_list->clear();
diff --git a/printing/backend/print_backend_cups.h b/printing/backend/print_backend_cups.h
index 173258f..e1eb435 100644
--- a/printing/backend/print_backend_cups.h
+++ b/printing/backend/print_backend_cups.h
@@ -10,6 +10,7 @@
 #include "base/files/file_util.h"
 #include "printing/backend/cups_helper.h"
 #include "printing/backend/print_backend.h"
+#include "printing/printing_export.h"
 #include "url/gurl.h"
 
 namespace printing {
@@ -20,6 +21,11 @@
                    http_encryption_t encryption,
                    bool blocking);
 
+  // This static function is exposed here for use in the tests.
+  PRINTING_EXPORT static bool PrinterBasicInfoFromCUPS(
+      const cups_dest_t& printer,
+      PrinterBasicInfo* printer_info);
+
  private:
   ~PrintBackendCUPS() override {}
 
diff --git a/printing/backend/print_backend_cups_linux_unittest.cc b/printing/backend/print_backend_cups_linux_unittest.cc
new file mode 100644
index 0000000..ae11eb2
--- /dev/null
+++ b/printing/backend/print_backend_cups_linux_unittest.cc
@@ -0,0 +1,34 @@
+// 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 <cups/cups.h>
+
+#include "printing/backend/print_backend.h"
+#include "printing/backend/print_backend_cups.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace printing {
+
+TEST(PrintBackendCupsLinuxTest, PrinterBasicInfoFromCUPS) {
+  const char kName[] = "printer";
+  cups_dest_t* printer = nullptr;
+  ASSERT_EQ(1, cupsAddDest(kName, nullptr, 0, &printer));
+
+  int num_options = 0;
+  cups_option_t* options = nullptr;
+  num_options =
+      cupsAddOption("printer-info", "description", num_options, &options);
+  printer->num_options = num_options;
+  printer->options = options;
+
+  PrinterBasicInfo printer_info;
+  PrintBackendCUPS::PrinterBasicInfoFromCUPS(*printer, &printer_info);
+  cupsFreeDests(1, printer);
+
+  EXPECT_EQ("printer", printer_info.printer_name);
+  EXPECT_EQ("printer", printer_info.display_name);
+  EXPECT_EQ("description", printer_info.printer_description);
+}
+
+}  // namespace printing
diff --git a/printing/backend/print_backend_cups_mac_unittest.cc b/printing/backend/print_backend_cups_mac_unittest.cc
new file mode 100644
index 0000000..6732df0
--- /dev/null
+++ b/printing/backend/print_backend_cups_mac_unittest.cc
@@ -0,0 +1,35 @@
+// 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 <cups/cups.h>
+
+#include "printing/backend/print_backend.h"
+#include "printing/backend/print_backend_cups.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace printing {
+
+TEST(PrintBackendCupsMacTest, PrinterBasicInfoFromCUPS) {
+  const char kName[] = "printer";
+  cups_dest_t* printer = nullptr;
+  ASSERT_EQ(1, cupsAddDest(kName, nullptr, 0, &printer));
+
+  int num_options = 0;
+  cups_option_t* options = nullptr;
+  num_options = cupsAddOption("printer-info", "name", num_options, &options);
+  num_options = cupsAddOption("printer-make-and-model", "description",
+                              num_options, &options);
+  printer->num_options = num_options;
+  printer->options = options;
+
+  PrinterBasicInfo printer_info;
+  PrintBackendCUPS::PrinterBasicInfoFromCUPS(*printer, &printer_info);
+  cupsFreeDests(1, printer);
+
+  EXPECT_EQ("printer", printer_info.printer_name);
+  EXPECT_EQ("name", printer_info.display_name);
+  EXPECT_EQ("description", printer_info.printer_description);
+}
+
+}  // namespace printing
diff --git a/printing/backend/win_helper.cc b/printing/backend/win_helper.cc
index f8638a1..2bd0480 100644
--- a/printing/backend/win_helper.cc
+++ b/printing/backend/win_helper.cc
@@ -347,6 +347,12 @@
     return false;
 
   printer_info->printer_name = base::WideToUTF8(info_2.get()->pPrinterName);
+  if (g_get_display_name_func) {
+    printer_info->display_name =
+        g_get_display_name_func(printer_info->printer_name);
+  } else {
+    printer_info->display_name = printer_info->printer_name;
+  }
   if (info_2.get()->pComment) {
     printer_info->printer_description =
         base::WideToUTF8(info_2.get()->pComment);
diff --git a/remoting/base/oauth_token_getter.h b/remoting/base/oauth_token_getter.h
index 361d01e..4720150 100644
--- a/remoting/base/oauth_token_getter.h
+++ b/remoting/base/oauth_token_getter.h
@@ -34,6 +34,10 @@
                                        const std::string& refresh_token)>
       CredentialsUpdatedCallback;
 
+  // Called if the current refresh token is exchanged for one with new scopes.
+  typedef base::RepeatingCallback<void(const std::string& refresh_token)>
+      RefreshTokenUpdatedCallback;
+
   // This structure contains information required to perform authorization
   // with the authorization server.
   struct OAuthAuthorizationCredentials {
diff --git a/remoting/base/oauth_token_getter_impl.cc b/remoting/base/oauth_token_getter_impl.cc
index c5548c8..308c82c 100644
--- a/remoting/base/oauth_token_getter_impl.cc
+++ b/remoting/base/oauth_token_getter_impl.cc
@@ -44,10 +44,13 @@
 
 OAuthTokenGetterImpl::OAuthTokenGetterImpl(
     std::unique_ptr<OAuthAuthorizationCredentials> authorization_credentials,
+    const OAuthTokenGetter::RefreshTokenUpdatedCallback&
+        on_refresh_token_updated,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     bool auto_refresh)
     : authorization_credentials_(std::move(authorization_credentials)),
       gaia_oauth_client_(new gaia::GaiaOAuthClient(url_loader_factory)),
+      refresh_token_updated_callback_(on_refresh_token_updated),
       token_exchanger_(url_loader_factory),
       weak_factory_(this) {
   if (auto_refresh) {
@@ -303,6 +306,13 @@
       NotifyTokenCallbacks(status, std::string(), std::string());
       break;
     case SUCCESS:
+      if (!refresh_token.empty() &&
+          refresh_token != authorization_credentials_->refresh_token) {
+        authorization_credentials_->refresh_token = refresh_token;
+        if (refresh_token_updated_callback_) {
+          refresh_token_updated_callback_.Run(refresh_token);
+        }
+      }
       NotifyTokenCallbacks(status, authorization_credentials_->login,
                            oauth_access_token_);
       break;
diff --git a/remoting/base/oauth_token_getter_impl.h b/remoting/base/oauth_token_getter_impl.h
index 9204720..1df91cc 100644
--- a/remoting/base/oauth_token_getter_impl.h
+++ b/remoting/base/oauth_token_getter_impl.h
@@ -39,6 +39,8 @@
       bool auto_refresh);
   OAuthTokenGetterImpl(
       std::unique_ptr<OAuthAuthorizationCredentials> authorization_credentials,
+      const OAuthTokenGetter::RefreshTokenUpdatedCallback&
+          on_refresh_token_updated,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       bool auto_refresh);
   ~OAuthTokenGetterImpl() override;
@@ -81,6 +83,7 @@
   std::unique_ptr<OAuthAuthorizationCredentials> authorization_credentials_;
   std::unique_ptr<gaia::GaiaOAuthClient> gaia_oauth_client_;
   OAuthTokenGetter::CredentialsUpdatedCallback credentials_updated_callback_;
+  OAuthTokenGetter::RefreshTokenUpdatedCallback refresh_token_updated_callback_;
 
   bool response_pending_ = false;
   bool email_verified_ = false;
diff --git a/remoting/host/daemon_process.cc b/remoting/host/daemon_process.cc
index 21b6743..6c7f325e 100644
--- a/remoting/host/daemon_process.cc
+++ b/remoting/host/daemon_process.cc
@@ -21,6 +21,7 @@
 #include "remoting/host/chromoting_messages.h"
 #include "remoting/host/config_file_watcher.h"
 #include "remoting/host/desktop_session.h"
+#include "remoting/host/host_config.h"
 #include "remoting/host/host_event_logger.h"
 #include "remoting/host/host_exit_codes.h"
 #include "remoting/host/host_status_observer.h"
@@ -112,6 +113,8 @@
                         StartProcessStatsReport)
     IPC_MESSAGE_HANDLER(ChromotingNetworkToAnyMsg_StopProcessStatsReport,
                         StopProcessStatsReport)
+    IPC_MESSAGE_HANDLER(ChromotingNetworkDaemonMsg_UpdateConfigRefreshToken,
+                        UpdateConfigRefreshToken)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
 
@@ -262,17 +265,8 @@
 void DaemonProcess::Initialize() {
   DCHECK(caller_task_runner()->BelongsToCurrentThread());
 
-  const base::CommandLine* command_line =
-      base::CommandLine::ForCurrentProcess();
-  // Get the name of the host configuration file.
-  base::FilePath default_config_dir = remoting::GetConfigDir();
-  base::FilePath config_path = default_config_dir.Append(
-      kDefaultHostConfigFile);
-  if (command_line->HasSwitch(kHostConfigSwitchName)) {
-    config_path = command_line->GetSwitchValuePath(kHostConfigSwitchName);
-  }
   config_watcher_.reset(new ConfigFileWatcher(
-      caller_task_runner(), io_task_runner(), config_path));
+      caller_task_runner(), io_task_runner(), GetConfigPath()));
   config_watcher_->Watch(this);
   host_event_logger_ =
       HostEventLogger::Create(status_monitor_, kApplicationName);
@@ -397,4 +391,38 @@
   SendToNetwork(new ChromotingAnyToNetworkMsg_ReportProcessStats(usage));
 }
 
+base::FilePath DaemonProcess::GetConfigPath() {
+  base::FilePath config_path;
+  const base::CommandLine* command_line =
+      base::CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(kHostConfigSwitchName)) {
+    config_path = command_line->GetSwitchValuePath(kHostConfigSwitchName);
+  } else {
+    base::FilePath default_config_dir = remoting::GetConfigDir();
+    config_path = default_config_dir.Append(kDefaultHostConfigFile);
+  }
+  return config_path;
+}
+
+void DaemonProcess::UpdateConfigRefreshToken(const std::string& token) {
+  io_task_runner_->PostTask(FROM_HERE,
+                            base::BindOnce(&UpdateConfigRefreshTokenOnIoThread,
+                                           GetConfigPath(), token));
+}
+
+void DaemonProcess::UpdateConfigRefreshTokenOnIoThread(
+    const base::FilePath& config_file,
+    const std::string& token) {
+  std::unique_ptr<base::DictionaryValue> config =
+      HostConfigFromJsonFile(config_file);
+  if (!config) {
+    LOG(ERROR) << "Failed to read config file for updating.";
+    return;
+  }
+  config->SetString(kOAuthRefreshTokenConfigPath, token);
+  if (!HostConfigToJsonFile(*config, config_file)) {
+    LOG(ERROR) << "Failed to write updated config file.";
+  }
+}
+
 }  // namespace remoting
diff --git a/remoting/host/daemon_process.h b/remoting/host/daemon_process.h
index 1d54ec1..d17db55 100644
--- a/remoting/host/daemon_process.h
+++ b/remoting/host/daemon_process.h
@@ -170,6 +170,16 @@
   void OnProcessStats(
       const protocol::AggregatedProcessResourceUsage& usage) override;
 
+  // Gets the location of the config file.
+  base::FilePath GetConfigPath();
+
+  // Updates the config file, replacing the current OAuth refresh token with the
+  // one provided.
+  void UpdateConfigRefreshToken(const std::string& token);
+  static void UpdateConfigRefreshTokenOnIoThread(
+      const base::FilePath& config_file,
+      const std::string& token);
+
   // Task runner on which public methods of this class must be called.
   scoped_refptr<AutoThreadTaskRunner> caller_task_runner_;
 
diff --git a/remoting/host/file_transfer/get_desktop_directory_win.cc b/remoting/host/file_transfer/get_desktop_directory_win.cc
index 9d7d0d65..5c8216e 100644
--- a/remoting/host/file_transfer/get_desktop_directory_win.cc
+++ b/remoting/host/file_transfer/get_desktop_directory_win.cc
@@ -4,9 +4,12 @@
 
 #include "remoting/host/file_transfer/get_desktop_directory.h"
 
-#include <Windows.h>
+#include <windows.h>
 #include <shlobj.h>
 
+#include "base/logging.h"
+#include "base/win/scoped_handle.h"
+
 namespace remoting {
 
 // We can't use PathService on Windows because it doesn't play nicely with
@@ -15,13 +18,28 @@
 // thread. As such, we have to call the relevant API directly and be explicit
 // about wanting impersonation handling.
 protocol::FileTransferResult<base::FilePath> GetDesktopDirectory() {
+  // SHGetFolderPath on Windows 7 doesn't seem to like the pseudo handle
+  // returned by GetCurrentThreadToken(), so call OpenThreadToken to get a real
+  // handle.
+  HANDLE user_token = nullptr;
+  if (!OpenThreadToken(GetCurrentThread(),
+                       TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE, TRUE,
+                       &user_token)) {
+    PLOG(ERROR) << "Failed to open thread token";
+    return protocol::MakeFileTransferError(
+        FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR,
+        GetLastError());
+  }
+
+  base::win::ScopedHandle scoped_user_token(user_token);
+
   wchar_t buffer[MAX_PATH];
   buffer[0] = 0;
   // While passing NULL for the third parameter would normally get the directory
   // for the current user, there are process-wide caches that can cause trouble
   // when impersonation is in play, so specify the token explicitly.
   HRESULT hr =
-      SHGetFolderPath(NULL, CSIDL_DESKTOPDIRECTORY, GetCurrentThreadToken(),
+      SHGetFolderPath(NULL, CSIDL_DESKTOPDIRECTORY, scoped_user_token.Get(),
                       SHGFP_TYPE_CURRENT, buffer);
   if (FAILED(hr)) {
     LOG(ERROR) << "Failed to get desktop directory: " << hr;
diff --git a/remoting/host/heartbeat_sender.cc b/remoting/host/heartbeat_sender.cc
index 65f40dfb..efb12a4 100644
--- a/remoting/host/heartbeat_sender.cc
+++ b/remoting/host/heartbeat_sender.cc
@@ -22,8 +22,11 @@
 #include "remoting/base/logging.h"
 #include "remoting/base/service_urls.h"
 #include "remoting/host/host_details.h"
+#include "remoting/host/server_log_entry_host.h"
 #include "remoting/proto/remoting/v1/directory_service.grpc.pb.h"
 #include "remoting/signaling/ftl_signal_strategy.h"
+#include "remoting/signaling/log_to_server.h"
+#include "remoting/signaling/server_log_entry.h"
 #include "remoting/signaling/signal_strategy.h"
 #include "remoting/signaling/signaling_address.h"
 #include "remoting/signaling/xmpp_signal_strategy.h"
@@ -116,15 +119,18 @@
     const std::string& host_id,
     MuxingSignalStrategy* signal_strategy,
     const scoped_refptr<const RsaKeyPair>& host_key_pair,
-    OAuthTokenGetter* oauth_token_getter)
+    OAuthTokenGetter* oauth_token_getter,
+    LogToServer* log_to_server)
     : on_heartbeat_successful_callback_(
           std::move(on_heartbeat_successful_callback)),
       on_unknown_host_id_error_(std::move(on_unknown_host_id_error)),
       host_id_(host_id),
       signal_strategy_(signal_strategy),
       host_key_pair_(host_key_pair),
-      client_(std::make_unique<HeartbeatClient>(oauth_token_getter)) {
+      client_(std::make_unique<HeartbeatClient>(oauth_token_getter)),
+      log_to_server_(log_to_server) {
   DCHECK(host_key_pair_.get());
+  DCHECK(log_to_server_);
 
   signal_strategy_->AddListener(this);
   OnSignalStrategyStateChange(signal_strategy_->GetState());
@@ -214,6 +220,11 @@
       CreateHeartbeatRequest(),
       base::BindOnce(&HeartbeatSender::OnResponse, base::Unretained(this)));
   ++sequence_id_;
+
+  // Send a heartbeat log
+  std::unique_ptr<ServerLogEntry> log_entry = MakeLogEntryForHeartbeat();
+  AddHostFieldsToLogEntry(log_entry.get());
+  log_to_server_->Log(*log_entry);
 }
 
 void HeartbeatSender::OnResponse(const grpc::Status& status,
diff --git a/remoting/host/heartbeat_sender.h b/remoting/host/heartbeat_sender.h
index bd736b4a..7ab8556 100644
--- a/remoting/host/heartbeat_sender.h
+++ b/remoting/host/heartbeat_sender.h
@@ -29,6 +29,7 @@
 
 namespace remoting {
 
+class LogToServer;
 class OAuthTokenGetter;
 class RsaKeyPair;
 
@@ -73,7 +74,8 @@
                   const std::string& host_id,
                   MuxingSignalStrategy* signal_strategy,
                   const scoped_refptr<const RsaKeyPair>& host_key_pair,
-                  OAuthTokenGetter* oauth_token_getter);
+                  OAuthTokenGetter* oauth_token_getter,
+                  LogToServer* log_to_server);
   ~HeartbeatSender() override;
 
   // Sets host offline reason for future heartbeat, and initiates sending a
@@ -121,6 +123,7 @@
   MuxingSignalStrategy* const signal_strategy_;
   scoped_refptr<const RsaKeyPair> host_key_pair_;
   std::unique_ptr<HeartbeatClient> client_;
+  LogToServer* const log_to_server_;
 
   base::OneShotTimer heartbeat_timer_;
 
diff --git a/remoting/host/heartbeat_sender_unittest.cc b/remoting/host/heartbeat_sender_unittest.cc
index 6089ab4..7b595096 100644
--- a/remoting/host/heartbeat_sender_unittest.cc
+++ b/remoting/host/heartbeat_sender_unittest.cc
@@ -8,6 +8,7 @@
 
 #include <memory>
 #include <utility>
+#include <vector>
 
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
@@ -22,6 +23,7 @@
 #include "remoting/base/test_rsa_key_pair.h"
 #include "remoting/proto/remoting/v1/directory_service.grpc.pb.h"
 #include "remoting/signaling/fake_signal_strategy.h"
+#include "remoting/signaling/log_to_server.h"
 #include "remoting/signaling/muxing_signal_strategy.h"
 #include "remoting/signaling/signaling_address.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -114,7 +116,7 @@
 
 }  // namespace
 
-class HeartbeatSenderTest : public testing::Test {
+class HeartbeatSenderTest : public testing::Test, public LogToServer {
  public:
   HeartbeatSenderTest() {
     auto ftl_signal_strategy =
@@ -137,7 +139,7 @@
     heartbeat_sender_ = std::make_unique<HeartbeatSender>(
         mock_heartbeat_successful_callback_.Get(),
         mock_unknown_host_id_error_callback_.Get(), kHostId,
-        muxing_signal_strategy_.get(), key_pair, &oauth_token_getter_);
+        muxing_signal_strategy_.get(), key_pair, &oauth_token_getter_, this);
     heartbeat_sender_->SetGrpcChannelForTest(
         test_server_.CreateInProcessChannel());
   }
@@ -155,7 +157,16 @@
   base::MockCallback<base::OnceClosure> mock_heartbeat_successful_callback_;
   base::MockCallback<base::OnceClosure> mock_unknown_host_id_error_callback_;
 
+  std::vector<ServerLogEntry> received_log_entries_;
+
  private:
+  // LogToServer interface.
+  void Log(const ServerLogEntry& entry) override {
+    received_log_entries_.push_back(entry);
+  }
+
+  ServerLogEntry::Mode mode() const override { return ServerLogEntry::ME2ME; }
+
   std::unique_ptr<MuxingSignalStrategy> muxing_signal_strategy_;
 
   // |heartbeat_sender_| must be deleted before |muxing_signal_strategy_|.
@@ -387,4 +398,25 @@
   run_loop.Run();
 }
 
+TEST_F(HeartbeatSenderTest, SendHeartbeatLogEntryOnHeartbeat) {
+  base::RunLoop run_loop;
+
+  EXPECT_CALL(*test_server_, Heartbeat(_, _, _))
+      .WillOnce(DoValidateHeartbeatAndRespondOk(/* ftl */ true,
+                                                /* xmpp */ true, 0));
+
+  EXPECT_CALL(mock_heartbeat_successful_callback_, Run()).WillOnce([&]() {
+    run_loop.Quit();
+  });
+
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindLambdaForTesting([&]() {
+        ftl_signal_strategy_->Connect();
+        xmpp_signal_strategy_->Connect();
+      }));
+  run_loop.Run();
+
+  ASSERT_EQ(1u, received_log_entries_.size());
+}
+
 }  // namespace remoting
diff --git a/remoting/host/host_config.cc b/remoting/host/host_config.cc
index da5afb08..17c04ee7 100644
--- a/remoting/host/host_config.cc
+++ b/remoting/host/host_config.cc
@@ -26,7 +26,7 @@
 const char kEnableVp9ConfigPath[] = "enable_vp9";
 const char kEnableH264ConfigPath[] = "enable_h264";
 const char kFrameRecorderBufferKbConfigPath[] = "frame-recorder-buffer-kb";
-const char kTokenUpgradedConfigPath[] = "token_upgraded";
+const char kIsFtlTokenConfigPath[] = "is_ftl_token";
 
 std::unique_ptr<base::DictionaryValue> HostConfigFromJson(
     const std::string& json) {
diff --git a/remoting/host/host_config.h b/remoting/host/host_config.h
index a9a1085..7e5883e 100644
--- a/remoting/host/host_config.h
+++ b/remoting/host/host_config.h
@@ -47,10 +47,10 @@
 extern const char kFrameRecorderBufferKbConfigPath[];
 // The GCD device ID of this host (if registered with GCD).
 extern const char kGcdDeviceIdConfigPath[];
-// Key which marks the config as already-upgraded. If present, the
+// Key which marks the config's token as up-to-date for FTL. If present, the
 // token-exchange will be skipped, which avoids querying over the network for
 // the current token's scopes.
-extern const char kTokenUpgradedConfigPath[];
+extern const char kIsFtlTokenConfigPath[];
 
 // Helpers for serializing/deserializing Host configuration dictonaries.
 std::unique_ptr<base::DictionaryValue> HostConfigFromJson(
diff --git a/remoting/host/host_config_upgrader.cc b/remoting/host/host_config_upgrader.cc
index 35fea3ee..03c2d99 100644
--- a/remoting/host/host_config_upgrader.cc
+++ b/remoting/host/host_config_upgrader.cc
@@ -95,7 +95,7 @@
 
   refresh_token_ = *refresh_token;
 
-  if (config_->FindKey(kTokenUpgradedConfigPath)) {
+  if (config_->FindKey(kIsFtlTokenConfigPath)) {
     HOST_LOG << "Host config is already upgraded.";
     return 0;
   }
@@ -141,7 +141,7 @@
   // Mark config as upgraded and write to disk (whether or not the token was
   // actually exchanged). The value is not important, only the presence of the
   // key is used.
-  config_->SetIntKey(kTokenUpgradedConfigPath, 1);
+  config_->SetIntKey(kIsFtlTokenConfigPath, 1);
 
   if (status == OfflineTokenExchanger::NO_EXCHANGE) {
     HOST_LOG << "No exchange needed, writing new config to mark as upgraded.";
diff --git a/remoting/host/host_status_logger.cc b/remoting/host/host_status_logger.cc
index 629b0a7..ca96732 100644
--- a/remoting/host/host_status_logger.cc
+++ b/remoting/host/host_status_logger.cc
@@ -14,11 +14,10 @@
 namespace remoting {
 
 HostStatusLogger::HostStatusLogger(scoped_refptr<HostStatusMonitor> monitor,
-                                   ServerLogEntry::Mode mode,
-                                   SignalStrategy* signal_strategy,
-                                   const std::string& directory_bot_jid)
-    : xmpp_log_to_server_(mode, signal_strategy, directory_bot_jid),
-      monitor_(monitor) {
+                                   LogToServer* log_to_server)
+    : log_to_server_(log_to_server), monitor_(monitor) {
+  DCHECK(log_to_server_);
+  DCHECK(monitor_);
   monitor_->AddStatusObserver(this);
 }
 
@@ -34,12 +33,12 @@
   std::unique_ptr<ServerLogEntry> entry(
       MakeLogEntryForSessionStateChange(connected));
   AddHostFieldsToLogEntry(entry.get());
-  entry->AddModeField(xmpp_log_to_server_.mode());
+  entry->AddModeField(log_to_server_->mode());
 
   if (connected && connection_route_type_.count(jid) > 0)
     AddConnectionTypeToLogEntry(entry.get(), connection_route_type_[jid]);
 
-  xmpp_log_to_server_.Log(*entry.get());
+  log_to_server_->Log(*entry.get());
 }
 
 void HostStatusLogger::OnClientConnected(const std::string& jid) {
@@ -64,8 +63,4 @@
   }
 }
 
-void HostStatusLogger::SetSignalingStateForTest(SignalStrategy::State state) {
-  xmpp_log_to_server_.OnSignalStrategyStateChange(state);
-}
-
 }  // namespace remoting
diff --git a/remoting/host/host_status_logger.h b/remoting/host/host_status_logger.h
index a737383..38dec37 100644
--- a/remoting/host/host_status_logger.h
+++ b/remoting/host/host_status_logger.h
@@ -12,7 +12,7 @@
 #include "base/sequence_checker.h"
 #include "remoting/host/host_status_observer.h"
 #include "remoting/protocol/transport.h"
-#include "remoting/signaling/xmpp_log_to_server.h"
+#include "remoting/signaling/log_to_server.h"
 
 namespace remoting {
 
@@ -24,9 +24,7 @@
 class HostStatusLogger : public HostStatusObserver {
  public:
   HostStatusLogger(scoped_refptr<HostStatusMonitor> monitor,
-                   ServerLogEntry::Mode mode,
-                   SignalStrategy* signal_strategy,
-                   const std::string& directory_bot_jid);
+                   LogToServer* log_to_server);
   ~HostStatusLogger() override;
 
   // Logs a session state change. Currently, this is either
@@ -40,11 +38,8 @@
                            const std::string& channel_name,
                            const protocol::TransportRoute& route) override;
 
-  // Allows test code to fake SignalStrategy state change events.
-  void SetSignalingStateForTest(SignalStrategy::State state);
-
  private:
-  XmppLogToServer xmpp_log_to_server_;
+  LogToServer* log_to_server_;
 
   scoped_refptr<HostStatusMonitor> monitor_;
 
diff --git a/remoting/host/host_status_logger_unittest.cc b/remoting/host/host_status_logger_unittest.cc
index d0dc3c5..5f3fe55 100644
--- a/remoting/host/host_status_logger_unittest.cc
+++ b/remoting/host/host_status_logger_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/run_loop.h"
 #include "remoting/host/host_status_monitor.h"
 #include "remoting/signaling/mock_signal_strategy.h"
+#include "remoting/signaling/xmpp_log_to_server.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gmock_mutant.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -129,15 +130,17 @@
         host_status_monitor_(new HostStatusMonitor()) {}
   void SetUp() override {
     EXPECT_CALL(signal_strategy_, AddListener(_));
-    host_status_logger_.reset(
-        new HostStatusLogger(host_status_monitor_, ServerLogEntry::ME2ME,
-                             &signal_strategy_, kTestBotJid));
+    log_to_server_ = std::make_unique<XmppLogToServer>(
+        ServerLogEntry::ME2ME, &signal_strategy_, kTestBotJid);
+    host_status_logger_ = std::make_unique<HostStatusLogger>(
+        host_status_monitor_, log_to_server_.get());
     EXPECT_CALL(signal_strategy_, RemoveListener(_));
   }
 
  protected:
   base::MessageLoop message_loop_;
   MockSignalStrategy signal_strategy_;
+  std::unique_ptr<XmppLogToServer> log_to_server_;
   std::unique_ptr<HostStatusLogger> host_status_logger_;
   scoped_refptr<HostStatusMonitor> host_status_monitor_;
 };
@@ -154,14 +157,13 @@
         .WillOnce(QuitRunLoop(&run_loop))
         .RetiresOnSaturation();
   }
-  host_status_logger_->SetSignalingStateForTest(SignalStrategy::CONNECTED);
+  log_to_server_->OnSignalStrategyStateChange(SignalStrategy::CONNECTED);
   protocol::TransportRoute route;
   route.type = protocol::TransportRoute::DIRECT;
   host_status_logger_->OnClientRouteChange(kClientJid1, "video", route);
   host_status_logger_->OnClientAuthenticated(kClientJid1);
   host_status_logger_->OnClientConnected(kClientJid1);
-  host_status_logger_->SetSignalingStateForTest(
-      SignalStrategy::DISCONNECTED);
+  log_to_server_->OnSignalStrategyStateChange(SignalStrategy::DISCONNECTED);
   run_loop.Run();
 }
 
@@ -183,8 +185,8 @@
         .WillOnce(QuitRunLoop(&run_loop))
         .RetiresOnSaturation();
   }
-  host_status_logger_->SetSignalingStateForTest(SignalStrategy::CONNECTED);
-  host_status_logger_->SetSignalingStateForTest(SignalStrategy::DISCONNECTED);
+  log_to_server_->OnSignalStrategyStateChange(SignalStrategy::CONNECTED);
+  log_to_server_->OnSignalStrategyStateChange(SignalStrategy::DISCONNECTED);
   run_loop.Run();
 }
 
@@ -212,8 +214,8 @@
         .WillOnce(QuitRunLoop(&run_loop))
         .RetiresOnSaturation();
   }
-  host_status_logger_->SetSignalingStateForTest(SignalStrategy::CONNECTED);
-  host_status_logger_->SetSignalingStateForTest(SignalStrategy::DISCONNECTED);
+  log_to_server_->OnSignalStrategyStateChange(SignalStrategy::CONNECTED);
+  log_to_server_->OnSignalStrategyStateChange(SignalStrategy::DISCONNECTED);
   run_loop.Run();
 }
 
@@ -236,7 +238,7 @@
         .WillOnce(QuitRunLoop(&run_loop))
         .RetiresOnSaturation();
   }
-  host_status_logger_->SetSignalingStateForTest(SignalStrategy::CONNECTED);
+  log_to_server_->OnSignalStrategyStateChange(SignalStrategy::CONNECTED);
   protocol::TransportRoute route1;
   route1.type = protocol::TransportRoute::DIRECT;
   host_status_logger_->OnClientRouteChange(kClientJid1, "video", route1);
@@ -248,7 +250,7 @@
   host_status_logger_->OnClientDisconnected(kClientJid1);
   host_status_logger_->OnClientAuthenticated(kClientJid2);
   host_status_logger_->OnClientConnected(kClientJid2);
-  host_status_logger_->SetSignalingStateForTest(SignalStrategy::DISCONNECTED);
+  log_to_server_->OnSignalStrategyStateChange(SignalStrategy::DISCONNECTED);
   run_loop.Run();
 }
 
diff --git a/remoting/host/input_injector_x11.cc b/remoting/host/input_injector_x11.cc
index ce33e31..55e5520 100644
--- a/remoting/host/input_injector_x11.cc
+++ b/remoting/host/input_injector_x11.cc
@@ -17,6 +17,7 @@
 #include "base/optional.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversion_utils.h"
+#include "base/time/time.h"
 #include "build/build_config.h"
 #include "remoting/base/logging.h"
 #include "remoting/host/clipboard.h"
@@ -44,6 +45,10 @@
 using protocol::MouseEvent;
 using protocol::TouchEvent;
 
+int sign(float num) {
+  return (num > 0) ? 1 : (num < 0) ? -1 : 0;
+}
+
 bool IsDomModifierKey(ui::DomCode dom_code) {
   return dom_code == ui::DomCode::CONTROL_LEFT ||
          dom_code == ui::DomCode::SHIFT_LEFT ||
@@ -59,6 +64,10 @@
 // From third_party/WebKit/Source/web/gtk/WebInputEventFactory.cpp .
 const float kWheelTicksPerPixel = 3.0f / 160.0f;
 
+// When the user is scrolling, generate at least one tick per time period.
+const base::TimeDelta kContinuousScrollTimeout =
+    base::TimeDelta::FromMilliseconds(500);
+
 // A class to generate events on X11.
 class InputInjectorX11 : public InputInjector {
  public:
@@ -138,6 +147,8 @@
     webrtc::DesktopVector latest_mouse_position_;
     float wheel_ticks_x_;
     float wheel_ticks_y_;
+    base::Time latest_tick_y_event_;
+    int latest_tick_y_direction_;
 
     // X11 graphics context.
     Display* display_;
@@ -211,10 +222,10 @@
       latest_mouse_position_(-1, -1),
       wheel_ticks_x_(0.0f),
       wheel_ticks_y_(0.0f),
+      latest_tick_y_direction_(0),
       display_(XOpenDisplay(nullptr)),
       root_window_(BadValue),
-      saved_auto_repeat_enabled_(false) {
-}
+      saved_auto_repeat_enabled_(false) {}
 
 bool InputInjectorX11::Core::Init() {
   CHECK(display_);
@@ -477,11 +488,8 @@
                          x11::CurrentTime);
   }
 
-  // Older client plugins always send scroll events in pixels, which
-  // must be accumulated host-side. Recent client plugins send both
-  // pixels and ticks with every scroll event, allowing the host to
-  // choose the best model on a per-platform basis. Since we can only
-  // inject ticks on Linux, use them if available.
+  // remotedesktop.google.com currently sends scroll events in pixels, which
+  // are accumulated host-side.
   int ticks_y = 0;
   if (event.has_wheel_ticks_y()) {
     ticks_y = event.wheel_ticks_y();
@@ -490,7 +498,44 @@
     ticks_y = static_cast<int>(wheel_ticks_y_);
     wheel_ticks_y_ -= ticks_y;
   }
+  if (ticks_y == 0 && event.has_wheel_delta_y()) {
+    // For the y-direction only (the common case), try to ensure that a tick is
+    // injected when the user would expect one, regardless of how many pixels
+    // the client sends per tick (even if it accelerates wheel events). To do
+    // this, generate a tick if one has not occurred recently in the current
+    // scroll direction. The accumulated pixels are not reset in this case.
+    //
+    // The effect when a physical mouse is used is as follows:
+    //
+    // Client sends slightly too few pixels per tick (e.g. Linux):
+    // * First scroll in either direction synthesizes a tick.
+    // * Subsequent scrolls in the same direction are unaffected (their
+    //   accumulated pixel deltas mostly meet the threshold for a regular
+    //   tick; occasionally a tick will be dropped if the user is scrolling
+    //   quickly).
+    //
+    // Client sends far too few pixels per tick, but applies acceleration
+    // (e.g. macOs, ChromeOS):
+    // * First scroll in either direction synthesizes a tick.
+    // * Slow scrolling will synthesize a tick a few times per second.
+    // * Fast scrolling is unaffected (acceleration means that enough pixels
+    //   are accumulated naturally).
+    //
+    // Client sends too many pixels per tick (e.g. Windows):
+    // * Scrolling is unaffected (most scroll events generate one tick; every
+    //   so often one generates two ticks).
+    //
+    // The effect when a trackpad is used is that the first tick in either
+    // direction occurs sooner; subsequent ticks are mostly unaffected.
+    const int current_tick_y_direction = sign(event.wheel_delta_y());
+    if ((base::Time::Now() - latest_tick_y_event_ > kContinuousScrollTimeout) ||
+        latest_tick_y_direction_ != current_tick_y_direction) {
+      ticks_y = current_tick_y_direction;
+    }
+  }
   if (ticks_y != 0) {
+    latest_tick_y_direction_ = sign(ticks_y);
+    latest_tick_y_event_ = base::Time::Now();
     InjectScrollWheelClicks(VerticalScrollWheelToX11ButtonNumber(ticks_y),
                             abs(ticks_y));
   }
diff --git a/remoting/host/installer/mac/PrivilegedHelperTools/org.chromium.chromoting.me2me.sh b/remoting/host/installer/mac/PrivilegedHelperTools/org.chromium.chromoting.me2me.sh
index 1d66189..e614448c 100755
--- a/remoting/host/installer/mac/PrivilegedHelperTools/org.chromium.chromoting.me2me.sh
+++ b/remoting/host/installer/mac/PrivilegedHelperTools/org.chromium.chromoting.me2me.sh
@@ -45,6 +45,12 @@
 }
 
 run_host() {
+  # Run the config-upgrade tool, but only if running as root, as normal users
+  # don't have permission to write the config file.
+  if [[ "$EUID" -eq 0 ]]; then
+    "$HOST_EXE" --upgrade-token --host-config="$CONFIG_FILE"
+  fi
+
   local host_failure_count=0
   local host_start_time=0
 
diff --git a/remoting/host/installer/mac/Scripts/remoting_postflight.sh b/remoting/host/installer/mac/Scripts/remoting_postflight.sh
index fc62ee5..9efb1cf 100755
--- a/remoting/host/installer/mac/Scripts/remoting_postflight.sh
+++ b/remoting/host/installer/mac/Scripts/remoting_postflight.sh
@@ -15,6 +15,8 @@
 PAM_CONFIG=/etc/pam.d/chrome-remote-desktop
 ENABLED_FILE="$HELPERTOOLS/$SERVICE_NAME.me2me_enabled"
 ENABLED_FILE_BACKUP="$ENABLED_FILE.backup"
+HOST_BUNDLE_NAME=@@HOST_BUNDLE_NAME@@
+HOST_EXE=$CONFIG_DIR/$HOST_BUNDLE_NAME/Contents/MacOS/remoting_me2me_host
 
 KSADMIN=/Library/Google/GoogleSoftwareUpdate/GoogleSoftwareUpdate.bundle/Contents/MacOS/ksadmin
 KSUPDATE=https://tools.google.com/service/update2
@@ -90,6 +92,9 @@
   logger PAM config has local edits. Not updating.
 fi
 
+# Run the config-upgrade tool.
+"$HOST_EXE" --upgrade-token --host-config="$CONFIG_FILE"
+
 # Load the service for each user for whom the service was unloaded in the
 # preflight script (this includes the root user, in case only the login screen
 # is being remoted and this is a Keystone-triggered update).
diff --git a/remoting/host/it2me/it2me_host.cc b/remoting/host/it2me/it2me_host.cc
index 959e407..46792c1 100644
--- a/remoting/host/it2me/it2me_host.cc
+++ b/remoting/host/it2me/it2me_host.cc
@@ -38,7 +38,7 @@
 #include "remoting/protocol/transport_context.h"
 #include "remoting/protocol/validating_authenticator.h"
 #include "remoting/signaling/jid_util.h"
-#include "remoting/signaling/server_log_entry.h"
+#include "remoting/signaling/log_to_server.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
 namespace remoting {
@@ -87,6 +87,7 @@
     std::unique_ptr<base::DictionaryValue> policies,
     std::unique_ptr<It2MeConfirmationDialogFactory> dialog_factory,
     std::unique_ptr<RegisterSupportHostRequest> register_request,
+    std::unique_ptr<LogToServer> log_to_server,
     base::WeakPtr<It2MeHost::Observer> observer,
     std::unique_ptr<SignalStrategy> signal_strategy,
     const std::string& username,
@@ -98,6 +99,7 @@
   observer_ = std::move(observer);
   confirmation_dialog_factory_ = std::move(dialog_factory);
   signal_strategy_ = std::move(signal_strategy);
+  log_to_server_ = std::move(log_to_server);
 
   OnPolicyUpdate(std::move(policies));
 
@@ -206,8 +208,7 @@
       host_context_->video_encode_task_runner(), options));
   host_->status_monitor()->AddStatusObserver(this);
   host_status_logger_.reset(
-      new HostStatusLogger(host_->status_monitor(), ServerLogEntry::IT2ME,
-                           signal_strategy_.get(), directory_bot_jid));
+      new HostStatusLogger(host_->status_monitor(), log_to_server_.get()));
 
   // Create event logger.
   host_event_logger_ =
@@ -486,6 +487,7 @@
 
   register_request_ = nullptr;
   host_status_logger_ = nullptr;
+  log_to_server_ = nullptr;
   signal_strategy_ = nullptr;
   host_event_logger_ = nullptr;
 
diff --git a/remoting/host/it2me/it2me_host.h b/remoting/host/it2me/it2me_host.h
index 420a0e1..c1cde09 100644
--- a/remoting/host/it2me/it2me_host.h
+++ b/remoting/host/it2me/it2me_host.h
@@ -33,6 +33,7 @@
 class DesktopEnvironmentFactory;
 class HostEventLogger;
 class HostStatusLogger;
+class LogToServer;
 class RegisterSupportHostRequest;
 class RsaKeyPair;
 
@@ -81,11 +82,15 @@
   // Methods called by the script object, from the plugin thread.
 
   // Creates It2Me host structures and starts the host.
+  //
+  // XmppLogToServer cannot be created and used in different sequence, so pass
+  // in a factory callback instead.
   virtual void Connect(
       std::unique_ptr<ChromotingHostContext> context,
       std::unique_ptr<base::DictionaryValue> policies,
       std::unique_ptr<It2MeConfirmationDialogFactory> dialog_factory,
       std::unique_ptr<RegisterSupportHostRequest> register_request,
+      std::unique_ptr<LogToServer> log_to_server,
       base::WeakPtr<It2MeHost::Observer> observer,
       std::unique_ptr<SignalStrategy> signal_strategy,
       const std::string& username,
@@ -167,6 +172,7 @@
   std::unique_ptr<ChromotingHostContext> host_context_;
   base::WeakPtr<It2MeHost::Observer> observer_;
   std::unique_ptr<SignalStrategy> signal_strategy_;
+  std::unique_ptr<LogToServer> log_to_server_;
 
   It2MeHostState state_ = kDisconnected;
 
diff --git a/remoting/host/it2me/it2me_host_unittest.cc b/remoting/host/it2me/it2me_host_unittest.cc
index 322bb2a..88f82de 100644
--- a/remoting/host/it2me/it2me_host_unittest.cc
+++ b/remoting/host/it2me/it2me_host_unittest.cc
@@ -29,6 +29,7 @@
 #include "remoting/protocol/errors.h"
 #include "remoting/protocol/transport_context.h"
 #include "remoting/signaling/fake_signal_strategy.h"
+#include "remoting/signaling/xmpp_log_to_server.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 #if defined(OS_LINUX)
@@ -294,11 +295,15 @@
   }
   auto register_host_request =
       std::make_unique<XmppRegisterSupportHostRequest>("fake_bot_jid");
-  it2me_host_->Connect(
-      host_context_->Copy(), policies_->CreateDeepCopy(),
-      std::move(dialog_factory), std::move(register_host_request),
-      weak_factory_.GetWeakPtr(), std::move(fake_signal_strategy),
-      kTestUserName, "fake_bot_jid", ice_config);
+  auto log_to_server = std::make_unique<XmppLogToServer>(
+      ServerLogEntry::IT2ME, fake_signal_strategy.get(), "fake_bot_jid",
+      host_context_->network_task_runner());
+  it2me_host_->Connect(host_context_->Copy(), policies_->CreateDeepCopy(),
+                       std::move(dialog_factory),
+                       std::move(register_host_request),
+                       std::move(log_to_server), weak_factory_.GetWeakPtr(),
+                       std::move(fake_signal_strategy), kTestUserName,
+                       "fake_bot_jid", ice_config);
 
   base::RunLoop run_loop;
   state_change_callback_ =
diff --git a/remoting/host/it2me/it2me_native_messaging_host.cc b/remoting/host/it2me/it2me_native_messaging_host.cc
index 6022a64..3357883 100644
--- a/remoting/host/it2me/it2me_native_messaging_host.cc
+++ b/remoting/host/it2me/it2me_native_messaging_host.cc
@@ -40,6 +40,9 @@
 #include "remoting/signaling/ftl_client_uuid_device_id_provider.h"
 #include "remoting/signaling/ftl_signal_strategy.h"
 #include "remoting/signaling/muxing_signal_strategy.h"
+#include "remoting/signaling/remoting_log_to_server.h"
+#include "remoting/signaling/server_log_entry.h"
+#include "remoting/signaling/xmpp_log_to_server.h"
 #include "remoting/signaling/xmpp_signal_strategy.h"
 
 #if defined(OS_WIN)
@@ -278,6 +281,7 @@
 
   std::unique_ptr<SignalStrategy> signal_strategy;
   std::unique_ptr<RegisterSupportHostRequest> register_host_request;
+  std::unique_ptr<LogToServer> log_to_server;
   if (use_signaling_proxy) {
     if (username.empty()) {
       // Allow unauthenticated users for the delegated signal strategy case.
@@ -286,6 +290,9 @@
     signal_strategy = CreateDelegatedSignalStrategy(message.get());
     register_host_request =
         std::make_unique<XmppRegisterSupportHostRequest>(directory_bot_jid);
+    log_to_server = std::make_unique<XmppLogToServer>(
+        ServerLogEntry::IT2ME, signal_strategy.get(), directory_bot_jid,
+        host_context_->network_task_runner());
   } else {
     std::string access_token = ExtractAccessToken(message.get());
     signal_strategy =
@@ -294,6 +301,9 @@
         std::make_unique<RemotingRegisterSupportHostRequest>(
             std::make_unique<PassthroguhOAuthTokenGetter>(username,
                                                           access_token));
+    log_to_server = std::make_unique<RemotingLogToServer>(
+        ServerLogEntry::IT2ME,
+        std::make_unique<PassthroguhOAuthTokenGetter>(username, access_token));
   }
   if (!signal_strategy) {
     SendErrorAndExit(std::move(response), ErrorCode::INCOMPATIBLE_PROTOCOL);
@@ -332,11 +342,11 @@
   it2me_host_->set_enable_dialogs(!no_dialogs);
   it2me_host_->set_terminate_upon_input(terminate_upon_input);
 #endif
-  it2me_host_->Connect(host_context_->Copy(), std::move(policies),
-                       std::make_unique<It2MeConfirmationDialogFactory>(),
-                       std::move(register_host_request), weak_ptr_,
-                       std::move(signal_strategy), username, directory_bot_jid,
-                       ice_config);
+  it2me_host_->Connect(
+      host_context_->Copy(), std::move(policies),
+      std::make_unique<It2MeConfirmationDialogFactory>(),
+      std::move(register_host_request), std::move(log_to_server), weak_ptr_,
+      std::move(signal_strategy), username, directory_bot_jid, ice_config);
 
   SendMessageToClient(std::move(response));
 }
diff --git a/remoting/host/it2me/it2me_native_messaging_host_unittest.cc b/remoting/host/it2me/it2me_native_messaging_host_unittest.cc
index fce9f42..f9911907 100644
--- a/remoting/host/it2me/it2me_native_messaging_host_unittest.cc
+++ b/remoting/host/it2me/it2me_native_messaging_host_unittest.cc
@@ -35,6 +35,7 @@
 #include "remoting/host/setup/test_util.h"
 #include "remoting/protocol/errors.h"
 #include "remoting/protocol/ice_config.h"
+#include "remoting/signaling/log_to_server.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace remoting {
@@ -119,6 +120,7 @@
                std::unique_ptr<base::DictionaryValue> policies,
                std::unique_ptr<It2MeConfirmationDialogFactory> dialog_factory,
                std::unique_ptr<RegisterSupportHostRequest> register_request,
+               std::unique_ptr<LogToServer> log_to_server,
                base::WeakPtr<It2MeHost::Observer> observer,
                std::unique_ptr<SignalStrategy> signal_strategy,
                const std::string& username,
@@ -139,6 +141,7 @@
     std::unique_ptr<base::DictionaryValue> policies,
     std::unique_ptr<It2MeConfirmationDialogFactory> dialog_factory,
     std::unique_ptr<RegisterSupportHostRequest> register_request,
+    std::unique_ptr<LogToServer> log_to_server,
     base::WeakPtr<It2MeHost::Observer> observer,
     std::unique_ptr<SignalStrategy> signal_strategy,
     const std::string& username,
diff --git a/remoting/host/remoting_me2me_host.cc b/remoting/host/remoting_me2me_host.cc
index 0615a41..27d8227 100644
--- a/remoting/host/remoting_me2me_host.cc
+++ b/remoting/host/remoting_me2me_host.cc
@@ -104,6 +104,8 @@
 #include "remoting/signaling/ftl_signal_strategy.h"
 #include "remoting/signaling/muxing_signal_strategy.h"
 #include "remoting/signaling/push_notification_subscriber.h"
+#include "remoting/signaling/remoting_log_to_server.h"
+#include "remoting/signaling/xmpp_log_to_server.h"
 #include "remoting/signaling/xmpp_signal_strategy.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "third_party/webrtc/api/scoped_refptr.h"
@@ -346,6 +348,8 @@
   void GoOffline(const std::string& host_offline_reason);
   void OnHostOfflineReasonAck(bool success);
 
+  void UpdateConfigRefreshToken(const std::string& token);
+
 #if defined(OS_WIN)
   // Initializes the pairing registry on Windows. This should be invoked on the
   // network thread.
@@ -421,6 +425,9 @@
   // |signaling_connector_|.
   std::unique_ptr<OAuthTokenGetterImpl> oauth_token_getter_;
 
+  // Must outlive |heartbeat_sender_| and |host_status_logger_|.
+  std::unique_ptr<LogToServer> log_to_server_;
+
   bool enable_ftl_signaling_ = false;
 
   // Signal strategies must outlive |signaling_connector_|, |gcd_subscriber_|,
@@ -1469,14 +1476,22 @@
       std::make_unique<OAuthTokenGetter::OAuthAuthorizationCredentials>(
           xmpp_server_config_.username, oauth_refresh_token_,
           use_service_account_);
+  // Unretained is sound because we own the OAuthTokenGetterImpl, and the
+  // callback will never be invoked once it is destroyed.
   oauth_token_getter_ = std::make_unique<OAuthTokenGetterImpl>(
-      std::move(oauth_credentials), context_->url_loader_factory(), false);
+      std::move(oauth_credentials),
+      base::BindRepeating(&HostProcess::UpdateConfigRefreshToken,
+                          base::Unretained(this)),
+      context_->url_loader_factory(), false);
   xmpp_signaling_connector_ = std::make_unique<SignalingConnector>(
       xmpp_signal_strategy_, std::move(dns_blackhole_checker),
       oauth_token_getter_.get(),
       base::BindRepeating(&HostProcess::OnAuthFailed, base::Unretained(this)));
 
   if (enable_ftl_signaling_) {
+    log_to_server_ = std::make_unique<RemotingLogToServer>(
+        ServerLogEntry::ME2ME, std::make_unique<OAuthTokenGetterProxy>(
+                                   oauth_token_getter_->GetWeakPtr()));
     auto ftl_signal_strategy = std::make_unique<FtlSignalStrategy>(
         std::make_unique<OAuthTokenGetterProxy>(
             oauth_token_getter_->GetWeakPtr()),
@@ -1493,7 +1508,7 @@
         base::BindOnce(&HostProcess::OnUnknownHostIdError,
                        base::Unretained(this)),
         host_id_, muxing_signal_strategy.get(), key_pair_,
-        oauth_token_getter_.get());
+        oauth_token_getter_.get(), log_to_server_.get());
     signal_strategy_ = std::move(muxing_signal_strategy);
   } else {
     xmpp_heartbeat_sender_.reset(new XmppHeartbeatSender(
@@ -1503,6 +1518,8 @@
                             base::Unretained(this)),
         host_id_, xmpp_signal_strategy_, key_pair_, directory_bot_jid_));
     signal_strategy_ = std::move(xmpp_signal_strategy);
+    log_to_server_ = std::make_unique<XmppLogToServer>(
+        ServerLogEntry::ME2ME, signal_strategy_.get(), directory_bot_jid_);
   }
 
 #if defined(USE_GCD)
@@ -1611,9 +1628,8 @@
   host_change_notification_listener_.reset(new HostChangeNotificationListener(
       this, host_id_, xmpp_signal_strategy_, directory_bot_jid_));
 
-  host_status_logger_.reset(
-      new HostStatusLogger(host_->status_monitor(), ServerLogEntry::ME2ME,
-                           xmpp_signal_strategy_, directory_bot_jid_));
+  host_status_logger_ = std::make_unique<HostStatusLogger>(
+      host_->status_monitor(), log_to_server_.get());
 
   power_save_blocker_.reset(new HostPowerSaveBlocker(
       host_->status_monitor(), context_->ui_task_runner(),
@@ -1769,6 +1785,13 @@
   }
 }
 
+void HostProcess::UpdateConfigRefreshToken(const std::string& token) {
+#if defined(REMOTING_MULTI_PROCESS)
+  daemon_channel_->Send(
+      new ChromotingNetworkDaemonMsg_UpdateConfigRefreshToken(token));
+#endif
+}
+
 void HostProcess::OnCrash(const std::string& function_name,
                           const std::string& file_name,
                           const int& line_number) {
diff --git a/remoting/ios/facade/remoting_oauth_authentication.mm b/remoting/ios/facade/remoting_oauth_authentication.mm
index ac6b575..1c378d4 100644
--- a/remoting/ios/facade/remoting_oauth_authentication.mm
+++ b/remoting/ios/facade/remoting_oauth_authentication.mm
@@ -12,6 +12,7 @@
 #import <Security/Security.h>
 
 #import "base/bind.h"
+#import "base/bind_helpers.h"
 #import "ios/third_party/material_components_ios/src/components/Snackbar/src/MaterialSnackbar.h"
 #import "remoting/ios/facade/ios_client_runtime_delegate.h"
 #import "remoting/ios/facade/remoting_service.h"
@@ -67,6 +68,7 @@
   std::unique_ptr<remoting::OAuthTokenGetter> oauth_tokenGetter(
       new remoting::OAuthTokenGetterImpl(
           std::move(oauth_credentials),
+          base::DoNothing(),
           RemotingService.instance.runtime->url_loader_factory(),
           /*auto_refresh=*/true));
   return oauth_tokenGetter;
diff --git a/remoting/proto/remoting/v1/BUILD.gn b/remoting/proto/remoting/v1/BUILD.gn
index 31391fe..6b1b24f 100644
--- a/remoting/proto/remoting/v1/BUILD.gn
+++ b/remoting/proto/remoting/v1/BUILD.gn
@@ -66,10 +66,18 @@
   ]
 }
 
-cc_grpc_library("telemetry_grpc_library") {
+proto_library("telemetry_messages") {
   sources = [
     "generic_log_entry.proto",
     "telemetry_messages.proto",
+  ]
+}
+
+cc_grpc_library("telemetry_grpc_library") {
+  sources = [
     "telemetry_service.proto",
   ]
+  deps = [
+    ":telemetry_messages",
+  ]
 }
diff --git a/remoting/signaling/BUILD.gn b/remoting/signaling/BUILD.gn
index 6f6ff25..4760a34 100644
--- a/remoting/signaling/BUILD.gn
+++ b/remoting/signaling/BUILD.gn
@@ -34,6 +34,8 @@
     "push_notification_subscriber.cc",
     "push_notification_subscriber.h",
     "registration_manager.h",
+    "remoting_log_to_server.cc",
+    "remoting_log_to_server.h",
     "server_log_entry.cc",
     "server_log_entry.h",
     "signal_strategy.h",
@@ -58,6 +60,7 @@
   public_deps = [
     "//remoting/proto",
     "//remoting/proto/ftl/v1:ftl_grpc_library",
+    "//remoting/proto/remoting/v1:telemetry_grpc_library",
     "//third_party/libjingle_xmpp",
     "//third_party/webrtc_overrides",
   ]
@@ -70,6 +73,7 @@
     "//net",
     "//remoting/base",
     "//remoting/base/grpc_support",
+    "//remoting/proto/remoting/v1:telemetry_messages",
     "//third_party/grpc:grpcpp",
   ]
 
@@ -89,6 +93,8 @@
       "ftl_registration_manager.h",
       "ftl_signal_strategy.cc",
       "ftl_signal_strategy.h",
+      "remoting_log_to_server.cc",
+      "remoting_log_to_server.h",
       "server_log_entry.cc",
       "xmpp_log_to_server.cc",
       "xmpp_signal_strategy.cc",
@@ -98,7 +104,10 @@
       "//remoting/base/grpc_support",
       "//third_party/grpc:grpcpp",
     ]
-    public_deps -= [ "//remoting/proto/ftl/v1:ftl_grpc_library" ]
+    public_deps -= [
+      "//remoting/proto/ftl/v1:ftl_grpc_library",
+      "//remoting/proto/remoting/v1:telemetry_grpc_library",
+    ]
   }
 }
 
@@ -130,6 +139,7 @@
     "message_tracker_unittest.cc",
     "muxing_signal_strategy_unittest.cc",
     "push_notification_subscriber_unittest.cc",
+    "remoting_log_to_server_unittest.cc",
     "server_log_entry_unittest.cc",
     "server_log_entry_unittest.h",
     "signaling_address_unittest.cc",
diff --git a/remoting/signaling/log_to_server.h b/remoting/signaling/log_to_server.h
new file mode 100644
index 0000000..042ae0e
--- /dev/null
+++ b/remoting/signaling/log_to_server.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 REMOTING_SIGNALING_LOG_TO_SERVER_H_
+#define REMOTING_SIGNALING_LOG_TO_SERVER_H_
+
+#include "remoting/signaling/server_log_entry.h"
+
+namespace remoting {
+
+// LogToServer sends log entries to a server.
+// The contents of the log entries are described in server_log_entry.cc.
+// They do not contain any personally identifiable information.
+class LogToServer {
+ public:
+  virtual ~LogToServer() = default;
+
+  virtual void Log(const ServerLogEntry& entry) = 0;
+  virtual ServerLogEntry::Mode mode() const = 0;
+
+ protected:
+  LogToServer() = default;
+};
+
+}  // namespace remoting
+
+#endif  // REMOTING_SIGNALING_LOG_TO_SERVER_H_
diff --git a/remoting/signaling/remoting_log_to_server.cc b/remoting/signaling/remoting_log_to_server.cc
new file mode 100644
index 0000000..e0e76abd
--- /dev/null
+++ b/remoting/signaling/remoting_log_to_server.cc
@@ -0,0 +1,167 @@
+// 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 "remoting/signaling/remoting_log_to_server.h"
+
+#include <sstream>
+
+#include "base/bind.h"
+#include "remoting/base/grpc_support/grpc_async_unary_request.h"
+#include "remoting/base/grpc_support/grpc_authenticated_executor.h"
+#include "remoting/base/grpc_support/grpc_channel.h"
+#include "remoting/base/service_urls.h"
+#include "remoting/proto/remoting/v1/telemetry_service.grpc.pb.h"
+#include "third_party/grpc/src/include/grpcpp/support/status.h"
+
+namespace remoting {
+
+namespace {
+
+const net::BackoffEntry::Policy kBackoffPolicy = {
+    // Number of initial errors (in sequence) to ignore before applying
+    // exponential back-off rules.
+    0,
+
+    // Initial delay for exponential back-off in ms.
+    1000,
+
+    // Factor by which the waiting time will be multiplied.
+    2,
+
+    // Fuzzing percentage. ex: 10% will spread requests randomly
+    // between 90%-100% of the calculated time.
+    0.5,
+
+    // Maximum amount of time we are willing to delay our request in ms.
+    60000,
+
+    // Time to keep an entry from being discarded even when it
+    // has no significant state, -1 to never discard.
+    -1,
+
+    // Starts with initial delay.
+    false,
+};
+
+using CreateLogEntryResponseCallback =
+    base::OnceCallback<void(const grpc::Status&,
+                            const apis::v1::CreateLogEntryResponse&)>;
+
+class TelemetryClient {
+ public:
+  explicit TelemetryClient(OAuthTokenGetter* token_getter);
+  ~TelemetryClient();
+
+  void CreateLogEntry(const apis::v1::CreateLogEntryRequest& request,
+                      CreateLogEntryResponseCallback callback);
+
+ private:
+  using TelemetryService = apis::v1::RemotingTelemetryService;
+  GrpcAuthenticatedExecutor executor_;
+  std::unique_ptr<TelemetryService::Stub> stub_;
+  DISALLOW_COPY_AND_ASSIGN(TelemetryClient);
+};
+
+TelemetryClient::TelemetryClient(OAuthTokenGetter* token_getter)
+    : executor_(token_getter) {
+  stub_ = TelemetryService::NewStub(CreateSslChannelForEndpoint(
+      ServiceUrls::GetInstance()->remoting_server_endpoint()));
+}
+
+TelemetryClient::~TelemetryClient() = default;
+
+void TelemetryClient::CreateLogEntry(
+    const apis::v1::CreateLogEntryRequest& request,
+    CreateLogEntryResponseCallback callback) {
+  executor_.ExecuteRpc(CreateGrpcAsyncUnaryRequest(
+      base::BindOnce(&TelemetryService::Stub::AsyncCreateLogEntry,
+                     base::Unretained(stub_.get())),
+      request, std::move(callback)));
+}
+
+}  // namespace
+
+RemotingLogToServer::RemotingLogToServer(
+    ServerLogEntry::Mode mode,
+    std::unique_ptr<OAuthTokenGetter> token_getter)
+    : mode_(mode),
+      token_getter_(std::move(token_getter)),
+      backoff_(&kBackoffPolicy),
+      create_log_entry_(base::BindRepeating(
+          &TelemetryClient::CreateLogEntry,
+          std::make_unique<TelemetryClient>(token_getter_.get()))) {
+  DETACH_FROM_SEQUENCE(sequence_checker_);
+}
+
+RemotingLogToServer::~RemotingLogToServer() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+void RemotingLogToServer::Log(const ServerLogEntry& entry) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  apis::v1::CreateLogEntryRequest request;
+  *request.mutable_payload()->mutable_entry() = entry.ToGenericLogEntry();
+  SendLogRequestWithBackoff(request, kMaxSendLogAttempts);
+}
+
+void RemotingLogToServer::SendLogRequest(
+    const apis::v1::CreateLogEntryRequest& request,
+    int attempts_left) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (VLOG_IS_ON(1)) {
+    std::ostringstream log_stream;
+    log_stream << "Sending log entry with " << attempts_left
+               << " attempts left: \n";
+    for (const auto& field : request.payload().entry().field()) {
+      log_stream << field.key() << ": " << field.value() << "\n";
+    }
+    log_stream << "=========================================================";
+    VLOG(1) << log_stream.str();
+  }
+  create_log_entry_.Run(
+      request,
+      base::BindOnce(&RemotingLogToServer::OnSendLogRequestResult,
+                     base::Unretained(this), request, attempts_left - 1));
+}
+
+void RemotingLogToServer::SendLogRequestWithBackoff(
+    const apis::v1::CreateLogEntryRequest& request,
+    int attempts_left) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  auto time_until_release = backoff_.GetTimeUntilRelease();
+  VLOG(1) << "Scheduling request in " << time_until_release
+          << ", attempts left: " << attempts_left;
+  backoff_timer_.Start(
+      FROM_HERE, time_until_release,
+      base::BindOnce(&RemotingLogToServer::SendLogRequest,
+                     base::Unretained(this), request, attempts_left));
+}
+
+void RemotingLogToServer::OnSendLogRequestResult(
+    const apis::v1::CreateLogEntryRequest& request,
+    int attempts_left,
+    const grpc::Status& status,
+    const apis::v1::CreateLogEntryResponse& response) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (status.ok()) {
+    VLOG(1) << "One log has been successfully sent.";
+    backoff_.InformOfRequest(true);
+    return;
+  }
+  LOG(WARNING) << "Failed to send one log."
+               << " Error: " << status.error_code()
+               << " Message: " << status.error_message();
+  backoff_.InformOfRequest(false);
+  if (attempts_left <= 0) {
+    LOG(WARNING) << "Exceeded maximum retry attempts. Dropping it...";
+    return;
+  }
+  SendLogRequestWithBackoff(request, attempts_left);
+}
+
+ServerLogEntry::Mode RemotingLogToServer::mode() const {
+  return mode_;
+}
+
+}  // namespace remoting
diff --git a/remoting/signaling/remoting_log_to_server.h b/remoting/signaling/remoting_log_to_server.h
new file mode 100644
index 0000000..e3b4ebbc
--- /dev/null
+++ b/remoting/signaling/remoting_log_to_server.h
@@ -0,0 +1,80 @@
+// 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 REMOTING_SIGNALING_REMOTING_LOG_TO_SERVER_H_
+#define REMOTING_SIGNALING_REMOTING_LOG_TO_SERVER_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/sequence_checker.h"
+#include "base/timer/timer.h"
+#include "net/base/backoff_entry.h"
+#include "remoting/signaling/log_to_server.h"
+
+namespace grpc {
+class Status;
+}  // namespace grpc
+
+namespace remoting {
+
+namespace apis {
+namespace v1 {
+class CreateLogEntryRequest;
+class CreateLogEntryResponse;
+}  // namespace v1
+}  // namespace apis
+
+class OAuthTokenGetter;
+
+// RemotingLogToServer sends log entries to to the remoting telemetry server.
+class RemotingLogToServer : public LogToServer {
+ public:
+  RemotingLogToServer(ServerLogEntry::Mode mode,
+                      std::unique_ptr<OAuthTokenGetter> token_getter);
+  ~RemotingLogToServer() override;
+
+  // LogToServer interface.
+  void Log(const ServerLogEntry& entry) override;
+  ServerLogEntry::Mode mode() const override;
+
+ private:
+  static constexpr int kMaxSendLogAttempts = 5;
+
+  using CreateLogEntryResponseCallback =
+      base::OnceCallback<void(const grpc::Status&,
+                              const apis::v1::CreateLogEntryResponse&)>;
+  using CreateLogEntryCallback =
+      base::RepeatingCallback<void(const apis::v1::CreateLogEntryRequest&,
+                                   CreateLogEntryResponseCallback callback)>;
+
+  friend class RemotingLogToServerTest;
+
+  void SendLogRequest(const apis::v1::CreateLogEntryRequest& request,
+                      int attempts_left);
+  void SendLogRequestWithBackoff(const apis::v1::CreateLogEntryRequest& request,
+                                 int attempts_left);
+  void OnSendLogRequestResult(const apis::v1::CreateLogEntryRequest& request,
+                              int attempts_left,
+                              const grpc::Status& status,
+                              const apis::v1::CreateLogEntryResponse& response);
+
+  ServerLogEntry::Mode mode_;
+  std::unique_ptr<OAuthTokenGetter> token_getter_;
+  net::BackoffEntry backoff_;
+  base::OneShotTimer backoff_timer_;
+
+  // Callback used to send the log entry to the server. Replaceable for
+  // unittest.
+  CreateLogEntryCallback create_log_entry_;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+
+  DISALLOW_COPY_AND_ASSIGN(RemotingLogToServer);
+};
+
+}  // namespace remoting
+
+#endif  // REMOTING_SIGNALING_REMOTING_LOG_TO_SERVER_H_
diff --git a/remoting/signaling/remoting_log_to_server_unittest.cc b/remoting/signaling/remoting_log_to_server_unittest.cc
new file mode 100644
index 0000000..ebc30d5
--- /dev/null
+++ b/remoting/signaling/remoting_log_to_server_unittest.cc
@@ -0,0 +1,160 @@
+// 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 "remoting/signaling/remoting_log_to_server.h"
+
+#include "base/test/mock_callback.h"
+#include "base/test/scoped_task_environment.h"
+#include "remoting/base/fake_oauth_token_getter.h"
+#include "remoting/proto/remoting/v1/telemetry_service.grpc.pb.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace remoting {
+
+namespace {
+
+using testing::_;
+
+}  // namespace
+
+class RemotingLogToServerTest : public testing::Test {
+ public:
+  RemotingLogToServerTest() {
+    EXPECT_EQ(ServerLogEntry::ME2ME, log_to_server_.mode());
+    log_to_server_.create_log_entry_ = mock_create_log_entry_.Get();
+  }
+
+  ~RemotingLogToServerTest() override {
+    scoped_task_environment_.FastForwardUntilNoTasksRemain();
+  }
+
+ protected:
+  const net::BackoffEntry& GetBackoffEntry() const {
+    return log_to_server_.backoff_;
+  }
+
+  int GetMaxSendLogAttempts() const {
+    return log_to_server_.kMaxSendLogAttempts;
+  }
+
+  using CreateLogEntryResponseCallback =
+      RemotingLogToServer::CreateLogEntryResponseCallback;
+
+  base::test::ScopedTaskEnvironment scoped_task_environment_{
+      base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME,
+      base::test::ScopedTaskEnvironment::NowSource::MAIN_THREAD_MOCK_TIME};
+
+  base::MockCallback<RemotingLogToServer::CreateLogEntryCallback>
+      mock_create_log_entry_;
+
+  RemotingLogToServer log_to_server_{
+      ServerLogEntry::ME2ME,
+      std::make_unique<FakeOAuthTokenGetter>(OAuthTokenGetter::SUCCESS,
+                                             "fake_email",
+                                             "fake_access_token")};
+};
+
+TEST_F(RemotingLogToServerTest, SuccessfullySendOneLog) {
+  EXPECT_CALL(mock_create_log_entry_, Run(_, _))
+      .WillOnce([&](const apis::v1::CreateLogEntryRequest& request,
+                    CreateLogEntryResponseCallback callback) {
+        ASSERT_EQ(1, request.payload().entry().field_size());
+        ASSERT_EQ("test-key", request.payload().entry().field(0).key());
+        ASSERT_EQ("test-value", request.payload().entry().field(0).value());
+        std::move(callback).Run(grpc::Status::OK, {});
+      });
+
+  ServerLogEntry entry;
+  entry.Set("test-key", "test-value");
+  log_to_server_.Log(entry);
+
+  scoped_task_environment_.FastForwardUntilNoTasksRemain();
+
+  ASSERT_EQ(0, GetBackoffEntry().failure_count());
+}
+
+TEST_F(RemotingLogToServerTest, FailedToSend_RetryWithBackoff) {
+  EXPECT_CALL(mock_create_log_entry_, Run(_, _))
+      .Times(GetMaxSendLogAttempts())
+      .WillRepeatedly([&](const apis::v1::CreateLogEntryRequest& request,
+                          CreateLogEntryResponseCallback callback) {
+        ASSERT_EQ(1, request.payload().entry().field_size());
+        ASSERT_EQ("test-key", request.payload().entry().field(0).key());
+        ASSERT_EQ("test-value", request.payload().entry().field(0).value());
+        std::move(callback).Run(
+            grpc::Status(grpc::StatusCode::UNAVAILABLE, "unavailable"), {});
+      });
+
+  ServerLogEntry entry;
+  entry.Set("test-key", "test-value");
+  log_to_server_.Log(entry);
+
+  for (int i = 1; i <= GetMaxSendLogAttempts(); i++) {
+    scoped_task_environment_.FastForwardBy(
+        GetBackoffEntry().GetTimeUntilRelease());
+    ASSERT_EQ(i, GetBackoffEntry().failure_count());
+  }
+}
+
+TEST_F(RemotingLogToServerTest, FailedToSendTwoLogs_RetryThenSucceeds) {
+  CreateLogEntryResponseCallback response_callback_1;
+  CreateLogEntryResponseCallback response_callback_2;
+  EXPECT_CALL(mock_create_log_entry_, Run(_, _))
+      .WillOnce([&](const apis::v1::CreateLogEntryRequest& request,
+                    CreateLogEntryResponseCallback callback) {
+        ASSERT_EQ(1, request.payload().entry().field_size());
+        ASSERT_EQ("test-key-1", request.payload().entry().field(0).key());
+        ASSERT_EQ("test-value-1", request.payload().entry().field(0).value());
+        response_callback_1 = std::move(callback);
+      })
+      .WillOnce([&](const apis::v1::CreateLogEntryRequest& request,
+                    CreateLogEntryResponseCallback callback) {
+        ASSERT_EQ(1, request.payload().entry().field_size());
+        ASSERT_EQ("test-key-2", request.payload().entry().field(0).key());
+        ASSERT_EQ("test-value-2", request.payload().entry().field(0).value());
+        response_callback_2 = std::move(callback);
+      })
+      .WillOnce([&](const apis::v1::CreateLogEntryRequest& request,
+                    CreateLogEntryResponseCallback callback) {
+        ASSERT_EQ(1, request.payload().entry().field_size());
+        ASSERT_EQ("test-key-1", request.payload().entry().field(0).key());
+        ASSERT_EQ("test-value-1", request.payload().entry().field(0).value());
+        response_callback_1 = std::move(callback);
+      })
+      .WillOnce([&](const apis::v1::CreateLogEntryRequest& request,
+                    CreateLogEntryResponseCallback callback) {
+        ASSERT_EQ(1, request.payload().entry().field_size());
+        ASSERT_EQ("test-key-2", request.payload().entry().field(0).key());
+        ASSERT_EQ("test-value-2", request.payload().entry().field(0).value());
+        response_callback_2 = std::move(callback);
+      });
+
+  ServerLogEntry entry_1;
+  entry_1.Set("test-key-1", "test-value-1");
+  log_to_server_.Log(entry_1);
+  scoped_task_environment_.FastForwardUntilNoTasksRemain();
+
+  ServerLogEntry entry_2;
+  entry_2.Set("test-key-2", "test-value-2");
+  log_to_server_.Log(entry_2);
+  scoped_task_environment_.FastForwardUntilNoTasksRemain();
+
+  ASSERT_EQ(0, GetBackoffEntry().failure_count());
+
+  std::move(response_callback_1)
+      .Run(grpc::Status(grpc::StatusCode::UNAVAILABLE, "unavailable"), {});
+  scoped_task_environment_.FastForwardUntilNoTasksRemain();
+  std::move(response_callback_2)
+      .Run(grpc::Status(grpc::StatusCode::UNAVAILABLE, "unavailable"), {});
+  scoped_task_environment_.FastForwardUntilNoTasksRemain();
+  ASSERT_EQ(2, GetBackoffEntry().failure_count());
+
+  std::move(response_callback_1).Run(grpc::Status::OK, {});
+  std::move(response_callback_2).Run(grpc::Status::OK, {});
+  scoped_task_environment_.FastForwardUntilNoTasksRemain();
+  ASSERT_EQ(0, GetBackoffEntry().failure_count());
+}
+
+}  // namespace remoting
diff --git a/remoting/signaling/server_log_entry.cc b/remoting/signaling/server_log_entry.cc
index 120e4809..df387dc 100644
--- a/remoting/signaling/server_log_entry.cc
+++ b/remoting/signaling/server_log_entry.cc
@@ -85,4 +85,14 @@
   return stanza;
 }
 
+apis::v1::GenericLogEntry ServerLogEntry::ToGenericLogEntry() const {
+  apis::v1::GenericLogEntry log_entry;
+  for (auto pair : values_map_) {
+    auto* field = log_entry.add_field();
+    field->set_key(pair.first);
+    field->set_value(pair.second);
+  }
+  return log_entry;
+}
+
 }  // namespace remoting
diff --git a/remoting/signaling/server_log_entry.h b/remoting/signaling/server_log_entry.h
index 65d9d51..6ae3a98 100644
--- a/remoting/signaling/server_log_entry.h
+++ b/remoting/signaling/server_log_entry.h
@@ -9,6 +9,7 @@
 #include <memory>
 #include <string>
 
+#include "remoting/proto/remoting/v1/generic_log_entry.pb.h"
 
 namespace jingle_xmpp {
 class XmlElement;
@@ -54,6 +55,8 @@
   // Converts this object to an XML stanza.
   std::unique_ptr<jingle_xmpp::XmlElement> ToStanza() const;
 
+  apis::v1::GenericLogEntry ToGenericLogEntry() const;
+
  private:
   typedef std::map<std::string, std::string> ValuesMap;
 
diff --git a/remoting/signaling/xmpp_log_to_server.cc b/remoting/signaling/xmpp_log_to_server.cc
index d38f7a4..380ce25 100644
--- a/remoting/signaling/xmpp_log_to_server.cc
+++ b/remoting/signaling/xmpp_log_to_server.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "base/bind.h"
 #include "remoting/base/constants.h"
 #include "remoting/signaling/iq_sender.h"
 #include "remoting/signaling/signal_strategy.h"
@@ -17,13 +18,23 @@
 
 namespace remoting {
 
-XmppLogToServer::XmppLogToServer(ServerLogEntry::Mode mode,
-                                 SignalStrategy* signal_strategy,
-                                 const std::string& directory_bot_jid)
+XmppLogToServer::XmppLogToServer(
+    ServerLogEntry::Mode mode,
+    SignalStrategy* signal_strategy,
+    const std::string& directory_bot_jid,
+    scoped_refptr<base::SequencedTaskRunner> caller_task_runner)
     : mode_(mode),
       signal_strategy_(signal_strategy),
-      directory_bot_jid_(directory_bot_jid) {
-  signal_strategy_->AddListener(this);
+      directory_bot_jid_(directory_bot_jid),
+      weak_factory_(this) {
+  DETACH_FROM_SEQUENCE(sequence_checker_);
+  if (!caller_task_runner || caller_task_runner->RunsTasksInCurrentSequence()) {
+    Init();
+    return;
+  }
+  caller_task_runner->PostTask(
+      FROM_HERE,
+      base::BindOnce(&XmppLogToServer::Init, weak_factory_.GetWeakPtr()));
 }
 
 XmppLogToServer::~XmppLogToServer() {
@@ -52,6 +63,11 @@
   SendPendingEntries();
 }
 
+void XmppLogToServer::Init() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  signal_strategy_->AddListener(this);
+}
+
 void XmppLogToServer::SendPendingEntries() {
   if (iq_sender_ == nullptr) {
     return;
@@ -71,4 +87,8 @@
                      std::move(stanza), IqSender::ReplyCallback());
 }
 
+ServerLogEntry::Mode XmppLogToServer::mode() const {
+  return mode_;
+}
+
 }  // namespace remoting
diff --git a/remoting/signaling/xmpp_log_to_server.h b/remoting/signaling/xmpp_log_to_server.h
index f8d4418..ba13056 100644
--- a/remoting/signaling/xmpp_log_to_server.h
+++ b/remoting/signaling/xmpp_log_to_server.h
@@ -10,7 +10,11 @@
 
 #include "base/containers/circular_deque.h"
 #include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
 #include "base/sequence_checker.h"
+#include "base/sequenced_task_runner.h"
+#include "remoting/signaling/log_to_server.h"
 #include "remoting/signaling/server_log_entry.h"
 #include "remoting/signaling/signal_strategy.h"
 
@@ -22,14 +26,17 @@
 
 class IqSender;
 
-// XmppLogToServer sends log entries to a server.
-// The contents of the log entries are described in server_log_entry.cc.
-// They do not contain any personally identifiable information.
-class XmppLogToServer : public SignalStrategy::Listener {
+// XmppLogToServer sends log entries to a server through the signaling strategy.
+class XmppLogToServer : public LogToServer, public SignalStrategy::Listener {
  public:
-  XmppLogToServer(ServerLogEntry::Mode mode,
-                  SignalStrategy* signal_strategy,
-                  const std::string& directory_bot_jid);
+  // The instance will be initialized on |caller_task_runner|, and thereafter
+  // it must be used on the sequence of |caller_task_runner|. By default it will
+  // be initialized on the current active sequence.
+  XmppLogToServer(
+      ServerLogEntry::Mode mode,
+      SignalStrategy* signal_strategy,
+      const std::string& directory_bot_jid,
+      scoped_refptr<base::SequencedTaskRunner> caller_task_runner = {});
   ~XmppLogToServer() override;
 
   // SignalStrategy::Listener interface.
@@ -37,11 +44,12 @@
   bool OnSignalStrategyIncomingStanza(
       const jingle_xmpp::XmlElement* stanza) override;
 
-  void Log(const ServerLogEntry& entry);
-
-  ServerLogEntry::Mode mode() { return mode_; }
+  // LogToServer interface.
+  void Log(const ServerLogEntry& entry) override;
+  ServerLogEntry::Mode mode() const override;
 
  private:
+  void Init();
   void SendPendingEntries();
 
   ServerLogEntry::Mode mode_;
@@ -53,6 +61,7 @@
 
   SEQUENCE_CHECKER(sequence_checker_);
 
+  base::WeakPtrFactory<XmppLogToServer> weak_factory_;
   DISALLOW_COPY_AND_ASSIGN(XmppLogToServer);
 };
 
diff --git a/remoting/test/test_oauth_token_getter.cc b/remoting/test/test_oauth_token_getter.cc
index 619e13a..3267c63 100644
--- a/remoting/test/test_oauth_token_getter.cc
+++ b/remoting/test/test_oauth_token_getter.cc
@@ -167,7 +167,7 @@
           email, refresh_token, is_service_account);
 
   return std::make_unique<OAuthTokenGetterImpl>(
-      std::move(oauth_credentials),
+      std::move(oauth_credentials), base::DoNothing(),
       url_loader_factory_owner_->GetURLLoaderFactory(),
       /*auto_refresh=*/true);
 }
diff --git a/services/network/cross_origin_read_blocking.cc b/services/network/cross_origin_read_blocking.cc
index 2c8acfd1..a6d6ee9 100644
--- a/services/network/cross_origin_read_blocking.cc
+++ b/services/network/cross_origin_read_blocking.cc
@@ -25,10 +25,8 @@
 #include "net/base/mime_sniffer.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "net/http/http_response_headers.h"
-#include "net/url_request/url_request.h"
 #include "services/network/cross_origin_resource_policy.h"
 #include "services/network/public/cpp/features.h"
-#include "services/network/public/cpp/resource_response.h"
 #include "services/network/public/cpp/resource_response_info.h"
 
 using base::StringPiece;
@@ -482,11 +480,11 @@
 
 // static
 void CrossOriginReadBlocking::SanitizeBlockedResponse(
-    const scoped_refptr<network::ResourceResponse>& response) {
+    network::ResourceResponseInfo* response) {
   DCHECK(response);
-  response->head.content_length = 0;
-  if (response->head.headers)
-    BlockResponseHeaders(response->head.headers);
+  response->content_length = 0;
+  if (response->headers)
+    BlockResponseHeaders(response->headers);
 }
 
 // static
@@ -592,17 +590,18 @@
 };
 
 CrossOriginReadBlocking::ResponseAnalyzer::ResponseAnalyzer(
-    const net::URLRequest& request,
-    const ResourceResponse& response,
+    const GURL& request_url,
+    const base::Optional<url::Origin>& request_initiator,
+    const ResourceResponseInfo& response,
     base::Optional<url::Origin> request_initiator_site_lock,
     mojom::FetchRequestMode fetch_request_mode) {
-  content_length_ = response.head.content_length;
+  content_length_ = response.content_length;
   http_response_code_ =
-      response.head.headers ? response.head.headers->response_code() : 0;
+      response.headers ? response.headers->response_code() : 0;
   request_initiator_site_lock_ = request_initiator_site_lock;
 
-  should_block_based_on_headers_ =
-      ShouldBlockBasedOnHeaders(fetch_request_mode, request, response);
+  should_block_based_on_headers_ = ShouldBlockBasedOnHeaders(
+      fetch_request_mode, request_url, request_initiator, response);
   if (should_block_based_on_headers_ == kNeedToSniffMore)
     CreateSniffers();
 }
@@ -612,16 +611,17 @@
 CrossOriginReadBlocking::ResponseAnalyzer::BlockingDecision
 CrossOriginReadBlocking::ResponseAnalyzer::ShouldBlockBasedOnHeaders(
     mojom::FetchRequestMode fetch_request_mode,
-    const net::URLRequest& request,
-    const ResourceResponse& response) {
+    const GURL& request_url,
+    const base::Optional<url::Origin>& request_initiator,
+    const ResourceResponseInfo& response) {
   // The checks in this method are ordered to rule out blocking in most cases as
   // quickly as possible.  Checks that are likely to lead to returning false or
   // that are inexpensive should be near the top.
-  url::Origin target_origin = url::Origin::Create(request.url());
+  url::Origin target_origin = url::Origin::Create(request_url);
 
   // Check if |target_origin| seems to match the factory lock in
   // |request_initiator_site_lock_|.  If so, then treat this request as
-  // same-origin (even if |request.initiator()| might be cross-origin).  See
+  // same-origin (even if |request_initiator| might be cross-origin).  See
   // also https://crbug.com/918660.
   if (VerifyRequestInitiatorLock(request_initiator_site_lock_, target_origin) ==
       InitiatorLockCompatibility::kCompatibleLock) {
@@ -635,7 +635,7 @@
   url::Origin initiator = GetTrustworthyInitiator(
       ShouldEnforceInitiatorLock() ? request_initiator_site_lock_
                                    : base::nullopt,
-      request);
+      request_initiator);
 
   // Don't block same-origin documents.
   if (initiator.IsSameOriginWith(target_origin))
@@ -664,8 +664,8 @@
     case mojom::FetchRequestMode::kCors:
     case mojom::FetchRequestMode::kCorsWithForcedPreflight:
       std::string cors_header;
-      response.head.headers->GetNormalizedHeader("access-control-allow-origin",
-                                                 &cors_header);
+      response.headers->GetNormalizedHeader("access-control-allow-origin",
+                                            &cors_header);
       if (IsValidCorsHeaderSet(initiator, cors_header))
         return kAllow;
       break;
@@ -677,8 +677,8 @@
   // for bar.example.com).  This is okay and should not be blocked by CORB,
   // unless the initiator opted out of CORS / opted into receiving an opaque
   // response.  See also https://crbug.com/803672.
-  if (response.head.was_fetched_via_service_worker) {
-    switch (response.head.response_type) {
+  if (response.was_fetched_via_service_worker) {
+    switch (response.response_type) {
       case network::mojom::FetchResponseType::kBasic:
       case network::mojom::FetchResponseType::kCors:
       case network::mojom::FetchResponseType::kDefault:
@@ -699,21 +699,21 @@
   // Note: if there is a nosniff header, it means we should honor the response
   // mime type without trying to confirm it.
   std::string nosniff_header;
-  response.head.headers->GetNormalizedHeader("x-content-type-options",
-                                             &nosniff_header);
+  response.headers->GetNormalizedHeader("x-content-type-options",
+                                        &nosniff_header);
   bool has_nosniff_header =
       base::LowerCaseEqualsASCII(nosniff_header, "nosniff");
 
   // CORB should look directly at the Content-Type header if one has been
-  // received from the network.  Ignoring |response.head.mime_type| helps avoid
+  // received from the network.  Ignoring |response.mime_type| helps avoid
   // breaking legitimate websites (which might happen more often when blocking
   // would be based on the mime type sniffed by MimeSniffingResourceHandler).
   //
   // TODO(nick): What if the mime type is omitted? Should that be treated the
   // same as text/plain? https://crbug.com/795971
   std::string mime_type;
-  if (response.head.headers)
-    response.head.headers->GetMimeType(&mime_type);
+  if (response.headers)
+    response.headers->GetMimeType(&mime_type);
   // Canonicalize the MIME type.  Note that even if it doesn't claim to be a
   // blockable type (i.e., HTML, XML, JSON, or plain text), it may still fail
   // the checks during the SniffForFetchOnlyResource() phase.
@@ -750,8 +750,8 @@
   constexpr mojom::FetchRequestMode kOverreachingFetchMode =
       mojom::FetchRequestMode::kNoCors;
   if (CrossOriginResourcePolicy::kBlock ==
-      CrossOriginResourcePolicy::Verify(request, response,
-                                        kOverreachingFetchMode,
+      CrossOriginResourcePolicy::Verify(request_url, request_initiator,
+                                        response, kOverreachingFetchMode,
                                         request_initiator_site_lock_)) {
     // Ignore mime types and/or sniffing and have CORB block all responses with
     // COR*P* header.
@@ -761,7 +761,7 @@
   // If this is a partial response, sniffing is not possible, so allow the
   // response if it's not a protected mime type.
   std::string range_header;
-  response.head.headers->GetNormalizedHeader("content-range", &range_header);
+  response.headers->GetNormalizedHeader("content-range", &range_header);
   bool has_range_header = !range_header.empty();
   if (has_range_header) {
     switch (canonical_mime_type_) {
@@ -794,7 +794,7 @@
     case MimeType::kOthers:
       // Stylesheets shouldn't be sniffed for JSON parser breakers - see
       // https://crbug.com/809259.
-      if (base::LowerCaseEqualsASCII(response.head.mime_type, "text/css"))
+      if (base::LowerCaseEqualsASCII(response.mime_type, "text/css"))
         return kAllow;
       else
         return kNeedToSniffMore;
diff --git a/services/network/cross_origin_read_blocking.h b/services/network/cross_origin_read_blocking.h
index d1df920d..e4be1df3 100644
--- a/services/network/cross_origin_read_blocking.h
+++ b/services/network/cross_origin_read_blocking.h
@@ -23,13 +23,9 @@
 FORWARD_DECLARE_TEST(CrossSiteDocumentResourceHandlerTest, ResponseBlocking);
 }  // namespace content
 
-namespace net {
-class URLRequest;
-}
-
 namespace network {
 
-struct ResourceResponse;
+struct ResourceResponseInfo;
 
 // CrossOriginReadBlocking (CORB) implements response blocking
 // policy for Site Isolation.  CORB will monitor network responses to a
@@ -75,10 +71,12 @@
   // and deciding whether CORB should block the response.
   class COMPONENT_EXPORT(NETWORK_SERVICE) ResponseAnalyzer {
    public:
-    // Creates a ResponseAnalyzer for the |request|, |response| pair.  The
-    // ResponseAnalyzer will decide whether |response| needs to be blocked.
-    ResponseAnalyzer(const net::URLRequest& request,
-                     const ResourceResponse& response,
+    // Creates a ResponseAnalyzer for the request (|request_url| and
+    // |request_initiator|), |response| pair.  The ResponseAnalyzer will decide
+    // whether |response| needs to be blocked.
+    ResponseAnalyzer(const GURL& request_url,
+                     const base::Optional<url::Origin>& request_initiator,
+                     const ResourceResponseInfo& response,
                      base::Optional<url::Origin> request_initiator_site_lock,
                      mojom::FetchRequestMode fetch_request_mode);
 
@@ -144,8 +142,9 @@
     };
     BlockingDecision ShouldBlockBasedOnHeaders(
         mojom::FetchRequestMode fetch_request_mode,
-        const net::URLRequest& request,
-        const ResourceResponse& response);
+        const GURL& request_url,
+        const base::Optional<url::Origin>& request_initiator,
+        const ResourceResponseInfo& response);
 
     // Populates |sniffers_| container based on |canonical_mime_type_|.  Called
     // if ShouldBlockBasedOnHeaders returns kNeedToSniffMore
@@ -184,8 +183,7 @@
   };
 
   // Used to strip response headers if a decision to block has been made.
-  static void SanitizeBlockedResponse(
-      const scoped_refptr<network::ResourceResponse>& response);
+  static void SanitizeBlockedResponse(ResourceResponseInfo* response);
 
   // This enum backs a histogram, so do not change the order of entries or
   // remove entries. When adding new entries update |kMaxValue| and enums.xml
diff --git a/services/network/cross_origin_resource_policy.cc b/services/network/cross_origin_resource_policy.cc
index 4737cc7..1f4450f 100644
--- a/services/network/cross_origin_resource_policy.cc
+++ b/services/network/cross_origin_resource_policy.cc
@@ -8,9 +8,8 @@
 
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "net/http/http_response_headers.h"
-#include "net/url_request/url_request.h"
 #include "services/network/initiator_lock_compatibility.h"
-#include "services/network/public/cpp/resource_response.h"
+#include "services/network/public/cpp/resource_response_info.h"
 #include "url/gurl.h"
 #include "url/origin.h"
 #include "url/url_constants.h"
@@ -97,8 +96,9 @@
 
 // static
 CrossOriginResourcePolicy::VerificationResult CrossOriginResourcePolicy::Verify(
-    const net::URLRequest& request,
-    const ResourceResponse& response,
+    const GURL& request_url,
+    const base::Optional<url::Origin>& request_initiator,
+    const ResourceResponseInfo& response,
     mojom::FetchRequestMode fetch_mode,
     base::Optional<url::Origin> request_initiator_site_lock) {
   // From https://fetch.spec.whatwg.org/#cross-origin-resource-policy-header:
@@ -113,7 +113,7 @@
   // We parse the header earlier than requested by the spec (i.e. we swap steps
   // 2 and 3 from the spec), to return early if there was no header (before
   // slightly more expensive steps needed to extract the origins below).
-  ParsedHeader policy = ParseHeader(response.head.headers.get());
+  ParsedHeader policy = ParseHeader(response.headers.get());
   if (policy == kNoHeader || policy == kParsingError) {
     // The algorithm only returns kBlock from steps 4 and 6, when policy is
     // either kSameOrigin or kSameSite.  For other policy values we can
@@ -127,9 +127,9 @@
   // From https://fetch.spec.whatwg.org/#cross-origin-resource-policy-header:
   // > 2. If request’s origin is same origin with request’s current URL’s
   //      origin, then return allowed.
-  url::Origin target_origin = url::Origin::Create(request.url());
+  url::Origin target_origin = url::Origin::Create(request_url);
   url::Origin initiator =
-      GetTrustworthyInitiator(request_initiator_site_lock, request);
+      GetTrustworthyInitiator(request_initiator_site_lock, request_initiator);
   if (initiator == target_origin)
     return kAllow;
 
diff --git a/services/network/cross_origin_resource_policy.h b/services/network/cross_origin_resource_policy.h
index 457ce93a..72cee992 100644
--- a/services/network/cross_origin_resource_policy.h
+++ b/services/network/cross_origin_resource_policy.h
@@ -11,14 +11,15 @@
 #include "services/network/public/mojom/fetch_api.mojom-shared.h"
 #include "url/origin.h"
 
+class GURL;
+
 namespace net {
-class URLRequest;
 class HttpResponseHeaders;
 }  // namespace net
 
 namespace network {
 
-struct ResourceResponse;
+struct ResourceResponseInfo;
 
 // Implementation of Cross-Origin-Resource-Policy - see:
 // - https://fetch.spec.whatwg.org/#cross-origin-resource-policy-header
@@ -36,8 +37,9 @@
     kAllow,
   };
   static VerificationResult Verify(
-      const net::URLRequest& request,
-      const ResourceResponse& response,
+      const GURL& request_url,
+      const base::Optional<url::Origin>& request_initiator,
+      const ResourceResponseInfo& response,
       mojom::FetchRequestMode fetch_mode,
       base::Optional<url::Origin> request_initiator_site_lock);
 
diff --git a/services/network/initiator_lock_compatibility.cc b/services/network/initiator_lock_compatibility.cc
index 0f8de645..526dfa7 100644
--- a/services/network/initiator_lock_compatibility.cc
+++ b/services/network/initiator_lock_compatibility.cc
@@ -72,22 +72,22 @@
 
 url::Origin GetTrustworthyInitiator(
     const base::Optional<url::Origin>& request_initiator_site_lock,
-    const net::URLRequest& request) {
+    const base::Optional<url::Origin>& request_initiator) {
   // Returning a unique origin as a fallback should be safe - such origin will
   // be considered cross-origin from all other origins.
   url::Origin unique_origin_fallback;
 
-  if (!request.initiator().has_value())
+  if (!request_initiator.has_value())
     return unique_origin_fallback;
 
   InitiatorLockCompatibility initiator_compatibility =
       VerifyRequestInitiatorLock(request_initiator_site_lock,
-                                 request.initiator());
+                                 request_initiator);
   if (initiator_compatibility == InitiatorLockCompatibility::kIncorrectLock)
     return unique_origin_fallback;
 
-  // If all the checks above passed, then |request.initiator()| is trustworthy.
-  return request.initiator().value();
+  // If all the checks above passed, then |request_initiator| is trustworthy.
+  return request_initiator.value();
 }
 
 }  // namespace network
diff --git a/services/network/initiator_lock_compatibility.h b/services/network/initiator_lock_compatibility.h
index edb3132..1deaddf 100644
--- a/services/network/initiator_lock_compatibility.h
+++ b/services/network/initiator_lock_compatibility.h
@@ -9,10 +9,6 @@
 #include "base/optional.h"
 #include "url/origin.h"
 
-namespace net {
-class URLRequest;
-}  // namespace net
-
 namespace network {
 
 namespace mojom {
@@ -57,15 +53,21 @@
     const base::Optional<url::Origin>& request_initiator_site_lock,
     const base::Optional<url::Origin>& request_initiator);
 
-// Gets initiator of |request|, falling back to a unique origin if
-// 1) |request.initiator()| is missing or
-// 2) |request.initiator()| is incompatible with |request_initiator_site_lock|.
+// Gets initiator of request, falling back to a unique origin if
+// 1) |request_initiator| is missing or
+// 2) |request_initiator| is incompatible with |request_initiator_site_lock|.
 //
-// |request_initiator_site_lock| should come from
-// URLLoaderFactoryParams::request_initiator_site_lock.
+// |request_initiator_site_lock| is the origin to which the URLLoaderFactory of
+// the request is locked in a trustworthy way.
+//   Example:
+//     URLLoaderFactoryParams::request_initiator_site_lock
+//     SubresourceSignedExchangeURLLoaderFactory::request_initiator_site_lock
+// |request_initiator| should come from net::URLRequest::initiator() or
+// network::ResourceRequest::request_initiator which may be initially set in an
+// untrustworthy process (eg: renderer process).
 url::Origin GetTrustworthyInitiator(
     const base::Optional<url::Origin>& request_initiator_site_lock,
-    const net::URLRequest& request);
+    const base::Optional<url::Origin>& request_initiator);
 
 }  // namespace network
 
diff --git a/services/network/sec_fetch_site.cc b/services/network/sec_fetch_site.cc
index 58c6b07..2355697d 100644
--- a/services/network/sec_fetch_site.cc
+++ b/services/network/sec_fetch_site.cc
@@ -65,7 +65,7 @@
   // full chain of request URLs.
   HeaderValue header_value = HeaderValue::kSameOrigin;
   url::Origin initiator = GetTrustworthyInitiator(
-      factory_params.request_initiator_site_lock, request);
+      factory_params.request_initiator_site_lock, request.initiator());
   for (const GURL& target_url : request.url_chain()) {
     header_value =
         std::max(header_value, CalculateHeaderValue(target_url, initiator));
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
index f984455..44497a4 100644
--- a/services/network/url_loader.cc
+++ b/services/network/url_loader.cc
@@ -24,6 +24,7 @@
 #include "mojo/public/cpp/system/simple_watcher.h"
 #include "net/base/elements_upload_data_stream.h"
 #include "net/base/ip_endpoint.h"
+#include "net/base/load_flags.h"
 #include "net/base/mime_sniffer.h"
 #include "net/base/static_cookie_policy.h"
 #include "net/base/upload_bytes_element_reader.h"
@@ -83,7 +84,9 @@
   response->head.network_accessed = response_info.network_accessed;
   response->head.async_revalidation_requested =
       response_info.async_revalidation_requested;
-
+  response->head.was_in_prefetch_cache =
+      !(request->load_flags() & net::LOAD_PREFETCH) &&
+      response_info.unused_since_prefetch;
   response->head.effective_connection_type =
       net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
 
@@ -727,8 +730,8 @@
   // Enforce the Cross-Origin-Resource-Policy (CORP) header.
   if (CrossOriginResourcePolicy::kBlock ==
       CrossOriginResourcePolicy::Verify(
-          *url_request_, *response, fetch_request_mode_,
-          factory_params_->request_initiator_site_lock)) {
+          url_request_->url(), url_request_->initiator(), response->head,
+          fetch_request_mode_, factory_params_->request_initiator_site_lock)) {
     CompleteBlockedResponse(net::ERR_BLOCKED_BY_RESPONSE, false);
     DeleteSelf();
     return;
@@ -874,8 +877,8 @@
   // Enforce the Cross-Origin-Resource-Policy (CORP) header.
   if (CrossOriginResourcePolicy::kBlock ==
       CrossOriginResourcePolicy::Verify(
-          *url_request_, *response_, fetch_request_mode_,
-          factory_params_->request_initiator_site_lock)) {
+          url_request_->url(), url_request_->initiator(), response_->head,
+          fetch_request_mode_, factory_params_->request_initiator_site_lock)) {
     CompleteBlockedResponse(net::ERR_BLOCKED_BY_RESPONSE, false);
     DeleteSelf();
     return;
@@ -889,7 +892,7 @@
 
     corb_analyzer_ =
         std::make_unique<CrossOriginReadBlocking::ResponseAnalyzer>(
-            *url_request_, *response_,
+            url_request_->url(), url_request_->initiator(), response_->head,
             factory_params_->request_initiator_site_lock, fetch_request_mode_);
     is_more_corb_sniffing_needed_ = corb_analyzer_->needs_sniffing();
     if (corb_analyzer_->ShouldBlock()) {
@@ -1412,7 +1415,7 @@
   DCHECK(consumer_handle_.is_valid());
 
   // Send stripped headers to the real URLLoaderClient.
-  CrossOriginReadBlocking::SanitizeBlockedResponse(response_);
+  CrossOriginReadBlocking::SanitizeBlockedResponse(&response_->head);
   url_loader_client_->OnReceiveResponse(response_->head);
 
   // Send empty body to the real URLLoaderClient.
diff --git a/services/service_manager/public/cpp/test/test_service.h b/services/service_manager/public/cpp/test/test_service.h
index 4d09fa13..c66db89a 100644
--- a/services/service_manager/public/cpp/test/test_service.h
+++ b/services/service_manager/public/cpp/test/test_service.h
@@ -17,7 +17,7 @@
 // Manager instance and have each test behave like a unique service instance
 // that can connect to any of various services under test.
 //
-// Typical usage is paired with ServiceManager::RegisterServiceForTesting, for
+// Typical usage is paired with ServiceManager::RegisterTestInstance, for
 // example:
 //
 //   class MyTest : public testing::Test {
diff --git a/services/tracing/perfetto/producer_host.cc b/services/tracing/perfetto/producer_host.cc
index 12da7a6..a8150a51 100644
--- a/services/tracing/perfetto/producer_host.cc
+++ b/services/tracing/perfetto/producer_host.cc
@@ -132,7 +132,10 @@
 }
 
 void ProducerHost::ClearIncrementalState(const perfetto::DataSourceInstanceID*,
-                                         size_t) {}
+                                         size_t) {
+  DCHECK(producer_client_);
+  producer_client_->ClearIncrementalState();
+}
 
 // This data can come from a malicious child process. We don't do any
 // sanitization here because ProducerEndpoint::CommitData() (And any other
diff --git a/services/tracing/public/cpp/perfetto/perfetto_config.cc b/services/tracing/public/cpp/perfetto/perfetto_config.cc
index 84fbef7..5d31211 100644
--- a/services/tracing/public/cpp/perfetto/perfetto_config.cc
+++ b/services/tracing/public/cpp/perfetto/perfetto_config.cc
@@ -51,6 +51,10 @@
   builtin_data_sources->set_disable_trace_config(privacy_filtering_enabled);
   builtin_data_sources->set_disable_system_info(privacy_filtering_enabled);
 
+  // Clear incremental state every 5 seconds, so that we lose at most the first
+  // 5 seconds of the trace (if we wrap around perfetto's central buffer).
+  perfetto_config.mutable_incremental_state_config()->set_clear_period_ms(5000);
+
   // We strip the process filter from the config string we send to Perfetto,
   // so perfetto doesn't reject it from a future
   // TracingService::ChangeTraceConfig call due to being an unsupported
diff --git a/services/tracing/public/cpp/perfetto/perfetto_traced_process.h b/services/tracing/public/cpp/perfetto/perfetto_traced_process.h
index abd7b7f..afe220d 100644
--- a/services/tracing/public/cpp/perfetto/perfetto_traced_process.h
+++ b/services/tracing/public/cpp/perfetto/perfetto_traced_process.h
@@ -48,6 +48,8 @@
     // Flush the data source.
     virtual void Flush(base::RepeatingClosure flush_complete_callback) = 0;
 
+    virtual void ClearIncrementalState() {}
+
     const std::string& name() const { return name_; }
     uint64_t data_source_id() const { return data_source_id_; }
 
diff --git a/services/tracing/public/cpp/perfetto/producer_client.cc b/services/tracing/public/cpp/perfetto/producer_client.cc
index 245624cf..c6509fb0 100644
--- a/services/tracing/public/cpp/perfetto/producer_client.cc
+++ b/services/tracing/public/cpp/perfetto/producer_client.cc
@@ -92,6 +92,7 @@
   new_registration.set_name(data_source->name());
   new_registration.set_will_notify_on_start(true);
   new_registration.set_will_notify_on_stop(true);
+  new_registration.set_handles_incremental_state_clear(true);
   producer_host_->RegisterDataSource(std::move(new_registration));
 }
 
@@ -175,6 +176,12 @@
   }
 }
 
+void ProducerClient::ClearIncrementalState() {
+  for (auto* data_source : PerfettoTracedProcess::Get()->data_sources()) {
+    data_source->ClearIncrementalState();
+  }
+}
+
 void ProducerClient::RegisterDataSource(const perfetto::DataSourceDescriptor&) {
   NOTREACHED();
 }
diff --git a/services/tracing/public/cpp/perfetto/producer_client.h b/services/tracing/public/cpp/perfetto/producer_client.h
index 2322307..6b218be 100644
--- a/services/tracing/public/cpp/perfetto/producer_client.h
+++ b/services/tracing/public/cpp/perfetto/producer_client.h
@@ -61,6 +61,7 @@
   void StopDataSource(uint64_t id, StopDataSourceCallback callback) override;
   void Flush(uint64_t flush_request_id,
              const std::vector<uint64_t>& data_source_ids) override;
+  void ClearIncrementalState() override;
 
   // perfetto::TracingService::ProducerEndpoint implementation.
   // Used by the TraceWriters
diff --git a/services/tracing/public/cpp/perfetto/thread_local_event_sink.cc b/services/tracing/public/cpp/perfetto/thread_local_event_sink.cc
index ec5a83a..0aa7890 100644
--- a/services/tracing/public/cpp/perfetto/thread_local_event_sink.cc
+++ b/services/tracing/public/cpp/perfetto/thread_local_event_sink.cc
@@ -25,6 +25,4 @@
       std::move(trace_writer_));
 }
 
-void ThreadLocalEventSink::ResetIncrementalState() {}
-
 }  // namespace tracing
diff --git a/services/tracing/public/cpp/perfetto/thread_local_event_sink.h b/services/tracing/public/cpp/perfetto/thread_local_event_sink.h
index f45e4a8..db85b12c 100644
--- a/services/tracing/public/cpp/perfetto/thread_local_event_sink.h
+++ b/services/tracing/public/cpp/perfetto/thread_local_event_sink.h
@@ -44,8 +44,6 @@
 
   virtual void Flush() = 0;
 
-  virtual void ResetIncrementalState();
-
   uint32_t session_id() const { return session_id_; }
 
  protected:
diff --git a/services/tracing/public/cpp/perfetto/trace_event_data_source.cc b/services/tracing/public/cpp/perfetto/trace_event_data_source.cc
index 90f2af8..99b3cce 100644
--- a/services/tracing/public/cpp/perfetto/trace_event_data_source.cc
+++ b/services/tracing/public/cpp/perfetto/trace_event_data_source.cc
@@ -368,12 +368,8 @@
       std::move(flush_complete_callback)));
 }
 
-void TraceEventDataSource::ResetIncrementalStateForTesting() {
-  auto* thread_local_event_sink =
-      static_cast<ThreadLocalEventSink*>(ThreadLocalEventSinkSlot()->Get());
-  if (thread_local_event_sink) {
-    thread_local_event_sink->ResetIncrementalState();
-  }
+void TraceEventDataSource::ClearIncrementalState() {
+  TrackEventThreadLocalEventSink::ClearIncrementalState();
 }
 
 ThreadLocalEventSink* TraceEventDataSource::CreateThreadLocalEventSink(
diff --git a/services/tracing/public/cpp/perfetto/trace_event_data_source.h b/services/tracing/public/cpp/perfetto/trace_event_data_source.h
index ec4c4d0..e19620d 100644
--- a/services/tracing/public/cpp/perfetto/trace_event_data_source.h
+++ b/services/tracing/public/cpp/perfetto/trace_event_data_source.h
@@ -112,11 +112,7 @@
   // Called from the PerfettoProducer.
   void StopTracing(base::OnceClosure stop_complete_callback) override;
   void Flush(base::RepeatingClosure flush_complete_callback) override;
-
-  // Resets emitted incremental state on the current thread and causes
-  // incremental data (e.g. interning index entries and a ThreadDescriptor) to
-  // be emitted again.
-  void ResetIncrementalStateForTesting();
+  void ClearIncrementalState() override;
 
   // Deletes TraceWriter safely on behalf of a ThreadLocalEventSink.
   void ReturnTraceWriter(
diff --git a/services/tracing/public/cpp/perfetto/trace_event_data_source_unittest.cc b/services/tracing/public/cpp/perfetto/trace_event_data_source_unittest.cc
index 74f985a9..50523d7 100644
--- a/services/tracing/public/cpp/perfetto/trace_event_data_source_unittest.cc
+++ b/services/tracing/public/cpp/perfetto/trace_event_data_source_unittest.cc
@@ -915,7 +915,7 @@
 
     // Resetting the interning state causes ThreadDescriptor and interning
     // entries to be emitted again, with the same interning IDs.
-    TraceEventDataSource::GetInstance()->ResetIncrementalStateForTesting();
+    TraceEventDataSource::GetInstance()->ClearIncrementalState();
   }
 }
 
diff --git a/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.cc b/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.cc
index dd0a5971..92dbece 100644
--- a/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.cc
+++ b/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.cc
@@ -34,12 +34,6 @@
 constexpr uint32_t kMagicChunkIndex =
     base::trace_event::TraceBufferChunk::kMaxChunkIndex;
 
-// Force an incremental state reset every 1000 events on each thread. This
-// limits the maximum number of events we lose when trace buffers wrap.
-// TODO(eseckler): Tune this value experimentally and/or replace it with a
-// signal by the service.
-constexpr int kMaxEventsBeforeIncrementalStateReset = 1000;
-
 // Replacement string for names of events with TRACE_EVENT_FLAG_COPY.
 const char* const kPrivacyFiltered = "PRIVACY_FILTERED";
 
@@ -119,6 +113,10 @@
 // static
 constexpr size_t TrackEventThreadLocalEventSink::kMaxCompleteEventDepth;
 
+// static
+std::atomic<uint32_t>
+    TrackEventThreadLocalEventSink::incremental_state_reset_id_{0};
+
 TrackEventThreadLocalEventSink::TrackEventThreadLocalEventSink(
     std::unique_ptr<perfetto::StartupTraceWriter> trace_writer,
     uint32_t session_id,
@@ -138,11 +136,9 @@
 
 TrackEventThreadLocalEventSink::~TrackEventThreadLocalEventSink() {}
 
-// TODO(eseckler): Trigger this upon a signal from the perfetto, once perfetto
-// supports this.
-void TrackEventThreadLocalEventSink::ResetIncrementalState() {
-  reset_incremental_state_ = true;
-  events_since_last_incremental_state_reset_ = 0;
+// static
+void TrackEventThreadLocalEventSink::ClearIncrementalState() {
+  incremental_state_reset_id_.fetch_add(1u, std::memory_order_relaxed);
 }
 
 void TrackEventThreadLocalEventSink::AddTraceEvent(
@@ -176,6 +172,15 @@
   bool copy_strings = flags & TRACE_EVENT_FLAG_COPY;
   bool explicit_timestamp = flags & TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP;
 
+  // We access |incremental_state_reset_id_| atomically but racily. It's OK if
+  // we don't notice the reset request immediately, as long as we will notice
+  // and service it eventually.
+  auto reset_id = incremental_state_reset_id_.load(std::memory_order_relaxed);
+  if (reset_id != last_incremental_state_reset_id_) {
+    reset_incremental_state_ = true;
+    last_incremental_state_reset_id_ = reset_id;
+  }
+
   if (reset_incremental_state_) {
     interned_event_categories_.ResetEmittedState();
     interned_event_names_.ResetEmittedState();
@@ -456,12 +461,6 @@
     interned_annotation_names_.Clear();
     interned_source_locations_.Clear();
   }
-
-  events_since_last_incremental_state_reset_++;
-  if (events_since_last_incremental_state_reset_ >=
-      kMaxEventsBeforeIncrementalStateReset) {
-    ResetIncrementalState();
-  }
 }
 
 void TrackEventThreadLocalEventSink::UpdateDuration(
diff --git a/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.h b/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.h
index 80d1227..7cae3bd7 100644
--- a/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.h
+++ b/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.h
@@ -34,8 +34,11 @@
       bool proto_writer_filtering_enabled);
   ~TrackEventThreadLocalEventSink() override;
 
+  // Resets emitted incremental state on all threads and causes incremental data
+  // (e.g. interning index entries and a ThreadDescriptor) to be emitted again.
+  static void ClearIncrementalState();
+
   // ThreadLocalEventSink implementation:
-  void ResetIncrementalState() override;
   void AddTraceEvent(base::trace_event::TraceEvent* trace_event,
                      base::trace_event::TraceEventHandle* handle) override;
   void UpdateDuration(base::trace_event::TraceEventHandle handle,
@@ -54,12 +57,14 @@
   InterningIndex<std::pair<const char*, const char*>>
       interned_source_locations_;
 
+  static std::atomic<uint32_t> incremental_state_reset_id_;
+
   bool reset_incremental_state_ = true;
+  uint32_t last_incremental_state_reset_id_ = 0;
   base::TimeTicks last_timestamp_;
   base::ThreadTicks last_thread_time_;
   int process_id_;
   int thread_id_;
-  int events_since_last_incremental_state_reset_ = 0;
 
   base::trace_event::TraceEvent complete_event_stack_[kMaxCompleteEventDepth];
   uint32_t current_stack_depth_ = 0;
diff --git a/services/tracing/public/mojom/data_source_descriptor_mojom_traits.cc b/services/tracing/public/mojom/data_source_descriptor_mojom_traits.cc
index e09645e1..3325748 100644
--- a/services/tracing/public/mojom/data_source_descriptor_mojom_traits.cc
+++ b/services/tracing/public/mojom/data_source_descriptor_mojom_traits.cc
@@ -18,6 +18,8 @@
   out->set_name(name);
   out->set_will_notify_on_start(data.will_notify_on_start());
   out->set_will_notify_on_stop(data.will_notify_on_stop());
+  out->set_handles_incremental_state_clear(
+      data.handles_incremental_state_clear());
   return true;
 }
 }  // namespace mojo
diff --git a/services/tracing/public/mojom/data_source_descriptor_mojom_traits.h b/services/tracing/public/mojom/data_source_descriptor_mojom_traits.h
index aaf6826e..b98db41 100644
--- a/services/tracing/public/mojom/data_source_descriptor_mojom_traits.h
+++ b/services/tracing/public/mojom/data_source_descriptor_mojom_traits.h
@@ -28,6 +28,10 @@
   static bool will_notify_on_stop(const perfetto::DataSourceDescriptor& src) {
     return src.will_notify_on_stop();
   }
+  static bool handles_incremental_state_clear(
+      const perfetto::DataSourceDescriptor& src) {
+    return src.handles_incremental_state_clear();
+  }
 
   static bool Read(tracing::mojom::DataSourceRegistrationDataView data,
                    perfetto::DataSourceDescriptor* out);
diff --git a/services/tracing/public/mojom/perfetto_service.mojom b/services/tracing/public/mojom/perfetto_service.mojom
index 799b2c4..423addf 100644
--- a/services/tracing/public/mojom/perfetto_service.mojom
+++ b/services/tracing/public/mojom/perfetto_service.mojom
@@ -90,6 +90,7 @@
   string name;
   bool will_notify_on_start;
   bool will_notify_on_stop;
+  bool handles_incremental_state_clear;
 };
 
 // This is implemented by the tracing service and represents the service-
@@ -127,6 +128,7 @@
   // sent in the StartDataSource call.
   StopDataSource(uint64 id) => ();
   Flush(uint64 flush_request_id, array<uint64> data_source_ids);
+  ClearIncrementalState();
 };
 
 // This is implemented by the tracing service, and is essentially a singleton
diff --git a/third_party/blink/PRESUBMIT.py b/third_party/blink/PRESUBMIT.py
index 6acac54..e6b80501 100644
--- a/third_party/blink/PRESUBMIT.py
+++ b/third_party/blink/PRESUBMIT.py
@@ -39,10 +39,6 @@
         return input_api.FilterSourceFile(path,
                                           black_list=[r'third_party/blink/common/', r'third_party/blink/public/common'])
 
-    # The list of files that we specifically want to allow including
-    # -blink variant files (e.g. because it has #if INSIDE_BLINK).
-    allow_blink_files = [r'third_party/blink/public/platform/modules/service_worker/web_service_worker_request.h']
-
     pattern = input_api.re.compile(r'#include\s+.+\.mojom(.*)\.h[>"]')
     public_folder = input_api.os_path.normpath('third_party/blink/public/')
     non_blink_mojom_errors = []
@@ -56,8 +52,7 @@
             match = pattern.match(line)
             if match:
                 if match.group(1) != '-shared':
-                    if f.LocalPath().startswith(public_folder) and \
-                            not f.LocalPath() in allow_blink_files:
+                    if f.LocalPath().startswith(public_folder):
                         error_list = public_blink_mojom_errors
                     elif match.group(1) not in ('-blink', '-blink-forward', '-blink-test-utils'):
                         # Neither -shared.h, -blink.h, -blink-forward.h nor -blink-test-utils.h.
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index bbcda6f..ba033271 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -238,13 +238,6 @@
 const base::Feature kForbidSyncXHRInPageDismissal{
     "ForbidSyncXHRInPageDismissal", base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Emergency lever that can be used to restore DeviceOrientationEvent and
-// DeviceMotionEvent functionality in non-secure browsing contexts.
-// See: https://crbug.com/932078.
-const base::Feature kRestrictDeviceSensorEventsToSecureContexts{
-    "RestrictDeviceSensorEventsToSecureContexts",
-    base::FEATURE_ENABLED_BY_DEFAULT};
-
 const char kMixedContentAutoupgradeModeParamName[] = "mode";
 const char kMixedContentAutoupgradeModeBlockable[] = "blockable";
 const char kMixedContentAutoupgradeModeOptionallyBlockable[] =
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn
index 6ce6667..97d8605 100644
--- a/third_party/blink/public/BUILD.gn
+++ b/third_party/blink/public/BUILD.gn
@@ -127,7 +127,6 @@
     "platform/linux/web_sandbox_support.h",
     "platform/mac/web_sandbox_support.h",
     "platform/mac/web_scrollbar_theme.h",
-    "platform/modules/background_fetch/web_background_fetch_registration.h",
     "platform/modules/indexeddb/web_idb_database_exception.h",
     "platform/modules/media_capabilities/web_audio_configuration.h",
     "platform/modules/media_capabilities/web_media_capabilities_decoding_info.h",
@@ -150,30 +149,17 @@
     "platform/modules/mediastream/web_platform_media_stream_source.h",
     "platform/modules/mediastream/web_platform_media_stream_track.h",
     "platform/modules/mediastream/webrtc_uma_histograms.h",
-    "platform/modules/notifications/web_notification_action.h",
-    "platform/modules/notifications/web_notification_constants.h",
-    "platform/modules/notifications/web_notification_data.h",
-    "platform/modules/payments/web_payment_currency_amount.h",
-    "platform/modules/payments/web_payment_details_modifier.h",
-    "platform/modules/payments/web_payment_handler_response.h",
-    "platform/modules/payments/web_payment_item.h",
-    "platform/modules/payments/web_payment_method_data.h",
-    "platform/modules/payments/web_payment_request_event_data.h",
     "platform/modules/push_messaging/web_push_client.h",
     "platform/modules/push_messaging/web_push_error.h",
     "platform/modules/push_messaging/web_push_subscription.h",
     "platform/modules/remoteplayback/web_remote_playback_client.h",
-    "platform/modules/service_worker/web_service_worker_clients_info.h",
     "platform/modules/service_worker/web_service_worker_error.h",
     "platform/modules/service_worker/web_service_worker_network_provider.h",
     "platform/modules/service_worker/web_service_worker_object_info.h",
     "platform/modules/service_worker/web_service_worker_provider.h",
     "platform/modules/service_worker/web_service_worker_provider_client.h",
     "platform/modules/service_worker/web_service_worker_registration_object_info.h",
-    "platform/modules/service_worker/web_service_worker_request.h",
-    "platform/modules/service_worker/web_service_worker_response.h",
     "platform/modules/service_worker/web_service_worker_stream_handle.h",
-    "platform/notification_data_conversions.h",
     "platform/platform.h",
     "platform/pointer_properties.h",
     "platform/scheduler/web_rail_mode_observer.h",
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index 5abc41f..1fc85ce 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -65,8 +65,6 @@
 BLINK_COMMON_EXPORT extern const base::Feature kNativeFileSystemAPI;
 BLINK_COMMON_EXPORT extern const base::Feature kFileHandlingAPI;
 BLINK_COMMON_EXPORT extern const base::Feature kForbidSyncXHRInPageDismissal;
-BLINK_COMMON_EXPORT extern const base::Feature
-    kRestrictDeviceSensorEventsToSecureContexts;
 
 BLINK_COMMON_EXPORT extern const char kMixedContentAutoupgradeModeParamName[];
 BLINK_COMMON_EXPORT extern const char kMixedContentAutoupgradeModeBlockable[];
diff --git a/third_party/blink/public/mojom/web_feature/web_feature.mojom b/third_party/blink/public/mojom/web_feature/web_feature.mojom
index 7da540d..74f4164 100644
--- a/third_party/blink/public/mojom/web_feature/web_feature.mojom
+++ b/third_party/blink/public/mojom/web_feature/web_feature.mojom
@@ -408,9 +408,9 @@
   kGetUserMediaSecureOrigin = 667,
   // The above items are available in M41 branch.
 
-  kDeviceMotionInsecureOrigin = 668,
+  kDeviceMotionInsecureOrigin_Obsolete = 668,
   kDeviceMotionSecureOrigin = 669,
-  kDeviceOrientationInsecureOrigin = 670,
+  kDeviceOrientationInsecureOrigin_Obsolete = 670,
   kDeviceOrientationSecureOrigin = 671,
   kSandboxViaIFrame = 672,
   kSandboxViaCSP = 673,
@@ -642,7 +642,7 @@
   kExternalAddSearchProvider = 981,
   kExternalIsSearchProviderInstalled = 982,
   kV8Permissions_RequestAll_Method = 983,
-  kDeviceOrientationAbsoluteInsecureOrigin = 987,
+  kDeviceOrientationAbsoluteInsecureOrigin_Obsolete = 987,
   kDeviceOrientationAbsoluteSecureOrigin = 988,
   kFontFaceConstructor = 989,
   kServiceWorkerControlledPage = 990,
@@ -2296,6 +2296,13 @@
   kNonPassiveTouchEventListener = 2903,
   kPassiveTouchEventListener = 2904,
   kCSSValueAppearanceSearchCancelForOthers2Rendered = 2905,
+  kWebXrFramebufferScale = 2906,
+  kWebXrIgnoreDepthValues = 2907,
+  kWebXrSessionCreated = 2908,
+  kV8XRReferenceSpace_GetOffsetReferenceSpace_Method = 2909,
+  kV8XRInputSource_Gamepad_AttributeGetter = 2910,
+  kV8XRSession_End_Method = 2911,
+  kV8XRWebGLLayer_Constructor = 2912,
 
   // Add new features immediately above this line. Don't change assigned
   // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/public/platform/modules/background_fetch/web_background_fetch_registration.h b/third_party/blink/public/platform/modules/background_fetch/web_background_fetch_registration.h
deleted file mode 100644
index ec1113d..0000000
--- a/third_party/blink/public/platform/modules/background_fetch/web_background_fetch_registration.h
+++ /dev/null
@@ -1,59 +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 THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_BACKGROUND_FETCH_WEB_BACKGROUND_FETCH_REGISTRATION_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_BACKGROUND_FETCH_WEB_BACKGROUND_FETCH_REGISTRATION_H_
-
-#include "mojo/public/cpp/system/message_pipe.h"
-#include "third_party/blink/public/mojom/background_fetch/background_fetch.mojom-shared.h"
-#include "third_party/blink/public/platform/web_common.h"
-#include "third_party/blink/public/platform/web_string.h"
-
-namespace blink {
-
-// Represents a BackgroundFetchRegistration object, added mainly for layering.
-// Analogous to the following structure in the spec:
-// https://wicg.github.io/background-fetch/#background-fetch-registration
-// Also contains a message pipe for registration functionality.
-struct WebBackgroundFetchRegistration {
-  WebBackgroundFetchRegistration(
-      const WebString& developer_id,
-      uint64_t upload_total,
-      uint64_t uploaded,
-      uint64_t download_total,
-      uint64_t downloaded,
-      mojom::BackgroundFetchResult result,
-      mojom::BackgroundFetchFailureReason failure_reason,
-      mojo::ScopedMessagePipeHandle registration_service_handle,
-      uint32_t registration_service_version)
-      : developer_id(developer_id),
-        upload_total(upload_total),
-        uploaded(uploaded),
-        download_total(download_total),
-        downloaded(downloaded),
-        result(result),
-        failure_reason(failure_reason),
-        registration_service_handle(std::move(registration_service_handle)),
-        registration_service_version(registration_service_version) {}
-
-  ~WebBackgroundFetchRegistration() = default;
-  WebBackgroundFetchRegistration(WebBackgroundFetchRegistration&&) = default;
-
-  WebString developer_id;
-  uint64_t upload_total;
-  uint64_t uploaded;
-  uint64_t download_total;
-  uint64_t downloaded;
-  mojom::BackgroundFetchResult result;
-  mojom::BackgroundFetchFailureReason failure_reason;
-
-  // This should be connected to the BackgroundFetchRegistrationService
-  // interface.
-  mojo::ScopedMessagePipeHandle registration_service_handle;
-  uint32_t registration_service_version;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_BACKGROUND_FETCH_WEB_BACKGROUND_FETCH_REGISTRATION_H_
diff --git a/third_party/blink/public/platform/modules/notifications/web_notification_action.h b/third_party/blink/public/platform/modules/notifications/web_notification_action.h
deleted file mode 100644
index 932a23c..0000000
--- a/third_party/blink/public/platform/modules/notifications/web_notification_action.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_NOTIFICATIONS_WEB_NOTIFICATION_ACTION_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_NOTIFICATIONS_WEB_NOTIFICATION_ACTION_H_
-
-#include "third_party/blink/public/platform/web_string.h"
-#include "third_party/blink/public/platform/web_url.h"
-
-namespace blink {
-
-// Structure representing the data associated with a Web Notification action.
-struct WebNotificationAction {
-  // Corresponds to NotificationActionType.
-  enum Type { kButton = 0, kText };
-
-  Type type;
-  WebString action;
-  WebString title;
-  WebURL icon;
-  WebString placeholder;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_NOTIFICATIONS_WEB_NOTIFICATION_ACTION_H_
diff --git a/third_party/blink/public/platform/modules/notifications/web_notification_data.h b/third_party/blink/public/platform/modules/notifications/web_notification_data.h
deleted file mode 100644
index 8d2a75ed..0000000
--- a/third_party/blink/public/platform/modules/notifications/web_notification_data.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_NOTIFICATIONS_WEB_NOTIFICATION_DATA_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_NOTIFICATIONS_WEB_NOTIFICATION_DATA_H_
-
-#include "base/optional.h"
-#include "base/time/time.h"
-#include "third_party/blink/public/mojom/notifications/notification.mojom-shared.h"
-#include "third_party/blink/public/platform/modules/notifications/web_notification_action.h"
-#include "third_party/blink/public/platform/web_string.h"
-#include "third_party/blink/public/platform/web_url.h"
-#include "third_party/blink/public/platform/web_vector.h"
-
-namespace blink {
-
-// Structure representing the data associated with a Web Notification.
-// Currently we're using the corresponding mojom struct
-// blink::mojom::blink::NotificationData everywhere inside Blink,
-// WebNotificationData is only used to carry notification data across the
-// boundary between Content layer and Blink (the only two functions:
-// WebServiceWorkerContextProxy::DispatchNotification{Click, Close}Event),
-// ultimately WebNotificationData will also be replaced by the mojom one there
-// via Onion Soup effort.
-struct WebNotificationData {
-  WebString title;
-  mojom::NotificationDirection direction =
-      mojom::NotificationDirection::LEFT_TO_RIGHT;
-  WebString lang;
-  WebString body;
-  WebString tag;
-  WebURL image;
-  WebURL icon;
-  WebURL badge;
-  WebVector<int> vibrate;
-  double timestamp = 0;
-  bool renotify = false;
-  bool silent = false;
-  bool require_interaction = false;
-  WebVector<char> data;
-  WebVector<WebNotificationAction> actions;
-  base::Optional<base::Time> show_trigger_timestamp;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_NOTIFICATIONS_WEB_NOTIFICATION_DATA_H_
diff --git a/third_party/blink/public/platform/modules/payments/OWNERS b/third_party/blink/public/platform/modules/payments/OWNERS
deleted file mode 100644
index 156471c..0000000
--- a/third_party/blink/public/platform/modules/payments/OWNERS
+++ /dev/null
@@ -1,10 +0,0 @@
-# TEAM: paymentrequest@chromium.org
-# COMPONENT: Blink>Payments
-
-jinho.bang@samsung.com
-mathp@chromium.org
-mek@chromium.org
-rouslan@chromium.org
-
-per-file *.mojom=set noparent
-per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/third_party/blink/public/platform/modules/payments/web_can_make_payment_event_data.h b/third_party/blink/public/platform/modules/payments/web_can_make_payment_event_data.h
deleted file mode 100644
index 2b79733..0000000
--- a/third_party/blink/public/platform/modules/payments/web_can_make_payment_event_data.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PAYMENTS_WEB_CAN_MAKE_PAYMENT_EVENT_DATA_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PAYMENTS_WEB_CAN_MAKE_PAYMENT_EVENT_DATA_H_
-
-#include "third_party/blink/public/platform/modules/payments/web_payment_details_modifier.h"
-#include "third_party/blink/public/platform/modules/payments/web_payment_item.h"
-#include "third_party/blink/public/platform/modules/payments/web_payment_method_data.h"
-#include "third_party/blink/public/platform/web_string.h"
-#include "third_party/blink/public/platform/web_vector.h"
-
-namespace blink {
-
-struct WebCanMakePaymentEventData {
-  WebString top_origin;
-  WebString payment_request_origin;
-  WebVector<WebPaymentMethodData> method_data;
-  WebVector<WebPaymentDetailsModifier> modifiers;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PAYMENTS_WEB_CAN_MAKE_PAYMENT_EVENT_DATA_H_
diff --git a/third_party/blink/public/platform/modules/payments/web_payment_currency_amount.h b/third_party/blink/public/platform/modules/payments/web_payment_currency_amount.h
deleted file mode 100644
index a078bea..0000000
--- a/third_party/blink/public/platform/modules/payments/web_payment_currency_amount.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PAYMENTS_WEB_PAYMENT_CURRENCY_AMOUNT_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PAYMENTS_WEB_PAYMENT_CURRENCY_AMOUNT_H_
-
-#include "third_party/blink/public/platform/web_string.h"
-
-namespace blink {
-
-// https://w3c.github.io/browser-payment-api/#paymentcurrencyamount-dictionary
-struct WebPaymentCurrencyAmount {
-  WebString currency;
-  WebString value;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PAYMENTS_WEB_PAYMENT_CURRENCY_AMOUNT_H_
diff --git a/third_party/blink/public/platform/modules/payments/web_payment_details_modifier.h b/third_party/blink/public/platform/modules/payments/web_payment_details_modifier.h
deleted file mode 100644
index 0c1bf2b..0000000
--- a/third_party/blink/public/platform/modules/payments/web_payment_details_modifier.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PAYMENTS_WEB_PAYMENT_DETAILS_MODIFIER_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PAYMENTS_WEB_PAYMENT_DETAILS_MODIFIER_H_
-
-#include "third_party/blink/public/platform/modules/payments/web_payment_item.h"
-#include "third_party/blink/public/platform/web_string.h"
-#include "third_party/blink/public/platform/web_vector.h"
-
-namespace blink {
-
-// https://w3c.github.io/browser-payment-api/#paymentdetailsmodifier-dictionary
-struct WebPaymentDetailsModifier {
-  WebString supported_method;
-  WebPaymentItem total;
-  WebVector<WebPaymentItem> additional_display_items;
-  WebString stringified_data;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PAYMENTS_WEB_PAYMENT_DETAILS_MODIFIER_H_
diff --git a/third_party/blink/public/platform/modules/payments/web_payment_handler_response.h b/third_party/blink/public/platform/modules/payments/web_payment_handler_response.h
deleted file mode 100644
index eab2235..0000000
--- a/third_party/blink/public/platform/modules/payments/web_payment_handler_response.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PAYMENTS_WEB_PAYMENT_HANDLER_RESPONSE_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PAYMENTS_WEB_PAYMENT_HANDLER_RESPONSE_H_
-
-#include "third_party/blink/public/platform/web_string.h"
-
-namespace blink {
-
-// https://w3c.github.io/payment-handler/#paymenthandlerresponse-dictionary
-struct WebPaymentHandlerResponse {
-  WebString method_name;
-  WebString stringified_details;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PAYMENTS_WEB_PAYMENT_HANDLER_RESPONSE_H_
diff --git a/third_party/blink/public/platform/modules/payments/web_payment_item.h b/third_party/blink/public/platform/modules/payments/web_payment_item.h
deleted file mode 100644
index f271eed..0000000
--- a/third_party/blink/public/platform/modules/payments/web_payment_item.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PAYMENTS_WEB_PAYMENT_ITEM_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PAYMENTS_WEB_PAYMENT_ITEM_H_
-
-#include "third_party/blink/public/platform/modules/payments/web_payment_currency_amount.h"
-#include "third_party/blink/public/platform/web_string.h"
-
-namespace blink {
-
-// https://w3c.github.io/browser-payment-api/#paymentitem-dictionary
-struct WebPaymentItem {
-  WebString label;
-  WebPaymentCurrencyAmount amount;
-  bool pending = false;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PAYMENTS_WEB_PAYMENT_ITEM_H_
diff --git a/third_party/blink/public/platform/modules/payments/web_payment_method_data.h b/third_party/blink/public/platform/modules/payments/web_payment_method_data.h
deleted file mode 100644
index bdd1821..0000000
--- a/third_party/blink/public/platform/modules/payments/web_payment_method_data.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PAYMENTS_WEB_PAYMENT_METHOD_DATA_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PAYMENTS_WEB_PAYMENT_METHOD_DATA_H_
-
-#include "third_party/blink/public/platform/modules/payments/web_payment_details_modifier.h"
-#include "third_party/blink/public/platform/modules/payments/web_payment_item.h"
-#include "third_party/blink/public/platform/modules/payments/web_payment_method_data.h"
-#include "third_party/blink/public/platform/web_string.h"
-#include "third_party/blink/public/platform/web_vector.h"
-
-namespace blink {
-
-// https://w3c.github.io/browser-payment-api/#paymentmethoddata-dictionary
-struct WebPaymentMethodData {
-  WebString supported_method;
-  WebString stringified_data;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PAYMENTS_WEB_PAYMENT_METHOD_DATA_H_
diff --git a/third_party/blink/public/platform/modules/payments/web_payment_request_event_data.h b/third_party/blink/public/platform/modules/payments/web_payment_request_event_data.h
deleted file mode 100644
index 0fb042a..0000000
--- a/third_party/blink/public/platform/modules/payments/web_payment_request_event_data.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PAYMENTS_WEB_PAYMENT_REQUEST_EVENT_DATA_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PAYMENTS_WEB_PAYMENT_REQUEST_EVENT_DATA_H_
-
-#include "mojo/public/cpp/system/message_pipe.h"
-#include "third_party/blink/public/platform/modules/payments/web_can_make_payment_event_data.h"
-#include "third_party/blink/public/platform/modules/payments/web_payment_currency_amount.h"
-#include "third_party/blink/public/platform/web_string.h"
-
-namespace blink {
-
-struct WebPaymentRequestEventData : public WebCanMakePaymentEventData {
-  WebString payment_request_id;
-  WebString instrument_key;
-  WebPaymentCurrencyAmount total;
-  // For payments::mojom::blink::PaymentHandlerHost.
-  mojo::ScopedMessagePipeHandle payment_handler_host_handle;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PAYMENTS_WEB_PAYMENT_REQUEST_EVENT_DATA_H_
diff --git a/third_party/blink/public/platform/modules/service_worker/web_service_worker_clients_info.h b/third_party/blink/public/platform/modules/service_worker/web_service_worker_clients_info.h
deleted file mode 100644
index 99569ad..0000000
--- a/third_party/blink/public/platform/modules/service_worker/web_service_worker_clients_info.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_SERVICE_WORKER_WEB_SERVICE_WORKER_CLIENTS_INFO_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_SERVICE_WORKER_WEB_SERVICE_WORKER_CLIENTS_INFO_H_
-
-#include "third_party/blink/public/mojom/loader/request_context_frame_type.mojom-shared.h"
-#include "third_party/blink/public/mojom/service_worker/service_worker_client.mojom-shared.h"
-#include "third_party/blink/public/platform/web_string.h"
-#include "third_party/blink/public/platform/web_url.h"
-
-namespace blink {
-
-// The only usage of this class is to carry the source of an extendable message
-// dispatched via content.mojom.ServiceWorker across the boundary of Content and
-// Blink.
-// TODO(crbug.com/879019): Remove this class once we move
-// content.mojom.ServiceWorker impl into Blink.
-struct WebServiceWorkerClientInfo {
-  WebServiceWorkerClientInfo() = default;
-
-  WebString uuid;
-
-  bool page_hidden = true;
-  bool is_focused = false;
-  WebURL url;
-  network::mojom::RequestContextFrameType frame_type =
-      network::mojom::RequestContextFrameType::kNone;
-  mojom::ServiceWorkerClientType client_type =
-      mojom::ServiceWorkerClientType::kWindow;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_SERVICE_WORKER_WEB_SERVICE_WORKER_CLIENTS_INFO_H_
diff --git a/third_party/blink/public/platform/modules/service_worker/web_service_worker_object_info.h b/third_party/blink/public/platform/modules/service_worker/web_service_worker_object_info.h
index 8eceeaa..052eb1b 100644
--- a/third_party/blink/public/platform/modules/service_worker/web_service_worker_object_info.h
+++ b/third_party/blink/public/platform/modules/service_worker/web_service_worker_object_info.h
@@ -16,7 +16,6 @@
 // across the boundary into Blink.
 // TODO(crbug.com/879019): Remove this class once we make the following Mojo
 // interfaces receive blink.mojom.ServiceWorkerObjectInfo directly inside Blink.
-//  - content.mojom.ServiceWorker
 //  - content.mojom.ServiceWorkerContainer
 //
 // As we're on the border line between non-Blink and Blink variants, we need
diff --git a/third_party/blink/public/platform/modules/service_worker/web_service_worker_request.h b/third_party/blink/public/platform/modules/service_worker/web_service_worker_request.h
deleted file mode 100644
index a9b0061..0000000
--- a/third_party/blink/public/platform/modules/service_worker/web_service_worker_request.h
+++ /dev/null
@@ -1,130 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_SERVICE_WORKER_WEB_SERVICE_WORKER_REQUEST_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_SERVICE_WORKER_WEB_SERVICE_WORKER_REQUEST_H_
-
-#include "mojo/public/cpp/system/message_pipe.h"
-#include "services/network/public/mojom/referrer_policy.mojom-shared.h"
-#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
-#include "third_party/blink/public/mojom/loader/request_context_frame_type.mojom-shared.h"
-#include "third_party/blink/public/platform/web_common.h"
-#include "third_party/blink/public/platform/web_private_ptr.h"
-#include "third_party/blink/public/platform/web_string.h"
-#include "third_party/blink/public/platform/web_url.h"
-#include "third_party/blink/public/platform/web_url_request.h"
-
-#if INSIDE_BLINK
-#include <utility>
-#include "third_party/blink/renderer/platform/network/http_header_map.h"  // nogncheck
-#include "third_party/blink/renderer/platform/weborigin/referrer.h"  // nogncheck
-#include "third_party/blink/renderer/platform/wtf/forward.h"  // nogncheck
-#include "third_party/blink/renderer/platform/wtf/text/string_hash.h"  // nogncheck
-#endif
-
-namespace base {
-class UnguessableToken;
-}
-namespace blink {
-
-class WebHTTPHeaderVisitor;
-class WebServiceWorkerRequestPrivate;
-
-// Represents a request for a web resource.
-//
-// Now this is used only to carry the request data of a fetch event dispatched
-// towards a service worker, from //content across the boundary into Blink.
-// TODO(crbug.com/879019): Remove this class once we make the following Mojo
-// interface receive the fetch event directly inside Blink.
-//  - content.mojom.ServiceWorker
-class BLINK_PLATFORM_EXPORT WebServiceWorkerRequest {
- public:
-  ~WebServiceWorkerRequest() { Reset(); }
-  WebServiceWorkerRequest();
-  WebServiceWorkerRequest(const WebServiceWorkerRequest& other) {
-    Assign(other);
-  }
-  WebServiceWorkerRequest& operator=(const WebServiceWorkerRequest& other) {
-    Assign(other);
-    return *this;
-  }
-
-  void Reset();
-  void Assign(const WebServiceWorkerRequest&);
-
-  void SetURL(const WebURL&);
-  const WebURL& Url() const;
-
-  void SetMethod(const WebString&);
-  const WebString& Method() const;
-
-  void SetHeader(const WebString& key, const WebString& value);
-
-  // If the key already exists, the value is appended to the existing value
-  // with a comma delimiter between them.
-  void AppendHeader(const WebString& key, const WebString& value);
-
-  void VisitHttpHeaderFields(WebHTTPHeaderVisitor*) const;
-
-  void SetBody(const WebHTTPBody&);
-  WebHTTPBody Body() const;
-
-  void SetReferrer(const WebString&, network::mojom::ReferrerPolicy);
-  WebURL ReferrerUrl() const;
-  network::mojom::ReferrerPolicy GetReferrerPolicy() const;
-
-  void SetMode(network::mojom::FetchRequestMode);
-  network::mojom::FetchRequestMode Mode() const;
-
-  void SetIsMainResourceLoad(bool);
-  bool IsMainResourceLoad() const;
-
-  void SetCredentialsMode(network::mojom::FetchCredentialsMode);
-  network::mojom::FetchCredentialsMode CredentialsMode() const;
-
-  void SetIntegrity(const WebString&);
-  const WebString& Integrity() const;
-
-  void SetPriority(WebURLRequest::Priority);
-  WebURLRequest::Priority Priority() const;
-
-  void SetCacheMode(mojom::FetchCacheMode);
-  mojom::FetchCacheMode CacheMode() const;
-
-  void SetKeepalive(bool);
-  bool Keepalive() const;
-
-  void SetRedirectMode(network::mojom::FetchRedirectMode);
-  network::mojom::FetchRedirectMode RedirectMode() const;
-
-  void SetRequestContext(mojom::RequestContextType);
-  mojom::RequestContextType GetRequestContext() const;
-
-  void SetFrameType(network::mojom::RequestContextFrameType);
-  network::mojom::RequestContextFrameType GetFrameType() const;
-
-  void SetClientId(const WebString&);
-  const WebString& ClientId() const;
-
-  void SetIsReload(bool);
-  bool IsReload() const;
-
-  void SetIsHistoryNavigation(bool);
-  bool IsHistoryNavigation() const;
-
-  void SetWindowId(const base::UnguessableToken&);
-  const base::UnguessableToken& GetWindowId() const;
-
-#if INSIDE_BLINK
-  const HTTPHeaderMap& Headers() const;
-  const Referrer& GetReferrer() const;
-#endif
-
- private:
-  WebPrivatePtr<WebServiceWorkerRequestPrivate> private_;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_SERVICE_WORKER_WEB_SERVICE_WORKER_REQUEST_H_
diff --git a/third_party/blink/public/platform/modules/service_worker/web_service_worker_response.h b/third_party/blink/public/platform/modules/service_worker/web_service_worker_response.h
deleted file mode 100644
index 43bf142..0000000
--- a/third_party/blink/public/platform/modules/service_worker/web_service_worker_response.h
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_SERVICE_WORKER_WEB_SERVICE_WORKER_RESPONSE_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_SERVICE_WORKER_WEB_SERVICE_WORKER_RESPONSE_H_
-
-#include "base/time/time.h"
-#include "mojo/public/cpp/system/message_pipe.h"
-#include "services/network/public/mojom/fetch_api.mojom-shared.h"
-#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
-#include "third_party/blink/public/mojom/service_worker/service_worker_error_type.mojom-shared.h"
-#include "third_party/blink/public/platform/web_common.h"
-#include "third_party/blink/public/platform/web_private_ptr.h"
-#include "third_party/blink/public/platform/web_string.h"
-#include "third_party/blink/public/platform/web_url.h"
-#include "third_party/blink/public/platform/web_vector.h"
-
-#if INSIDE_BLINK
-#include "third_party/blink/renderer/platform/wtf/forward.h"   // nogncheck
-#include "third_party/blink/renderer/platform/wtf/hash_map.h"  // nogncheck
-#include "third_party/blink/renderer/platform/wtf/text/string_hash.h"  // nogncheck
-#endif
-
-namespace blink {
-
-class BlobDataHandle;
-class HTTPHeaderMap;
-class WebHTTPHeaderVisitor;
-class WebServiceWorkerResponsePrivate;
-
-// Represents a response to a fetch operation. ServiceWorker uses this to
-// respond to a FetchEvent dispatched by the browser. The plan is for the Cache
-// and fetch() API to also use it.
-class BLINK_PLATFORM_EXPORT WebServiceWorkerResponse {
- public:
-  ~WebServiceWorkerResponse() { Reset(); }
-  WebServiceWorkerResponse();
-  WebServiceWorkerResponse(const WebServiceWorkerResponse& other) {
-    Assign(other);
-  }
-  WebServiceWorkerResponse& operator=(const WebServiceWorkerResponse& other) {
-    Assign(other);
-    return *this;
-  }
-
-  void Reset();
-  void Assign(const WebServiceWorkerResponse&);
-
-  void SetURLList(const WebVector<WebURL>&);
-  const WebVector<WebURL>& UrlList() const;
-
-  void SetStatus(uint16_t);
-  uint16_t Status() const;
-
-  void SetStatusText(const WebString&);
-  const WebString& StatusText() const;
-
-  void SetResponseType(network::mojom::FetchResponseType);
-  network::mojom::FetchResponseType ResponseType() const;
-
-  void SetResponseSource(network::mojom::FetchResponseSource);
-  network::mojom::FetchResponseSource ResponseSource() const;
-
-  void SetHeader(const WebString& key, const WebString& value);
-
-  // If the key already exists, appends the value to the same key (comma
-  // delimited) else creates a new entry.
-  void AppendHeader(const WebString& key, const WebString& value);
-
-  WebVector<WebString> GetHeaderKeys() const;
-  WebString GetHeader(const WebString& key) const;
-  void VisitHttpHeaderFields(WebHTTPHeaderVisitor*) const;
-
-  void SetBlob(const WebString& uuid,
-               uint64_t size,
-               mojo::ScopedMessagePipeHandle);
-  WebString BlobUUID() const;
-  uint64_t BlobSize() const;
-
-  mojo::ScopedMessagePipeHandle CloneBlobPtr() const;
-
-  WebString SideDataBlobUUID() const;
-  uint64_t SideDataBlobSize() const;
-  mojo::ScopedMessagePipeHandle CloneSideDataBlobPtr() const;
-
-  // Provides a more detailed error when status() is zero.
-  void SetError(mojom::ServiceWorkerResponseError);
-  mojom::ServiceWorkerResponseError GetError() const;
-
-  void SetResponseTime(base::Time);
-  base::Time ResponseTime() const;
-
-  void SetCacheStorageCacheName(const WebString&);
-  const WebString& CacheStorageCacheName() const;
-
-  void SetCorsExposedHeaderNames(const WebVector<WebString>&);
-  const WebVector<WebString>& CorsExposedHeaderNames() const;
-
-#if INSIDE_BLINK
-  const HTTPHeaderMap& Headers() const;
-
-  void SetBlobDataHandle(scoped_refptr<BlobDataHandle>);
-  scoped_refptr<BlobDataHandle> GetBlobDataHandle() const;
-
-  void SetSideDataBlobDataHandle(scoped_refptr<BlobDataHandle>);
-#endif
-
- private:
-  WebPrivatePtr<WebServiceWorkerResponsePrivate> private_;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_SERVICE_WORKER_WEB_SERVICE_WORKER_RESPONSE_H_
diff --git a/third_party/blink/public/platform/notification_data_conversions.h b/third_party/blink/public/platform/notification_data_conversions.h
deleted file mode 100644
index 96aa2fb..0000000
--- a/third_party/blink/public/platform/notification_data_conversions.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_NOTIFICATION_DATA_CONVERSIONS_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_NOTIFICATION_DATA_CONVERSIONS_H_
-
-#include "third_party/blink/public/common/notifications/platform_notification_data.h"
-#include "third_party/blink/public/platform/modules/notifications/web_notification_data.h"
-
-namespace blink {
-
-// Converts blink::PlatformNotificationData to Blink WebNotificationData.
-BLINK_PLATFORM_EXPORT WebNotificationData
-ToWebNotificationData(const PlatformNotificationData& platform_data);
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_NOTIFICATION_DATA_CONVERSIONS_H_
diff --git a/third_party/blink/public/platform/platform.h b/third_party/blink/public/platform/platform.h
index 23173b3..2697e8f 100644
--- a/third_party/blink/public/platform/platform.h
+++ b/third_party/blink/public/platform/platform.h
@@ -659,6 +659,10 @@
       const WebSecurityOrigin& script_origin) {
     return false;
   }
+  virtual bool IsExcludedHeaderForServiceWorkerFetchEvent(
+      const WebString& header_name) {
+    return false;
+  }
 
   // WebCrypto ----------------------------------------------------------
 
diff --git a/third_party/blink/public/platform/web_media_stream_track.h b/third_party/blink/public/platform/web_media_stream_track.h
index 9234b84..05a1bacb 100644
--- a/third_party/blink/public/platform/web_media_stream_track.h
+++ b/third_party/blink/public/platform/web_media_stream_track.h
@@ -60,7 +60,6 @@
     bool HasSampleSize() const { return sample_size >= 0; }
     bool HasChannelCount() const { return channel_count >= 0; }
     bool HasLatency() const { return latency >= 0; }
-    bool HasVolume() const { return volume >= 0; }
     bool HasVideoKind() const { return !video_kind.IsNull(); }
     // The variables are read from
     // MediaStreamTrack::GetSettings only.
@@ -80,7 +79,6 @@
     int32_t sample_size = -1;
     int32_t channel_count = -1;
     double latency = -1.0;
-    double volume = -1.0;
 
     // Media Capture Depth Stream Extensions.
     WebString video_kind;
diff --git a/third_party/blink/public/platform/web_runtime_features.h b/third_party/blink/public/platform/web_runtime_features.h
index d6998821..92fdb45 100644
--- a/third_party/blink/public/platform/web_runtime_features.h
+++ b/third_party/blink/public/platform/web_runtime_features.h
@@ -165,8 +165,6 @@
   BLINK_PLATFORM_EXPORT static void EnableRemotePlaybackAPI(bool);
   BLINK_PLATFORM_EXPORT static void EnableRenderingPipelineThrottling(bool);
   BLINK_PLATFORM_EXPORT static void EnableResourceLoadScheduler(bool);
-  BLINK_PLATFORM_EXPORT static void
-  EnableRestrictDeviceSensorEventsToSecureContexts(bool);
   BLINK_PLATFORM_EXPORT static void EnableRestrictLazyFrameLoadingToDataSaver(
       bool);
   BLINK_PLATFORM_EXPORT static void EnableRestrictLazyImageLoadingToDataSaver(
diff --git a/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h b/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h
index 66d88e1..f0b597aa 100644
--- a/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h
+++ b/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h
@@ -35,10 +35,10 @@
 
 #include "base/memory/scoped_refptr.h"
 #include "base/time/time.h"
+#include "mojo/public/cpp/system/message_pipe.h"
 #include "third_party/blink/public/mojom/devtools/console_message.mojom-shared.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom-shared.h"
 #include "third_party/blink/public/mojom/web_feature/web_feature.mojom-shared.h"
-#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_stream_handle.h"
 #include "third_party/blink/public/platform/web_url.h"
 #include "third_party/blink/public/platform/web_worker_fetch_context.h"
 #include "v8/include/v8.h"
@@ -49,12 +49,19 @@
 
 namespace blink {
 
-struct WebPaymentHandlerResponse;
 class WebServiceWorkerContextProxy;
 class WebServiceWorkerNetworkProvider;
-class WebServiceWorkerResponse;
 class WebString;
 
+// Used to pass the mojom struct blink.mojom.FetchEventPreloadHandle across the
+// boundary between //content and Blink.
+struct WebFetchEventPreloadHandle {
+  // For network::mojom::URLLoaderPtrInfo.
+  mojo::ScopedMessagePipeHandle url_loader;
+  // For network::mojom::URLLoaderClientRequest.
+  mojo::ScopedMessagePipeHandle url_loader_client_request;
+};
+
 // WebServiceWorkerContextClient is a "client" of a service worker execution
 // context. This interface is implemented by the embedder and allows the
 // embedder to communicate with the service worker execution context.  It is
@@ -65,6 +72,8 @@
 // thread.
 class WebServiceWorkerContextClient {
  public:
+  using RequestTerminationCallback = base::OnceCallback<void(bool)>;
+
   virtual ~WebServiceWorkerContextClient() = default;
 
   // ServiceWorker has prepared everything for script loading and is now ready
@@ -169,127 +178,15 @@
                                     int line_number,
                                     const WebString& source_url) {}
 
-  // Called after an 'activate' event completed.
-  virtual void DidHandleActivateEvent(int event_id,
-                                      mojom::ServiceWorkerEventStatus) {}
-
-  // Called after Background Fetch events (dispatched via
-  // WebServiceWorkerContextProxy) are handled by the service worker.
-  virtual void DidHandleBackgroundFetchAbortEvent(
-      int event_id,
-      mojom::ServiceWorkerEventStatus) {}
-  virtual void DidHandleBackgroundFetchClickEvent(
-      int event_id,
-      mojom::ServiceWorkerEventStatus) {}
-  virtual void DidHandleBackgroundFetchFailEvent(
-      int event_id,
-      mojom::ServiceWorkerEventStatus) {}
-  virtual void DidHandleBackgroundFetchSuccessEvent(
-      int event_id,
-      mojom::ServiceWorkerEventStatus) {}
-
-  // Called after 'cookiechange' events are handled by the service worker.
-  virtual void DidHandleCookieChangeEvent(int event_id,
-                                          mojom::ServiceWorkerEventStatus) {}
-
-  // Called after ExtendableMessageEvent was handled by the service worker.
-  virtual void DidHandleExtendableMessageEvent(
-      int event_id,
-      mojom::ServiceWorkerEventStatus) {}
-
-  // RespondToFetchEvent* will be called after the service worker returns a
-  // response to a FetchEvent, and DidHandleFetchEvent will be called after the
-  // end of FetchEvent's lifecycle. |fetch_event_id| is the id that was passed
-  // to DispatchFetchEvent.
-
-  // Used when respondWith() is not called. Tells the browser to fall back to
-  // native fetch.
-  virtual void RespondToFetchEventWithNoResponse(
+  // Called when the navigation preload (FetchEvent#preloadResponse) is needed.
+  virtual void SetupNavigationPreload(
       int fetch_event_id,
-      base::TimeTicks event_dispatch_time,
-      base::TimeTicks respond_with_settled_time) {}
-  // Responds to the fetch event with |response|.
-  virtual void RespondToFetchEvent(int fetch_event_id,
-                                   const WebServiceWorkerResponse& response,
-                                   base::TimeTicks event_dispatch_time,
-                                   base::TimeTicks respond_with_settled_time) {}
-  // Responds to the fetch event with |response|, where body is
-  // |body_as_stream|.
-  virtual void RespondToFetchEventWithResponseStream(
-      int fetch_event_id,
-      const WebServiceWorkerResponse& response,
-      WebServiceWorkerStreamHandle* body_as_stream,
-      base::TimeTicks event_dispatch_time,
-      base::TimeTicks respond_with_settled_time) {}
-  virtual void DidHandleFetchEvent(int fetch_event_id,
-                                   mojom::ServiceWorkerEventStatus) {}
+      const WebURL& url,
+      std::unique_ptr<WebFetchEventPreloadHandle> preload_handle) {}
 
-  // Called after InstallEvent (dispatched via WebServiceWorkerContextProxy) is
-  // handled by the service worker.
-  virtual void DidHandleInstallEvent(int install_event_id,
-                                     mojom::ServiceWorkerEventStatus) {}
-
-  // Called after NotificationClickEvent (dispatched via
-  // WebServiceWorkerContextProxy) is handled by the service worker.
-  virtual void DidHandleNotificationClickEvent(
-      int event_id,
-      mojom::ServiceWorkerEventStatus) {}
-
-  // Called after NotificationCloseEvent (dispatched via
-  // WebServiceWorkerContextProxy) is handled by the service worker.
-  virtual void DidHandleNotificationCloseEvent(
-      int event_id,
-      mojom::ServiceWorkerEventStatus) {}
-
-  // Called after PushEvent (dispatched via WebServiceWorkerContextProxy) is
-  // handled by the service worker.
-  virtual void DidHandlePushEvent(int push_event_id,
-                                  mojom::ServiceWorkerEventStatus) {}
-
-  // Called after SyncEvent (dispatched via WebServiceWorkerContextProxy) is
-  // handled by the service worker.
-  virtual void DidHandleSyncEvent(int sync_event_id,
-                                  mojom::ServiceWorkerEventStatus) {}
-
-  // Called after PeriodicSyncEvent (dispatched via
-  // WebServiceWorkerContextProxy) is handled by the service worker.
-  virtual void DidHandlePeriodicSyncEvent(int sync_event_id,
-                                          mojom::ServiceWorkerEventStatus) {}
-
-  // RespondToAbortPaymentEvent will be called after the service worker
-  // returns a response to a AbortPaymentEvent, and DidHandleAbortPaymentEvent
-  // will be called after the end of AbortPaymentEvent's lifecycle.
-  // |event_id| is the id that was passed to DispatchAbortPaymentEvent.
-  virtual void RespondToAbortPaymentEvent(int event_id, bool abort_payment) {}
-  // Called after AbortPaymentEvent (dispatched
-  // via WebServiceWorkerContextProxy) is handled by the service worker.
-  virtual void DidHandleAbortPaymentEvent(int abort_payment_event_id,
-                                          mojom::ServiceWorkerEventStatus) {}
-
-  // RespondToCanMakePaymentEvent will be called after the service worker
-  // returns a response to a CanMakePaymentEvent, and
-  // DidHandleCanMakePaymentEvent will be called after the end of
-  // CanMakePaymentEvent's lifecycle. |event_id| is the id that was passed
-  // to DispatchCanMakePaymentEvent.
-  virtual void RespondToCanMakePaymentEvent(int event_id,
-                                            bool can_make_payment) {}
-  // Called after CanMakePaymentEvent (dispatched
-  // via WebServiceWorkerContextProxy) is handled by the service worker.
-  virtual void DidHandleCanMakePaymentEvent(int payment_request_event_id,
-                                            mojom::ServiceWorkerEventStatus) {}
-
-  // RespondToPaymentRequestEvent will be called after the service worker
-  // returns a response to a PaymentRequestEvent, and
-  // DidHandlePaymentRequestEvent will be called after the end of
-  // PaymentRequestEvent's lifecycle. |event_id| is the id that was passed
-  // to DispatchPaymentRequestEvent.
-  virtual void RespondToPaymentRequestEvent(
-      int event_id,
-      const WebPaymentHandlerResponse& response) {}
-  // Called after PaymentRequestEvent (dispatched via
-  // WebServiceWorkerContextProxy) is handled by the service worker.
-  virtual void DidHandlePaymentRequestEvent(int payment_request_event_id,
-                                            mojom::ServiceWorkerEventStatus) {}
+  // Called when we need to request to terminate this worker due to idle
+  // timeout.
+  virtual void RequestTermination(RequestTerminationCallback) {}
 
   // Called on the main thread.
   virtual std::unique_ptr<WebServiceWorkerNetworkProvider>
@@ -302,16 +199,6 @@
       WebServiceWorkerNetworkProvider*) {
     return nullptr;
   }
-
-  // Called when a task is going to be scheduled on the service worker.
-  // The service worker shouldn't request to be terminated until the task is
-  // finished. Returns an id for the task. The caller must call DidEndTask()
-  // with the returned id to notify that the task is finished.
-  virtual int WillStartTask() { return -1; }
-
-  // Called when a task is finished. |task_id| must be a return value of
-  // WillStartTask().
-  virtual void DidEndTask(int task_id) {}
 };
 
 }  // namespace blink
diff --git a/third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h b/third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h
index f93891a..e473c82 100644
--- a/third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h
+++ b/third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h
@@ -32,111 +32,28 @@
 #define THIRD_PARTY_BLINK_PUBLIC_WEB_MODULES_SERVICE_WORKER_WEB_SERVICE_WORKER_CONTEXT_PROXY_H_
 
 #include "base/time/time.h"
-#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
-#include "third_party/blink/public/common/messaging/transferable_message.h"
-#include "third_party/blink/public/mojom/background_fetch/background_fetch.mojom-shared.h"
-#include "third_party/blink/public/mojom/service_worker/service_worker.mojom-shared.h"
-#include "third_party/blink/public/platform/modules/background_fetch/web_background_fetch_registration.h"
-#include "third_party/blink/public/platform/web_canonical_cookie.h"
+#include "mojo/public/cpp/system/data_pipe.h"
+#include "mojo/public/cpp/system/message_pipe.h"
 
 #include <memory>
 
 namespace blink {
 
-struct WebCanMakePaymentEventData;
-class WebSecurityOrigin;
-class WebServiceWorkerRequest;
-class WebString;
-struct WebNotificationData;
-struct WebPaymentRequestEventData;
-struct WebServiceWorkerClientInfo;
 struct WebServiceWorkerError;
-struct WebServiceWorkerObjectInfo;
-struct WebServiceWorkerRegistrationObjectInfo;
 class WebURLResponse;
 
 // A proxy interface to talk to the worker's GlobalScope implementation.
 // All methods of this class must be called on the worker thread.
 class WebServiceWorkerContextProxy {
  public:
-  using FetchHandlerExistence = mojom::FetchHandlerExistence;
-
   virtual ~WebServiceWorkerContextProxy() = default;
 
-  virtual void BindServiceWorkerHost(
-      mojo::ScopedInterfaceEndpointHandle service_worker_host) = 0;
-
-  virtual void SetRegistration(WebServiceWorkerRegistrationObjectInfo) = 0;
-  virtual void SetFetchHandlerExistence(
-      FetchHandlerExistence fetch_handler_existence) = 0;
-
-  // Script evaluation does not start until this function is called.
-  virtual void ReadyToEvaluateScript() = 0;
-
-  virtual void DispatchActivateEvent(int event_id) = 0;
-
-  virtual void DispatchBackgroundFetchAbortEvent(
-      int event_id,
-      WebBackgroundFetchRegistration registration) = 0;
-  virtual void DispatchBackgroundFetchClickEvent(
-      int event_id,
-      WebBackgroundFetchRegistration registration) = 0;
-  virtual void DispatchBackgroundFetchFailEvent(
-      int event_id,
-      WebBackgroundFetchRegistration registration) = 0;
-  virtual void DispatchBackgroundFetchSuccessEvent(
-      int event_id,
-      WebBackgroundFetchRegistration registration) = 0;
-  virtual void DispatchCookieChangeEvent(
-      int event_id,
-      const WebCanonicalCookie& cookie,
-      network::mojom::CookieChangeCause change_cause) = 0;
-  virtual void DispatchExtendableMessageEvent(
-      int event_id,
-      TransferableMessage,
-      const WebSecurityOrigin& source_origin,
-      const WebServiceWorkerClientInfo&) = 0;
-  virtual void DispatchExtendableMessageEvent(
-      int event_id,
-      TransferableMessage,
-      const WebSecurityOrigin& source_origin,
-      WebServiceWorkerObjectInfo) = 0;
-  virtual void DispatchInstallEvent(int event_id) = 0;
-  virtual void DispatchFetchEvent(int fetch_event_id,
-                                  const WebServiceWorkerRequest& web_request,
-                                  bool navigation_preload_sent) = 0;
-  virtual void DispatchNotificationClickEvent(int event_id,
-                                              const WebString& notification_id,
-                                              const WebNotificationData&,
-                                              int action_index,
-                                              const WebString& reply) = 0;
-  virtual void DispatchNotificationCloseEvent(int event_id,
-                                              const WebString& notification_id,
-                                              const WebNotificationData&) = 0;
-  virtual void DispatchPushEvent(int event_id, const WebString& data) = 0;
-
-  virtual bool HasFetchEventHandler() = 0;
-
-  // Once the ServiceWorker has finished handling the periodicSync event,
-  // DidHandleSyncEvent is called on the context client.
-  virtual void DispatchSyncEvent(int sync_event_id,
-                                 const WebString& tag,
-                                 bool last_chance) = 0;
-
-  // Once the ServiceWorker has finished handling the sync event,
-  // DidHandlePeriodicSyncEvent is called on the context client.
-  virtual void DispatchPeriodicSyncEvent(int sync_event_id,
-                                         const WebString& tag) = 0;
-
-  virtual void DispatchAbortPaymentEvent(int event_id) = 0;
-
-  virtual void DispatchCanMakePaymentEvent(
-      int event_id,
-      const WebCanMakePaymentEventData&) = 0;
-
-  virtual void DispatchPaymentRequestEvent(
-      int event_id,
-      std::unique_ptr<WebPaymentRequestEventData>) = 0;
+  virtual void BindServiceWorker(
+      // A handle for mojom::ServiceWorkerRequest.
+      mojo::ScopedMessagePipeHandle request) = 0;
+  virtual void BindControllerServiceWorker(
+      // A handle for mojom::ControllerServiceWorkerRequest.
+      mojo::ScopedMessagePipeHandle request) = 0;
 
   virtual void OnNavigationPreloadResponse(
       int fetch_event_id,
diff --git a/third_party/blink/renderer/DEPS b/third_party/blink/renderer/DEPS
index 63df6e5..5ba4fc2 100644
--- a/third_party/blink/renderer/DEPS
+++ b/third_party/blink/renderer/DEPS
@@ -38,11 +38,13 @@
     "+base/test/test_simple_task_runner.h",
     "+base/thread_annotations.h",
     "+base/threading/thread_checker.h",
+    "+base/time/default_tick_clock.h",
     "+base/time/time.h",
     "+base/timer/elapsed_timer.h",
     "+base/trace_event/memory_dump_manager.h",
     "+base/trace_event/memory_dump_provider.h",
     "+base/trace_event/trace_event.h",
+    "+base/timer/timer.h",
     "+build",
     "+components/crash/core/common/crash_key.h",
     "+services/network/public/mojom",
diff --git a/third_party/blink/renderer/bindings/core/v8/binding_security_test.cc b/third_party/blink/renderer/bindings/core/v8/binding_security_test.cc
index baa9f58..b81da29 100644
--- a/third_party/blink/renderer/bindings/core/v8/binding_security_test.cc
+++ b/third_party/blink/renderer/bindings/core/v8/binding_security_test.cc
@@ -146,62 +146,80 @@
 
 TEST_P(BindingSecurityCounterTest, CrossOriginWindow) {
   LoadWindowAndAccessProperty(OriginDisposition::CrossOrigin, GetParam());
-  EXPECT_TRUE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
-      WebFeature::kCrossOriginPropertyAccess));
-  EXPECT_TRUE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
-      WebFeature::kCrossOriginPropertyAccessFromOpener));
-  EXPECT_FALSE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
-      WebFeature::kDocumentDomainEnabledCrossOriginAccess));
+  EXPECT_TRUE(
+      GetDocument().Loader()->GetUseCounterHelper().HasRecordedMeasurement(
+          WebFeature::kCrossOriginPropertyAccess));
+  EXPECT_TRUE(
+      GetDocument().Loader()->GetUseCounterHelper().HasRecordedMeasurement(
+          WebFeature::kCrossOriginPropertyAccessFromOpener));
+  EXPECT_FALSE(
+      GetDocument().Loader()->GetUseCounterHelper().HasRecordedMeasurement(
+          WebFeature::kDocumentDomainEnabledCrossOriginAccess));
 }
 
 TEST_P(BindingSecurityCounterTest, SameOriginWindow) {
   LoadWindowAndAccessProperty(OriginDisposition::SameOrigin, GetParam());
-  EXPECT_FALSE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
-      WebFeature::kCrossOriginPropertyAccess));
-  EXPECT_FALSE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
-      WebFeature::kCrossOriginPropertyAccessFromOpener));
-  EXPECT_FALSE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
-      WebFeature::kDocumentDomainEnabledCrossOriginAccess));
+  EXPECT_FALSE(
+      GetDocument().Loader()->GetUseCounterHelper().HasRecordedMeasurement(
+          WebFeature::kCrossOriginPropertyAccess));
+  EXPECT_FALSE(
+      GetDocument().Loader()->GetUseCounterHelper().HasRecordedMeasurement(
+          WebFeature::kCrossOriginPropertyAccessFromOpener));
+  EXPECT_FALSE(
+      GetDocument().Loader()->GetUseCounterHelper().HasRecordedMeasurement(
+          WebFeature::kDocumentDomainEnabledCrossOriginAccess));
 }
 
 TEST_P(BindingSecurityCounterTest, SameOriginDomainWindow) {
   LoadWindowAndAccessProperty(OriginDisposition::SameOriginDomain, GetParam());
-  EXPECT_FALSE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
-      WebFeature::kCrossOriginPropertyAccess));
-  EXPECT_FALSE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
-      WebFeature::kCrossOriginPropertyAccessFromOpener));
-  EXPECT_TRUE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
-      WebFeature::kDocumentDomainEnabledCrossOriginAccess));
+  EXPECT_FALSE(
+      GetDocument().Loader()->GetUseCounterHelper().HasRecordedMeasurement(
+          WebFeature::kCrossOriginPropertyAccess));
+  EXPECT_FALSE(
+      GetDocument().Loader()->GetUseCounterHelper().HasRecordedMeasurement(
+          WebFeature::kCrossOriginPropertyAccessFromOpener));
+  EXPECT_TRUE(
+      GetDocument().Loader()->GetUseCounterHelper().HasRecordedMeasurement(
+          WebFeature::kDocumentDomainEnabledCrossOriginAccess));
 }
 
 TEST_P(BindingSecurityCounterTest, CrossOriginFrame) {
   LoadFrameAndAccessProperty(OriginDisposition::CrossOrigin, GetParam());
-  EXPECT_TRUE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
-      WebFeature::kCrossOriginPropertyAccess));
-  EXPECT_FALSE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
-      WebFeature::kCrossOriginPropertyAccessFromOpener));
-  EXPECT_FALSE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
-      WebFeature::kDocumentDomainEnabledCrossOriginAccess));
+  EXPECT_TRUE(
+      GetDocument().Loader()->GetUseCounterHelper().HasRecordedMeasurement(
+          WebFeature::kCrossOriginPropertyAccess));
+  EXPECT_FALSE(
+      GetDocument().Loader()->GetUseCounterHelper().HasRecordedMeasurement(
+          WebFeature::kCrossOriginPropertyAccessFromOpener));
+  EXPECT_FALSE(
+      GetDocument().Loader()->GetUseCounterHelper().HasRecordedMeasurement(
+          WebFeature::kDocumentDomainEnabledCrossOriginAccess));
 }
 
 TEST_P(BindingSecurityCounterTest, SameOriginFrame) {
   LoadFrameAndAccessProperty(OriginDisposition::SameOrigin, GetParam());
-  EXPECT_FALSE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
-      WebFeature::kCrossOriginPropertyAccess));
-  EXPECT_FALSE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
-      WebFeature::kCrossOriginPropertyAccessFromOpener));
-  EXPECT_FALSE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
-      WebFeature::kDocumentDomainEnabledCrossOriginAccess));
+  EXPECT_FALSE(
+      GetDocument().Loader()->GetUseCounterHelper().HasRecordedMeasurement(
+          WebFeature::kCrossOriginPropertyAccess));
+  EXPECT_FALSE(
+      GetDocument().Loader()->GetUseCounterHelper().HasRecordedMeasurement(
+          WebFeature::kCrossOriginPropertyAccessFromOpener));
+  EXPECT_FALSE(
+      GetDocument().Loader()->GetUseCounterHelper().HasRecordedMeasurement(
+          WebFeature::kDocumentDomainEnabledCrossOriginAccess));
 }
 
 TEST_P(BindingSecurityCounterTest, SameOriginDomainFrame) {
   LoadFrameAndAccessProperty(OriginDisposition::SameOriginDomain, GetParam());
-  EXPECT_FALSE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
-      WebFeature::kCrossOriginPropertyAccess));
-  EXPECT_FALSE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
-      WebFeature::kCrossOriginPropertyAccessFromOpener));
-  EXPECT_TRUE(GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
-      WebFeature::kDocumentDomainEnabledCrossOriginAccess));
+  EXPECT_FALSE(
+      GetDocument().Loader()->GetUseCounterHelper().HasRecordedMeasurement(
+          WebFeature::kCrossOriginPropertyAccess));
+  EXPECT_FALSE(
+      GetDocument().Loader()->GetUseCounterHelper().HasRecordedMeasurement(
+          WebFeature::kCrossOriginPropertyAccessFromOpener));
+  EXPECT_TRUE(
+      GetDocument().Loader()->GetUseCounterHelper().HasRecordedMeasurement(
+          WebFeature::kDocumentDomainEnabledCrossOriginAccess));
 }
 
 }  // namespace
diff --git a/third_party/blink/renderer/bindings/core/v8/custom/v8_event_target_custom.cc b/third_party/blink/renderer/bindings/core/v8/custom/v8_event_target_custom.cc
index 342f622..48f80b7 100644
--- a/third_party/blink/renderer/bindings/core/v8/custom/v8_event_target_custom.cc
+++ b/third_party/blink/renderer/bindings/core/v8/custom/v8_event_target_custom.cc
@@ -31,6 +31,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/v8_event_target.h"
 
 #include "third_party/blink/renderer/bindings/core/v8/v8_window.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/frame/use_counter.h"
 
diff --git a/third_party/blink/renderer/bindings/core/v8/initialize_v8_extras_binding_test.cc b/third_party/blink/renderer/bindings/core/v8/initialize_v8_extras_binding_test.cc
index b26ab984..0f15023e 100644
--- a/third_party/blink/renderer/bindings/core/v8/initialize_v8_extras_binding_test.cc
+++ b/third_party/blink/renderer/bindings/core/v8/initialize_v8_extras_binding_test.cc
@@ -38,8 +38,8 @@
   ScriptValue rv = EvalWithPrintingError(
       &scope, "binding.countUse('TransformStreamConstructor');");
   EXPECT_TRUE(rv.IsUndefined());
-  EXPECT_TRUE(UseCounter::IsCounted(scope.GetDocument(),
-                                    WebFeature::kTransformStreamConstructor));
+  EXPECT_TRUE(scope.GetDocument().IsUseCounted(
+      WebFeature::kTransformStreamConstructor));
 }
 
 TEST(InitializeV8ExtrasBindingTest, UnsupportedId) {
diff --git a/third_party/blink/renderer/bindings/core/v8/use_counter_callback.cc b/third_party/blink/renderer/bindings/core/v8/use_counter_callback.cc
index d77ae57..a34dbb22 100644
--- a/third_party/blink/renderer/bindings/core/v8/use_counter_callback.cc
+++ b/third_party/blink/renderer/bindings/core/v8/use_counter_callback.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/use_counter_callback.h"
 
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/frame/deprecation.h"
 #include "third_party/blink/renderer/core/frame/use_counter.h"
 #include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
diff --git a/third_party/blink/renderer/build/scripts/core/css/css_properties.py b/third_party/blink/renderer/build/scripts/core/css/css_properties.py
index aaf60b6..880ed8c9 100755
--- a/third_party/blink/renderer/build/scripts/core/css/css_properties.py
+++ b/third_party/blink/renderer/build/scripts/core/css/css_properties.py
@@ -241,8 +241,14 @@
         set_if_none(property_, 'custom_compare', False)
         set_if_none(property_, 'mutable', False)
 
-        if property_['direction_aware_options'] and not property_['style_builder_template']:
-            property_['style_builder_template'] = 'direction_aware'
+        if property_['direction_aware_options']:
+            if not property_['style_builder_template']:
+                property_['style_builder_template'] = 'direction_aware'
+            options = property_['direction_aware_options']
+            assert 'resolver' in options, 'resolver option is required'
+            assert 'physical_group' in options, 'physical_group option is required'
+            options['resolver_name'] = NameStyleConverter(options['resolver'])
+            options['physical_group_name'] = NameStyleConverter(options['physical_group'])
 
     @property
     def default_parameters(self):
diff --git a/third_party/blink/renderer/build/scripts/core/css/properties/make_css_property_subclasses.py b/third_party/blink/renderer/build/scripts/core/css/properties/make_css_property_subclasses.py
index 6f84b47..730d15a9 100755
--- a/third_party/blink/renderer/build/scripts/core/css/properties/make_css_property_subclasses.py
+++ b/third_party/blink/renderer/build/scripts/core/css/properties/make_css_property_subclasses.py
@@ -113,7 +113,7 @@
         else:
             yield "third_party/blink/renderer/core/css/properties/" + property_['namespace_group'].lower() + ".h"
             if property_['direction_aware_options']:
-                yield "third_party/blink/renderer/core/style_property_shorthand.h"
+                yield "third_party/blink/renderer/core/css/properties/css_direction_aware_resolver.h"
             for include in self.apply_includes(property_):
                 yield 'third_party/blink/renderer/' + include
         if property_['runtime_flag']:
diff --git a/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_property_subclass.h.tmpl b/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_property_subclass.h.tmpl
index a6748255..685800e 100644
--- a/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_property_subclass.h.tmpl
+++ b/third_party/blink/renderer/build/scripts/core/css/properties/templates/css_property_subclass.h.tmpl
@@ -96,37 +96,20 @@
       const LayoutObject*,
       Node*,
       bool allow_visited_style) const override {
-    // Directional properties are resolved by resolveDirectionAwareProperty()
+    // Directional properties are resolved by CSSDirectionAwareResolver
     // before calling CSSValueFromComputedStyleInternal.
     NOTREACHED();
     return nullptr;
   }
-    {% if property.direction_aware_options.logical_side == "width" %}
+    {% set options = property.direction_aware_options %}
+    {% set resolver_name = options.resolver_name.to_upper_camel_case() %}
+    {% set physical_group_name = options.physical_group_name.to_upper_camel_case() %}
   const CSSProperty& ResolveDirectionAwareProperty(
       TextDirection direction,
       blink::WritingMode writing_mode) const override {
-    if (IsHorizontalWritingMode(writing_mode))
-      return Get{{property.direction_aware_options.shorthand_for_physical_side}}Width();
-    return Get{{property.direction_aware_options.shorthand_for_physical_side}}Height();
+    return CSSDirectionAwareResolver::Resolve{{resolver_name}}(direction, writing_mode,
+        CSSDirectionAwareResolver::{{physical_group_name}}Group());
   }
-    {% elif property.direction_aware_options.logical_side == "height" %}
-  const CSSProperty& ResolveDirectionAwareProperty(
-      TextDirection direction,
-      blink::WritingMode writing_mode) const override {
-    if (IsHorizontalWritingMode(writing_mode))
-      return Get{{property.direction_aware_options.shorthand_for_physical_side}}Height();
-    return Get{{property.direction_aware_options.shorthand_for_physical_side}}Width();
-  }
-    {% else %}
-  const CSSProperty& ResolveDirectionAwareProperty(
-      TextDirection direction,
-      blink::WritingMode writing_mode) const override {
-    return Resolve{{property.direction_aware_options.logical_side[0].upper() + property.direction_aware_options.logical_side[1:]}}ToPhysicalProperty(
-      direction,
-      writing_mode,
-      {{property.direction_aware_options.shorthand_for_physical_side}}());
-  }
-    {% endif %}
   {% endif %}
   {% if property.style_builder_declare %}
 
diff --git a/third_party/blink/renderer/build/scripts/core/css/templates/css_property_names.h.tmpl b/third_party/blink/renderer/build/scripts/core/css/templates/css_property_names.h.tmpl
index cd3cccc2..b7523f4 100644
--- a/third_party/blink/renderer/build/scripts/core/css/templates/css_property_names.h.tmpl
+++ b/third_party/blink/renderer/build/scripts/core/css/templates/css_property_names.h.tmpl
@@ -65,7 +65,7 @@
 
 inline bool isPropertyAlias(CSSPropertyID id) { return static_cast<int>(id) & {{alias_offset}}; }
 
-CSSPropertyID unresolvedCSSPropertyID(const WTF::String&);
+CSSPropertyID CORE_EXPORT unresolvedCSSPropertyID(const WTF::String&);
 
 CSSPropertyID CORE_EXPORT cssPropertyID(const WTF::String&);
 
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn
index a1dfeaab..cb5c292 100644
--- a/third_party/blink/renderer/core/BUILD.gn
+++ b/third_party/blink/renderer/core/BUILD.gn
@@ -1812,6 +1812,7 @@
     "fetch/bytes_consumer_test_util.h",
     "fetch/fetch_data_loader_test.cc",
     "fetch/fetch_header_list_test.cc",
+    "fetch/fetch_request_data_test.cc",
     "fetch/fetch_response_data_test.cc",
     "fetch/form_data_bytes_consumer_test.cc",
     "fetch/multipart_parser_test.cc",
@@ -1944,7 +1945,6 @@
     "inspector/protocol_parser_test.cc",
     "inspector/protocol_unittest.cc",
     "intersection_observer/intersection_observer_test.cc",
-    "invisible_dom/find_invisible_test.cc",
     "layout/api/selection_state_test.cc",
     "layout/collapsed_border_value_test.cc",
     "layout/custom/layout_worklet_test.cc",
diff --git a/third_party/blink/renderer/core/animation/css/css_animations.cc b/third_party/blink/renderer/core/animation/css/css_animations.cc
index 2f5cfc03..1296b836 100644
--- a/third_party/blink/renderer/core/animation/css/css_animations.cc
+++ b/third_party/blink/renderer/core/animation/css/css_animations.cc
@@ -141,8 +141,8 @@
 
   for (const CSSProperty* property : specified_properties_for_use_counter) {
     DCHECK(isValidCSSPropertyID(property->PropertyID()));
-    UseCounter::CountAnimatedCSS(element_for_scoping->GetDocument(),
-                                 property->PropertyID());
+    element_for_scoping->GetDocument().CountUse(
+        property->PropertyID(), UseCounterHelper::CSSPropertyType::kAnimation);
   }
 
   // Merge duplicate keyframes.
@@ -626,8 +626,9 @@
     running_transition.animation = animation;
     transitions_.Set(property, running_transition);
     DCHECK(isValidCSSPropertyID(property.GetCSSProperty().PropertyID()));
-    UseCounter::CountAnimatedCSS(element->GetDocument(),
-                                 property.GetCSSProperty().PropertyID());
+    element->GetDocument().CountUse(
+        property.GetCSSProperty().PropertyID(),
+        UseCounterHelper::CSSPropertyType::kAnimation);
   }
   ClearPendingUpdate();
 }
diff --git a/third_party/blink/renderer/core/css/BUILD.gn b/third_party/blink/renderer/core/css/BUILD.gn
index d2c9d63..36dafd9 100644
--- a/third_party/blink/renderer/core/css/BUILD.gn
+++ b/third_party/blink/renderer/core/css/BUILD.gn
@@ -420,6 +420,8 @@
     "part_names.h",
     "properties/computed_style_utils.cc",
     "properties/computed_style_utils.h",
+    "properties/css_direction_aware_resolver.cc",
+    "properties/css_direction_aware_resolver.h",
     "properties/css_parsing_utils.cc",
     "properties/css_parsing_utils.h",
     "properties/css_property.cc",
diff --git a/third_party/blink/renderer/core/css/css_font_face_src_value.cc b/third_party/blink/renderer/core/css/css_font_face_src_value.cc
index a17355c2..b7b52c32 100644
--- a/third_party/blink/renderer/core/css/css_font_face_src_value.cc
+++ b/third_party/blink/renderer/core/css/css_font_face_src_value.cc
@@ -85,9 +85,8 @@
                                          FontResourceClient* client) const {
   if (!fetched_) {
     ResourceRequest resource_request(absolute_resource_);
-    resource_request.SetReferrerPolicy(
-        ReferrerPolicyResolveDefault(referrer_.referrer_policy));
-    resource_request.SetReferrerString(referrer_.referrer);
+    resource_request.SetHttpReferrer(SecurityPolicy::GenerateReferrer(
+        referrer_.referrer_policy, resource_request.Url(), referrer_.referrer));
     ResourceLoaderOptions options;
     options.initiator_info.name = fetch_initiator_type_names::kCSS;
     FetchParameters params(resource_request, options);
diff --git a/third_party/blink/renderer/core/css/css_image_set_value.cc b/third_party/blink/renderer/core/css/css_image_set_value.cc
index bbb39a7f..a8cd7be2 100644
--- a/third_party/blink/renderer/core/css/css_image_set_value.cc
+++ b/third_party/blink/renderer/core/css/css_image_set_value.cc
@@ -64,8 +64,9 @@
 
     ImageWithScale image;
     image.image_url = image_url;
-    image.referrer.referrer = image_value.GetReferrer().referrer;
-    image.referrer.referrer_policy = image_value.GetReferrer().referrer_policy;
+    image.referrer = SecurityPolicy::GenerateReferrer(
+        image_value.GetReferrer().referrer_policy, KURL(image_url),
+        image_value.GetReferrer().referrer);
     image.scale_factor = scale_factor;
     images_in_set_.push_back(image);
     ++i;
@@ -113,9 +114,7 @@
     // transforms. https://bugs.webkit.org/show_bug.cgi?id=81698
     ImageWithScale image = BestImageForScaleFactor(device_scale_factor);
     ResourceRequest resource_request(document.CompleteURL(image.image_url));
-    resource_request.SetReferrerPolicy(
-        ReferrerPolicyResolveDefault(image.referrer.referrer_policy));
-    resource_request.SetReferrerString(image.referrer.referrer);
+    resource_request.SetHttpReferrer(image.referrer);
     ResourceLoaderOptions options;
     options.initiator_info.name = parser_mode_ == kUASheetMode
                                       ? fetch_initiator_type_names::kUacss
diff --git a/third_party/blink/renderer/core/css/css_image_value.cc b/third_party/blink/renderer/core/css/css_image_value.cc
index ec63168..f0b8c04 100644
--- a/third_party/blink/renderer/core/css/css_image_value.cc
+++ b/third_party/blink/renderer/core/css/css_image_value.cc
@@ -62,9 +62,8 @@
     if (absolute_url_.IsEmpty())
       ReResolveURL(document);
     ResourceRequest resource_request(absolute_url_);
-    resource_request.SetReferrerPolicy(
-        ReferrerPolicyResolveDefault(referrer_.referrer_policy));
-    resource_request.SetReferrerString(referrer_.referrer);
+    resource_request.SetHttpReferrer(SecurityPolicy::GenerateReferrer(
+        referrer_.referrer_policy, resource_request.Url(), referrer_.referrer));
     ResourceLoaderOptions options;
     options.initiator_info.name = initiator_name_.IsEmpty()
                                       ? fetch_initiator_type_names::kCSS
diff --git a/third_party/blink/renderer/core/css/css_keyframe_rule.cc b/third_party/blink/renderer/core/css/css_keyframe_rule.cc
index 1b4157af..c17bbbf 100644
--- a/third_party/blink/renderer/core/css/css_keyframe_rule.cc
+++ b/third_party/blink/renderer/core/css/css_keyframe_rule.cc
@@ -28,6 +28,7 @@
 #include "third_party/blink/renderer/core/css/css_keyframes_rule.h"
 #include "third_party/blink/renderer/core/css/css_style_sheet.h"
 #include "third_party/blink/renderer/core/css/keyframe_style_rule_css_style_declaration.h"
+#include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
 
diff --git a/third_party/blink/renderer/core/css/css_keyframes_rule.cc b/third_party/blink/renderer/core/css/css_keyframes_rule.cc
index 14af5ae..c2e25d8 100644
--- a/third_party/blink/renderer/core/css/css_keyframes_rule.cc
+++ b/third_party/blink/renderer/core/css/css_keyframes_rule.cc
@@ -31,6 +31,7 @@
 #include "third_party/blink/renderer/core/css/css_rule_list.h"
 #include "third_party/blink/renderer/core/css/css_style_sheet.h"
 #include "third_party/blink/renderer/core/css/parser/css_parser.h"
+#include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/frame/use_counter.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
@@ -178,8 +179,8 @@
   const Document* parent_document =
       CSSStyleSheet::SingleOwnerDocument(parentStyleSheet());
   if (parent_document) {
-    UseCounter::Count(*parent_document,
-                      WebFeature::kCSSKeyframesRuleAnonymousIndexedGetter);
+    parent_document->CountUse(
+        WebFeature::kCSSKeyframesRuleAnonymousIndexedGetter);
   }
   return Item(index);
 }
diff --git a/third_party/blink/renderer/core/css/css_properties.json5 b/third_party/blink/renderer/core/css/css_properties.json5
index 66f4656..16111634 100644
--- a/third_party/blink/renderer/core/css/css_properties.json5
+++ b/third_party/blink/renderer/core/css/css_properties.json5
@@ -324,19 +324,33 @@
     converter: {
     },
 
-    // - logical_side
-    // The logical side represented by a direction-dependent property
-    // - shorthand_for_physical_side
-    // Shorthand to be used for resolving direction-dependent properties to
-    // physical properties
+    // Options used for properties that depend on writing-mode and/or
+    // text-direction (e.g. css-logical).
     direction_aware_options: {
-      logical_side: {
+      // The name of the mapping function used to convert from a logical
+      // property to a physical property. Corresponds to a function in
+      // CSSDirectionAwareResolver. E.g. a value of "baz" corresponds to
+      // CSSDirectionAwareResolver::ResolveBaz(...).
+      resolver: {
         valid_type: "str",
-        valid_values: ["after", "before", "end", "start", "width", "height"],
+        valid_values: ["inline-start", "inline-end", "block-start", "block-end",
+                       "inline", "block"],
       },
-      shorthand_for_physical_side: {
+      // The name of the physical property group to pass to the resolver.
+      // The group represents the physical part of the "logical property group"
+      // described by css-logical [1].
+      //
+      // In terms of code generation, each value corresponds to a function in
+      // CSSDirectionAwareResolver. E.g. a value of "foo-bar" would correspond
+      // to CSSDirectionAwareResolver::FooBarGroup().
+      //
+      // [1] https://drafts.csswg.org/css-logical/#logical-property-group
+      physical_group: {
         valid_type: "str",
-      },
+        valid_values: ["border", "border-color", "border-style", "border-width",
+                       "inset", "margin", "max-size", "min-size", "padding",
+                       "scroll-margin", "scroll-padding", "size"],
+      }
     },
 
     // - priority: "High"
@@ -2633,8 +2647,8 @@
       name: "scroll-margin-block-end",
       property_methods: ["ParseSingleValue"],
       direction_aware_options: {
-        logical_side: "after",
-        shorthand_for_physical_side: "scrollMarginShorthand",
+        resolver: "block-end",
+        physical_group: "scroll-margin",
       },
       typedom_types: ["Keyword", "Length"]
     },
@@ -2654,8 +2668,8 @@
       name: "scroll-margin-block-start",
       property_methods: ["ParseSingleValue"],
       direction_aware_options: {
-        logical_side: "before",
-        shorthand_for_physical_side: "scrollMarginShorthand",
+        resolver: "block-start",
+        physical_group: "scroll-margin",
       },
       typedom_types: ["Keyword", "Length"]
     },
@@ -2673,8 +2687,8 @@
       name: "scroll-margin-inline-end",
       property_methods: ["ParseSingleValue"],
       direction_aware_options: {
-        logical_side: "end",
-        shorthand_for_physical_side: "scrollMarginShorthand",
+        resolver: "inline-end",
+        physical_group: "scroll-margin",
       },
       typedom_types: ["Keyword", "Length"]
     },
@@ -2682,8 +2696,8 @@
       name: "scroll-margin-inline-start",
       property_methods: ["ParseSingleValue"],
       direction_aware_options: {
-        logical_side: "start",
-        shorthand_for_physical_side: "scrollMarginShorthand",
+        resolver: "inline-start",
+        physical_group: "scroll-margin",
       },
       typedom_types: ["Keyword", "Length"]
     },
@@ -2725,8 +2739,8 @@
       type_name: "Length",
       converter: "ConvertLength",
       direction_aware_options: {
-        logical_side: "after",
-        shorthand_for_physical_side: "scrollPaddingShorthand",
+        resolver: "block-end",
+        physical_group: "scroll-padding",
       },
     },
     {
@@ -2737,8 +2751,8 @@
       type_name: "Length",
       converter: "ConvertLength",
       direction_aware_options: {
-        logical_side: "before",
-        shorthand_for_physical_side: "scrollPaddingShorthand",
+        resolver: "block-start",
+        physical_group: "scroll-padding",
       },
     },
     {
@@ -2758,8 +2772,8 @@
       type_name: "Length",
       converter: "ConvertLength",
       direction_aware_options: {
-        logical_side: "end",
-        shorthand_for_physical_side: "scrollPaddingShorthand",
+        resolver: "inline-end",
+        physical_group: "scroll-padding",
       },
     },
     {
@@ -2770,8 +2784,8 @@
       type_name: "Length",
       converter: "ConvertLength",
       direction_aware_options: {
-        logical_side: "start",
-        shorthand_for_physical_side: "scrollPaddingShorthand",
+        resolver: "inline-start",
+        physical_group: "scroll-padding",
       },
     },
     {
@@ -4059,8 +4073,8 @@
       property_methods: ["ParseSingleValue"],
       layout_dependent: true,
       direction_aware_options: {
-        logical_side: "width",
-        shorthand_for_physical_side: "CSSProperty",
+        resolver: "inline",
+        physical_group: "size",
       },
       keywords: ["auto"],
       typedom_types: ["Keyword", "Length", "Percentage"],
@@ -4070,8 +4084,8 @@
       property_methods: ["ParseSingleValue"],
       layout_dependent: true,
       direction_aware_options: {
-        logical_side: "height",
-        shorthand_for_physical_side: "CSSProperty",
+        resolver: "block",
+        physical_group: "size",
       },
       keywords: ["auto"],
       typedom_types: ["Keyword", "Length", "Percentage"],
@@ -4080,8 +4094,8 @@
       name: "min-inline-size",
       property_methods: ["ParseSingleValue"],
       direction_aware_options: {
-        logical_side: "width",
-        shorthand_for_physical_side: "CSSPropertyMin",
+        resolver: "inline",
+        physical_group: "min-size",
       },
       typedom_types: ["Length", "Percentage"],
     },
@@ -4089,8 +4103,8 @@
       name: "min-block-size",
       property_methods: ["ParseSingleValue"],
       direction_aware_options: {
-        logical_side: "height",
-        shorthand_for_physical_side: "CSSPropertyMin",
+        resolver: "block",
+        physical_group: "min-size",
       },
       typedom_types: ["Length", "Percentage"],
     },
@@ -4098,8 +4112,8 @@
       name: "max-inline-size",
       property_methods: ["ParseSingleValue"],
       direction_aware_options: {
-        logical_side: "width",
-        shorthand_for_physical_side: "CSSPropertyMax",
+        resolver: "inline",
+        physical_group: "max-size",
       },
       keywords: ["none"],
       typedom_types: ["Keyword", "Length", "Percentage"],
@@ -4108,8 +4122,8 @@
       name: "max-block-size",
       property_methods: ["ParseSingleValue"],
       direction_aware_options: {
-        logical_side: "height",
-        shorthand_for_physical_side: "CSSPropertyMax",
+        resolver: "block",
+        physical_group: "max-size",
       },
       keywords: ["none"],
       typedom_types: ["Keyword", "Length", "Percentage"],
@@ -4118,8 +4132,8 @@
       name: "margin-inline-start",
       property_methods: ["ParseSingleValue"],
       direction_aware_options: {
-        logical_side: "start",
-        shorthand_for_physical_side: "marginShorthand",
+        resolver: "inline-start",
+        physical_group: "margin",
       },
       keywords: ["auto"]
     },
@@ -4127,8 +4141,8 @@
       name: "margin-inline-end",
       property_methods: ["ParseSingleValue"],
       direction_aware_options: {
-        logical_side: "end",
-        shorthand_for_physical_side: "marginShorthand",
+        resolver: "inline-end",
+        physical_group: "margin",
       },
       keywords: ["auto"]
     },
@@ -4136,8 +4150,8 @@
       name: "margin-block-start",
       property_methods: ["ParseSingleValue"],
       direction_aware_options: {
-        logical_side: "before",
-        shorthand_for_physical_side: "marginShorthand",
+        resolver: "block-start",
+        physical_group: "margin",
       },
       keywords: ["auto"]
     },
@@ -4145,8 +4159,8 @@
       name: "margin-block-end",
       property_methods: ["ParseSingleValue"],
       direction_aware_options: {
-        logical_side: "after",
-        shorthand_for_physical_side: "marginShorthand",
+        resolver: "block-end",
+        physical_group: "margin",
       },
       keywords: ["auto"]
     },
@@ -4154,47 +4168,47 @@
       name: "padding-inline-start",
       property_methods: ["ParseSingleValue"],
       direction_aware_options: {
-        logical_side: "start",
-        shorthand_for_physical_side: "paddingShorthand",
+        resolver: "inline-start",
+        physical_group: "padding",
       }
     },
     {
       name: "padding-inline-end",
       property_methods: ["ParseSingleValue"],
       direction_aware_options: {
-        logical_side: "end",
-        shorthand_for_physical_side: "paddingShorthand",
+        resolver: "inline-end",
+        physical_group: "padding",
       }
     },
     {
       name: "padding-block-start",
       property_methods: ["ParseSingleValue"],
       direction_aware_options: {
-        logical_side: "before",
-        shorthand_for_physical_side: "paddingShorthand",
+        resolver: "block-start",
+        physical_group: "padding",
       }
     },
     {
       name: "padding-block-end",
       property_methods: ["ParseSingleValue"],
       direction_aware_options: {
-        logical_side: "after",
-        shorthand_for_physical_side: "paddingShorthand",
+        resolver: "block-end",
+        physical_group: "padding",
       }
     },
     {
       name: "border-inline-start-width",
       property_methods: ["ParseSingleValue"],
       direction_aware_options: {
-        logical_side: "start",
-        shorthand_for_physical_side: "borderWidthShorthand",
+        resolver: "inline-start",
+        physical_group: "border-width",
       },
     },
     {
       name: "border-inline-start-style",
       direction_aware_options: {
-        logical_side: "start",
-        shorthand_for_physical_side: "borderStyleShorthand",
+        resolver: "inline-start",
+        physical_group: "border-style",
       },
     },
     {
@@ -4202,23 +4216,23 @@
       property_methods: ["ParseSingleValue"],
       valid_for_visited_link: true,
       direction_aware_options: {
-        logical_side: "start",
-        shorthand_for_physical_side: "borderColorShorthand",
+        resolver: "inline-start",
+        physical_group: "border-color",
       },
     },
     {
       name: "border-inline-end-width",
       property_methods: ["ParseSingleValue"],
       direction_aware_options: {
-        logical_side: "end",
-        shorthand_for_physical_side: "borderWidthShorthand",
+        resolver: "inline-end",
+        physical_group: "border-width",
       },
     },
     {
       name: "border-inline-end-style",
       direction_aware_options: {
-        logical_side: "end",
-        shorthand_for_physical_side: "borderStyleShorthand",
+        resolver: "inline-end",
+        physical_group: "border-style",
       },
     },
     {
@@ -4226,23 +4240,23 @@
       property_methods: ["ParseSingleValue"],
       valid_for_visited_link: true,
       direction_aware_options: {
-        logical_side: "end",
-        shorthand_for_physical_side: "borderColorShorthand",
+        resolver: "inline-end",
+        physical_group: "border-color",
       },
     },
     {
       name: "border-block-start-width",
       property_methods: ["ParseSingleValue"],
       direction_aware_options: {
-        logical_side: "before",
-        shorthand_for_physical_side: "borderWidthShorthand",
+        resolver: "block-start",
+        physical_group: "border-width",
       },
     },
     {
       name: "border-block-start-style",
       direction_aware_options: {
-        logical_side: "before",
-        shorthand_for_physical_side: "borderStyleShorthand",
+        resolver: "block-start",
+        physical_group: "border-style",
       },
     },
     {
@@ -4250,23 +4264,23 @@
       property_methods: ["ParseSingleValue"],
       valid_for_visited_link: true,
       direction_aware_options: {
-        logical_side: "before",
-        shorthand_for_physical_side: "borderColorShorthand",
+        resolver: "block-start",
+        physical_group: "border-color",
       },
     },
     {
       name: "border-block-end-width",
       property_methods: ["ParseSingleValue"],
       direction_aware_options: {
-        logical_side: "after",
-        shorthand_for_physical_side: "borderWidthShorthand",
+        resolver: "block-end",
+        physical_group: "border-width",
       },
     },
     {
       name: "border-block-end-style",
       direction_aware_options: {
-        logical_side: "after",
-        shorthand_for_physical_side: "borderStyleShorthand",
+        resolver: "block-end",
+        physical_group: "border-style",
       },
     },
     {
@@ -4274,8 +4288,8 @@
       property_methods: ["ParseSingleValue"],
       valid_for_visited_link: true,
       direction_aware_options: {
-        logical_side: "after",
-        shorthand_for_physical_side: "borderColorShorthand",
+        resolver: "block-end",
+        physical_group: "border-color",
       },
     },
     {
@@ -4283,8 +4297,8 @@
       property_methods: ["ParseSingleValue"],
       runtime_flag: "CSSLogical",
       direction_aware_options: {
-        logical_side: "start",
-        shorthand_for_physical_side: "insetShorthand",
+        resolver: "inline-start",
+        physical_group: "inset",
       }
     },
     {
@@ -4292,8 +4306,8 @@
       property_methods: ["ParseSingleValue"],
       runtime_flag: "CSSLogical",
       direction_aware_options: {
-        logical_side: "end",
-        shorthand_for_physical_side: "insetShorthand",
+        resolver: "inline-end",
+        physical_group: "inset",
       }
     },
     {
@@ -4301,8 +4315,8 @@
       property_methods: ["ParseSingleValue"],
       runtime_flag: "CSSLogical",
       direction_aware_options: {
-        logical_side: "before",
-        shorthand_for_physical_side: "insetShorthand",
+        resolver: "block-start",
+        physical_group: "inset",
       }
     },
     {
@@ -4310,8 +4324,8 @@
       property_methods: ["ParseSingleValue"],
       runtime_flag: "CSSLogical",
       direction_aware_options: {
-        logical_side: "after",
-        shorthand_for_physical_side: "insetShorthand",
+        resolver: "block-end",
+        physical_group: "inset",
       }
     },
 
@@ -4555,8 +4569,8 @@
       ],
       property_methods: ["ParseShorthand"],
       direction_aware_options: {
-        logical_side: "after",
-        shorthand_for_physical_side: "BorderDirections",
+        resolver: "block-end",
+        physical_group: "border",
       },
     },
     {
@@ -4567,8 +4581,8 @@
       ],
       property_methods: ["ParseShorthand"],
       direction_aware_options: {
-        logical_side: "before",
-        shorthand_for_physical_side: "BorderDirections",
+        resolver: "block-start",
+        physical_group: "border",
       },
     },
     {
@@ -4629,8 +4643,8 @@
       ],
       property_methods: ["ParseShorthand"],
       direction_aware_options: {
-        logical_side: "end",
-        shorthand_for_physical_side: "BorderDirections",
+        resolver: "inline-end",
+        physical_group: "border",
       },
     },
     {
@@ -4641,8 +4655,8 @@
       ],
       property_methods: ["ParseShorthand"],
       direction_aware_options: {
-        logical_side: "start",
-        shorthand_for_physical_side: "BorderDirections",
+        resolver: "inline-start",
+        physical_group: "border",
       },
     },
     {
diff --git a/third_party/blink/renderer/core/css/parser/css_lazy_parsing_test.cc b/third_party/blink/renderer/core/css/parser/css_lazy_parsing_test.cc
index aafc8f6b..2d60547d 100644
--- a/third_party/blink/renderer/core/css/parser/css_lazy_parsing_test.cc
+++ b/third_party/blink/renderer/core/css/parser/css_lazy_parsing_test.cc
@@ -131,10 +131,13 @@
 
     EXPECT_EQ(&dummy_holder->GetDocument(),
               cached_contents_->SingleOwnerDocument());
-    UseCounter& use_counter1 =
-        dummy_holder->GetDocument().Loader()->GetUseCounter();
-    EXPECT_TRUE(use_counter1.IsCounted(CSSPropertyID::kBackgroundColor));
-    EXPECT_FALSE(use_counter1.IsCounted(CSSPropertyID::kColor));
+    UseCounterHelper& use_counter1 =
+        dummy_holder->GetDocument().Loader()->GetUseCounterHelper();
+    EXPECT_TRUE(
+        use_counter1.IsCounted(CSSPropertyID::kBackgroundColor,
+                               UseCounterHelper::CSSPropertyType::kDefault));
+    EXPECT_FALSE(use_counter1.IsCounted(
+        CSSPropertyID::kColor, UseCounterHelper::CSSPropertyType::kDefault));
 
     // Change owner document.
     cached_contents_->UnregisterClient(sheet);
@@ -157,11 +160,15 @@
   rule2->Properties();
   EXPECT_TRUE(HasParsedProperties(rule2));
 
-  UseCounter& use_counter2 =
-      dummy_holder2->GetDocument().Loader()->GetUseCounter();
+  UseCounterHelper& use_counter2 =
+      dummy_holder2->GetDocument().Loader()->GetUseCounterHelper();
   EXPECT_TRUE(sheet2);
-  EXPECT_TRUE(use_counter2.IsCounted(CSSPropertyID::kColor));
-  EXPECT_FALSE(use_counter2.IsCounted(CSSPropertyID::kBackgroundColor));
+  EXPECT_TRUE(use_counter2.IsCounted(
+      CSSPropertyID::kColor, UseCounterHelper::CSSPropertyType::kDefault));
+
+  EXPECT_FALSE(
+      use_counter2.IsCounted(CSSPropertyID::kBackgroundColor,
+                             UseCounterHelper::CSSPropertyType::kDefault));
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/parser/css_parser_context.cc b/third_party/blink/renderer/core/css/parser/css_parser_context.cc
index abf881d..cf95554 100644
--- a/third_party/blink/renderer/core/css/parser/css_parser_context.cc
+++ b/third_party/blink/renderer/core/css/parser/css_parser_context.cc
@@ -217,7 +217,7 @@
 
 void CSSParserContext::Count(WebFeature feature) const {
   if (IsUseCounterRecordingEnabled())
-    UseCounter::Count(*document_, feature);
+    document_->CountUse(feature);
 }
 
 void CSSParserContext::CountDeprecation(WebFeature feature) const {
@@ -226,10 +226,8 @@
 }
 
 void CSSParserContext::Count(CSSParserMode mode, CSSPropertyID property) const {
-  if (IsUseCounterRecordingEnabled() && document_->Loader()) {
-    UseCounter* use_counter = &document_->Loader()->GetUseCounter();
-    if (use_counter)
-      use_counter->Count(mode, property, document_->GetFrame());
+  if (IsUseCounterRecordingEnabled() && IsUseCounterEnabledForMode(mode)) {
+    document_->CountUse(property, UseCounterHelper::CSSPropertyType::kDefault);
   }
 }
 
diff --git a/third_party/blink/renderer/core/css/parser/css_property_parser_test.cc b/third_party/blink/renderer/core/css/parser/css_property_parser_test.cc
index d60910e..98538609 100644
--- a/third_party/blink/renderer/core/css/parser/css_property_parser_test.cc
+++ b/third_party/blink/renderer/core/css/parser/css_property_parser_test.cc
@@ -317,18 +317,14 @@
   CSSParser::ParseSingleValue(CSSPropertyID::kClipPath,
                               "ellipse(1px 2px at invalid)", context);
 
-  EXPECT_FALSE(
-      UseCounter::IsCounted(*doc, WebFeature::kBasicShapeEllipseTwoRadius));
+  EXPECT_FALSE(doc->IsUseCounted(WebFeature::kBasicShapeEllipseTwoRadius));
   CSSParser::ParseSingleValue(CSSPropertyID::kClipPath, "ellipse(1px 2px)",
                               context);
-  EXPECT_TRUE(
-      UseCounter::IsCounted(*doc, WebFeature::kBasicShapeEllipseTwoRadius));
+  EXPECT_TRUE(doc->IsUseCounted(WebFeature::kBasicShapeEllipseTwoRadius));
 
-  EXPECT_FALSE(
-      UseCounter::IsCounted(*doc, WebFeature::kBasicShapeEllipseNoRadius));
+  EXPECT_FALSE(doc->IsUseCounted(WebFeature::kBasicShapeEllipseNoRadius));
   CSSParser::ParseSingleValue(CSSPropertyID::kClipPath, "ellipse()", context);
-  EXPECT_TRUE(
-      UseCounter::IsCounted(*doc, WebFeature::kBasicShapeEllipseNoRadius));
+  EXPECT_TRUE(doc->IsUseCounted(WebFeature::kBasicShapeEllipseNoRadius));
 }
 
 TEST(CSSPropertyParserTest, ScrollCustomizationPropertySingleValue) {
@@ -381,10 +377,10 @@
   Document& document = dummy_page_holder->GetDocument();
   Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
   WebFeature feature = WebFeature::kCSSGradient;
-  EXPECT_FALSE(UseCounter::IsCounted(document, feature));
+  EXPECT_FALSE(document.IsUseCounted(feature));
   document.documentElement()->SetInnerHTMLFromString(
       "<style>* { background-image: linear-gradient(red, blue); }</style>");
-  EXPECT_TRUE(UseCounter::IsCounted(document, feature));
+  EXPECT_TRUE(document.IsUseCounted(feature));
 }
 
 TEST(CSSPropertyParserTest, PaintUseCount) {
@@ -393,10 +389,10 @@
   Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
   document.SetSecureContextStateForTesting(SecureContextState::kSecure);
   WebFeature feature = WebFeature::kCSSPaintFunction;
-  EXPECT_FALSE(UseCounter::IsCounted(document, feature));
+  EXPECT_FALSE(document.IsUseCounted(feature));
   document.documentElement()->SetInnerHTMLFromString(
       "<style>span { background-image: paint(geometry); }</style>");
-  EXPECT_TRUE(UseCounter::IsCounted(document, feature));
+  EXPECT_TRUE(document.IsUseCounted(feature));
 }
 
 TEST(CSSPropertyParserTest, CrossFadeUseCount) {
@@ -404,11 +400,11 @@
   Document& document = dummy_page_holder->GetDocument();
   Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
   WebFeature feature = WebFeature::kWebkitCrossFade;
-  EXPECT_FALSE(UseCounter::IsCounted(document, feature));
+  EXPECT_FALSE(document.IsUseCounted(feature));
   document.documentElement()->SetInnerHTMLFromString(
       "<style>div { background-image: -webkit-cross-fade(url('from.png'), "
       "url('to.png'), 0.2); }</style>");
-  EXPECT_TRUE(UseCounter::IsCounted(document, feature));
+  EXPECT_TRUE(document.IsUseCounted(feature));
 }
 
 TEST(CSSPropertyParserTest, DropViewportDescriptor) {
@@ -447,7 +443,7 @@
   }
 
   bool IsCounted(WebFeature feature) {
-    return UseCounter::IsCounted(GetDocument(), feature);
+    return GetDocument().IsUseCounted(feature);
   }
 
   Document& GetDocument() { return dummy_page_holder_->GetDocument(); }
diff --git a/third_party/blink/renderer/core/css/parser/css_selector_parser_test.cc b/third_party/blink/renderer/core/css/parser/css_selector_parser_test.cc
index 822cc5a..8bc5292 100644
--- a/third_party/blink/renderer/core/css/parser/css_selector_parser_test.cc
+++ b/third_party/blink/renderer/core/css/parser/css_selector_parser_test.cc
@@ -596,14 +596,14 @@
 
   auto ExpectCount = [doc, context, sheet](const char* selector,
                                            WebFeature feature) {
-    EXPECT_FALSE(UseCounter::IsCounted(*doc, feature));
+    EXPECT_FALSE(doc->IsUseCounted(feature));
 
     CSSTokenizer tokenizer(selector);
     const auto tokens = tokenizer.TokenizeToEOF();
     CSSParserTokenRange range(tokens);
     CSSSelectorParser::ParseSelector(range, context, sheet);
 
-    EXPECT_TRUE(UseCounter::IsCounted(*doc, feature));
+    EXPECT_TRUE(doc->IsUseCounted(feature));
   };
 
   ExpectCount("::cue", WebFeature::kCSSSelectorCue);
diff --git a/third_party/blink/renderer/core/css/properties/computed_style_utils.h b/third_party/blink/renderer/core/css/properties/computed_style_utils.h
index 7623fa0..909160c 100644
--- a/third_party/blink/renderer/core/css/properties/computed_style_utils.h
+++ b/third_party/blink/renderer/core/css/properties/computed_style_utils.h
@@ -22,6 +22,7 @@
 class ComputedStyle;
 class CSSValue;
 class StyleColor;
+class StylePropertyShorthand;
 
 class ComputedStyleUtils {
   STATIC_ONLY(ComputedStyleUtils);
diff --git a/third_party/blink/renderer/core/css/properties/css_direction_aware_resolver.cc b/third_party/blink/renderer/core/css/properties/css_direction_aware_resolver.cc
new file mode 100644
index 0000000..deb663e
--- /dev/null
+++ b/third_party/blink/renderer/core/css/properties/css_direction_aware_resolver.cc
@@ -0,0 +1,165 @@
+// 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/css/properties/css_direction_aware_resolver.h"
+
+#include "base/stl_util.h"
+#include "third_party/blink/renderer/core/style_property_shorthand.h"
+
+namespace blink {
+namespace {
+
+template <size_t size>
+using PhysicalGroup = CSSDirectionAwareResolver::PhysicalGroup<size>;
+
+enum PhysicalAxis { kPhysicalAxisX, kPhysicalAxisY };
+enum PhysicalBoxSide { kTopSide, kRightSide, kBottomSide, kLeftSide };
+
+}  // namespace
+
+template <size_t size>
+CSSDirectionAwareResolver::PhysicalGroup<size>::PhysicalGroup(
+    const StylePropertyShorthand& shorthand)
+    : properties_(shorthand.properties()) {
+  DCHECK_EQ(size, shorthand.length());
+}
+
+template <size_t size>
+CSSDirectionAwareResolver::PhysicalGroup<size>::PhysicalGroup(
+    const CSSProperty* (&properties)[size])
+    : properties_(properties) {}
+
+template <size_t size>
+const CSSProperty& CSSDirectionAwareResolver::PhysicalGroup<size>::GetProperty(
+    size_t index) const {
+  DCHECK_LT(index, size);
+  return *properties_[index];
+}
+
+PhysicalGroup<4> CSSDirectionAwareResolver::BorderGroup() {
+  static const CSSProperty* kProperties[] = {
+      &GetCSSPropertyBorderTop(), &GetCSSPropertyBorderRight(),
+      &GetCSSPropertyBorderBottom(), &GetCSSPropertyBorderLeft()};
+  return PhysicalGroup<4>(kProperties);
+}
+
+PhysicalGroup<4> CSSDirectionAwareResolver::BorderColorGroup() {
+  return PhysicalGroup<4>(borderColorShorthand());
+}
+
+PhysicalGroup<4> CSSDirectionAwareResolver::BorderStyleGroup() {
+  return PhysicalGroup<4>(borderStyleShorthand());
+}
+
+PhysicalGroup<4> CSSDirectionAwareResolver::BorderWidthGroup() {
+  return PhysicalGroup<4>(borderWidthShorthand());
+}
+
+PhysicalGroup<4> CSSDirectionAwareResolver::InsetGroup() {
+  return PhysicalGroup<4>(insetShorthand());
+}
+
+PhysicalGroup<4> CSSDirectionAwareResolver::MarginGroup() {
+  return PhysicalGroup<4>(marginShorthand());
+}
+
+PhysicalGroup<2> CSSDirectionAwareResolver::MaxSizeGroup() {
+  static const CSSProperty* kProperties[] = {&GetCSSPropertyMaxWidth(),
+                                             &GetCSSPropertyMaxHeight()};
+  return PhysicalGroup<2>(kProperties);
+}
+
+PhysicalGroup<2> CSSDirectionAwareResolver::MinSizeGroup() {
+  static const CSSProperty* kProperties[] = {&GetCSSPropertyMinWidth(),
+                                             &GetCSSPropertyMinHeight()};
+  return PhysicalGroup<2>(kProperties);
+}
+
+PhysicalGroup<4> CSSDirectionAwareResolver::PaddingGroup() {
+  return PhysicalGroup<4>(paddingShorthand());
+}
+
+PhysicalGroup<4> CSSDirectionAwareResolver::ScrollMarginGroup() {
+  return PhysicalGroup<4>(scrollMarginShorthand());
+}
+
+PhysicalGroup<4> CSSDirectionAwareResolver::ScrollPaddingGroup() {
+  return PhysicalGroup<4>(scrollPaddingShorthand());
+}
+
+PhysicalGroup<2> CSSDirectionAwareResolver::SizeGroup() {
+  static const CSSProperty* kProperties[] = {&GetCSSPropertyWidth(),
+                                             &GetCSSPropertyHeight()};
+  return PhysicalGroup<2>(kProperties);
+}
+
+const CSSProperty& CSSDirectionAwareResolver::ResolveInlineStart(
+    TextDirection direction,
+    WritingMode writing_mode,
+    const PhysicalGroup<4>& group) {
+  if (direction == TextDirection::kLtr) {
+    if (IsHorizontalWritingMode(writing_mode))
+      return group.GetProperty(kLeftSide);
+    return group.GetProperty(kTopSide);
+  }
+  if (IsHorizontalWritingMode(writing_mode))
+    return group.GetProperty(kRightSide);
+  return group.GetProperty(kBottomSide);
+}
+
+const CSSProperty& CSSDirectionAwareResolver::ResolveInlineEnd(
+    TextDirection direction,
+    WritingMode writing_mode,
+    const PhysicalGroup<4>& group) {
+  if (direction == TextDirection::kLtr) {
+    if (IsHorizontalWritingMode(writing_mode))
+      return group.GetProperty(kRightSide);
+    return group.GetProperty(kBottomSide);
+  }
+  if (IsHorizontalWritingMode(writing_mode))
+    return group.GetProperty(kLeftSide);
+  return group.GetProperty(kTopSide);
+}
+
+const CSSProperty& CSSDirectionAwareResolver::ResolveBlockStart(
+    TextDirection direction,
+    WritingMode writing_mode,
+    const PhysicalGroup<4>& group) {
+  if (IsHorizontalWritingMode(writing_mode))
+    return group.GetProperty(kTopSide);
+  if (IsFlippedLinesWritingMode(writing_mode))
+    return group.GetProperty(kLeftSide);
+  return group.GetProperty(kRightSide);
+}
+
+const CSSProperty& CSSDirectionAwareResolver::ResolveBlockEnd(
+    TextDirection direction,
+    WritingMode writing_mode,
+    const PhysicalGroup<4>& group) {
+  if (IsHorizontalWritingMode(writing_mode))
+    return group.GetProperty(kBottomSide);
+  if (IsFlippedLinesWritingMode(writing_mode))
+    return group.GetProperty(kRightSide);
+  return group.GetProperty(kLeftSide);
+}
+
+const CSSProperty& CSSDirectionAwareResolver::ResolveInline(
+    TextDirection,
+    WritingMode writing_mode,
+    const PhysicalGroup<2>& group) {
+  if (IsHorizontalWritingMode(writing_mode))
+    return group.GetProperty(kPhysicalAxisX);
+  return group.GetProperty(kPhysicalAxisY);
+}
+
+const CSSProperty& CSSDirectionAwareResolver::ResolveBlock(
+    TextDirection,
+    WritingMode writing_mode,
+    const PhysicalGroup<2>& group) {
+  if (IsHorizontalWritingMode(writing_mode))
+    return group.GetProperty(kPhysicalAxisY);
+  return group.GetProperty(kPhysicalAxisX);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/css/properties/css_direction_aware_resolver.h b/third_party/blink/renderer/core/css/properties/css_direction_aware_resolver.h
new file mode 100644
index 0000000..e189f7c
--- /dev/null
+++ b/third_party/blink/renderer/core/css/properties/css_direction_aware_resolver.h
@@ -0,0 +1,74 @@
+// 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_CSS_PROPERTIES_CSS_DIRECTION_AWARE_RESOLVER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_PROPERTIES_CSS_DIRECTION_AWARE_RESOLVER_H_
+
+#include "third_party/blink/renderer/platform/text/text_direction.h"
+#include "third_party/blink/renderer/platform/text/writing_mode.h"
+#include "third_party/blink/renderer/platform/wtf/allocator.h"
+
+namespace blink {
+
+class CSSProperty;
+class StylePropertyShorthand;
+
+class CSSDirectionAwareResolver {
+  STATIC_ONLY(CSSDirectionAwareResolver);
+
+ public:
+  // A group of physical properties that's used by the 'Resolve*' functions
+  // to convert a direction-aware property into a physical property.
+  template <size_t size>
+  class PhysicalGroup {
+   public:
+    PhysicalGroup(const StylePropertyShorthand&);
+    PhysicalGroup(const CSSProperty* (&properties)[size]);
+    const CSSProperty& GetProperty(size_t index) const;
+
+   private:
+    const CSSProperty** properties_;
+  };
+
+  static PhysicalGroup<4> BorderGroup();
+  static PhysicalGroup<4> BorderColorGroup();
+  static PhysicalGroup<4> BorderStyleGroup();
+  static PhysicalGroup<4> BorderWidthGroup();
+  static PhysicalGroup<4> InsetGroup();
+  static PhysicalGroup<4> MarginGroup();
+  static PhysicalGroup<2> MaxSizeGroup();
+  static PhysicalGroup<2> MinSizeGroup();
+  static PhysicalGroup<4> PaddingGroup();
+  static PhysicalGroup<4> ScrollMarginGroup();
+  static PhysicalGroup<4> ScrollPaddingGroup();
+  static PhysicalGroup<2> SizeGroup();
+
+  // These resolvers expect a PhysicalGroup with box sides, in the following
+  // order: top, right, bottom, left.
+  static const CSSProperty& ResolveInlineStart(TextDirection,
+                                               WritingMode,
+                                               const PhysicalGroup<4>&);
+  static const CSSProperty& ResolveInlineEnd(TextDirection,
+                                             WritingMode,
+                                             const PhysicalGroup<4>&);
+  static const CSSProperty& ResolveBlockStart(TextDirection,
+                                              WritingMode,
+                                              const PhysicalGroup<4>&);
+  static const CSSProperty& ResolveBlockEnd(TextDirection,
+                                            WritingMode,
+                                            const PhysicalGroup<4>&);
+
+  // These resolvers expect a PhysicalGroup with dimensions, in the following
+  // order: horizontal, vertical.
+  static const CSSProperty& ResolveInline(TextDirection,
+                                          WritingMode,
+                                          const PhysicalGroup<2>&);
+  static const CSSProperty& ResolveBlock(TextDirection,
+                                         WritingMode,
+                                         const PhysicalGroup<2>&);
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_PROPERTIES_CSS_DIRECTION_AWARE_RESOLVER_H_
diff --git a/third_party/blink/renderer/core/css/properties/css_parsing_utils_test.cc b/third_party/blink/renderer/core/css/properties/css_parsing_utils_test.cc
index 701c77e..9b2e8e5 100644
--- a/third_party/blink/renderer/core/css/properties/css_parsing_utils_test.cc
+++ b/third_party/blink/renderer/core/css/properties/css_parsing_utils_test.cc
@@ -15,10 +15,10 @@
   Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
   Document& document = dummy_page_holder->GetDocument();
   WebFeature feature = WebFeature::kCSSBasicShape;
-  EXPECT_FALSE(UseCounter::IsCounted(document, feature));
+  EXPECT_FALSE(document.IsUseCounted(feature));
   document.documentElement()->SetInnerHTMLFromString(
       "<style>span { shape-outside: circle(); }</style>");
-  EXPECT_TRUE(UseCounter::IsCounted(document, feature));
+  EXPECT_TRUE(document.IsUseCounted(feature));
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/properties/css_property.cc b/third_party/blink/renderer/core/css/properties/css_property.cc
index 2d8f6eb..7493852 100644
--- a/third_party/blink/renderer/core/css/properties/css_property.cc
+++ b/third_party/blink/renderer/core/css/properties/css_property.cc
@@ -57,70 +57,6 @@
   }
 }
 
-const StylePropertyShorthand& CSSProperty::BorderDirections() {
-  static const CSSProperty* kProperties[4] = {
-      &GetCSSPropertyBorderTop(), &GetCSSPropertyBorderRight(),
-      &GetCSSPropertyBorderBottom(), &GetCSSPropertyBorderLeft()};
-  DEFINE_STATIC_LOCAL(
-      StylePropertyShorthand, border_directions,
-      (CSSPropertyID::kBorder, kProperties, base::size(kProperties)));
-  return border_directions;
-}
-
-const CSSProperty& CSSProperty::ResolveAfterToPhysicalProperty(
-    TextDirection direction,
-    WritingMode writing_mode,
-    const StylePropertyShorthand& shorthand) {
-  const CSSProperty** shorthand_properties = shorthand.properties();
-  if (IsHorizontalWritingMode(writing_mode))
-    return *shorthand_properties[kBottomSide];
-  if (IsFlippedLinesWritingMode(writing_mode))
-    return *shorthand_properties[kRightSide];
-  return *shorthand_properties[kLeftSide];
-}
-
-const CSSProperty& CSSProperty::ResolveBeforeToPhysicalProperty(
-    TextDirection direction,
-    WritingMode writing_mode,
-    const StylePropertyShorthand& shorthand) {
-  const CSSProperty** shorthand_properties = shorthand.properties();
-  if (IsHorizontalWritingMode(writing_mode))
-    return *shorthand_properties[kTopSide];
-  if (IsFlippedLinesWritingMode(writing_mode))
-    return *shorthand_properties[kLeftSide];
-  return *shorthand_properties[kRightSide];
-}
-
-const CSSProperty& CSSProperty::ResolveEndToPhysicalProperty(
-    TextDirection direction,
-    WritingMode writing_mode,
-    const StylePropertyShorthand& shorthand) {
-  const CSSProperty** shorthand_properties = shorthand.properties();
-  if (direction == TextDirection::kLtr) {
-    if (IsHorizontalWritingMode(writing_mode))
-      return *shorthand_properties[kRightSide];
-    return *shorthand_properties[kBottomSide];
-  }
-  if (IsHorizontalWritingMode(writing_mode))
-    return *shorthand_properties[kLeftSide];
-  return *shorthand_properties[kTopSide];
-}
-
-const CSSProperty& CSSProperty::ResolveStartToPhysicalProperty(
-    TextDirection direction,
-    WritingMode writing_mode,
-    const StylePropertyShorthand& shorthand) {
-  const CSSProperty** shorthand_properties = shorthand.properties();
-  if (direction == TextDirection::kLtr) {
-    if (IsHorizontalWritingMode(writing_mode))
-      return *shorthand_properties[kLeftSide];
-    return *shorthand_properties[kTopSide];
-  }
-  if (IsHorizontalWritingMode(writing_mode))
-    return *shorthand_properties[kRightSide];
-  return *shorthand_properties[kBottomSide];
-}
-
 const CSSValue* CSSProperty::CSSValueFromComputedStyle(
     const ComputedStyle& style,
     const LayoutObject* layout_object,
diff --git a/third_party/blink/renderer/core/css/properties/css_property.h b/third_party/blink/renderer/core/css/properties/css_property.h
index 33fd538..2ca09d8 100644
--- a/third_party/blink/renderer/core/css/properties/css_property.h
+++ b/third_party/blink/renderer/core/css/properties/css_property.h
@@ -20,11 +20,8 @@
 class ComputedStyle;
 class CrossThreadStyleValue;
 class LayoutObject;
-class StylePropertyShorthand;
 class SVGComputedStyle;
 
-enum PhysicalBoxSide { kTopSide, kRightSide, kBottomSide, kLeftSide };
-
 class CORE_EXPORT CSSProperty : public CSSUnresolvedProperty {
  public:
   static const CSSProperty& Get(CSSPropertyID);
@@ -108,24 +105,6 @@
         flags_(flags),
         repetition_separator_(repetition_separator) {}
 
-  static const StylePropertyShorthand& BorderDirections();
-  static const CSSProperty& ResolveAfterToPhysicalProperty(
-      TextDirection,
-      WritingMode,
-      const StylePropertyShorthand&);
-  static const CSSProperty& ResolveBeforeToPhysicalProperty(
-      TextDirection,
-      WritingMode,
-      const StylePropertyShorthand&);
-  static const CSSProperty& ResolveEndToPhysicalProperty(
-      TextDirection,
-      WritingMode,
-      const StylePropertyShorthand&);
-  static const CSSProperty& ResolveStartToPhysicalProperty(
-      TextDirection,
-      WritingMode,
-      const StylePropertyShorthand&);
-
  private:
   CSSPropertyID property_id_;
   uint16_t flags_;
diff --git a/third_party/blink/renderer/core/css/resolver/filter_operation_resolver.cc b/third_party/blink/renderer/core/css/resolver/filter_operation_resolver.cc
index f4d3121..df8257d 100644
--- a/third_party/blink/renderer/core/css/resolver/filter_operation_resolver.cc
+++ b/third_party/blink/renderer/core/css/resolver/filter_operation_resolver.cc
@@ -117,7 +117,7 @@
       feature = WebFeature::kCSSFilterDropShadow;
       break;
   };
-  UseCounter::Count(document, feature);
+  document.CountUse(feature);
 }
 
 static double ResolveFirstArgumentForFunction(const CSSFunctionValue& filter,
diff --git a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
index 47091573..d0cd0e1a 100644
--- a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
@@ -204,7 +204,7 @@
     family_name = AtomicString(font_family_value->Value());
 #if defined(OS_MACOSX)
     if (family_name == FontCache::LegacySystemFontFamily()) {
-      UseCounter::Count(*document_for_count, WebFeature::kBlinkMacSystemFont);
+      document_for_count->CountUse(WebFeature::kBlinkMacSystemFont);
       family_name = font_family_names::kSystemUi;
     }
 #endif
diff --git a/third_party/blink/renderer/core/css/style_engine_context.cc b/third_party/blink/renderer/core/css/style_engine_context.cc
index 410608e2..88e2c9c 100644
--- a/third_party/blink/renderer/core/css/style_engine_context.cc
+++ b/third_party/blink/renderer/core/css/style_engine_context.cc
@@ -38,8 +38,7 @@
   if (!added_pending_sheet_before_body_) {
     added_pending_sheet_before_body_ = !document.body();
     if (!added_pending_sheet_before_body_) {
-      UseCounter::Count(document,
-                        WebFeature::kPendingStylesheetAddedAfterBodyStarted);
+      document.CountUse(WebFeature::kPendingStylesheetAddedAfterBodyStarted);
     }
   }
 }
diff --git a/third_party/blink/renderer/core/css/style_engine_test.cc b/third_party/blink/renderer/core/css/style_engine_test.cc
index ceacaa7..122bca6 100644
--- a/third_party/blink/renderer/core/css/style_engine_test.cc
+++ b/third_party/blink/renderer/core/css/style_engine_test.cc
@@ -1781,8 +1781,8 @@
   GetDocument().View()->UpdateAllLifecyclePhases(
       DocumentLifecycle::LifecycleUpdateReason::kTest);
 
-  EXPECT_FALSE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kCSSSelectorEmptyWhitespaceOnlyFail));
+  EXPECT_FALSE(GetDocument().IsUseCounted(
+      WebFeature::kCSSSelectorEmptyWhitespaceOnlyFail));
 
   auto* div_elements = GetDocument().getElementsByTagName("div");
   ASSERT_TRUE(div_elements);
@@ -1792,8 +1792,7 @@
     element->setAttribute(blink::html_names::kClassAttr, "match");
     element->GetDocument().View()->UpdateAllLifecyclePhases(
         DocumentLifecycle::LifecycleUpdateReason::kTest);
-    return UseCounter::IsCounted(
-        element->GetDocument(),
+    return element->GetDocument().IsUseCounted(
         WebFeature::kCSSSelectorEmptyWhitespaceOnlyFail);
   };
 
diff --git a/third_party/blink/renderer/core/css/style_environment_variables_test.cc b/third_party/blink/renderer/core/css/style_environment_variables_test.cc
index 656c075..ba504a91 100644
--- a/third_party/blink/renderer/core/css/style_environment_variables_test.cc
+++ b/third_party/blink/renderer/core/css/style_environment_variables_test.cc
@@ -376,68 +376,61 @@
 TEST_F(StyleEnvironmentVariablesTest, RecordUseCounter_IgnoreMediaControls) {
   InitializeWithHTML(GetFrame(), "<video controls />");
 
-  EXPECT_FALSE(UseCounter::IsCounted(GetDocument(),
-                                     WebFeature::kCSSEnvironmentVariable));
-  EXPECT_FALSE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kCSSEnvironmentVariable_SafeAreaInsetTop));
-  EXPECT_FALSE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kCSSEnvironmentVariable_SafeAreaInsetLeft));
-  EXPECT_FALSE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kCSSEnvironmentVariable_SafeAreaInsetBottom));
-  EXPECT_FALSE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kCSSEnvironmentVariable_SafeAreaInsetRight));
+  EXPECT_FALSE(GetDocument().IsUseCounted(WebFeature::kCSSEnvironmentVariable));
+  EXPECT_FALSE(GetDocument().IsUseCounted(
+      WebFeature::kCSSEnvironmentVariable_SafeAreaInsetTop));
+  EXPECT_FALSE(GetDocument().IsUseCounted(
+      WebFeature::kCSSEnvironmentVariable_SafeAreaInsetLeft));
+  EXPECT_FALSE(GetDocument().IsUseCounted(
+      WebFeature::kCSSEnvironmentVariable_SafeAreaInsetBottom));
+  EXPECT_FALSE(GetDocument().IsUseCounted(
+      WebFeature::kCSSEnvironmentVariable_SafeAreaInsetRight));
 }
 
 TEST_F(StyleEnvironmentVariablesTest, RecordUseCounter_InvalidProperty) {
   InitializeTestPageWithVariableNamed(GetFrame(), kVariableName);
-  EXPECT_TRUE(UseCounter::IsCounted(GetDocument(),
-                                    WebFeature::kCSSEnvironmentVariable));
+  EXPECT_TRUE(GetDocument().IsUseCounted(WebFeature::kCSSEnvironmentVariable));
 }
 
 TEST_F(StyleEnvironmentVariablesTest, RecordUseCounter_NoVariable) {
   InitializeWithHTML(GetFrame(), "");
-  EXPECT_FALSE(UseCounter::IsCounted(GetDocument(),
-                                     WebFeature::kCSSEnvironmentVariable));
+  EXPECT_FALSE(GetDocument().IsUseCounted(WebFeature::kCSSEnvironmentVariable));
 }
 
 TEST_F(StyleEnvironmentVariablesTest, RecordUseCounter_SafeAreaInsetBottom) {
   InitializeTestPageWithVariableNamed(GetFrame(),
                                       UADefinedVariable::kSafeAreaInsetBottom);
 
-  EXPECT_TRUE(UseCounter::IsCounted(GetDocument(),
-                                    WebFeature::kCSSEnvironmentVariable));
-  EXPECT_TRUE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kCSSEnvironmentVariable_SafeAreaInsetBottom));
+  EXPECT_TRUE(GetDocument().IsUseCounted(WebFeature::kCSSEnvironmentVariable));
+  EXPECT_TRUE(GetDocument().IsUseCounted(
+      WebFeature::kCSSEnvironmentVariable_SafeAreaInsetBottom));
 }
 
 TEST_F(StyleEnvironmentVariablesTest, RecordUseCounter_SafeAreaInsetLeft) {
   InitializeTestPageWithVariableNamed(GetFrame(),
                                       UADefinedVariable::kSafeAreaInsetLeft);
 
-  EXPECT_TRUE(UseCounter::IsCounted(GetDocument(),
-                                    WebFeature::kCSSEnvironmentVariable));
-  EXPECT_TRUE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kCSSEnvironmentVariable_SafeAreaInsetLeft));
+  EXPECT_TRUE(GetDocument().IsUseCounted(WebFeature::kCSSEnvironmentVariable));
+  EXPECT_TRUE(GetDocument().IsUseCounted(
+      WebFeature::kCSSEnvironmentVariable_SafeAreaInsetLeft));
 }
 
 TEST_F(StyleEnvironmentVariablesTest, RecordUseCounter_SafeAreaInsetRight) {
   InitializeTestPageWithVariableNamed(GetFrame(),
                                       UADefinedVariable::kSafeAreaInsetRight);
 
-  EXPECT_TRUE(UseCounter::IsCounted(GetDocument(),
-                                    WebFeature::kCSSEnvironmentVariable));
-  EXPECT_TRUE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kCSSEnvironmentVariable_SafeAreaInsetRight));
+  EXPECT_TRUE(GetDocument().IsUseCounted(WebFeature::kCSSEnvironmentVariable));
+  EXPECT_TRUE(GetDocument().IsUseCounted(
+      WebFeature::kCSSEnvironmentVariable_SafeAreaInsetRight));
 }
 
 TEST_F(StyleEnvironmentVariablesTest, RecordUseCounter_SafeAreaInsetTop) {
   InitializeTestPageWithVariableNamed(GetFrame(),
                                       UADefinedVariable::kSafeAreaInsetTop);
 
-  EXPECT_TRUE(UseCounter::IsCounted(GetDocument(),
-                                    WebFeature::kCSSEnvironmentVariable));
-  EXPECT_TRUE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kCSSEnvironmentVariable_SafeAreaInsetTop));
+  EXPECT_TRUE(GetDocument().IsUseCounted(WebFeature::kCSSEnvironmentVariable));
+  EXPECT_TRUE(GetDocument().IsUseCounted(
+      WebFeature::kCSSEnvironmentVariable_SafeAreaInsetTop));
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index bb3aff0..acfcd30 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -3327,7 +3327,7 @@
                          const AtomicString& replace,
                          ExceptionState& exception_state) {
   if (replace == "replace") {
-    UseCounter::Count(Loader(), WebFeature::kDocumentOpenTwoArgsWithReplace);
+    CountUse(WebFeature::kDocumentOpenTwoArgsWithReplace);
   }
   open(EnteredDOMWindow(isolate)->document(), exception_state);
   return this;
@@ -5285,7 +5285,7 @@
   if (GetSettings() && !GetSettings()->GetCookieEnabled())
     return String();
 
-  UseCounter::Count(*this, WebFeature::kCookieGet);
+  CountUse(WebFeature::kCookieGet);
 
   // FIXME: The HTML5 DOM spec states that this attribute can raise an
   // InvalidStateError exception on getting if the Document has no
@@ -5302,7 +5302,7 @@
       exception_state.ThrowSecurityError("Access is denied for this document.");
     return String();
   } else if (GetSecurityOrigin()->IsLocal()) {
-    UseCounter::Count(*this, WebFeature::kFileAccessedCookies);
+    CountUse(WebFeature::kFileAccessedCookies);
   }
 
   KURL cookie_url = CookieURL();
@@ -7501,13 +7501,12 @@
 bool Document::IsSecureContext() const {
   bool is_secure = secure_context_state_ == SecureContextState::kSecure;
   if (GetSandboxFlags() != WebSandboxFlags::kNone) {
-    UseCounter::Count(
-        *this, is_secure
-                   ? WebFeature::kSecureContextCheckForSandboxedOriginPassed
-                   : WebFeature::kSecureContextCheckForSandboxedOriginFailed);
+    CountUse(is_secure
+                 ? WebFeature::kSecureContextCheckForSandboxedOriginPassed
+                 : WebFeature::kSecureContextCheckForSandboxedOriginFailed);
   }
-  UseCounter::Count(*this, is_secure ? WebFeature::kSecureContextCheckPassed
-                                     : WebFeature::kSecureContextCheckFailed);
+  CountUse(is_secure ? WebFeature::kSecureContextCheckPassed
+                     : WebFeature::kSecureContextCheckFailed);
   return is_secure;
 }
 
@@ -7859,7 +7858,7 @@
         ad ? WebFeature::kFocusWithoutUserActivationNotSandboxedAdFrame
            : WebFeature::kFocusWithoutUserActivationNotSandboxedNotAdFrame;
   }
-  UseCounter::Count(*this, uma_type);
+  CountUse(uma_type);
   if (!RuntimeEnabledFeatures::BlockingFocusWithoutUserActivationEnabled())
     return true;
   return IsFeatureEnabled(
@@ -8070,6 +8069,52 @@
   MediaQueryAffectingValueChanged();
 }
 
+void Document::CountUse(mojom::WebFeature feature) const {
+  if (DocumentLoader* loader = Loader()) {
+    loader->CountUse(feature);
+  }
+}
+
+void Document::CountUse(mojom::WebFeature feature) {
+  if (DocumentLoader* loader = Loader()) {
+    loader->CountUse(feature);
+  }
+}
+
+void Document::CountUse(CSSPropertyID property,
+                        UseCounterHelper::CSSPropertyType type) const {
+  if (DocumentLoader* loader = Loader()) {
+    loader->GetUseCounterHelper().Count(property, type, GetFrame());
+  }
+}
+
+void Document::CountUseOnlyInCrossOriginIframe(
+    mojom::WebFeature feature) const {
+  LocalFrame* frame = GetFrame();
+  if (frame && frame->IsCrossOriginSubframe())
+    CountUse(feature);
+}
+
+bool Document::IsUseCounted(mojom::WebFeature feature) const {
+  if (DocumentLoader* loader = Loader()) {
+    return loader->GetUseCounterHelper().HasRecordedMeasurement(feature);
+  }
+  return false;
+}
+
+bool Document::IsUseCounted(CSSPropertyID property,
+                            UseCounterHelper::CSSPropertyType type) const {
+  if (DocumentLoader* loader = Loader()) {
+    return loader->GetUseCounterHelper().IsCounted(property, type);
+  }
+  return false;
+}
+
+void Document::ClearUseCounterForTesting(mojom::WebFeature feature) {
+  if (DocumentLoader* loader = Loader())
+    loader->GetUseCounterHelper().ClearMeasurementForTesting(feature);
+}
+
 template class CORE_TEMPLATE_EXPORT Supplement<Document>;
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h
index 2652e41..5f0cd9e 100644
--- a/third_party/blink/renderer/core/dom/document.h
+++ b/third_party/blink/renderer/core/dom/document.h
@@ -39,10 +39,12 @@
 #include "services/metrics/public/cpp/ukm_source_id.h"
 #include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom-blink.h"
 #include "third_party/blink/public/mojom/frame/navigation_initiator.mojom-blink.h"
+#include "third_party/blink/public/mojom/web_feature/web_feature.mojom-shared.h"
 #include "third_party/blink/public/platform/web_focus_type.h"
 #include "third_party/blink/public/platform/web_insecure_request_policy.h"
 #include "third_party/blink/renderer/core/accessibility/axid.h"
 #include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/css/css_property_names.h"
 #include "third_party/blink/renderer/core/dom/container_node.h"
 #include "third_party/blink/renderer/core/dom/create_element_flags.h"
 #include "third_party/blink/renderer/core/dom/document_encoding_data.h"
@@ -64,6 +66,7 @@
 #include "third_party/blink/renderer/core/execution_context/security_context.h"
 #include "third_party/blink/renderer/core/frame/dom_timer_coordinator.h"
 #include "third_party/blink/renderer/core/frame/hosts_using_features.h"
+#include "third_party/blink/renderer/core/frame/use_counter.h"
 #include "third_party/blink/renderer/core/html/custom/v0_custom_element.h"
 #include "third_party/blink/renderer/core/html/parser/parser_synchronization_policy.h"
 #include "third_party/blink/renderer/core/scroll/scroll_types.h"
@@ -1557,6 +1560,23 @@
   // Update the presentation level color-scheme property for the root element.
   void ColorSchemeMetaChanged();
 
+  // Use counter related functions.
+  void CountUse(mojom::WebFeature feature) final;
+  void CountUse(mojom::WebFeature feature) const;
+  void CountUse(CSSPropertyID property_id,
+                UseCounterHelper::CSSPropertyType) const;
+  // Count |feature| only when this document is associated with a cross-origin
+  // iframe.
+  void CountUseOnlyInCrossOriginIframe(mojom::WebFeature feature) const;
+  // Return whether the Feature was previously counted for this document.
+  // NOTE: only for use in testing.
+  bool IsUseCounted(mojom::WebFeature) const;
+  // Return whether the property was previously counted for this document.
+  // NOTE: only for use in testing.
+  bool IsUseCounted(CSSPropertyID property,
+                    UseCounterHelper::CSSPropertyType) const;
+  void ClearUseCounterForTesting(mojom::WebFeature);
+
  protected:
   void DidUpdateSecurityOrigin() final;
 
diff --git a/third_party/blink/renderer/core/dom/events/event_target.cc b/third_party/blink/renderer/core/dom/events/event_target.cc
index 3fcb76c..5b28648 100644
--- a/third_party/blink/renderer/core/dom/events/event_target.cc
+++ b/third_party/blink/renderer/core/dom/events/event_target.cc
@@ -150,7 +150,7 @@
 bool CheckTypeThenUseCount(const Event& event,
                            const AtomicString& event_type_to_count,
                            const WebFeature feature,
-                           const Document* document) {
+                           Document* document) {
   if (event.type() != event_type_to_count)
     return false;
   UseCounter::Count(*document, feature);
@@ -448,10 +448,9 @@
       event_type == event_type_names::kTouchstart) {
     if (const LocalDOMWindow* executing_window = ExecutingWindow()) {
       if (const Document* document = executing_window->document()) {
-        UseCounter::Count(*document,
-                          options->passive()
-                              ? WebFeature::kPassiveTouchEventListener
-                              : WebFeature::kNonPassiveTouchEventListener);
+        document->CountUse(options->passive()
+                               ? WebFeature::kPassiveTouchEventListener
+                               : WebFeature::kNonPassiveTouchEventListener);
       }
     }
   }
@@ -483,7 +482,7 @@
     const AtomicString& event_type,
     RegisteredEventListener& registered_listener) {
   if (const LocalDOMWindow* executing_window = ExecutingWindow()) {
-    if (const Document* document = executing_window->document()) {
+    if (Document* document = executing_window->document()) {
       if (event_type == event_type_names::kAuxclick)
         UseCounter::Count(*document, WebFeature::kAuxclickAddListenerCount);
       else if (event_type == event_type_names::kAppinstalled)
@@ -733,7 +732,7 @@
   }
 
   if (const LocalDOMWindow* executing_window = ExecutingWindow()) {
-    if (const Document* document = executing_window->document()) {
+    if (Document* document = executing_window->document()) {
       if (legacy_listeners_vector) {
         if (listeners_vector)
           UseCounter::Count(*document, prefixed_and_unprefixed_feature);
@@ -819,7 +818,7 @@
   };
 
   if (const LocalDOMWindow* executing_window = ExecutingWindow()) {
-    if (const Document* document = executing_window->document()) {
+    if (Document* document = executing_window->document()) {
       if (CheckTypeThenUseCount(event, event_type_names::kBeforeunload,
                                 WebFeature::kDocumentBeforeUnloadFired,
                                 document)) {
diff --git a/third_party/blink/renderer/core/dom/events/event_target_test.cc b/third_party/blink/renderer/core/dom/events/event_target_test.cc
index b8fc6cd..6f9250e3 100644
--- a/third_party/blink/renderer/core/dom/events/event_target_test.cc
+++ b/third_party/blink/renderer/core/dom/events/event_target_test.cc
@@ -52,40 +52,40 @@
 }
 
 TEST_F(EventTargetTest, UseCountPassiveTouchEventListener) {
-  EXPECT_FALSE(UseCounter::IsCounted(GetDocument(),
-                                     WebFeature::kPassiveTouchEventListener));
+  EXPECT_FALSE(
+      GetDocument().IsUseCounted(WebFeature::kPassiveTouchEventListener));
   GetDocument().GetSettings()->SetScriptEnabled(true);
   GetDocument().GetFrame()->GetScriptController().ExecuteScriptInMainWorld(
       "window.addEventListener('touchstart', function() {}, {passive: true});");
-  EXPECT_TRUE(UseCounter::IsCounted(GetDocument(),
-                                    WebFeature::kPassiveTouchEventListener));
-  EXPECT_FALSE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kNonPassiveTouchEventListener));
+  EXPECT_TRUE(
+      GetDocument().IsUseCounted(WebFeature::kPassiveTouchEventListener));
+  EXPECT_FALSE(
+      GetDocument().IsUseCounted(WebFeature::kNonPassiveTouchEventListener));
 }
 
 TEST_F(EventTargetTest, UseCountNonPassiveTouchEventListener) {
-  EXPECT_FALSE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kNonPassiveTouchEventListener));
+  EXPECT_FALSE(
+      GetDocument().IsUseCounted(WebFeature::kNonPassiveTouchEventListener));
   GetDocument().GetSettings()->SetScriptEnabled(true);
   GetDocument().GetFrame()->GetScriptController().ExecuteScriptInMainWorld(
       "window.addEventListener('touchstart', function() {}, {passive: "
       "false});");
-  EXPECT_TRUE(UseCounter::IsCounted(GetDocument(),
-                                    WebFeature::kNonPassiveTouchEventListener));
-  EXPECT_FALSE(UseCounter::IsCounted(GetDocument(),
-                                     WebFeature::kPassiveTouchEventListener));
+  EXPECT_TRUE(
+      GetDocument().IsUseCounted(WebFeature::kNonPassiveTouchEventListener));
+  EXPECT_FALSE(
+      GetDocument().IsUseCounted(WebFeature::kPassiveTouchEventListener));
 }
 
 TEST_F(EventTargetTest, UseCountPassiveTouchEventListenerPassiveNotSpecified) {
-  EXPECT_FALSE(UseCounter::IsCounted(GetDocument(),
-                                     WebFeature::kPassiveTouchEventListener));
+  EXPECT_FALSE(
+      GetDocument().IsUseCounted(WebFeature::kPassiveTouchEventListener));
   GetDocument().GetSettings()->SetScriptEnabled(true);
   GetDocument().GetFrame()->GetScriptController().ExecuteScriptInMainWorld(
       "window.addEventListener('touchstart', function() {});");
-  EXPECT_TRUE(UseCounter::IsCounted(GetDocument(),
-                                    WebFeature::kPassiveTouchEventListener));
-  EXPECT_FALSE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kNonPassiveTouchEventListener));
+  EXPECT_TRUE(
+      GetDocument().IsUseCounted(WebFeature::kPassiveTouchEventListener));
+  EXPECT_FALSE(
+      GetDocument().IsUseCounted(WebFeature::kNonPassiveTouchEventListener));
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/editing/finder/find_buffer.cc b/third_party/blink/renderer/core/editing/finder/find_buffer.cc
index 3006efe..9c691fd 100644
--- a/third_party/blink/renderer/core/editing/finder/find_buffer.cc
+++ b/third_party/blink/renderer/core/editing/finder/find_buffer.cc
@@ -97,46 +97,6 @@
   return result;
 }
 
-void FindBuffer::InvisibleLayoutScope::EnsureRecalc(Node& block_root) {
-  if (!RuntimeEnabledFeatures::InvisibleDOMEnabled())
-    return;
-  if (did_recalc_)
-    return;
-  did_recalc_ = true;
-  DCHECK(block_root.GetDocument().Lifecycle().GetState() >=
-         DocumentLifecycle::kStyleClean);
-  // If we're in an invisible subtree, we should recalc style from the invisible
-  // root/the highest ancestor of |block_root| with the invisible attribute,
-  // otherwise we should recalc from |block_root|.
-  // InvisibleRoot is always non-null when IsInsideInvisibleSubtree is true.
-  if (InvisibleDOM::IsInsideInvisibleSubtree(block_root))
-    invisible_root_ = InvisibleDOM::InvisibleRoot(block_root);
-  else
-    invisible_root_ = &ToElement(block_root);
-
-  DCHECK(invisible_root_);
-  invisible_root_->GetDocument().SetFindInPageRoot(invisible_root_);
-  invisible_root_->SetNeedsStyleRecalc(
-      kSubtreeStyleChange,
-      StyleChangeReasonForTracing::Create(style_change_reason::kFindInvisible));
-  // TODO(rakina): This currently does layout too and might be expensive. In the
-  // future, we might to figure out a way to make NGOffsetMapping work with only
-  // style & layout tree so that we don't have to do layout here.
-  invisible_root_->GetDocument().UpdateStyleAndLayout();
-}
-
-FindBuffer::InvisibleLayoutScope::~InvisibleLayoutScope() {
-  if (!RuntimeEnabledFeatures::InvisibleDOMEnabled())
-    return;
-  if (!did_recalc_)
-    return;
-  invisible_root_->GetDocument().SetFindInPageRoot(nullptr);
-  invisible_root_->SetNeedsStyleRecalc(
-      kSubtreeStyleChange,
-      StyleChangeReasonForTracing::Create(style_change_reason::kFindInvisible));
-  invisible_root_->GetDocument().UpdateStyleAndLayout();
-}
-
 bool ShouldIgnoreContents(const Node& node) {
   const auto* element = DynamicTo<HTMLElement>(node);
   if (!element)
@@ -333,12 +293,6 @@
       FlatTreeTraversal::LastWithinOrSelf(block_ancestor));
   const LayoutBlockFlow* last_block_flow = nullptr;
 
-  // Calculate layout tree and style for invisible nodes inside the whole
-  // subtree of |block_ancestor|.
-  if (RuntimeEnabledFeatures::InvisibleDOMEnabled() && node &&
-      InvisibleDOM::IsInsideInvisibleSubtree(*node))
-    invisible_layout_scope_.EnsureRecalc(block_ancestor);
-
   // Collect all text under |block_ancestor| to |buffer_|,
   // unless we meet another block on the way. If so, we should split.
   // Example: <div id="outer">a<span>b</span>c<div>d</div></div>
@@ -369,19 +323,6 @@
       node = FlatTreeTraversal::NextSkippingChildren(*node);
       continue;
     }
-    if (RuntimeEnabledFeatures::InvisibleDOMEnabled() &&
-        node->IsElementNode() && ToElement(node)->HasInvisibleAttribute() &&
-        !invisible_layout_scope_.DidRecalc()) {
-      // We found and invisible node. Calculate the layout & style for the whole
-      // block at once, and we need to recalculate the NGOffsetMapping and start
-      // from the beginning again because the layout tree had changed.
-      mapping_needs_recalc_ = true;
-      node = first_traversed_node;
-      last_block_flow = nullptr;
-      buffer_.clear();
-      invisible_layout_scope_.EnsureRecalc(block_ancestor);
-      continue;
-    }
     const ComputedStyle* style = node->EnsureComputedStyle();
     if (style->Display() == EDisplay::kNone) {
       // This element and its descendants are not visible, skip it.
@@ -473,10 +414,8 @@
 void FindBuffer::AddTextToBuffer(const Text& text_node,
                                  LayoutBlockFlow& block_flow,
                                  const EphemeralRangeInFlatTree& range) {
-  if (!offset_mapping_ || mapping_needs_recalc_) {
+  if (!offset_mapping_)
     offset_mapping_ = NGInlineNode::GetOffsetMapping(&block_flow);
-    mapping_needs_recalc_ = false;
-  }
 
   Position node_start =
       (&text_node == range.StartPosition().ComputeContainerNode())
diff --git a/third_party/blink/renderer/core/editing/finder/find_buffer.h b/third_party/blink/renderer/core/editing/finder/find_buffer.h
index 35a882f..9c29ff5 100644
--- a/third_party/blink/renderer/core/editing/finder/find_buffer.h
+++ b/third_party/blink/renderer/core/editing/finder/find_buffer.h
@@ -134,21 +134,6 @@
                                   const Node* search_range_end_node,
                                   const Node* node_after_block);
 
-  class CORE_EXPORT InvisibleLayoutScope {
-    STACK_ALLOCATED();
-
-   public:
-    InvisibleLayoutScope() {}
-    ~InvisibleLayoutScope();
-
-    void EnsureRecalc(Node& block_root);
-    bool DidRecalc() { return did_recalc_; }
-
-   private:
-    bool did_recalc_ = false;
-    Member<Element> invisible_root_;
-  };
-
   // Mapping for position in buffer -> actual node where the text came from,
   // along with the offset in the NGOffsetMapping of this find_buffer.
   // This is needed because when we find a match in the buffer, we want to know
@@ -190,14 +175,12 @@
                        LayoutBlockFlow& block_flow,
                        const EphemeralRangeInFlatTree& range);
 
-  InvisibleLayoutScope invisible_layout_scope_;
   Member<Node> node_after_block_;
   Vector<UChar> buffer_;
   Vector<BufferNodeMapping> buffer_node_mappings_;
   Vector<DisplayLockContext::ScopedForcedUpdate> scoped_forced_update_list_;
 
   const NGOffsetMapping* offset_mapping_ = nullptr;
-  bool mapping_needs_recalc_ = false;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/editing/finder/find_buffer_test.cc b/third_party/blink/renderer/core/editing/finder/find_buffer_test.cc
index 713fdd8..0eb99506 100644
--- a/third_party/blink/renderer/core/editing/finder/find_buffer_test.cc
+++ b/third_party/blink/renderer/core/editing/finder/find_buffer_test.cc
@@ -266,8 +266,7 @@
 }
 
 TEST_F(FindBufferTest, FindMatchInRange) {
-  SetBodyContent(
-      "<div id='div' invisible>foo<a id='a'>foof</a><b id='b'>oo</b></div>");
+  SetBodyContent("<div id='div'>foo<a id='a'>foof</a><b id='b'>oo</b></div>");
   Element* div = GetElementById("div");
   Element* a = GetElementById("a");
   Element* b = GetElementById("b");
diff --git a/third_party/blink/renderer/core/editing/iterators/text_iterator.cc b/third_party/blink/renderer/core/editing/iterators/text_iterator.cc
index b3b841e..c757ad3 100644
--- a/third_party/blink/renderer/core/editing/iterators/text_iterator.cc
+++ b/third_party/blink/renderer/core/editing/iterators/text_iterator.cc
@@ -238,11 +238,11 @@
     return;
   const Document& document = OwnerDocument();
   if (behavior_.ForInnerText())
-    UseCounter::Count(document, WebFeature::kInnerTextWithShadowTree);
+    document.CountUse(WebFeature::kInnerTextWithShadowTree);
   if (behavior_.ForSelectionToString())
-    UseCounter::Count(document, WebFeature::kSelectionToStringWithShadowTree);
+    document.CountUse(WebFeature::kSelectionToStringWithShadowTree);
   if (behavior_.ForWindowFind())
-    UseCounter::Count(document, WebFeature::kWindowFindWithShadowTree);
+    document.CountUse(WebFeature::kWindowFindWithShadowTree);
 }
 
 template <typename Strategy>
diff --git a/third_party/blink/renderer/core/events/visual_viewport_resize_event.cc b/third_party/blink/renderer/core/events/visual_viewport_resize_event.cc
index 164c61c..5b1ac749 100644
--- a/third_party/blink/renderer/core/events/visual_viewport_resize_event.cc
+++ b/third_party/blink/renderer/core/events/visual_viewport_resize_event.cc
@@ -6,6 +6,7 @@
 
 #include "third_party/blink/renderer/core/dom/events/event_target.h"
 #include "third_party/blink/renderer/core/event_type_names.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/frame/use_counter.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/events/visual_viewport_scroll_event.cc b/third_party/blink/renderer/core/events/visual_viewport_scroll_event.cc
index daecfa32..13471c7c 100644
--- a/third_party/blink/renderer/core/events/visual_viewport_scroll_event.cc
+++ b/third_party/blink/renderer/core/events/visual_viewport_scroll_event.cc
@@ -6,6 +6,7 @@
 
 #include "third_party/blink/renderer/core/dom/events/event_target.h"
 #include "third_party/blink/renderer/core/event_type_names.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/frame/use_counter.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/execution_context/execution_context.h b/third_party/blink/renderer/core/execution_context/execution_context.h
index 5e8eed4..405de973 100644
--- a/third_party/blink/renderer/core/execution_context/execution_context.h
+++ b/third_party/blink/renderer/core/execution_context/execution_context.h
@@ -39,6 +39,7 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/execution_context/context_lifecycle_notifier.h"
 #include "third_party/blink/renderer/core/execution_context/context_lifecycle_observer.h"
+#include "third_party/blink/renderer/core/frame/use_counter.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/loader/fetch/console_logger.h"
 #include "third_party/blink/renderer/platform/loader/fetch/https_state.h"
@@ -121,6 +122,7 @@
 class CORE_EXPORT ExecutionContext : public ContextLifecycleNotifier,
                                      public Supplementable<ExecutionContext>,
                                      public ConsoleLogger,
+                                     public UseCounter,
                                      public FeatureContext {
   MERGE_GARBAGE_COLLECTED_MIXINS();
 
diff --git a/third_party/blink/renderer/core/exported/web_view_test.cc b/third_party/blink/renderer/core/exported/web_view_test.cc
index 66717cff..6059a3c2 100644
--- a/third_party/blink/renderer/core/exported/web_view_test.cc
+++ b/third_party/blink/renderer/core/exported/web_view_test.cc
@@ -4686,8 +4686,8 @@
     frame->ExecuteScript(
         WebScriptSource("addEventListener('beforeunload', function() {});"));
     web_view->MainFrameImpl()->DispatchBeforeUnloadEvent(false);
-    EXPECT_FALSE(UseCounter::IsCounted(*document,
-                                       WebFeature::kSubFrameBeforeUnloadFired));
+    EXPECT_FALSE(
+        document->IsUseCounted(WebFeature::kSubFrameBeforeUnloadFired));
   }
 
   // Add a beforeunload handler in the iframe and dispatch. Make sure we do
@@ -4706,8 +4706,8 @@
                                                   ->Tree()
                                                   .FirstChild())
                                    ->GetDocument();
-    EXPECT_TRUE(UseCounter::IsCounted(*child_document,
-                                      WebFeature::kSubFrameBeforeUnloadFired));
+    EXPECT_TRUE(
+        child_document->IsUseCounted(WebFeature::kSubFrameBeforeUnloadFired));
   }
 }
 
diff --git a/third_party/blink/renderer/core/feature_policy/feature_policy_test.cc b/third_party/blink/renderer/core/feature_policy/feature_policy_test.cc
index 0dd34da..6b7eec5 100644
--- a/third_party/blink/renderer/core/feature_policy/feature_policy_test.cc
+++ b/third_party/blink/renderer/core/feature_policy/feature_policy_test.cc
@@ -772,8 +772,8 @@
     auto dummy = std::make_unique<DummyPageHolder>();
     FeaturePolicyParser::ParseHeader("payment; fullscreen", origin_a_.get(),
                                      &messages, &dummy->GetDocument());
-    EXPECT_FALSE(UseCounter::IsCounted(dummy->GetDocument(),
-                                       WebFeature::kUnoptimizedImagePolicies));
+    EXPECT_FALSE(dummy->GetDocument().IsUseCounted(
+        WebFeature::kUnoptimizedImagePolicies));
   }
 
   // Validate that declarations which should trigger the use counter do.
@@ -781,8 +781,8 @@
     auto dummy = std::make_unique<DummyPageHolder>();
     FeaturePolicyParser::ParseHeader(declaration, origin_a_.get(), &messages,
                                      &dummy->GetDocument());
-    EXPECT_TRUE(UseCounter::IsCounted(dummy->GetDocument(),
-                                      WebFeature::kUnoptimizedImagePolicies))
+    EXPECT_TRUE(dummy->GetDocument().IsUseCounted(
+        WebFeature::kUnoptimizedImagePolicies))
         << declaration << " should trigger the origin trial use counter.";
   }
 }
diff --git a/third_party/blink/renderer/core/fetch/fetch_request_data.cc b/third_party/blink/renderer/core/fetch/fetch_request_data.cc
index 637e405..ce69202 100644
--- a/third_party/blink/renderer/core/fetch/fetch_request_data.cc
+++ b/third_party/blink/renderer/core/fetch/fetch_request_data.cc
@@ -4,7 +4,7 @@
 
 #include "third_party/blink/renderer/core/fetch/fetch_request_data.h"
 
-#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_request.h"
+#include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/web_http_body.h"
 #include "third_party/blink/public/platform/web_url_request.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
@@ -19,48 +19,64 @@
 #include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
 #include "third_party/blink/renderer/platform/network/http_names.h"
 
+namespace mojo {
+
+template <>
+struct TypeConverter<::blink::ResourceLoadPriority,
+                     network::mojom::blink::RequestPriority> {
+  static ::blink::ResourceLoadPriority Convert(
+      network::mojom::blink::RequestPriority priority) {
+    switch (priority) {
+      case network::mojom::blink::RequestPriority::kThrottled:
+        break;
+      case network::mojom::blink::RequestPriority::kIdle:
+        return ::blink::ResourceLoadPriority::kVeryLow;
+      case network::mojom::blink::RequestPriority::kLowest:
+        return ::blink::ResourceLoadPriority::kLow;
+      case network::mojom::blink::RequestPriority::kLow:
+        return ::blink::ResourceLoadPriority::kMedium;
+      case network::mojom::blink::RequestPriority::kMedium:
+        return ::blink::ResourceLoadPriority::kHigh;
+      case network::mojom::blink::RequestPriority::kHighest:
+        return ::blink::ResourceLoadPriority::kVeryHigh;
+    }
+
+    NOTREACHED() << priority;
+    return blink::ResourceLoadPriority::kUnresolved;
+  }
+};
+
+}  // namespace mojo
+
 namespace blink {
 
+namespace {
+
+bool IsExcludedHeaderForServiceWorkerFetchEvent(const String& header_name) {
+  // Excluding Sec-Fetch-... headers as suggested in
+  // https://crbug.com/949997#c4.
+  if (header_name.StartsWithIgnoringASCIICase("sec-fetch-")) {
+    return true;
+  }
+
+  if (Platform::Current()->IsExcludedHeaderForServiceWorkerFetchEvent(
+          header_name)) {
+    return true;
+  }
+
+  return false;
+}
+
+}  // namespace
+
 FetchRequestData* FetchRequestData::Create() {
   return MakeGarbageCollected<FetchRequestData>();
 }
 
 FetchRequestData* FetchRequestData::Create(
     ScriptState* script_state,
-    const WebServiceWorkerRequest& web_request) {
-  FetchRequestData* request = FetchRequestData::Create();
-  request->url_ = web_request.Url();
-  request->method_ = web_request.Method();
-  for (HTTPHeaderMap::const_iterator it = web_request.Headers().begin();
-       it != web_request.Headers().end(); ++it)
-    request->header_list_->Append(it->key, it->value);
-  if (scoped_refptr<EncodedFormData> body = web_request.Body()) {
-    request->SetBuffer(MakeGarbageCollected<BodyStreamBuffer>(
-        script_state,
-        MakeGarbageCollected<FormDataBytesConsumer>(
-            ExecutionContext::From(script_state), std::move(body)),
-        nullptr /* AbortSignal */));
-  }
-  request->SetContext(web_request.GetRequestContext());
-  request->SetReferrerString(web_request.ReferrerUrl().GetString());
-  request->SetReferrerPolicy(web_request.GetReferrerPolicy());
-  request->SetMode(web_request.Mode());
-  request->SetCredentials(web_request.CredentialsMode());
-  request->SetCacheMode(web_request.CacheMode());
-  request->SetRedirect(web_request.RedirectMode());
-  request->SetMimeType(request->header_list_->ExtractMIMEType());
-  request->SetIntegrity(web_request.Integrity());
-  request->SetPriority(
-      static_cast<ResourceLoadPriority>(web_request.Priority()));
-  request->SetKeepalive(web_request.Keepalive());
-  request->SetIsHistoryNavigation(web_request.IsHistoryNavigation());
-  request->SetWindowId(web_request.GetWindowId());
-  return request;
-}
-
-FetchRequestData* FetchRequestData::Create(
-    ScriptState* script_state,
-    const mojom::blink::FetchAPIRequest& fetch_api_request) {
+    const mojom::blink::FetchAPIRequest& fetch_api_request,
+    ForServiceWorkerFetchEvent for_service_worker_fetch_event) {
   FetchRequestData* request = FetchRequestData::Create();
   request->url_ = fetch_api_request.url;
   request->method_ = AtomicString(fetch_api_request.method);
@@ -69,15 +85,28 @@
     // whether we really need this filter.
     if (DeprecatedEqualIgnoringCase(pair.key, "referer"))
       continue;
+    if (for_service_worker_fetch_event == ForServiceWorkerFetchEvent::kTrue &&
+        IsExcludedHeaderForServiceWorkerFetchEvent(pair.key)) {
+      continue;
+    }
     request->header_list_->Append(pair.key, pair.value);
   }
+
   if (fetch_api_request.blob) {
+    DCHECK(!fetch_api_request.body);
     request->SetBuffer(MakeGarbageCollected<BodyStreamBuffer>(
         script_state,
         MakeGarbageCollected<BlobBytesConsumer>(
             ExecutionContext::From(script_state), fetch_api_request.blob),
         nullptr /* AbortSignal */));
+  } else if (fetch_api_request.body) {
+    request->SetBuffer(MakeGarbageCollected<BodyStreamBuffer>(
+        script_state,
+        MakeGarbageCollected<FormDataBytesConsumer>(
+            ExecutionContext::From(script_state), fetch_api_request.body),
+        nullptr /* AbortSignal */));
   }
+
   request->SetContext(fetch_api_request.request_context_type);
   request->SetReferrerString(AtomicString(Referrer::NoReferrer()));
   if (fetch_api_request.referrer) {
@@ -93,6 +122,10 @@
   request->SetIntegrity(fetch_api_request.integrity);
   request->SetKeepalive(fetch_api_request.keepalive);
   request->SetIsHistoryNavigation(fetch_api_request.is_history_navigation);
+  request->SetPriority(
+      mojo::ConvertTo<ResourceLoadPriority>(fetch_api_request.priority));
+  if (fetch_api_request.fetch_window_id)
+    request->SetWindowId(fetch_api_request.fetch_window_id.value());
   return request;
 }
 
diff --git a/third_party/blink/renderer/core/fetch/fetch_request_data.h b/third_party/blink/renderer/core/fetch/fetch_request_data.h
index 6d5b47f..d0b6fef 100644
--- a/third_party/blink/renderer/core/fetch/fetch_request_data.h
+++ b/third_party/blink/renderer/core/fetch/fetch_request_data.h
@@ -12,7 +12,6 @@
 #include "services/network/public/mojom/referrer_policy.mojom-shared.h"
 #include "services/network/public/mojom/url_loader_factory.mojom-blink.h"
 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
-#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_request.h"
 #include "third_party/blink/public/platform/web_url_request.h"
 #include "third_party/blink/renderer/core/fetch/body_stream_buffer.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
@@ -29,17 +28,17 @@
 class FetchHeaderList;
 class SecurityOrigin;
 class ScriptState;
-class WebServiceWorkerRequest;
 
-class FetchRequestData final
+class CORE_EXPORT FetchRequestData final
     : public GarbageCollectedFinalized<FetchRequestData> {
  public:
   enum Tainting { kBasicTainting, kCorsTainting, kOpaqueTainting };
+  enum class ForServiceWorkerFetchEvent { kFalse, kTrue };
 
   static FetchRequestData* Create();
-  static FetchRequestData* Create(ScriptState*, const WebServiceWorkerRequest&);
   static FetchRequestData* Create(ScriptState*,
-                                  const mojom::blink::FetchAPIRequest&);
+                                  const mojom::blink::FetchAPIRequest&,
+                                  ForServiceWorkerFetchEvent);
   FetchRequestData* Clone(ScriptState*, ExceptionState&);
   FetchRequestData* Pass(ScriptState*, ExceptionState&);
 
diff --git a/third_party/blink/renderer/core/fetch/fetch_request_data_test.cc b/third_party/blink/renderer/core/fetch/fetch_request_data_test.cc
new file mode 100644
index 0000000..983ab9e
--- /dev/null
+++ b/third_party/blink/renderer/core/fetch/fetch_request_data_test.cc
@@ -0,0 +1,93 @@
+// 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/fetch/fetch_request_data.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/fetch/fetch_header_list.h"
+#include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
+
+namespace blink {
+
+namespace {
+
+mojom::blink::FetchAPIRequestPtr PrepareFetchAPIRequest() {
+  auto request = mojom::blink::FetchAPIRequest::New();
+  request->url = KURL("https://example.com");
+  // "sec-fetch-" will be excluded forcibly for service worker fetch events.
+  request->headers.insert(String("sec-fetch-xx"), String("xxx"));
+  request->headers.insert(String("sec-fetch-yy"), String("xxx"));
+  // "x-bye-bye" will be excluded by FetchRequestDataTestingPlatformSupport for
+  // service worker fetch events.
+  request->headers.insert(String("x-bye-bye"), String("xxx"));
+  // "x-hi-hi" will be kept in any case.
+  request->headers.insert(String("x-hi-hi"), String("xxx"));
+  return request;
+}
+
+}  // namespace
+
+class FetchRequestDataTestingPlatformSupport : public TestingPlatformSupport {
+ public:
+  bool IsExcludedHeaderForServiceWorkerFetchEvent(
+      const WebString& header_name) override {
+    return header_name == "x-bye-bye";
+  }
+};
+
+TEST(FetchRequestDataTest, For_ServiceWorkerFetchEvent_Headers) {
+  {
+    FetchRequestData* request_data = FetchRequestData::Create(
+        nullptr /* script_state */, *PrepareFetchAPIRequest(),
+        FetchRequestData::ForServiceWorkerFetchEvent::kTrue);
+    EXPECT_EQ(2U, request_data->HeaderList()->size());
+    EXPECT_TRUE(request_data->HeaderList()->Has("x-hi-hi"));
+    EXPECT_TRUE(request_data->HeaderList()->Has("x-bye-bye"));
+    EXPECT_FALSE(request_data->HeaderList()->Has("sec-fetch-xx"));
+    EXPECT_FALSE(request_data->HeaderList()->Has("sec-fetch-yy"));
+  }
+
+  {
+    ScopedTestingPlatformSupport<FetchRequestDataTestingPlatformSupport>
+        platform;
+
+    FetchRequestData* request_data = FetchRequestData::Create(
+        nullptr /* script_state */, *PrepareFetchAPIRequest(),
+        FetchRequestData::ForServiceWorkerFetchEvent::kTrue);
+    EXPECT_EQ(1U, request_data->HeaderList()->size());
+    EXPECT_TRUE(request_data->HeaderList()->Has("x-hi-hi"));
+    EXPECT_FALSE(request_data->HeaderList()->Has("x-bye-bye"));
+    EXPECT_FALSE(request_data->HeaderList()->Has("sec-fetch-xx"));
+    EXPECT_FALSE(request_data->HeaderList()->Has("sec-fetch-yy"));
+  }
+}
+
+TEST(FetchRequestDataTest, Not_For_ServiceWorkerFetchEvent_Headers) {
+  {
+    FetchRequestData* request_data = FetchRequestData::Create(
+        nullptr /* script_state */, *PrepareFetchAPIRequest(),
+        FetchRequestData::ForServiceWorkerFetchEvent::kFalse);
+    EXPECT_EQ(4U, request_data->HeaderList()->size());
+    EXPECT_TRUE(request_data->HeaderList()->Has("x-hi-hi"));
+    EXPECT_TRUE(request_data->HeaderList()->Has("x-bye-bye"));
+    EXPECT_TRUE(request_data->HeaderList()->Has("sec-fetch-xx"));
+    EXPECT_TRUE(request_data->HeaderList()->Has("sec-fetch-yy"));
+  }
+
+  {
+    ScopedTestingPlatformSupport<FetchRequestDataTestingPlatformSupport>
+        platform;
+
+    FetchRequestData* request_data = FetchRequestData::Create(
+        nullptr /* script_state */, *PrepareFetchAPIRequest(),
+        FetchRequestData::ForServiceWorkerFetchEvent::kFalse);
+    EXPECT_EQ(4U, request_data->HeaderList()->size());
+    EXPECT_TRUE(request_data->HeaderList()->Has("x-hi-hi"));
+    EXPECT_TRUE(request_data->HeaderList()->Has("x-bye-bye"));
+    EXPECT_TRUE(request_data->HeaderList()->Has("sec-fetch-xx"));
+    EXPECT_TRUE(request_data->HeaderList()->Has("sec-fetch-yy"));
+  }
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/fetch/fetch_response_data.cc b/third_party/blink/renderer/core/fetch/fetch_response_data.cc
index 83eed1d..7bba68b 100644
--- a/third_party/blink/renderer/core/fetch/fetch_response_data.cc
+++ b/third_party/blink/renderer/core/fetch/fetch_response_data.cc
@@ -4,7 +4,6 @@
 
 #include "third_party/blink/renderer/core/fetch/fetch_response_data.h"
 
-#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_response.h"
 #include "third_party/blink/renderer/core/fetch/fetch_header_list.h"
 #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
@@ -21,16 +20,6 @@
 
 namespace {
 
-WebVector<WebString> HeaderSetToWebVector(const WebHTTPHeaderSet& headers) {
-  // Can't just pass *headers to the WebVector constructor because HashSet
-  // iterators are not stl iterator compatible.
-  WebVector<WebString> result(static_cast<size_t>(headers.size()));
-  int idx = 0;
-  for (const auto& header : headers)
-    result[idx++] = WebString::FromASCII(header);
-  return result;
-}
-
 Vector<String> HeaderSetToVector(const WebHTTPHeaderSet& headers) {
   Vector<String> result;
   result.ReserveInitialCapacity(SafeCast<wtf_size_t>(headers.size()));
@@ -240,30 +229,6 @@
   return new_response;
 }
 
-void FetchResponseData::PopulateWebServiceWorkerResponse(
-    WebServiceWorkerResponse& response) {
-  if (internal_response_) {
-    internal_response_->PopulateWebServiceWorkerResponse(response);
-    response.SetResponseType(type_);
-    response.SetResponseSource(response_source_);
-    response.SetCorsExposedHeaderNames(
-        HeaderSetToWebVector(cors_exposed_header_names_));
-    return;
-  }
-  response.SetURLList(url_list_);
-  response.SetStatus(Status());
-  response.SetStatusText(StatusMessage());
-  response.SetResponseType(type_);
-  response.SetResponseSource(response_source_);
-  response.SetResponseTime(ResponseTime());
-  response.SetCacheStorageCacheName(CacheStorageCacheName());
-  response.SetCorsExposedHeaderNames(
-      HeaderSetToWebVector(cors_exposed_header_names_));
-  for (const auto& header : HeaderList()->List()) {
-    response.AppendHeader(header.first, header.second);
-  }
-}
-
 mojom::blink::FetchAPIResponsePtr
 FetchResponseData::PopulateFetchAPIResponse() {
   if (internal_response_) {
diff --git a/third_party/blink/renderer/core/fetch/fetch_response_data.h b/third_party/blink/renderer/core/fetch/fetch_response_data.h
index 0f1cef4..e2f07660 100644
--- a/third_party/blink/renderer/core/fetch/fetch_response_data.h
+++ b/third_party/blink/renderer/core/fetch/fetch_response_data.h
@@ -12,7 +12,6 @@
 #include "services/network/public/mojom/fetch_api.mojom-blink.h"
 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
 #include "third_party/blink/public/mojom/fetch/fetch_api_response.mojom-blink.h"
-#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_request.h"
 #include "third_party/blink/public/platform/web_http_header_set.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/fetch/body_stream_buffer.h"
@@ -27,7 +26,6 @@
 class ExceptionState;
 class FetchHeaderList;
 class ScriptState;
-class WebServiceWorkerResponse;
 
 class CORE_EXPORT FetchResponseData final
     : public GarbageCollectedFinalized<FetchResponseData> {
@@ -108,9 +106,7 @@
   // If the type is Error or Opaque, does nothing.
   void ReplaceBodyStreamBuffer(BodyStreamBuffer*);
 
-  // Does not call response.setBlobDataHandle().
-  void PopulateWebServiceWorkerResponse(
-      WebServiceWorkerResponse& /* response */);
+  // Does not contain the blob response body.
   mojom::blink::FetchAPIResponsePtr PopulateFetchAPIResponse();
 
   void Trace(blink::Visitor*);
diff --git a/third_party/blink/renderer/core/fetch/fetch_response_data_test.cc b/third_party/blink/renderer/core/fetch/fetch_response_data_test.cc
index 2615d1a..1639df2 100644
--- a/third_party/blink/renderer/core/fetch/fetch_response_data_test.cc
+++ b/third_party/blink/renderer/core/fetch/fetch_response_data_test.cc
@@ -5,7 +5,6 @@
 #include "third_party/blink/renderer/core/fetch/fetch_response_data.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_response.h"
 #include "third_party/blink/renderer/core/fetch/fetch_header_list.h"
 #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
 #include "third_party/blink/renderer/platform/blob/blob_data.h"
@@ -27,10 +26,10 @@
     return internal_response;
   }
 
-  void CheckHeaders(const WebServiceWorkerResponse& web_response) {
-    EXPECT_EQ("foo", web_response.GetHeader("set-cookie"));
-    EXPECT_EQ("bar", web_response.GetHeader("bar"));
-    EXPECT_EQ("no-cache", web_response.GetHeader("cache-control"));
+  void CheckHeaders(const mojom::blink::FetchAPIResponse& response) {
+    EXPECT_EQ("foo", response.headers.at("set-cookie"));
+    EXPECT_EQ("bar", response.headers.at("bar"));
+    EXPECT_EQ("no-cache", response.headers.at("cache-control"));
   }
 };
 
@@ -51,14 +50,14 @@
   EXPECT_EQ("no-cache", cache_control_value);
 }
 
-TEST_F(FetchResponseDataTest, ToWebServiceWorkerDefaultType) {
-  WebServiceWorkerResponse web_response;
+TEST_F(FetchResponseDataTest, ToFetchAPIResponseDefaultType) {
   FetchResponseData* internal_response = CreateInternalResponse();
 
-  internal_response->PopulateWebServiceWorkerResponse(web_response);
+  mojom::blink::FetchAPIResponsePtr fetch_api_response =
+      internal_response->PopulateFetchAPIResponse();
   EXPECT_EQ(network::mojom::FetchResponseType::kDefault,
-            web_response.ResponseType());
-  CheckHeaders(web_response);
+            fetch_api_response->response_type);
+  CheckHeaders(*fetch_api_response);
 }
 
 TEST_F(FetchResponseDataTest, BasicFilter) {
@@ -80,16 +79,16 @@
   EXPECT_EQ("no-cache", cache_control_value);
 }
 
-TEST_F(FetchResponseDataTest, ToWebServiceWorkerBasicType) {
-  WebServiceWorkerResponse web_response;
+TEST_F(FetchResponseDataTest, ToFetchAPIResponseBasicType) {
   FetchResponseData* internal_response = CreateInternalResponse();
   FetchResponseData* basic_response_data =
       internal_response->CreateBasicFilteredResponse();
 
-  basic_response_data->PopulateWebServiceWorkerResponse(web_response);
+  mojom::blink::FetchAPIResponsePtr fetch_api_response =
+      basic_response_data->PopulateFetchAPIResponse();
   EXPECT_EQ(network::mojom::FetchResponseType::kBasic,
-            web_response.ResponseType());
-  CheckHeaders(web_response);
+            fetch_api_response->response_type);
+  CheckHeaders(*fetch_api_response);
 }
 
 TEST_F(FetchResponseDataTest, CorsFilter) {
@@ -183,16 +182,16 @@
   EXPECT_EQ("bar", bar_value);
 }
 
-TEST_F(FetchResponseDataTest, ToWebServiceWorkerCorsType) {
-  WebServiceWorkerResponse web_response;
+TEST_F(FetchResponseDataTest, ToFetchAPIResponseCorsType) {
   FetchResponseData* internal_response = CreateInternalResponse();
   FetchResponseData* cors_response_data =
       internal_response->CreateCorsFilteredResponse(WebHTTPHeaderSet());
 
-  cors_response_data->PopulateWebServiceWorkerResponse(web_response);
+  mojom::blink::FetchAPIResponsePtr fetch_api_response =
+      cors_response_data->PopulateFetchAPIResponse();
   EXPECT_EQ(network::mojom::FetchResponseType::kCors,
-            web_response.ResponseType());
-  CheckHeaders(web_response);
+            fetch_api_response->response_type);
+  CheckHeaders(*fetch_api_response);
 }
 
 TEST_F(FetchResponseDataTest, OpaqueFilter) {
@@ -234,28 +233,28 @@
   EXPECT_FALSE(opaque_response_data->HeaderList()->Has("cache-control"));
 }
 
-TEST_F(FetchResponseDataTest, ToWebServiceWorkerOpaqueType) {
-  WebServiceWorkerResponse web_response;
+TEST_F(FetchResponseDataTest, ToFetchAPIResponseOpaqueType) {
   FetchResponseData* internal_response = CreateInternalResponse();
   FetchResponseData* opaque_response_data =
       internal_response->CreateOpaqueFilteredResponse();
 
-  opaque_response_data->PopulateWebServiceWorkerResponse(web_response);
+  mojom::blink::FetchAPIResponsePtr fetch_api_response =
+      opaque_response_data->PopulateFetchAPIResponse();
   EXPECT_EQ(network::mojom::FetchResponseType::kOpaque,
-            web_response.ResponseType());
-  CheckHeaders(web_response);
+            fetch_api_response->response_type);
+  CheckHeaders(*fetch_api_response);
 }
 
-TEST_F(FetchResponseDataTest, ToWebServiceWorkerOpaqueRedirectType) {
-  WebServiceWorkerResponse web_response;
+TEST_F(FetchResponseDataTest, ToFetchAPIResponseOpaqueRedirectType) {
   FetchResponseData* internal_response = CreateInternalResponse();
   FetchResponseData* opaque_redirect_response_data =
       internal_response->CreateOpaqueRedirectFilteredResponse();
 
-  opaque_redirect_response_data->PopulateWebServiceWorkerResponse(web_response);
+  mojom::blink::FetchAPIResponsePtr fetch_api_response =
+      opaque_redirect_response_data->PopulateFetchAPIResponse();
   EXPECT_EQ(network::mojom::FetchResponseType::kOpaqueRedirect,
-            web_response.ResponseType());
-  CheckHeaders(web_response);
+            fetch_api_response->response_type);
+  CheckHeaders(*fetch_api_response);
 }
 
 TEST_F(FetchResponseDataTest, DefaultResponseTime) {
diff --git a/third_party/blink/renderer/core/fetch/request.cc b/third_party/blink/renderer/core/fetch/request.cc
index f634618..5882c05 100644
--- a/third_party/blink/renderer/core/fetch/request.cc
+++ b/third_party/blink/renderer/core/fetch/request.cc
@@ -5,7 +5,6 @@
 #include "third_party/blink/renderer/core/fetch/request.h"
 
 #include "third_party/blink/public/common/blob/blob_utils.h"
-#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_request.h"
 #include "third_party/blink/public/platform/web_url_request.h"
 #include "third_party/blink/renderer/bindings/core/v8/dictionary.h"
 #include "third_party/blink/renderer/bindings/core/v8/idl_types.h"
@@ -625,17 +624,12 @@
   return MakeGarbageCollected<Request>(script_state, request);
 }
 
-Request* Request::Create(ScriptState* script_state,
-                         const WebServiceWorkerRequest& web_request) {
-  FetchRequestData* data = FetchRequestData::Create(script_state, web_request);
-  return MakeGarbageCollected<Request>(script_state, data);
-}
-
 Request* Request::Create(
     ScriptState* script_state,
-    const mojom::blink::FetchAPIRequest& fetch_api_request) {
-  FetchRequestData* data =
-      FetchRequestData::Create(script_state, fetch_api_request);
+    const mojom::blink::FetchAPIRequest& fetch_api_request,
+    ForServiceWorkerFetchEvent for_service_worker_fetch_event) {
+  FetchRequestData* data = FetchRequestData::Create(
+      script_state, fetch_api_request, for_service_worker_fetch_event);
   return MakeGarbageCollected<Request>(script_state, data);
 }
 
diff --git a/third_party/blink/renderer/core/fetch/request.h b/third_party/blink/renderer/core/fetch/request.h
index cb51267..9fdd88d 100644
--- a/third_party/blink/renderer/core/fetch/request.h
+++ b/third_party/blink/renderer/core/fetch/request.h
@@ -25,7 +25,6 @@
 class BodyStreamBuffer;
 class ExceptionState;
 class RequestInit;
-class WebServiceWorkerRequest;
 
 using RequestInfo = RequestOrUSVString;
 
@@ -33,6 +32,9 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
+  using ForServiceWorkerFetchEvent =
+      FetchRequestData::ForServiceWorkerFetchEvent;
+
   // These "create" function must be called with entering an appropriate
   // V8 context.
   // From Request.idl:
@@ -52,8 +54,9 @@
                          const RequestInit*,
                          ExceptionState&);
   static Request* Create(ScriptState*, FetchRequestData*);
-  static Request* Create(ScriptState*, const WebServiceWorkerRequest&);
-  static Request* Create(ScriptState*, const mojom::blink::FetchAPIRequest&);
+  static Request* Create(ScriptState*,
+                         const mojom::blink::FetchAPIRequest&,
+                         ForServiceWorkerFetchEvent);
 
   Request(ScriptState*, FetchRequestData*, Headers*, AbortSignal*);
   Request(ScriptState*, FetchRequestData*);
diff --git a/third_party/blink/renderer/core/fetch/request_test.cc b/third_party/blink/renderer/core/fetch/request_test.cc
index 59f18f1c..1e216e0 100644
--- a/third_party/blink/renderer/core/fetch/request_test.cc
+++ b/third_party/blink/renderer/core/fetch/request_test.cc
@@ -7,7 +7,6 @@
 #include <memory>
 #include "services/network/public/mojom/fetch_api.mojom-blink.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_request.h"
 #include "third_party/blink/public/platform/web_url_request.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
@@ -83,7 +82,8 @@
       mojom::blink::Referrer::New(KURL(NullURL(), referrer), kReferrerPolicy);
 
   Request* request =
-      Request::Create(scope.GetScriptState(), *fetch_api_request);
+      Request::Create(scope.GetScriptState(), *fetch_api_request,
+                      Request::ForServiceWorkerFetchEvent::kFalse);
   DCHECK(request);
   EXPECT_EQ(url, request->url());
   EXPECT_EQ(method, request->method());
diff --git a/third_party/blink/renderer/core/fetch/response.cc b/third_party/blink/renderer/core/fetch/response.cc
index 2debd16..b33f86b 100644
--- a/third_party/blink/renderer/core/fetch/response.cc
+++ b/third_party/blink/renderer/core/fetch/response.cc
@@ -9,7 +9,6 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/optional.h"
 #include "services/network/public/mojom/fetch_api.mojom-blink.h"
-#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_response.h"
 #include "third_party/blink/renderer/bindings/core/v8/dictionary.h"
 #include "third_party/blink/renderer/bindings/core/v8/idl_types.h"
 #include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
@@ -464,11 +463,6 @@
   return Body::HasPendingActivity();
 }
 
-void Response::PopulateWebServiceWorkerResponse(
-    WebServiceWorkerResponse& response) {
-  response_->PopulateWebServiceWorkerResponse(response);
-}
-
 mojom::blink::FetchAPIResponsePtr Response::PopulateFetchAPIResponse() {
   return response_->PopulateFetchAPIResponse();
 }
diff --git a/third_party/blink/renderer/core/fetch/response.h b/third_party/blink/renderer/core/fetch/response.h
index 00e2071..b9c824b0 100644
--- a/third_party/blink/renderer/core/fetch/response.h
+++ b/third_party/blink/renderer/core/fetch/response.h
@@ -24,7 +24,6 @@
 class ExceptionState;
 class ResponseInit;
 class ScriptState;
-class WebServiceWorkerResponse;
 
 class CORE_EXPORT Response final : public Body {
   DEFINE_WRAPPERTYPEINFO();
@@ -77,9 +76,7 @@
   // ScriptWrappable
   bool HasPendingActivity() const final;
 
-  // Does not call response.setBlobDataHandle().
-  void PopulateWebServiceWorkerResponse(
-      WebServiceWorkerResponse& /* response */);
+  // Does not contain the blob response body.
   mojom::blink::FetchAPIResponsePtr PopulateFetchAPIResponse();
 
   bool HasBody() const;
diff --git a/third_party/blink/renderer/core/fetch/response_test.cc b/third_party/blink/renderer/core/fetch/response_test.cc
index 998abfe6..27a406e3 100644
--- a/third_party/blink/renderer/core/fetch/response_test.cc
+++ b/third_party/blink/renderer/core/fetch/response_test.cc
@@ -7,7 +7,6 @@
 #include <memory>
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
-#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_response.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/fetch/body_stream_buffer.h"
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 d249fc9..d5c937c 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
@@ -136,7 +136,8 @@
   return nonceable;
 }
 
-static WebFeature GetUseCounterType(ContentSecurityPolicyHeaderType type) {
+static WebFeature GetUseCounterHelperType(
+    ContentSecurityPolicyHeaderType type) {
   switch (type) {
     case kContentSecurityPolicyHeaderTypeEnforce:
       return WebFeature::kContentSecurityPolicy;
@@ -208,7 +209,7 @@
   console_messages_.clear();
 
   for (const auto& policy : policies_) {
-    Count(GetUseCounterType(policy->HeaderType()));
+    Count(GetUseCounterHelperType(policy->HeaderType()));
     if (policy->AllowDynamic(
             ContentSecurityPolicy::DirectiveType::kScriptSrcAttr) ||
         policy->AllowDynamic(
diff --git a/third_party/blink/renderer/core/frame/deprecation.cc b/third_party/blink/renderer/core/frame/deprecation.cc
index 3998f4f..7ed7364 100644
--- a/third_party/blink/renderer/core/frame/deprecation.cc
+++ b/third_party/blink/renderer/core/frame/deprecation.cc
@@ -160,24 +160,6 @@
   return 0;
 }
 
-String GetDeviceSensorDeprecationMessage(const char* event_name,
-                                         const char* status_url) {
-  static constexpr char kConcreteMessage[] =
-      "The `%s` event is deprecated on insecure origins and will be removed in "
-      "%s. Event handlers can still be registered but are no longer invoked "
-      "since %s. See %s for more details.";
-  static constexpr char kGenericMessage[] =
-      "The `%s` event is deprecated on insecure origins and will be removed. "
-      "See %s for more details.";
-
-  if (blink::RuntimeEnabledFeatures::
-          RestrictDeviceSensorEventsToSecureContextsEnabled()) {
-    return String::Format(kConcreteMessage, event_name, MilestoneString(kM76),
-                          MilestoneString(kM74), status_url);
-  }
-  return String::Format(kGenericMessage, event_name, status_url);
-}
-
 struct DeprecationInfo {
   String id;
   Milestone anticipated_removal;
@@ -305,24 +287,6 @@
                   "https://www.chromestatus.com/feature/6170540112871424")};
 
     // Powerful features on insecure origins (https://goo.gl/rStTGz)
-    case WebFeature::kDeviceMotionInsecureOrigin:
-      return {"DeviceMotionInsecureOrigin", kM76,
-              GetDeviceSensorDeprecationMessage(
-                  "devicemotion",
-                  "https://www.chromestatus.com/feature/5688035094036480")};
-
-    case WebFeature::kDeviceOrientationInsecureOrigin:
-      return {"DeviceOrientationInsecureOrigin", kM76,
-              GetDeviceSensorDeprecationMessage(
-                  "deviceorientation",
-                  "https://www.chromestatus.com/feature/5468407470227456")};
-
-    case WebFeature::kDeviceOrientationAbsoluteInsecureOrigin:
-      return {"DeviceOrientationAbsoluteInsecureOrigin", kM76,
-              GetDeviceSensorDeprecationMessage(
-                  "deviceorientationabsolute",
-                  "https://www.chromestatus.com/feature/5468407470227456")};
-
     case WebFeature::kGeolocationInsecureOrigin:
     case WebFeature::kGeolocationInsecureOriginIframe:
       return {"GeolocationInsecureOrigin", kUnknown,
diff --git a/third_party/blink/renderer/core/frame/deprecation.h b/third_party/blink/renderer/core/frame/deprecation.h
index 560a44c..7c836676 100644
--- a/third_party/blink/renderer/core/frame/deprecation.h
+++ b/third_party/blink/renderer/core/frame/deprecation.h
@@ -16,7 +16,9 @@
 enum class FeaturePolicyFeature;
 }  // namespace mojom
 
+class Document;
 class DocumentLoader;
+class ExecutionContext;
 class LocalFrame;
 
 class CORE_EXPORT Deprecation final {
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc
index 97845a5..90da3808 100644
--- a/third_party/blink/renderer/core/frame/local_dom_window.cc
+++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
@@ -650,8 +650,8 @@
     return;
   }
 
-  UseCounter::CountCrossOriginIframe(*document(),
-                                     WebFeature::kCrossOriginWindowPrint);
+  document()->CountUseOnlyInCrossOriginIframe(
+      WebFeature::kCrossOriginWindowPrint);
 
   should_print_when_finished_loading_ = false;
   page->GetChromeClient().Print(GetFrame());
@@ -687,8 +687,8 @@
   if (!page)
     return;
 
-  UseCounter::CountCrossOriginIframe(*document(),
-                                     WebFeature::kCrossOriginWindowAlert);
+  document()->CountUseOnlyInCrossOriginIframe(
+      WebFeature::kCrossOriginWindowAlert);
 
   page->GetChromeClient().OpenJavaScriptAlert(GetFrame(), message);
 }
@@ -717,8 +717,8 @@
   if (!page)
     return false;
 
-  UseCounter::CountCrossOriginIframe(*document(),
-                                     WebFeature::kCrossOriginWindowConfirm);
+  document()->CountUseOnlyInCrossOriginIframe(
+      WebFeature::kCrossOriginWindowConfirm);
 
   return page->GetChromeClient().OpenJavaScriptConfirm(GetFrame(), message);
 }
@@ -754,8 +754,8 @@
                                                    default_value, return_value))
     return return_value;
 
-  UseCounter::CountCrossOriginIframe(*document(),
-                                     WebFeature::kCrossOriginWindowPrompt);
+  document()->CountUseOnlyInCrossOriginIframe(
+      WebFeature::kCrossOriginWindowPrompt);
 
   return String();
 }
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index 58df3d9..6e08900 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -75,6 +75,7 @@
 #include "third_party/blink/renderer/core/frame/report.h"
 #include "third_party/blink/renderer/core/frame/reporting_context.h"
 #include "third_party/blink/renderer/core/frame/settings.h"
+#include "third_party/blink/renderer/core/frame/use_counter.h"
 #include "third_party/blink/renderer/core/html/html_frame_element_base.h"
 #include "third_party/blink/renderer/core/html/html_plugin_element.h"
 #include "third_party/blink/renderer/core/html/plugin_document.h"
@@ -1390,7 +1391,7 @@
   // Do not track PageVisits for inspector, web page popups, and validation
   // message overlays (the other callers of this method).
   if (GetDocument()->IsSVGDocument())
-    loader_.GetDocumentLoader()->GetUseCounter().DidCommitLoad(this);
+    loader_.GetDocumentLoader()->GetUseCounterHelper().DidCommitLoad(this);
 }
 
 bool LocalFrame::IsProvisional() const {
@@ -1733,4 +1734,32 @@
     UseCounter::Count(GetDocument(), WebFeature::kAdClickNavigation);
 }
 
+void LocalFrame::CountUseIfFeatureWouldBeBlockedByFeaturePolicy(
+    mojom::WebFeature blocked_cross_origin,
+    mojom::WebFeature blocked_same_origin) {
+  // Get the origin of the top-level document
+  const SecurityOrigin* topOrigin =
+      Tree().Top().GetSecurityContext()->GetSecurityOrigin();
+
+  // Check if this frame is same-origin with the top-level
+  if (!GetSecurityContext()->GetSecurityOrigin()->CanAccess(topOrigin)) {
+    // This frame is cross-origin with the top-level frame, and so would be
+    // blocked without a feature policy.
+    UseCounter::Count(GetDocument(), blocked_cross_origin);
+    return;
+  }
+
+  // Walk up the frame tree looking for any cross-origin embeds. Even if this
+  // frame is same-origin with the top-level, if it is embedded by a cross-
+  // origin frame (like A->B->A) it would be blocked without a feature policy.
+  const Frame* f = this;
+  while (!f->IsMainFrame()) {
+    if (!f->GetSecurityContext()->GetSecurityOrigin()->CanAccess(topOrigin)) {
+      UseCounter::Count(GetDocument(), blocked_same_origin);
+      return;
+    }
+    f = f->Tree().Parent();
+  }
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/frame/local_frame.h b/third_party/blink/renderer/core/frame/local_frame.h
index 25884090..adc0c0f 100644
--- a/third_party/blink/renderer/core/frame/local_frame.h
+++ b/third_party/blink/renderer/core/frame/local_frame.h
@@ -39,6 +39,7 @@
 #include "third_party/blink/public/mojom/loader/pause_subresource_loading_handle.mojom-blink.h"
 #include "third_party/blink/public/mojom/loader/previews_resource_loading_hints.mojom-blink.h"
 #include "third_party/blink/public/mojom/reporting/reporting.mojom-blink.h"
+#include "third_party/blink/public/mojom/web_feature/web_feature.mojom-blink.h"
 #include "third_party/blink/public/platform/task_type.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/dom/user_gesture_indicator.h"
@@ -422,6 +423,16 @@
   // navigations go through.
   void MaybeLogAdClickNavigation();
 
+  // Triggers a use counter if a feature, which is currently available in all
+  // frames, would be blocked by the introduction of feature policy. This takes
+  // two counters (which may be the same). It triggers |blockedCrossOrigin| if
+  // the frame is cross-origin relative to the top-level document, and triggers
+  // |blockedSameOrigin| if it is same-origin with the top level, but is
+  // embedded in any way through a cross-origin frame. (A->B->A embedding)
+  void CountUseIfFeatureWouldBeBlockedByFeaturePolicy(
+      mojom::WebFeature blocked_cross_origin,
+      mojom::WebFeature blocked_same_origin);
+
  private:
   friend class FrameNavigationDisabler;
 
diff --git a/third_party/blink/renderer/core/frame/use_counter.cc b/third_party/blink/renderer/core/frame/use_counter.cc
index f1f65d8..b25a812 100644
--- a/third_party/blink/renderer/core/frame/use_counter.cc
+++ b/third_party/blink/renderer/core/frame/use_counter.cc
@@ -38,8 +38,6 @@
 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
 #include "third_party/blink/renderer/core/frame/settings.h"
 #include "third_party/blink/renderer/core/inspector/console_message.h"
-#include "third_party/blink/renderer/core/loader/document_loader.h"
-#include "third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h"
 #include "third_party/blink/renderer/platform/histogram.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
 #include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
@@ -49,18 +47,18 @@
 UseCounterMuteScope::UseCounterMuteScope(const Element& element)
     : loader_(element.GetDocument().Loader()) {
   if (loader_)
-    loader_->GetUseCounter().MuteForInspector();
+    loader_->GetUseCounterHelper().MuteForInspector();
 }
 
 UseCounterMuteScope::~UseCounterMuteScope() {
   if (loader_)
-    loader_->GetUseCounter().UnmuteForInspector();
+    loader_->GetUseCounterHelper().UnmuteForInspector();
 }
 
 // TODO(loonybear): Move CSSPropertyID to
 // public/mojom/use_counter/css_property_id.mojom to plumb CSS metrics end to
 // end to PageLoadMetrics.
-int UseCounter::MapCSSPropertyIdToCSSSampleIdForHistogram(
+int UseCounterHelper::MapCSSPropertyIdToCSSSampleIdForHistogram(
     CSSPropertyID unresolved_property) {
   switch (unresolved_property) {
     // Begin at 2, because 1 is reserved for totalPagesMeasuredCSSSampleId.
@@ -1255,19 +1253,19 @@
   return 0;
 }
 
-UseCounter::UseCounter(Context context, CommitState commit_state)
+UseCounterHelper::UseCounterHelper(Context context, CommitState commit_state)
     : mute_count_(0), context_(context), commit_state_(commit_state) {}
 
-void UseCounter::MuteForInspector() {
+void UseCounterHelper::MuteForInspector() {
   mute_count_++;
 }
 
-void UseCounter::UnmuteForInspector() {
+void UseCounterHelper::UnmuteForInspector() {
   mute_count_--;
 }
 
-void UseCounter::RecordMeasurement(WebFeature feature,
-                                   const LocalFrame& source_frame) {
+void UseCounterHelper::RecordMeasurement(WebFeature feature,
+                                         const LocalFrame& source_frame) {
   if (mute_count_)
     return;
 
@@ -1285,7 +1283,7 @@
   features_recorded_.set(feature_id);
 }
 
-void UseCounter::ReportAndTraceMeasurementByFeatureId(
+void UseCounterHelper::ReportAndTraceMeasurementByFeatureId(
     int feature_id,
     const LocalFrame& source_frame) {
   if (context_ != kDisabledContext) {
@@ -1301,7 +1299,7 @@
   }
 }
 
-bool UseCounter::HasRecordedMeasurement(WebFeature feature) const {
+bool UseCounterHelper::HasRecordedMeasurement(WebFeature feature) const {
   if (mute_count_)
     return false;
 
@@ -1313,45 +1311,15 @@
   return features_recorded_[static_cast<size_t>(feature)];
 }
 
-void UseCounter::ClearMeasurementForTesting(WebFeature feature) {
+void UseCounterHelper::ClearMeasurementForTesting(WebFeature feature) {
   features_recorded_.reset(static_cast<size_t>(feature));
 }
 
-// Static
-void UseCounter::CountIfFeatureWouldBeBlockedByFeaturePolicy(
-    const LocalFrame& frame,
-    WebFeature blocked_cross_origin,
-    WebFeature blocked_same_origin) {
-  // Get the origin of the top-level document
-  const SecurityOrigin* topOrigin =
-      frame.Tree().Top().GetSecurityContext()->GetSecurityOrigin();
-
-  // Check if this frame is same-origin with the top-level
-  if (!frame.GetSecurityContext()->GetSecurityOrigin()->CanAccess(topOrigin)) {
-    // This frame is cross-origin with the top-level frame, and so would be
-    // blocked without a feature policy.
-    UseCounter::Count(frame.GetDocument(), blocked_cross_origin);
-    return;
-  }
-
-  // Walk up the frame tree looking for any cross-origin embeds. Even if this
-  // frame is same-origin with the top-level, if it is embedded by a cross-
-  // origin frame (like A->B->A) it would be blocked without a feature policy.
-  const Frame* f = &frame;
-  while (!f->IsMainFrame()) {
-    if (!f->GetSecurityContext()->GetSecurityOrigin()->CanAccess(topOrigin)) {
-      UseCounter::Count(frame.GetDocument(), blocked_same_origin);
-      return;
-    }
-    f = f->Tree().Parent();
-  }
-}
-
-void UseCounter::Trace(blink::Visitor* visitor) {
+void UseCounterHelper::Trace(blink::Visitor* visitor) {
   visitor->Trace(observers_);
 }
 
-void UseCounter::DidCommitLoad(const LocalFrame* frame) {
+void UseCounterHelper::DidCommitLoad(const LocalFrame* frame) {
   const KURL url = frame->GetDocument()->Url();
   if (url.ProtocolIs("chrome-extension"))
     context_ = kExtensionContext;
@@ -1383,68 +1351,30 @@
   }
 }
 
-void UseCounter::Count(DocumentLoader* loader, WebFeature feature) {
-  if (!loader)
-    return;
-  loader->GetUseCounter().Count(feature, loader->GetFrame());
-}
-
-void UseCounter::Count(const Document& document, WebFeature feature) {
-  if (DocumentLoader* loader = document.Loader())
-    loader->GetUseCounter().Count(feature, document.GetFrame());
-}
-
-void UseCounter::Count(ExecutionContext* context, WebFeature feature) {
-  if (!context)
-    return;
-  if (auto* document = DynamicTo<Document>(context)) {
-    Count(*document, feature);
-    return;
+bool UseCounterHelper::IsCounted(CSSPropertyID unresolved_property,
+                                 CSSPropertyType type) const {
+  if (unresolved_property == CSSPropertyID::kInvalid) {
+    return false;
   }
-  if (auto* scope = DynamicTo<WorkerOrWorkletGlobalScope>(context))
-    scope->CountFeature(feature);
+  switch (type) {
+    case CSSPropertyType::kDefault:
+      return css_recorded_[MapCSSPropertyIdToCSSSampleIdForHistogram(
+          unresolved_property)];
+    case CSSPropertyType::kAnimation:
+      return animated_css_recorded_[MapCSSPropertyIdToCSSSampleIdForHistogram(
+          unresolved_property)];
+  }
 }
 
-bool UseCounter::IsCounted(Document& document, WebFeature feature) {
-  DocumentLoader* loader = document.Loader();
-  return loader ? loader->GetUseCounter().HasRecordedMeasurement(feature)
-                : false;
-}
-
-bool UseCounter::IsCounted(CSSPropertyID unresolved_property) {
-  return css_recorded_[MapCSSPropertyIdToCSSSampleIdForHistogram(
-      unresolved_property)];
-}
-
-void UseCounter::ClearCountForTesting(Document& document, WebFeature feature) {
-  if (DocumentLoader* loader = document.Loader())
-    loader->GetUseCounter().ClearMeasurementForTesting(feature);
-}
-
-void UseCounter::AddObserver(Observer* observer) {
+void UseCounterHelper::AddObserver(Observer* observer) {
   DCHECK(!observers_.Contains(observer));
   observers_.insert(observer);
 }
 
-bool UseCounter::IsCounted(Document& document, const String& string) {
-  CSSPropertyID unresolved_property = unresolvedCSSPropertyID(string);
-  if (unresolved_property == CSSPropertyID::kInvalid)
-    return false;
-  DocumentLoader* loader = document.Loader();
-  return loader ? loader->GetUseCounter().IsCounted(unresolved_property)
-                : false;
-}
-
-void UseCounter::CountCrossOriginIframe(const Document& document,
-                                        WebFeature feature) {
-  LocalFrame* frame = document.GetFrame();
-  if (frame && frame->IsCrossOriginSubframe())
-    Count(document, feature);
-}
-
-void UseCounter::ReportAndTraceMeasurementByCSSSampleId(int sample_id,
-                                                        const LocalFrame* frame,
-                                                        bool is_animated) {
+void UseCounterHelper::ReportAndTraceMeasurementByCSSSampleId(
+    int sample_id,
+    const LocalFrame* frame,
+    bool is_animated) {
   // Note that HTTPArchive tooling looks specifically for this event - see
   // https://github.com/HTTPArchive/httparchive/issues/59
   if (context_ != kDisabledContext && context_ != kExtensionContext) {
@@ -1456,71 +1386,44 @@
   }
 }
 
-void UseCounter::Count(CSSParserMode css_parser_mode,
-                       CSSPropertyID property,
-                       const LocalFrame* source_frame) {
-  DCHECK(isCSSPropertyIDWithName(property) ||
-         property == CSSPropertyID::kVariable);
-
-  if (!IsUseCounterEnabledForMode(css_parser_mode) || mute_count_)
-    return;
-
-  int sample_id = MapCSSPropertyIdToCSSSampleIdForHistogram(property);
-  if (css_recorded_[sample_id])
-    return;
-  if (commit_state_ >= kCommited)
-    ReportAndTraceMeasurementByCSSSampleId(sample_id, source_frame, false);
-
-  css_recorded_.set(sample_id);
-}
-
-void UseCounter::Count(WebFeature feature, const LocalFrame* source_frame) {
-  if (!source_frame)
-    return;
-  RecordMeasurement(feature, *source_frame);
-}
-
-bool UseCounter::IsCountedAnimatedCSS(CSSPropertyID unresolved_property) {
-  return animated_css_recorded_[MapCSSPropertyIdToCSSSampleIdForHistogram(
-      unresolved_property)];
-}
-
-bool UseCounter::IsCountedAnimatedCSS(Document& document,
-                                      const String& string) {
-  CSSPropertyID unresolved_property = unresolvedCSSPropertyID(string);
-  if (unresolved_property == CSSPropertyID::kInvalid)
-    return false;
-  DocumentLoader* loader = document.Loader();
-  return loader
-             ? loader->GetUseCounter().IsCountedAnimatedCSS(unresolved_property)
-             : false;
-}
-
-void UseCounter::CountAnimatedCSS(const Document& document,
-                                  CSSPropertyID property) {
-  DocumentLoader* loader = document.Loader();
-  if (loader)
-    loader->GetUseCounter().CountAnimatedCSS(property, document.GetFrame());
-}
-
-void UseCounter::CountAnimatedCSS(CSSPropertyID property,
-                                  const LocalFrame* source_frame) {
+void UseCounterHelper::Count(CSSPropertyID property,
+                             CSSPropertyType type,
+                             const LocalFrame* source_frame) {
   DCHECK(isCSSPropertyIDWithName(property) ||
          property == CSSPropertyID::kVariable);
 
   if (mute_count_)
     return;
 
-  int sample_id = MapCSSPropertyIdToCSSSampleIdForHistogram(property);
-  if (animated_css_recorded_[sample_id])
-    return;
-  if (commit_state_ >= kCommited)
-    ReportAndTraceMeasurementByCSSSampleId(sample_id, source_frame, true);
+  const int sample_id = MapCSSPropertyIdToCSSSampleIdForHistogram(property);
+  switch (type) {
+    case CSSPropertyType::kDefault:
+      if (css_recorded_[sample_id])
+        return;
+      if (commit_state_ >= kCommited)
+        ReportAndTraceMeasurementByCSSSampleId(sample_id, source_frame, false);
 
-  animated_css_recorded_.set(sample_id);
+      css_recorded_.set(sample_id);
+      break;
+    case CSSPropertyType::kAnimation:
+      if (animated_css_recorded_[sample_id])
+        return;
+      if (commit_state_ >= kCommited)
+        ReportAndTraceMeasurementByCSSSampleId(sample_id, source_frame, true);
+
+      animated_css_recorded_.set(sample_id);
+      break;
+  }
 }
 
-void UseCounter::NotifyFeatureCounted(WebFeature feature) {
+void UseCounterHelper::Count(WebFeature feature,
+                             const LocalFrame* source_frame) {
+  if (!source_frame)
+    return;
+  RecordMeasurement(feature, *source_frame);
+}
+
+void UseCounterHelper::NotifyFeatureCounted(WebFeature feature) {
   DCHECK(!mute_count_);
   DCHECK_NE(kDisabledContext, context_);
   HeapHashSet<Member<Observer>> to_be_removed;
@@ -1531,7 +1434,7 @@
   observers_.RemoveAll(to_be_removed);
 }
 
-EnumerationHistogram& UseCounter::FeaturesHistogram() const {
+EnumerationHistogram& UseCounterHelper::FeaturesHistogram() const {
   DEFINE_STATIC_LOCAL(blink::EnumerationHistogram, extension_histogram,
                       ("Blink.UseCounter.Extensions.Features",
                        static_cast<int32_t>(WebFeature::kNumberOfFeatures)));
diff --git a/third_party/blink/renderer/core/frame/use_counter.h b/third_party/blink/renderer/core/frame/use_counter.h
index 0b7c5e4..4a948b3 100644
--- a/third_party/blink/renderer/core/frame/use_counter.h
+++ b/third_party/blink/renderer/core/frame/use_counter.h
@@ -34,16 +34,14 @@
 #include "third_party/blink/renderer/core/frame/web_feature.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 
 namespace blink {
 
-class CSSStyleSheet;
-class Document;
 class DocumentLoader;
-class EnumerationHistogram;
 class Element;
-class ExecutionContext;
+class EnumerationHistogram;
 class LocalFrame;
 class StyleSheetContents;
 
@@ -62,23 +60,10 @@
   Member<DocumentLoader> loader_;
 };
 
-// Definition for UseCounter features can be found in:
-// third_party/blink/public/mojom/web_feature/web_feature.mojom
-
-// UseCounter is used for counting the number of times features of
-// Blink are used on real web pages and help us know commonly
-// features are used and thus when it's safe to remove or change them.
-//
-// The Chromium Content layer controls what is done with this data.
-//
-// For instance, in Google Chrome, these counts are submitted anonymously
-// through the UMA histogram recording system in Chrome for users who have the
-// "Automatically send usage statistics and crash reports to Google" setting
-// enabled:
-// http://www.google.com/chrome/intl/en/privacy.html
-//
-// Changes on UseCounter are observable by UseCounter::Observer.
-class CORE_EXPORT UseCounter {
+// This class provides an implementation of UseCounter - see the class comment
+// of blink::UseCounter for the feature.
+// Changes on UseCounterHelper are observable by UseCounterHelper::Observer.
+class CORE_EXPORT UseCounterHelper final {
   DISALLOW_NEW();
 
  public:
@@ -99,9 +84,14 @@
 
   enum CommitState { kPreCommit, kCommited };
 
-  UseCounter(Context = kDefaultContext, CommitState = kPreCommit);
+  // CSS properties for animation are separately counted. This enum is used to
+  // distinguish them.
+  enum class CSSPropertyType { kDefault, kAnimation };
 
-  // An interface to observe UseCounter changes. Note that this is never
+  explicit UseCounterHelper(Context = kDefaultContext,
+                            CommitState = kPreCommit);
+
+  // An interface to observe UseCounterHelper changes. Note that this is never
   // notified when the counter is disabled by |m_muteCount| or when |m_context|
   // is kDisabledContext.
   class Observer : public GarbageCollected<Observer> {
@@ -114,44 +104,19 @@
     virtual void Trace(blink::Visitor* visitor) {}
   };
 
-  // "count" sets the bit for this feature to 1. Repeated calls are ignored.
-  static void Count(DocumentLoader*, WebFeature);
-  static void Count(const Document&, WebFeature);
-  static void Count(ExecutionContext*, WebFeature);
-
-  void Count(CSSParserMode, CSSPropertyID, const LocalFrame*);
+  // Repeated calls are ignored.
+  void Count(CSSPropertyID, CSSPropertyType, const LocalFrame*);
+  // Repeated calls are ignored.
   void Count(WebFeature, const LocalFrame*);
 
-  static void CountAnimatedCSS(const Document&, CSSPropertyID);
-  void CountAnimatedCSS(CSSPropertyID, const LocalFrame*);
+  bool IsCounted(CSSPropertyID unresolved_property, CSSPropertyType) const;
 
-  // Count only features if they're being used in an iframe which does not
-  // have script access into the top level document.
-  static void CountCrossOriginIframe(const Document&, WebFeature);
-
-  // Return whether the Feature was previously counted for this document.
-  // NOTE: only for use in testing.
-  static bool IsCounted(Document&, WebFeature);
-  // Return whether the CSSPropertyID was previously counted for this document.
-  // NOTE: only for use in testing.
-  static bool IsCounted(Document&, const String&);
-  bool IsCounted(CSSPropertyID unresolved_property);
-
-  static void ClearCountForTesting(Document& document, WebFeature feature);
-
-  // Return whether the CSSPropertyID was previously counted for this document.
-  // NOTE: only for use in testing.
-  static bool IsCountedAnimatedCSS(Document&, const String&);
-  bool IsCountedAnimatedCSS(CSSPropertyID unresolved_property);
-
-  // Retains a reference to the observer to notify of UseCounter changes.
+  // Retains a reference to the observer to notify of UseCounterHelper changes.
   void AddObserver(Observer*);
 
   // Invoked when a new document is loaded into the main frame of the page.
   void DidCommitLoad(const LocalFrame*);
 
-  static int MapCSSPropertyIdToCSSSampleIdForHistogram(CSSPropertyID);
-
   // When muted, all calls to "count" functions are ignoed.  May be nested.
   void MuteForInspector();
   void UnmuteForInspector();
@@ -169,17 +134,6 @@
 
   void ClearMeasurementForTesting(WebFeature);
 
-  // Triggers a use counter if a feature, which is currently available in all
-  // frames, would be blocked by the introduction of feature policy. This takes
-  // two counters (which may be the same). It triggers |blockedCrossOrigin| if
-  // the frame is cross-origin relative to the top-level document, and triggers
-  // |blockedSameOrigin| if it is same-origin with the top level, but is
-  // embedded in any way through a cross-origin frame. (A->B->A embedding)
-  static void CountIfFeatureWouldBeBlockedByFeaturePolicy(
-      const LocalFrame&,
-      WebFeature blockedCrossOrigin,
-      WebFeature blockedSameOrigin);
-
   void Trace(blink::Visitor*);
 
  private:
@@ -192,11 +146,13 @@
   EnumerationHistogram& CssHistogram() const;
   EnumerationHistogram& AnimatedCSSHistogram() const;
 
+  static int MapCSSPropertyIdToCSSSampleIdForHistogram(CSSPropertyID);
+
   // If non-zero, ignore all 'count' calls completely.
   unsigned mute_count_;
 
-  // The scope represented by this UseCounter instance, which must be fixed for
-  // the duration of a page but can change when a new page is loaded.
+  // The scope represented by this UseCounterHelper instance, which must be
+  // fixed for the duration of a page but can change when a new page is loaded.
   Context context_;
   // CommitState tracks whether navigation has commited. Prior to commit,
   // UseCounters are logged locally and delivered to the browser only once the
@@ -212,7 +168,7 @@
 
   HeapHashSet<Member<Observer>> observers_;
 
-  DISALLOW_COPY_AND_ASSIGN(UseCounter);
+  DISALLOW_COPY_AND_ASSIGN(UseCounterHelper);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/frame/use_counter_test.cc b/third_party/blink/renderer/core/frame/use_counter_test.cc
index 94fe81e..ca4a76a 100644
--- a/third_party/blink/renderer/core/frame/use_counter_test.cc
+++ b/third_party/blink/renderer/core/frame/use_counter_test.cc
@@ -34,9 +34,9 @@
 namespace blink {
 using WebFeature = mojom::WebFeature;
 
-class UseCounterTest : public testing::Test {
+class UseCounterHelperTest : public testing::Test {
  public:
-  UseCounterTest() : dummy_(std::make_unique<DummyPageHolder>()) {
+  UseCounterHelperTest() : dummy_(std::make_unique<DummyPageHolder>()) {
     Page::InsertOrdinaryPageForTesting(&dummy_->GetPage());
   }
 
@@ -55,15 +55,15 @@
   }
 };
 
-TEST_F(UseCounterTest, RecordingExtensions) {
+TEST_F(UseCounterHelperTest, RecordingExtensions) {
   const std::string histogram = kExtensionFeaturesHistogramName;
   constexpr auto item = mojom::WebFeature::kFetch;
   constexpr auto second_item = WebFeature::kFetchBodyStream;
   const std::string url = kExtensionUrl;
-  UseCounter::Context context = UseCounter::kExtensionContext;
+  UseCounterHelper::Context context = UseCounterHelper::kExtensionContext;
   int page_visits_bucket = GetPageVisitsBucketforHistogram(histogram);
 
-  UseCounter use_counter0(context, UseCounter::kCommited);
+  UseCounterHelper use_counter0(context, UseCounterHelper::kCommited);
 
   // Test recording a single (arbitrary) counter
   EXPECT_FALSE(use_counter0.HasRecordedMeasurement(item));
@@ -85,7 +85,7 @@
 
   // After a page load, the histograms will be updated, even when the URL
   // scheme is internal
-  UseCounter use_counter1(context);
+  UseCounterHelper use_counter1(context);
   SetURL(url_test_helpers::ToKURL(url));
   use_counter1.DidCommitLoad(GetFrame());
   histogram_tester_.ExpectBucketCount(histogram, static_cast<int>(item), 1);
@@ -103,17 +103,16 @@
   histogram_tester_.ExpectTotalCount(histogram, 4);
 }
 
-TEST_F(UseCounterTest, CSSSelectorPseudoWhere) {
+TEST_F(UseCounterHelperTest, CSSSelectorPseudoWhere) {
   auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
   Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
   Document& document = dummy_page_holder->GetDocument();
   WebFeature feature = WebFeature::kCSSSelectorPseudoWhere;
-  EXPECT_FALSE(UseCounter::IsCounted(document, feature));
+  EXPECT_FALSE(document.IsUseCounted(feature));
   document.documentElement()->SetInnerHTMLFromString(
       "<style>.a+:where(.b, .c+.d) { color: red; }</style>");
-  EXPECT_TRUE(UseCounter::IsCounted(document, feature));
-  EXPECT_FALSE(
-      UseCounter::IsCounted(document, WebFeature::kCSSSelectorPseudoIs));
+  EXPECT_TRUE(document.IsUseCounted(feature));
+  EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSSelectorPseudoIs));
 }
 
 /*
@@ -127,181 +126,180 @@
  * won't find in unit testing anyway.
  */
 
-TEST_F(UseCounterTest, CSSSelectorPseudoAnyLink) {
+TEST_F(UseCounterHelperTest, CSSSelectorPseudoAnyLink) {
   auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
   Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
   Document& document = dummy_page_holder->GetDocument();
   WebFeature feature = WebFeature::kCSSSelectorPseudoAnyLink;
-  EXPECT_FALSE(UseCounter::IsCounted(document, feature));
+  EXPECT_FALSE(document.IsUseCounted(feature));
   document.documentElement()->SetInnerHTMLFromString(
       "<style>:any-link { color: red; }</style>");
-  EXPECT_TRUE(UseCounter::IsCounted(document, feature));
+  EXPECT_TRUE(document.IsUseCounted(feature));
 }
 
-TEST_F(UseCounterTest, CSSSelectorPseudoWebkitAnyLink) {
+TEST_F(UseCounterHelperTest, CSSSelectorPseudoWebkitAnyLink) {
   auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
   Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
   Document& document = dummy_page_holder->GetDocument();
   WebFeature feature = WebFeature::kCSSSelectorPseudoWebkitAnyLink;
-  EXPECT_FALSE(UseCounter::IsCounted(document, feature));
+  EXPECT_FALSE(document.IsUseCounted(feature));
   document.documentElement()->SetInnerHTMLFromString(
       "<style>:-webkit-any-link { color: red; }</style>");
-  EXPECT_TRUE(UseCounter::IsCounted(document, feature));
+  EXPECT_TRUE(document.IsUseCounted(feature));
 }
 
-TEST_F(UseCounterTest, CSSTypedOMStylePropertyMap) {
-  UseCounter use_counter;
+TEST_F(UseCounterHelperTest, CSSTypedOMStylePropertyMap) {
+  UseCounterHelper use_counter;
   WebFeature feature = WebFeature::kCSSTypedOMStylePropertyMap;
-  EXPECT_FALSE(use_counter.IsCounted(GetDocument(), feature));
-  use_counter.Count(GetDocument(), feature);
-  EXPECT_TRUE(use_counter.IsCounted(GetDocument(), feature));
+  EXPECT_FALSE(GetDocument().IsUseCounted(feature));
+  GetDocument().CountUse(feature);
+  EXPECT_TRUE(GetDocument().IsUseCounted(feature));
 }
 
-TEST_F(UseCounterTest, CSSSelectorPseudoIs) {
+TEST_F(UseCounterHelperTest, CSSSelectorPseudoIs) {
   auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
   Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
   Document& document = dummy_page_holder->GetDocument();
   WebFeature feature = WebFeature::kCSSSelectorPseudoIs;
-  EXPECT_FALSE(UseCounter::IsCounted(document, feature));
+  EXPECT_FALSE(document.IsUseCounted(feature));
   document.documentElement()->SetInnerHTMLFromString(
       "<style>.a+:is(.b, .c+.d) { color: red; }</style>");
-  EXPECT_TRUE(UseCounter::IsCounted(document, feature));
-  EXPECT_FALSE(
-      UseCounter::IsCounted(document, WebFeature::kCSSSelectorPseudoWhere));
+  EXPECT_TRUE(document.IsUseCounted(feature));
+  EXPECT_FALSE(document.IsUseCounted(WebFeature::kCSSSelectorPseudoWhere));
 }
 
-TEST_F(UseCounterTest, CSSContainLayoutNonPositionedDescendants) {
+TEST_F(UseCounterHelperTest, CSSContainLayoutNonPositionedDescendants) {
   auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
   Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
   Document& document = dummy_page_holder->GetDocument();
   WebFeature feature = WebFeature::kCSSContainLayoutPositionedDescendants;
-  EXPECT_FALSE(UseCounter::IsCounted(document, feature));
+  EXPECT_FALSE(document.IsUseCounted(feature));
   document.documentElement()->SetInnerHTMLFromString(
       "<div style='contain: layout;'>"
       "</div>");
   UpdateAllLifecyclePhases(document);
-  EXPECT_FALSE(UseCounter::IsCounted(document, feature));
+  EXPECT_FALSE(document.IsUseCounted(feature));
 }
 
-TEST_F(UseCounterTest, CSSContainLayoutAbsolutelyPositionedDescendants) {
+TEST_F(UseCounterHelperTest, CSSContainLayoutAbsolutelyPositionedDescendants) {
   auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
   Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
   Document& document = dummy_page_holder->GetDocument();
   WebFeature feature = WebFeature::kCSSContainLayoutPositionedDescendants;
-  EXPECT_FALSE(UseCounter::IsCounted(document, feature));
+  EXPECT_FALSE(document.IsUseCounted(feature));
   document.documentElement()->SetInnerHTMLFromString(
       "<div style='contain: layout;'>"
       "  <div style='position: absolute;'></div>"
       "</div>");
   UpdateAllLifecyclePhases(document);
-  EXPECT_TRUE(UseCounter::IsCounted(document, feature));
+  EXPECT_TRUE(document.IsUseCounted(feature));
 }
 
-TEST_F(UseCounterTest,
+TEST_F(UseCounterHelperTest,
        CSSContainLayoutAbsolutelyPositionedDescendantsAlreadyContainingBlock) {
   auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
   Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
   Document& document = dummy_page_holder->GetDocument();
   WebFeature feature = WebFeature::kCSSContainLayoutPositionedDescendants;
-  EXPECT_FALSE(UseCounter::IsCounted(document, feature));
+  EXPECT_FALSE(document.IsUseCounted(feature));
   document.documentElement()->SetInnerHTMLFromString(
       "<div style='position: relative; contain: layout;'>"
       "  <div style='position: absolute;'></div>"
       "</div>");
   UpdateAllLifecyclePhases(document);
-  EXPECT_FALSE(UseCounter::IsCounted(document, feature));
+  EXPECT_FALSE(document.IsUseCounted(feature));
 }
 
-TEST_F(UseCounterTest, CSSContainLayoutFixedPositionedDescendants) {
+TEST_F(UseCounterHelperTest, CSSContainLayoutFixedPositionedDescendants) {
   auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
   Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
   Document& document = dummy_page_holder->GetDocument();
   WebFeature feature = WebFeature::kCSSContainLayoutPositionedDescendants;
-  EXPECT_FALSE(UseCounter::IsCounted(document, feature));
+  EXPECT_FALSE(document.IsUseCounted(feature));
   document.documentElement()->SetInnerHTMLFromString(
       "<div style='contain: layout;'>"
       "  <div style='position: fixed;'></div>"
       "</div>");
   UpdateAllLifecyclePhases(document);
-  EXPECT_TRUE(UseCounter::IsCounted(document, feature));
+  EXPECT_TRUE(document.IsUseCounted(feature));
 }
 
-TEST_F(UseCounterTest,
+TEST_F(UseCounterHelperTest,
        CSSContainLayoutFixedPositionedDescendantsAlreadyContainingBlock) {
   auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
   Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
   Document& document = dummy_page_holder->GetDocument();
   WebFeature feature = WebFeature::kCSSContainLayoutPositionedDescendants;
-  EXPECT_FALSE(UseCounter::IsCounted(document, feature));
+  EXPECT_FALSE(document.IsUseCounted(feature));
   document.documentElement()->SetInnerHTMLFromString(
       "<div style='transform: translateX(100px); contain: layout;'>"
       "  <div style='position: fixed;'></div>"
       "</div>");
   UpdateAllLifecyclePhases(document);
-  EXPECT_FALSE(UseCounter::IsCounted(document, feature));
+  EXPECT_FALSE(document.IsUseCounted(feature));
 }
 
-TEST_F(UseCounterTest, CSSGridLayoutPercentageColumnIndefiniteWidth) {
+TEST_F(UseCounterHelperTest, CSSGridLayoutPercentageColumnIndefiniteWidth) {
   auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
   Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
   Document& document = dummy_page_holder->GetDocument();
   WebFeature feature = WebFeature::kGridRowTrackPercentIndefiniteHeight;
-  EXPECT_FALSE(UseCounter::IsCounted(document, feature));
+  EXPECT_FALSE(document.IsUseCounted(feature));
   document.documentElement()->SetInnerHTMLFromString(
       "<div style='display: inline-grid; grid-template-columns: 50%;'>"
       "</div>");
   UpdateAllLifecyclePhases(document);
-  EXPECT_FALSE(UseCounter::IsCounted(document, feature));
+  EXPECT_FALSE(document.IsUseCounted(feature));
 }
 
-TEST_F(UseCounterTest, CSSGridLayoutPercentageRowIndefiniteHeight) {
+TEST_F(UseCounterHelperTest, CSSGridLayoutPercentageRowIndefiniteHeight) {
   auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
   Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
   Document& document = dummy_page_holder->GetDocument();
   WebFeature feature = WebFeature::kGridRowTrackPercentIndefiniteHeight;
-  EXPECT_FALSE(UseCounter::IsCounted(document, feature));
+  EXPECT_FALSE(document.IsUseCounted(feature));
   document.documentElement()->SetInnerHTMLFromString(
       "<div style='display: inline-grid; grid-template-rows: 50%;'>"
       "</div>");
   UpdateAllLifecyclePhases(document);
-  EXPECT_TRUE(UseCounter::IsCounted(document, feature));
+  EXPECT_TRUE(document.IsUseCounted(feature));
 }
 
-TEST_F(UseCounterTest, CSSFlexibleBox) {
+TEST_F(UseCounterHelperTest, CSSFlexibleBox) {
   auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
   Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
   Document& document = dummy_page_holder->GetDocument();
   WebFeature feature = WebFeature::kCSSFlexibleBox;
-  EXPECT_FALSE(UseCounter::IsCounted(document, feature));
+  EXPECT_FALSE(document.IsUseCounted(feature));
   document.documentElement()->SetInnerHTMLFromString(
       "<div style='display: flex;'>flexbox</div>");
   UpdateAllLifecyclePhases(document);
-  EXPECT_TRUE(UseCounter::IsCounted(document, feature));
+  EXPECT_TRUE(document.IsUseCounted(feature));
 }
 
-TEST_F(UseCounterTest, CSSFlexibleBoxInline) {
+TEST_F(UseCounterHelperTest, CSSFlexibleBoxInline) {
   auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
   Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
   Document& document = dummy_page_holder->GetDocument();
   WebFeature feature = WebFeature::kCSSFlexibleBox;
-  EXPECT_FALSE(UseCounter::IsCounted(document, feature));
+  EXPECT_FALSE(document.IsUseCounted(feature));
   document.documentElement()->SetInnerHTMLFromString(
       "<div style='display: inline-flex;'>flexbox</div>");
   UpdateAllLifecyclePhases(document);
-  EXPECT_TRUE(UseCounter::IsCounted(document, feature));
+  EXPECT_TRUE(document.IsUseCounted(feature));
 }
 
-TEST_F(UseCounterTest, CSSFlexibleBoxButton) {
+TEST_F(UseCounterHelperTest, CSSFlexibleBoxButton) {
   // LayoutButton is a subclass of LayoutFlexibleBox, however we don't want it
   // to be counted as usage of flexboxes as it's an implementation detail.
   auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
   Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
   Document& document = dummy_page_holder->GetDocument();
   WebFeature feature = WebFeature::kCSSFlexibleBox;
-  EXPECT_FALSE(UseCounter::IsCounted(document, feature));
+  EXPECT_FALSE(document.IsUseCounted(feature));
   document.documentElement()->SetInnerHTMLFromString("<button>button</button>");
   UpdateAllLifecyclePhases(document);
-  EXPECT_FALSE(UseCounter::IsCounted(document, feature));
+  EXPECT_FALSE(document.IsUseCounted(feature));
 }
 
 class DeprecationTest : public testing::Test {
@@ -309,7 +307,7 @@
   DeprecationTest()
       : dummy_(std::make_unique<DummyPageHolder>()),
         deprecation_(dummy_->GetPage().GetDeprecation()),
-        use_counter_(dummy_->GetDocument().Loader()->GetUseCounter()) {
+        use_counter_(dummy_->GetDocument().Loader()->GetUseCounterHelper()) {
     Page::InsertOrdinaryPageForTesting(&dummy_->GetPage());
   }
 
@@ -318,7 +316,7 @@
 
   std::unique_ptr<DummyPageHolder> dummy_;
   Deprecation& deprecation_;
-  UseCounter& use_counter_;
+  UseCounterHelper& use_counter_;
 };
 
 TEST_F(DeprecationTest, InspectorDisablesDeprecation) {
@@ -354,12 +352,12 @@
   EXPECT_TRUE(use_counter_.HasRecordedMeasurement(feature));
 }
 
-TEST_F(UseCounterTest, CSSUnknownNamespacePrefixInSelector) {
+TEST_F(UseCounterHelperTest, CSSUnknownNamespacePrefixInSelector) {
   auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
   Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
   Document& document = dummy_page_holder->GetDocument();
   WebFeature feature = WebFeature::kCSSUnknownNamespacePrefixInSelector;
-  EXPECT_FALSE(UseCounter::IsCounted(document, feature));
+  EXPECT_FALSE(document.IsUseCounted(feature));
 
   document.documentElement()->SetInnerHTMLFromString(R"HTML(
     <style>
@@ -369,14 +367,14 @@
     </style>
   )HTML");
   UpdateAllLifecyclePhases(document);
-  EXPECT_FALSE(UseCounter::IsCounted(document, feature));
+  EXPECT_FALSE(document.IsUseCounted(feature));
 
   document.documentElement()->SetInnerHTMLFromString("<style>foo|a {}</style>");
   UpdateAllLifecyclePhases(document);
-  EXPECT_TRUE(UseCounter::IsCounted(document, feature));
+  EXPECT_TRUE(document.IsUseCounted(feature));
 }
 
-TEST_F(UseCounterTest, CSSSelectorHostContextInLiveProfile) {
+TEST_F(UseCounterHelperTest, CSSSelectorHostContextInLiveProfile) {
   auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
   Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
   Document& document = dummy_page_holder->GetDocument();
@@ -393,7 +391,7 @@
   ShadowRoot& shadow_root =
       host->AttachShadowRootInternal(ShadowRootType::kOpen);
   UpdateAllLifecyclePhases(document);
-  EXPECT_FALSE(UseCounter::IsCounted(document, feature));
+  EXPECT_FALSE(document.IsUseCounted(feature));
 
   shadow_root.SetInnerHTMLFromString(R"HTML(
       <style>
@@ -405,10 +403,10 @@
   )HTML");
 
   UpdateAllLifecyclePhases(document);
-  EXPECT_TRUE(UseCounter::IsCounted(document, feature));
+  EXPECT_TRUE(document.IsUseCounted(feature));
 }
 
-TEST_F(UseCounterTest, CSSSelectorHostContextInSnapshotProfile) {
+TEST_F(UseCounterHelperTest, CSSSelectorHostContextInSnapshotProfile) {
   auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
   Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
   Document& document = dummy_page_holder->GetDocument();
@@ -425,15 +423,15 @@
   ShadowRoot& shadow_root =
       host->AttachShadowRootInternal(ShadowRootType::kOpen);
   UpdateAllLifecyclePhases(document);
-  EXPECT_FALSE(UseCounter::IsCounted(document, feature));
+  EXPECT_FALSE(document.IsUseCounted(feature));
 
   shadow_root.SetInnerHTMLFromString("<span></span>");
   UpdateAllLifecyclePhases(document);
-  EXPECT_FALSE(UseCounter::IsCounted(document, feature));
+  EXPECT_FALSE(document.IsUseCounted(feature));
 
   Element* span = shadow_root.QuerySelector(":host-context(#parent) span");
   EXPECT_TRUE(span);
-  EXPECT_TRUE(UseCounter::IsCounted(document, feature));
+  EXPECT_TRUE(document.IsUseCounted(feature));
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
index c8174f4b..88bb36db 100644
--- a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
+++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
@@ -957,10 +957,10 @@
   String referrer = referrer_url.IsEmpty()
                         ? GetFrame()->GetDocument()->OutgoingReferrer()
                         : String(referrer_url.GetString());
-  ResourceRequest& resource_request = request.ToMutableResourceRequest();
-  resource_request.SetReferrerPolicy(
-      GetFrame()->GetDocument()->GetReferrerPolicy());
-  resource_request.SetReferrerString(referrer);
+  request.ToMutableResourceRequest().SetHttpReferrer(
+      SecurityPolicy::GenerateReferrer(
+          GetFrame()->GetDocument()->GetReferrerPolicy(), request.Url(),
+          referrer));
 }
 
 WebAssociatedURLLoader* WebLocalFrameImpl::CreateAssociatedURLLoader(
diff --git a/third_party/blink/renderer/core/html/html_iframe_element.cc b/third_party/blink/renderer/core/html/html_iframe_element.cc
index 7d866f9e..3c64ce86 100644
--- a/third_party/blink/renderer/core/html/html_iframe_element.cc
+++ b/third_party/blink/renderer/core/html/html_iframe_element.cc
@@ -258,7 +258,7 @@
     // To avoid polluting the console, this is being recorded only once per
     // page.
     if (name == "gesture" && value == "media" && GetDocument().Loader() &&
-        !GetDocument().Loader()->GetUseCounter().HasRecordedMeasurement(
+        !GetDocument().Loader()->GetUseCounterHelper().HasRecordedMeasurement(
             WebFeature::kHTMLIFrameElementGestureMedia)) {
       UseCounter::Count(GetDocument(),
                         WebFeature::kHTMLIFrameElementGestureMedia);
diff --git a/third_party/blink/renderer/core/inspector/main_thread_debugger.cc b/third_party/blink/renderer/core/inspector/main_thread_debugger.cc
index 15af6b6..672e62d 100644
--- a/third_party/blink/renderer/core/inspector/main_thread_debugger.cc
+++ b/third_party/blink/renderer/core/inspector/main_thread_debugger.cc
@@ -266,7 +266,7 @@
   if (!frame)
     return;
   if (frame->GetDocument() && frame->GetDocument()->Loader())
-    frame->GetDocument()->Loader()->GetUseCounter().MuteForInspector();
+    frame->GetDocument()->Loader()->GetUseCounterHelper().MuteForInspector();
   if (frame->GetPage())
     frame->GetPage()->GetDeprecation().MuteForInspector();
 }
@@ -276,7 +276,7 @@
   if (!frame)
     return;
   if (frame->GetDocument() && frame->GetDocument()->Loader())
-    frame->GetDocument()->Loader()->GetUseCounter().UnmuteForInspector();
+    frame->GetDocument()->Loader()->GetUseCounterHelper().UnmuteForInspector();
   if (frame->GetPage())
     frame->GetPage()->GetDeprecation().UnmuteForInspector();
 }
diff --git a/third_party/blink/renderer/core/invisible_dom/find_invisible_test.cc b/third_party/blink/renderer/core/invisible_dom/find_invisible_test.cc
deleted file mode 100644
index 74dd77a..0000000
--- a/third_party/blink/renderer/core/invisible_dom/find_invisible_test.cc
+++ /dev/null
@@ -1,222 +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 "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
-#include "third_party/blink/renderer/core/editing/finder/text_finder.h"
-#include "third_party/blink/renderer/core/frame/find_in_page.h"
-#include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
-#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
-#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
-#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
-#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
-
-namespace blink {
-class InvisibleFindInPageClient : public mojom::blink::FindInPageClient {
- public:
-  InvisibleFindInPageClient()
-      : binding_(this),
-        active_index_(-1),
-        count_(-1),
-        find_results_are_ready_(false) {}
-
-  ~InvisibleFindInPageClient() override = default;
-
-  void SetFrame(WebLocalFrameImpl* frame) {
-    mojom::blink::FindInPageClientPtr client;
-    binding_.Bind(MakeRequest(&client));
-    frame->GetFindInPage()->SetClient(std::move(client));
-  }
-
-  void SetNumberOfMatches(
-      int request_id,
-      unsigned int current_number_of_matches,
-      mojom::blink::FindMatchUpdateType final_update) final {
-    count_ = current_number_of_matches;
-    find_results_are_ready_ =
-        (final_update == mojom::blink::FindMatchUpdateType::kFinalUpdate);
-  }
-
-  void SetActiveMatch(int request_id,
-                      const WebRect& active_match_rect,
-                      int active_match_ordinal,
-                      mojom::blink::FindMatchUpdateType final_update) final {
-    active_index_ = active_match_ordinal;
-    find_results_are_ready_ =
-        (final_update == mojom::blink::FindMatchUpdateType::kFinalUpdate);
-  }
-
-  bool FindResultsAreReady() const { return find_results_are_ready_; }
-  int Count() const { return count_; }
-  int ActiveIndex() const { return active_index_; }
-
-  void Reset() {
-    find_results_are_ready_ = false;
-    count_ = -1;
-    active_index_ = -1;
-  }
-
- private:
-  mojo::Binding<mojom::blink::FindInPageClient> binding_;
-  int active_index_;
-  int count_;
-  bool find_results_are_ready_;
-};
-
-class FindInvisibleTest : public ::testing::WithParamInterface<bool>,
-                          public testing::Test,
-                          private ScopedLayoutNGForTest {
- protected:
-  FindInvisibleTest() : ScopedLayoutNGForTest(GetParam()) {}
-
-  bool LayoutNGEnabled() const { return GetParam(); }
-
-  void SetUp() override { web_view_helper_.Initialize(); }
-
-  void TearDown() override { web_view_helper_.Reset(); }
-
-  Document& GetDocument() {
-    return *static_cast<Document*>(
-        web_view_helper_.LocalMainFrame()->GetDocument());
-  }
-
-  FindInPage* GetFindInPage() {
-    return web_view_helper_.LocalMainFrame()->GetFindInPage();
-  }
-
-  WebLocalFrameImpl* LocalMainFrame() {
-    return web_view_helper_.LocalMainFrame();
-  }
-
-  void UpdateAllLifecyclePhasesForTest() {
-    GetDocument().View()->UpdateAllLifecyclePhases(
-        DocumentLifecycle::LifecycleUpdateReason::kTest);
-  }
-
-  void SetInnerHTML(const char* content) {
-    GetDocument().documentElement()->SetInnerHTMLFromString(
-        String::FromUTF8(content));
-    UpdateAllLifecyclePhasesForTest();
-  }
-
-  void ResizeAndFocus() {
-    web_view_helper_.Resize(WebSize(640, 480));
-    web_view_helper_.GetWebView()->MainFrameWidget()->SetFocus(true);
-    test::RunPendingTasks();
-  }
-
- private:
-  frame_test_helpers::WebViewHelper web_view_helper_;
-};
-
-INSTANTIATE_TEST_SUITE_P(All, FindInvisibleTest, ::testing::Bool());
-
-TEST_P(FindInvisibleTest, FindingInvisibleTextHasCorrectCount) {
-  ResizeAndFocus();
-  SetInnerHTML(
-      "<div invisible>"
-      " foo1"
-      " <div>foo2</div>"
-      " foo3"
-      "</div>"
-      "<div>"
-      " bar"
-      " <span invisible>foo4</span>"
-      "</div>");
-  auto* find_in_page = GetFindInPage();
-
-  InvisibleFindInPageClient client;
-  client.SetFrame(LocalMainFrame());
-  auto find_options = mojom::blink::FindOptions::New();
-  find_options->run_synchronously_for_testing = true;
-  find_options->find_next = false;
-  find_options->forward = true;
-
-  int current_id = 0;
-  find_in_page->Find(current_id++, "foo", find_options->Clone());
-  EXPECT_FALSE(client.FindResultsAreReady());
-  test::RunPendingTasks();
-  EXPECT_TRUE(client.FindResultsAreReady());
-  EXPECT_EQ(4, client.Count());
-  EXPECT_EQ(1, client.ActiveIndex());
-}
-
-TEST_P(FindInvisibleTest, FindingInvisibleTextHasCorrectActiveMatch) {
-  ResizeAndFocus();
-  SetInnerHTML(
-      "<div id='div'>1foo<div invisible>22foo</div>333foo</div>"
-      "<div invisible><input id='input' value='4444foo'></div>55555foo");
-  auto* find_in_page = GetFindInPage();
-
-  InvisibleFindInPageClient client;
-  client.SetFrame(LocalMainFrame());
-  auto find_options = mojom::blink::FindOptions::New();
-  find_options->run_synchronously_for_testing = true;
-  find_options->find_next = false;
-  find_options->forward = true;
-
-  int current_id = 0;
-  find_in_page->Find(current_id++, "foo", find_options->Clone());
-  test::RunPendingTasks();
-  find_in_page->StopFinding(
-      mojom::blink::StopFindAction::kStopFindActionKeepSelection);
-  EXPECT_TRUE(client.FindResultsAreReady());
-  EXPECT_EQ(5, client.Count());
-
-  // Finding next focuses on "1foo".
-  WebRange range = LocalMainFrame()->SelectionRange();
-  ASSERT_FALSE(range.IsNull());
-  EXPECT_EQ(1, client.ActiveIndex());
-  EXPECT_EQ(1, range.StartOffset());
-  EXPECT_EQ(4, range.EndOffset());
-
-  find_options->find_next = true;
-  find_in_page->Find(current_id++, "foo", find_options->Clone());
-  test::RunPendingTasks();
-  find_in_page->StopFinding(
-      mojom::blink::StopFindAction::kStopFindActionKeepSelection);
-  // Finding next focuses on "22foo".
-  range = LocalMainFrame()->SelectionRange();
-  ASSERT_FALSE(range.IsNull());
-  EXPECT_EQ(2, client.ActiveIndex());
-  EXPECT_EQ(2, range.StartOffset());
-  EXPECT_EQ(5, range.EndOffset());
-
-  find_options->find_next = true;
-  find_in_page->Find(current_id++, "foo", find_options->Clone());
-  test::RunPendingTasks();
-  find_in_page->StopFinding(
-      mojom::blink::StopFindAction::kStopFindActionKeepSelection);
-  // Finding next focuses on "333foo".
-  range = LocalMainFrame()->SelectionRange();
-  ASSERT_FALSE(range.IsNull());
-  EXPECT_EQ(3, client.ActiveIndex());
-  EXPECT_EQ(3, range.StartOffset());
-  EXPECT_EQ(6, range.EndOffset());
-
-  find_options->find_next = true;
-  find_in_page->Find(current_id++, "foo", find_options->Clone());
-  test::RunPendingTasks();
-  find_in_page->StopFinding(
-      mojom::blink::StopFindAction::kStopFindActionKeepSelection);
-  // Finding next focuses on "4444foo".
-  range = LocalMainFrame()->SelectionRange();
-  ASSERT_FALSE(range.IsNull());
-  EXPECT_EQ(4, client.ActiveIndex());
-  EXPECT_EQ(4, range.StartOffset());
-  EXPECT_EQ(7, range.EndOffset());
-
-  find_options->find_next = true;
-  find_in_page->Find(current_id++, "foo", find_options->Clone());
-  test::RunPendingTasks();
-  find_in_page->StopFinding(
-      mojom::blink::StopFindAction::kStopFindActionKeepSelection);
-  // Finding next focuses on "55555foo".
-  range = LocalMainFrame()->SelectionRange();
-  ASSERT_FALSE(range.IsNull());
-  EXPECT_EQ(5, client.ActiveIndex());
-  EXPECT_EQ(5, range.StartOffset());
-  EXPECT_EQ(8, range.EndOffset());
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc
index 3e02a22..cdd25b9 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc
@@ -11,6 +11,7 @@
 #include "third_party/blink/renderer/core/layout/ng/inline/layout_ng_text.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_dirty_lines.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_builder.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
 #include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h"
@@ -276,7 +277,7 @@
 
 template <typename OffsetMappingBuilder>
 bool NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::AppendTextReusing(
-    const String& original_string,
+    const NGInlineNodeData& original_data,
     LayoutText* layout_text) {
   DCHECK(layout_text);
   const NGInlineItems& items = layout_text->InlineItems();
@@ -284,6 +285,8 @@
   if (!old_item0.Length())
     return false;
 
+  const String& original_string = original_data.text_content;
+
   // Don't reuse existing items if they might be affected by whitespace
   // collapsing.
   // TODO(layout-dev): This could likely be optimized further.
@@ -341,12 +344,14 @@
       return false;
   }
 
-  if (bidi_context_.size() && new_style.PreserveNewline()) {
-    // We exit and then re-enter all bidi contexts around a forced breaks. We
+  if (new_style.PreserveNewline()) {
+    // We exit and then re-enter all bidi contexts around a forced break. So, We
     // must go through the full pipeline to ensure that we exit and enter the
-    // contexts in the same in the re-layout.
-    if (layout_text->GetText().Contains(kNewlineCharacter))
-      return false;
+    // correct bidi contexts the re-layout.
+    if (bidi_context_.size() || original_data.IsBidiEnabled()) {
+      if (layout_text->GetText().Contains(kNewlineCharacter))
+        return false;
+    }
   }
 
   if (UNLIKELY(old_item0.StartOffset() > 0 &&
@@ -407,7 +412,7 @@
 
 template <>
 bool NGInlineItemsBuilderTemplate<NGOffsetMappingBuilder>::AppendTextReusing(
-    const String&,
+    const NGInlineNodeData&,
     LayoutText*) {
   NOTREACHED();
   return false;
@@ -416,14 +421,14 @@
 template <typename OffsetMappingBuilder>
 void NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::AppendText(
     LayoutText* layout_text,
-    const String* previous_text) {
+    const NGInlineNodeData* previous_data) {
   // Mark dirty lines. Clear if marked, only the first dirty line is relevant.
   if (dirty_lines_ && dirty_lines_->HandleText(layout_text))
     dirty_lines_ = nullptr;
 
   // If the LayoutText element hasn't changed, reuse the existing items.
-  if (previous_text && layout_text->HasValidInlineItems()) {
-    if (AppendTextReusing(*previous_text, layout_text)) {
+  if (previous_data && layout_text->HasValidInlineItems()) {
+    if (AppendTextReusing(*previous_data, layout_text)) {
       return;
     }
   }
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h
index d0cb0015..b7c9530 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h
@@ -21,6 +21,7 @@
 class LayoutInline;
 class LayoutObject;
 class LayoutText;
+struct NGInlineNodeData;
 class NGDirtyLines;
 
 // NGInlineItemsBuilder builds a string and a list of NGInlineItem from inlines.
@@ -70,15 +71,17 @@
 
   // Append a string from |LayoutText|.
   //
-  // If |previous_text| is given, reuse existing items if they exist and are
+  // If |previous_data| is given, reuse existing items if they exist and are
   // reusable. Otherwise appends new items.
-  void AppendText(LayoutText* layout_text, const String* previous_text);
+  void AppendText(LayoutText* layout_text,
+                  const NGInlineNodeData* previous_data);
 
   // Append existing items from an unchanged LayoutObject.
   // Returns whether the existing items could be reused.
   // NOTE: The state of the builder remains unchanged if the append operation
   // fails (i.e. if it returns false).
-  bool AppendTextReusing(const String& previous_text, LayoutText* layout_text);
+  bool AppendTextReusing(const NGInlineNodeData& previous_data,
+                         LayoutText* layout_text);
 
   // Append a string.
   // When appending, spaces are collapsed according to CSS Text, The white space
@@ -221,8 +224,10 @@
 };
 
 template <>
-CORE_EXPORT bool NGInlineItemsBuilderTemplate<
-    NGOffsetMappingBuilder>::AppendTextReusing(const String&, LayoutText*);
+CORE_EXPORT bool
+NGInlineItemsBuilderTemplate<NGOffsetMappingBuilder>::AppendTextReusing(
+    const NGInlineNodeData&,
+    LayoutText*);
 
 template <>
 CORE_EXPORT void
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder_test.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder_test.cc
index 868bbe90..56fa24da 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder_test.cc
@@ -7,13 +7,12 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/core/layout/layout_inline.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/layout_ng_text.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_layout_test.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
 
 namespace blink {
 
-namespace {
-
 // The spec turned into a discussion that may change. Put this logic on hold
 // until CSSWG resolves the issue.
 // https://github.com/w3c/csswg-drafts/issues/337
@@ -79,7 +78,7 @@
     builder.ExitBlock();
     text_ = builder.ToString();
     ValidateItems();
-    CheckReuseItemsProducesSameResult(inputs);
+    CheckReuseItemsProducesSameResult(inputs, builder.HasBidiControls());
     for (LayoutObject* anonymous_object : anonymous_objects)
       anonymous_object->Destroy();
     return text_;
@@ -111,7 +110,12 @@
     EXPECT_EQ(current_offset, text_.length());
   }
 
-  void CheckReuseItemsProducesSameResult(Vector<Input> inputs) {
+  void CheckReuseItemsProducesSameResult(Vector<Input> inputs,
+                                         bool has_bidi_controls) {
+    NGInlineNodeData fake_data;
+    fake_data.text_content = text_;
+    fake_data.is_bidi_enabled_ = has_bidi_controls;
+
     Vector<NGInlineItem> reuse_items;
     NGInlineItemsBuilder reuse_builder(&reuse_items);
     for (Input& input : inputs) {
@@ -131,8 +135,9 @@
       }
 
       // Try to re-use previous items, or Append if it was not re-usable.
-      bool reused = input.layout_text->HasValidInlineItems() &&
-                    reuse_builder.AppendTextReusing(text_, input.layout_text);
+      bool reused =
+          input.layout_text->HasValidInlineItems() &&
+          reuse_builder.AppendTextReusing(fake_data, input.layout_text);
       if (!reused) {
         reuse_builder.AppendText(input.text, input.layout_text);
       }
@@ -493,6 +498,4 @@
             builder.ToString());
 }
 
-}  // namespace
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
index 68a5dc0..9e36e92 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
@@ -75,7 +75,7 @@
  public:
   ItemsBuilderForMarkLineBoxesDirty(NGDirtyLines* dirty_lines)
       : dirty_lines_(dirty_lines) {}
-  void AppendText(LayoutText* layout_text, const String*) {
+  void AppendText(LayoutText* layout_text, const NGInlineItemsData*) {
     if (dirty_lines_ && dirty_lines_->HandleText(layout_text))
       dirty_lines_ = nullptr;
   }
@@ -145,7 +145,7 @@
 template <typename ItemsBuilder>
 void CollectInlinesInternal(LayoutBlockFlow* block,
                             ItemsBuilder* builder,
-                            const String* previous_text) {
+                            const NGInlineNodeData* previous_data) {
   builder->EnterBlock(block->Style());
   LayoutObject* node = GetLayoutObjectForFirstChildNode(block);
 
@@ -153,7 +153,7 @@
       LayoutNGListItem::FindSymbolMarkerLayoutText(block);
   while (node) {
     if (LayoutText* layout_text = ToLayoutTextOrNull(node)) {
-      builder->AppendText(layout_text, previous_text);
+      builder->AppendText(layout_text, previous_data);
 
       if (symbol == layout_text)
         builder->SetIsSymbolMarker(true);
@@ -476,11 +476,9 @@
   LayoutBlockFlow* block = GetLayoutBlockFlow();
   block->WillCollectInlines();
 
-  String* previous_text =
-      previous_data ? &previous_data->text_content : nullptr;
   data->items.ReserveCapacity(EstimateInlineItemsCount(*block));
   NGInlineItemsBuilder builder(&data->items, dirty_lines);
-  CollectInlinesInternal(block, &builder, previous_text);
+  CollectInlinesInternal(block, &builder, previous_data);
   data->text_content = builder.ToString();
 
   // Set |is_bidi_enabled_| for all UTF-16 strings for now, because at this
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h
index 661a642..833d639 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h
@@ -31,6 +31,7 @@
     base_direction_ = static_cast<unsigned>(direction);
   }
 
+  friend class NGInlineItemsBuilderTest;
   friend class NGInlineNode;
   friend class NGInlineNodeLegacy;
   friend class NGInlineNodeForTest;
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 9379a42..10fe619 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
@@ -1420,6 +1420,18 @@
   EXPECT_EQ(String(u"foo\u2066\u2069\n\u2066\u2069bar\nbaz"), GetText());
 }
 
+TEST_F(NGInlineNodeTest, PreservedNewlineWithRemovedBidiAndRelayout) {
+  SetupHtml("container",
+            "<pre id=container>foo<span dir=rtl>\nbar</span></pre>");
+  EXPECT_EQ(String(u"foo\u2067\u2069\n\u2067bar\u2069"), GetText());
+
+  GetDocument().QuerySelector("span")->removeAttribute(html_names::kDirAttr);
+  UpdateAllLifecyclePhasesForTest();
+
+  // The bidi control characters around '\n' should not preserve
+  EXPECT_EQ("foo\nbar", GetText());
+}
+
 #if SEGMENT_BREAK_TRANSFORMATION_FOR_EAST_ASIAN_WIDTH
 // https://crbug.com/879088
 TEST_F(NGInlineNodeTest, RemoveSegmentBreakFromJapaneseInRelayout) {
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc
index 4021c72..a6e42b72 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc
@@ -16,7 +16,6 @@
 
 void NGLineBoxFragmentBuilder::Reset() {
   children_.Shrink(0);
-  offsets_.Shrink(0);
   child_break_tokens_.Shrink(0);
   inline_break_tokens_.Shrink(0);
   oof_positioned_candidates_.Shrink(0);
@@ -78,7 +77,6 @@
 }
 
 void NGLineBoxFragmentBuilder::AddChildren(ChildList& children) {
-  offsets_.ReserveCapacity(children.size());
   children_.ReserveCapacity(children.size());
 
   for (auto& child : children) {
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
index a3c7404..9682f1d 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
@@ -285,8 +285,8 @@
 void NGLineBreaker::PrepareNextLine(NGLineInfo* line_info) {
   // NGLineInfo is not supposed to be re-used becase it's not much gain and to
   // avoid rare code path.
-  NGInlineItemResults* item_results = line_info->MutableResults();
-  DCHECK(item_results->IsEmpty());
+  const NGInlineItemResults& item_results = line_info->Results();
+  DCHECK(item_results.IsEmpty());
 
   if (item_index_) {
     // We're past the first line
@@ -338,9 +338,9 @@
             out_floats_for_min_max, line_info);
   RemoveTrailingCollapsibleSpace(line_info);
 
-  NGInlineItemResults* item_results = line_info->MutableResults();
+  const NGInlineItemResults& item_results = line_info->Results();
 #if DCHECK_IS_ON()
-  for (const auto& result : *item_results)
+  for (const auto& result : item_results)
     result.CheckConsistency(mode_ == NGLineBreakerMode::kMinContent);
 #endif
 
@@ -352,7 +352,7 @@
   //
   // TODO(kojii): There are cases where we need to PlaceItems() without creating
   // line boxes. These cases need to be reviewed.
-  bool should_create_line_box = ShouldCreateLineBox(*item_results) ||
+  bool should_create_line_box = ShouldCreateLineBox(item_results) ||
                                 (has_list_marker_ && line_info->IsLastLine()) ||
                                 mode_ != NGLineBreakerMode::kContent;
 
@@ -389,7 +389,7 @@
       return;
     }
 
-    NGInlineItemResults* item_results = line_info->MutableResults();
+    const NGInlineItemResults& item_results = line_info->Results();
 
     // Handle trailable items first. These items may not be break before.
     // They (or part of them) may also overhang the available width.
@@ -400,8 +400,8 @@
       else
         HandleEmptyText(item, line_info);
 #if DCHECK_IS_ON()
-      if (!item_results->IsEmpty())
-        item_results->back().CheckConsistency(true);
+      if (!item_results.IsEmpty())
+        item_results.back().CheckConsistency(true);
 #endif
       continue;
     }
@@ -425,12 +425,12 @@
     // Items after this point are not trailable. Break at the earliest break
     // opportunity if we're trailing.
     if (state_ == LineBreakState::kTrailing &&
-        CanBreakAfterLast(*item_results)) {
+        CanBreakAfterLast(item_results)) {
       // If the sticky images quirk is enabled, and this is an image that
       // follows text that doesn't end with something breakable, we cannot break
       // between the two items.
       if (sticky_images_quirk_ &&
-          IsStickyImage(item, *item_results, trailing_whitespace_, Text())) {
+          IsStickyImage(item, item_results, trailing_whitespace_, Text())) {
         HandleAtomicInline(item, percentage_resolution_block_size_for_min_max,
                            line_info);
         continue;
@@ -489,7 +489,7 @@
 
   // If we're trailing, only trailing spaces can be included in this line.
   if (state_ == LineBreakState::kTrailing) {
-    if (CanBreakAfterLast(*line_info->MutableResults()))
+    if (CanBreakAfterLast(line_info->Results()))
       return HandleTrailingSpaces(item, shape_result, line_info);
     // When a run of preserved spaces are across items, |CanBreakAfterLast| is
     // false for between spaces. But we still need to handle them as trailing
@@ -1285,7 +1285,7 @@
 
   // Check if we already have a pending float. That's because a float cannot be
   // higher than any block or floated box generated before.
-  if (HasUnpositionedFloats(*line_info->MutableResults()) || float_after_line) {
+  if (HasUnpositionedFloats(line_info->Results()) || float_after_line) {
     item_result->has_unpositioned_floats = true;
   } else {
     NGPositionedFloat positioned_float = PositionFloat(
@@ -1358,8 +1358,8 @@
   MoveToNextOf(item);
 
   DCHECK(!item_result->can_break_after);
-  NGInlineItemResults* item_results = line_info->MutableResults();
-  if (UNLIKELY(!was_auto_wrap && auto_wrap_ && item_results->size() >= 2)) {
+  const NGInlineItemResults& item_results = line_info->Results();
+  if (UNLIKELY(!was_auto_wrap && auto_wrap_ && item_results.size() >= 2)) {
     ComputeCanBreakAfter(std::prev(item_result), auto_wrap_, break_iterator_);
   }
 }
@@ -1385,8 +1385,8 @@
   // If the line can break after the previous item, prohibit it and allow break
   // after this close tag instead.
   if (was_auto_wrap) {
-    NGInlineItemResults* item_results = line_info->MutableResults();
-    if (item_results->size() >= 2) {
+    const NGInlineItemResults& item_results = line_info->Results();
+    if (item_results.size() >= 2) {
       NGInlineItemResult* last = std::prev(item_result);
       item_result->can_break_after = last->can_break_after;
       last->can_break_after = false;
@@ -1589,7 +1589,7 @@
 const ComputedStyle& NGLineBreaker::ComputeCurrentStyle(
     unsigned item_result_index,
     NGLineInfo* line_info) const {
-  NGInlineItemResults& item_results = *line_info->MutableResults();
+  const NGInlineItemResults& item_results = line_info->Results();
 
   // Use the current item if it can compute the current style.
   const NGInlineItem* item = item_results[item_result_index].item;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
index f0a1d460..1a361e12 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
@@ -36,6 +36,16 @@
 namespace blink {
 namespace {
 
+inline scoped_refptr<const NGLayoutResult> LayoutInflow(
+    const NGConstraintSpace& space,
+    const NGBreakToken* break_token,
+    NGLayoutInputNode* node,
+    NGInlineChildLayoutContext* context) {
+  auto* inline_node = DynamicTo<NGInlineNode>(node);
+  return inline_node ? inline_node->Layout(space, break_token, context)
+                     : To<NGBlockNode>(node)->Layout(space, break_token);
+}
+
 // Return true if a child is to be cleared past adjoining floats. These are
 // floats that would otherwise (if 'clear' were 'none') be pulled down by the
 // BFC block offset of the child. If the child is to clear floats, though, we
@@ -1240,8 +1250,8 @@
   NGConstraintSpace child_space = CreateConstraintSpaceForChild(
       child, child_data, child_available_size_, /* is_new_fc */ false,
       forced_bfc_block_offset, has_clearance_past_adjoining_floats);
-  scoped_refptr<const NGLayoutResult> layout_result =
-      child.Layout(child_space, child_break_token, inline_child_layout_context);
+  scoped_refptr<const NGLayoutResult> layout_result = LayoutInflow(
+      child_space, child_break_token, &child, inline_child_layout_context);
 
   // To save space of the stack when we recurse into |NGBlockNode::Layout|
   // above, the rest of this function is continued within |FinishInflow|.
@@ -1422,7 +1432,7 @@
     NGConstraintSpace new_child_space = CreateConstraintSpaceForChild(
         child, *child_data, child_available_size_, /* is_new_fc */ false,
         child_bfc_block_offset);
-    layout_result = child.Layout(new_child_space, child_break_token,
+    layout_result = LayoutInflow(new_child_space, child_break_token, &child,
                                  inline_child_layout_context);
 
     if (layout_result->Status() == NGLayoutResult::kBfcBlockOffsetResolved) {
@@ -1436,7 +1446,7 @@
       new_child_space = CreateConstraintSpaceForChild(
           child, *child_data, child_available_size_, /* is_new_fc */ false,
           child_bfc_block_offset);
-      layout_result = child.Layout(new_child_space, child_break_token,
+      layout_result = LayoutInflow(new_child_space, child_break_token, &child,
                                    inline_child_layout_context);
     }
 
@@ -2188,23 +2198,23 @@
 // Add a baseline from a child box fragment.
 // @return false if the specified child is not a box or is OOF.
 bool NGBlockLayoutAlgorithm::AddBaseline(const NGBaselineRequest& request,
-                                         const NGPhysicalFragment* child,
+                                         const NGPhysicalFragment& child,
                                          LayoutUnit child_offset) {
-  if (child->IsLineBox()) {
-    const auto* line_box = To<NGPhysicalLineBoxFragment>(child);
+  if (child.IsLineBox()) {
+    const auto& line_box = To<NGPhysicalLineBoxFragment>(child);
 
     // Skip over a line-box which is empty. These don't have any baselines which
     // should be added.
-    if (line_box->IsEmptyLineBox())
+    if (line_box.IsEmptyLineBox())
       return false;
 
     LayoutUnit offset =
-        ComputeLineBoxBaselineOffset(request, *line_box, child_offset);
+        ComputeLineBoxBaselineOffset(request, line_box, child_offset);
     container_builder_.AddBaseline(request, offset);
     return true;
   }
 
-  if (child->IsFloatingOrOutOfFlowPositioned())
+  if (child.IsFloatingOrOutOfFlowPositioned())
     return false;
 
   if (const auto* box = DynamicTo<NGPhysicalBoxFragment>(child)) {
@@ -2226,21 +2236,20 @@
 
   for (const auto& request : requests) {
     switch (request.AlgorithmType()) {
-      case NGBaselineAlgorithmType::kAtomicInline:
+      case NGBaselineAlgorithmType::kAtomicInline: {
         if (Node().UseLogicalBottomMarginEdgeForInlineBlockBaseline())
           break;
 
-        for (unsigned i = container_builder_.Children().size(); i--;) {
-          if (AddBaseline(request, container_builder_.Children()[i].get(),
-                          container_builder_.Offsets()[i].block_offset))
+        const auto& children = container_builder_.Children();
+        for (auto it = children.rbegin(); it != children.rend(); ++it) {
+          if (AddBaseline(request, *it->fragment, it->offset.block_offset))
             break;
         }
         break;
-
+      }
       case NGBaselineAlgorithmType::kFirstLine:
-        for (unsigned i = 0; i < container_builder_.Children().size(); i++) {
-          if (AddBaseline(request, container_builder_.Children()[i].get(),
-                          container_builder_.Offsets()[i].block_offset))
+        for (const auto& child : container_builder_.Children()) {
+          if (AddBaseline(request, *child.fragment, child.offset.block_offset))
             break;
         }
         break;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h
index f3fb75b..70db5f9 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h
@@ -233,7 +233,7 @@
 
   void PropagateBaselinesFromChildren();
   bool AddBaseline(const NGBaselineRequest&,
-                   const NGPhysicalFragment*,
+                   const NGPhysicalFragment&,
                    LayoutUnit child_offset);
 
   // Compute the baseline offset of a line box from the content box.
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
index 09a320d..cf3108c 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
@@ -31,9 +31,10 @@
 void GatherInlineContainerFragmentsFromLinebox(
     NGBoxFragmentBuilder::InlineContainingBlockMap* inline_containing_block_map,
     HashMap<const LayoutObject*, LineBoxPair>* containing_linebox_map,
-    const NGPhysicalLineBoxFragment* linebox,
+    const NGPhysicalLineBoxFragment& linebox,
     const PhysicalOffset linebox_offset) {
-  for (auto& descendant : NGInlineFragmentTraversal::DescendantsOf(*linebox)) {
+  for (const auto& descendant :
+       NGInlineFragmentTraversal::DescendantsOf(linebox)) {
     if (!descendant.fragment->IsBox())
       continue;
     const LayoutObject* key = descendant.fragment->GetLayoutObject();
@@ -58,19 +59,19 @@
     PhysicalRect fragment_rect(
         linebox_offset + descendant.offset_to_container_box,
         descendant.fragment->Size());
-    if (containing_lineboxes.first == linebox) {
+    if (containing_lineboxes.first == &linebox) {
       containing_block_geometry->start_fragment_union_rect.Unite(fragment_rect);
     } else if (!containing_lineboxes.first) {
-      containing_lineboxes.first = linebox;
+      containing_lineboxes.first = &linebox;
       containing_block_geometry =
           NGBoxFragmentBuilder::InlineContainingBlockGeometry{fragment_rect,
                                                               PhysicalRect()};
     }
     // Skip fragments within an empty line boxes for the end fragment.
-    if (containing_lineboxes.second == linebox) {
+    if (containing_lineboxes.second == &linebox) {
       containing_block_geometry->end_fragment_union_rect.Unite(fragment_rect);
-    } else if (!containing_lineboxes.second || !linebox->IsEmptyLineBox()) {
-      containing_lineboxes.second = linebox;
+    } else if (!containing_lineboxes.second || !linebox.IsEmptyLineBox()) {
+      containing_lineboxes.second = &linebox;
       containing_block_geometry->end_fragment_union_rect = fragment_rect;
     }
   }
@@ -82,7 +83,6 @@
   child_break_tokens_.resize(0);
   inline_break_tokens_.resize(0);
   children_.resize(0);
-  offsets_.resize(0);
 }
 
 NGBoxFragmentBuilder& NGBoxFragmentBuilder::AddBreakBeforeChild(
@@ -121,13 +121,12 @@
     DCHECK_GT(children_.size(), 0UL);
     for (int i = children_.size() - 1; i >= 0; i--) {
       DCHECK_NE(i, 0);
-      if (!children_[i]->IsLineBox())
+      if (!children_[i].fragment->IsLineBox())
         continue;
       if (!--lines_to_remove) {
         // This is the first line that is going to the next fragment. Remove it,
         // and everything after it.
         children_.resize(i);
-        offsets_.resize(i);
         break;
       }
     }
@@ -287,20 +286,20 @@
 #endif
 
   HashMap<const LayoutObject*, LineBoxPair> containing_linebox_map;
-  for (wtf_size_t i = 0; i < children_.size(); i++) {
-    if (children_[i]->IsLineBox()) {
-      const auto* linebox = To<NGPhysicalLineBoxFragment>(children_[i].get());
-      const PhysicalOffset linebox_offset = offsets_[i].ConvertToPhysical(
+  for (const auto& child : children_) {
+    if (child.fragment->IsLineBox()) {
+      const auto& linebox = To<NGPhysicalLineBoxFragment>(*child.fragment);
+      const PhysicalOffset linebox_offset = child.offset.ConvertToPhysical(
           GetWritingMode(), Direction(),
-          ToPhysicalSize(Size(), GetWritingMode()), linebox->Size());
+          ToPhysicalSize(Size(), GetWritingMode()), linebox.Size());
       GatherInlineContainerFragmentsFromLinebox(inline_containing_block_map,
                                                 &containing_linebox_map,
                                                 linebox, linebox_offset);
-    } else if (children_[i]->IsBox()) {
-      const auto* box_fragment = To<NGPhysicalBoxFragment>(children_[i].get());
+    } else if (child.fragment->IsBox()) {
+      const auto& box_fragment = To<NGPhysicalBoxFragment>(*child.fragment);
       bool is_anonymous_container =
-          box_fragment->GetLayoutObject() &&
-          box_fragment->GetLayoutObject()->IsAnonymousBlock();
+          box_fragment.GetLayoutObject() &&
+          box_fragment.GetLayoutObject()->IsAnonymousBlock();
       if (!is_anonymous_container)
         continue;
       // If child is an anonymous container, this might be a special case of
@@ -309,15 +308,15 @@
       // lineboxes inside anonymous box.
       // For more on this special case, see "css container is an inline, with
       // inline splitting" comment in NGOutOfFlowLayoutPart::LayoutDescendant.
-      const PhysicalOffset box_offset = offsets_[i].ConvertToPhysical(
+      const PhysicalOffset box_offset = child.offset.ConvertToPhysical(
           GetWritingMode(), Direction(),
-          ToPhysicalSize(Size(), GetWritingMode()), box_fragment->Size());
+          ToPhysicalSize(Size(), GetWritingMode()), box_fragment.Size());
 
       // Traverse lineboxes of anonymous box.
-      for (const auto& child : box_fragment->Children()) {
-        if (child->IsLineBox()) {
-          const auto* linebox = To<NGPhysicalLineBoxFragment>(child.get());
-          const PhysicalOffset linebox_offset = child.Offset() + box_offset;
+      for (const auto& box_child : box_fragment.Children()) {
+        if (box_child->IsLineBox()) {
+          const auto& linebox = To<NGPhysicalLineBoxFragment>(*box_child);
+          const PhysicalOffset linebox_offset = box_child.Offset() + box_offset;
           GatherInlineContainerFragmentsFromLinebox(inline_containing_block_map,
                                                     &containing_linebox_map,
                                                     linebox, linebox_offset);
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
index 7c7bb04..d491b25 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
@@ -172,9 +172,6 @@
   scoped_refptr<const NGLayoutResult> Abort(
       NGLayoutResult::NGLayoutResultStatus);
 
-  // A vector of child offsets. Initially set by AddChild().
-  const OffsetVector& Offsets() const { return offsets_; }
-
   NGPhysicalFragment::NGBoxType BoxType() const;
   NGBoxFragmentBuilder& SetBoxType(NGPhysicalFragment::NGBoxType box_type) {
     box_type_ = box_type;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
index 679586e..c25cde4 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
@@ -142,34 +142,32 @@
   // In order to know where list-markers are within the children list (for the
   // |NGSimplifiedLayoutAlgorithm|) we always place them as the first child.
   if (child->IsListMarker()) {
-    children_.push_front(std::move(child));
-    offsets_.push_front(child_offset);
+    children_.push_front(ChildWithOffset(child_offset, std::move(child)));
     return;
   }
 
-  children_.emplace_back(std::move(child));
-  offsets_.push_back(child_offset);
+  children_.emplace_back(child_offset, std::move(child));
 }
 
 LogicalOffset NGContainerFragmentBuilder::GetChildOffset(
-    const LayoutObject* child) const {
-  for (wtf_size_t i = 0; i < children_.size(); ++i) {
-    if (children_[i]->GetLayoutObject() == child)
-      return offsets_[i];
+    const LayoutObject* object) const {
+  for (const auto& child : children_) {
+    if (child.fragment->GetLayoutObject() == object)
+      return child.offset;
 
     // TODO(layout-dev): ikilpatrick thinks we may need to traverse
     // further than the initial line-box children for a nested inline
     // container. We could not come up with a testcase, it would be
     // something with split inlines, and nested oof/fixed descendants maybe.
-    if (children_[i]->IsLineBox()) {
+    if (child.fragment->IsLineBox()) {
       const auto& line_box_fragment =
-          To<NGPhysicalLineBoxFragment>(*children_[i]);
+          To<NGPhysicalLineBoxFragment>(*child.fragment);
       for (const auto& line_box_child : line_box_fragment.Children()) {
-        if (line_box_child->GetLayoutObject() == child) {
-          return offsets_[i] + line_box_child.Offset().ConvertToLogical(
-                                   GetWritingMode(), Direction(),
-                                   line_box_fragment.Size(),
-                                   line_box_child->Size());
+        if (line_box_child->GetLayoutObject() == object) {
+          return child.offset + line_box_child.Offset().ConvertToLogical(
+                                    GetWritingMode(), Direction(),
+                                    line_box_fragment.Size(),
+                                    line_box_child->Size());
         }
       }
     }
@@ -275,7 +273,7 @@
                        InlineSize().ToFloat(), BlockSize().ToFloat(),
                        children_.size());
   for (auto& child : children_) {
-    builder.Append(child->DumpFragmentTree(
+    builder.Append(child.fragment->DumpFragmentTree(
         NGPhysicalFragment::DumpAll & ~NGPhysicalFragment::DumpHeaderText));
   }
   return builder.ToString();
diff --git a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
index fd945bc..5d9ccf7 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
@@ -31,8 +31,18 @@
   STACK_ALLOCATED();
 
  public:
-  typedef Vector<scoped_refptr<const NGPhysicalFragment>, 4> ChildrenVector;
-  typedef Vector<LogicalOffset, 4> OffsetVector;
+  struct ChildWithOffset {
+    DISALLOW_NEW();
+    ChildWithOffset(LogicalOffset offset,
+                    scoped_refptr<const NGPhysicalFragment> fragment)
+        : offset(offset), fragment(std::move(fragment)) {}
+
+    // We store logical offsets (instead of the final physical), as we can't
+    // convert into the physical coordinate space until we know our final size.
+    LogicalOffset offset;
+    scoped_refptr<const NGPhysicalFragment> fragment;
+  };
+  typedef Vector<ChildWithOffset, 4> ChildrenVector;
 
   LayoutUnit BfcLineOffset() const { return bfc_line_offset_; }
   NGContainerFragmentBuilder& SetBfcLineOffset(LayoutUnit bfc_line_offset) {
@@ -40,8 +50,8 @@
     return *this;
   }
 
-  // The NGBfcOffset is where this fragment was positioned within the BFC. If
-  // it is not set, this fragment may be placed anywhere within the BFC.
+  // The BFC block-offset is where this fragment was positioned within the BFC.
+  // If it is not set, this fragment may be placed anywhere within the BFC.
   const base::Optional<LayoutUnit>& BfcBlockOffset() const {
     return bfc_block_offset_;
   }
@@ -241,11 +251,6 @@
 
   ChildrenVector children_;
 
-  // Logical offsets for the children. Stored as logical offsets as we can't
-  // convert to physical offsets until layout of all children has been
-  // determined.
-  OffsetVector offsets_;
-
   // Only used by the NGBoxFragmentBuilder subclass, but defined here to avoid
   // a virtual function call.
   NGBreakTokenVector child_break_tokens_;
@@ -267,4 +272,7 @@
 
 }  // namespace blink
 
+WTF_ALLOW_MOVE_INIT_AND_COMPARE_WITH_MEM_FUNCTIONS(
+    blink::NGContainerFragmentBuilder::ChildWithOffset)
+
 #endif  // NGContainerFragmentBuilder
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc b/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc
index b2a11c8..53338b8 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc
@@ -62,15 +62,6 @@
 
 }  // namespace
 
-scoped_refptr<const NGLayoutResult> NGLayoutInputNode::Layout(
-    const NGConstraintSpace& space,
-    const NGBreakToken* break_token,
-    NGInlineChildLayoutContext* context) {
-  auto* inline_node = DynamicTo<NGInlineNode>(this);
-  return inline_node ? inline_node->Layout(space, break_token, context)
-                     : To<NGBlockNode>(*this).Layout(space, break_token);
-}
-
 MinMaxSize NGLayoutInputNode::ComputeMinMaxSize(
     WritingMode writing_mode,
     const MinMaxSizeInput& input,
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h b/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
index ce3c4c9..85b3b29 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
@@ -22,10 +22,7 @@
 class Document;
 class LayoutObject;
 class LayoutBox;
-class NGBreakToken;
 class NGConstraintSpace;
-class NGInlineChildLayoutContext;
-class NGLayoutResult;
 class NGPaintFragment;
 struct MinMaxSize;
 struct LogicalSize;
@@ -159,11 +156,6 @@
     return false;
   }
 
-  // Performs layout on this input node, will return the layout result.
-  scoped_refptr<const NGLayoutResult> Layout(const NGConstraintSpace&,
-                                             const NGBreakToken*,
-                                             NGInlineChildLayoutContext*);
-
   // Returns border box.
   MinMaxSize ComputeMinMaxSize(WritingMode,
                                const MinMaxSizeInput&,
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc
index f017736a..6ce7d4c 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc
@@ -45,17 +45,16 @@
       builder->may_have_descendant_above_block_start_;
   depends_on_percentage_block_size_ = DependsOnPercentageBlockSize(*builder);
 
-  DCHECK_EQ(builder->children_.size(), builder->offsets_.size());
   // Because flexible arrays need to be the last member in a class, we need to
   // have the buffer passed as a constructor argument and have the actual
   // storage be part of the subclass.
   wtf_size_t i = 0;
   for (auto& child : builder->children_) {
-    buffer[i].fragment = child.get();
+    buffer[i].fragment = child.fragment.get();
     buffer[i].fragment->AddRef();
-    buffer[i].offset = builder->offsets_[i].ConvertToPhysical(
+    buffer[i].offset = child.offset.ConvertToPhysical(
         block_or_line_writing_mode, builder->Direction(), Size(),
-        child->Size());
+        child.fragment->Size());
     ++i;
   }
 }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc
index 17a7ecf..ce5ce374 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc
@@ -455,6 +455,22 @@
   return TextDirection::kLtr;
 }
 
+bool NGPhysicalFragment::ShouldPaintCursorCaret() const {
+  // TODO(xiaochengh): Merge cursor caret painting functions from LayoutBlock to
+  // FrameSelection.
+  if (const auto* block = DynamicTo<LayoutBlock>(GetLayoutObject()))
+    return block->ShouldPaintCursorCaret();
+  return false;
+}
+
+bool NGPhysicalFragment::ShouldPaintDragCaret() const {
+  // TODO(xiaochengh): Merge drag caret painting functions from LayoutBlock to
+  // DragCaret.
+  if (const auto* block = DynamicTo<LayoutBlock>(GetLayoutObject()))
+    return block->ShouldPaintDragCaret();
+  return false;
+}
+
 String NGPhysicalFragment::ToString() const {
   StringBuilder output;
   output.AppendFormat("Type: '%d' Size: '%s'", Type(),
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h
index 6bbf0cf..f47c0e3 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h
@@ -232,6 +232,14 @@
   // be confused with the CSS 'direction' property.
   TextDirection ResolvedDirection() const;
 
+  // Utility functions for caret painting. Note that carets are painted as part
+  // of the containing block's foreground.
+  bool ShouldPaintCursorCaret() const;
+  bool ShouldPaintDragCaret() const;
+  bool ShouldPaintCarets() const {
+    return ShouldPaintCursorCaret() || ShouldPaintDragCaret();
+  }
+
   String ToString() const;
 
   void CheckCanUpdateInkOverflow() const;
diff --git a/third_party/blink/renderer/core/layout/scrollbars_test.cc b/third_party/blink/renderer/core/layout/scrollbars_test.cc
index 36e4aa9..412d5c7 100644
--- a/third_party/blink/renderer/core/layout/scrollbars_test.cc
+++ b/third_party/blink/renderer/core/layout/scrollbars_test.cc
@@ -2270,50 +2270,50 @@
                                 IntPoint(100, 100), ScrollOffset(0, -100)));
   WebView().MainFrameWidget()->HandleInputEvent(GenerateWheelGestureEvent(
       WebInputEvent::kGestureScrollEnd, IntPoint(100, 100)));
-  EXPECT_FALSE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kVerticalScrollbarThumbScrollingWithMouse));
+  EXPECT_FALSE(GetDocument().IsUseCounted(
+      WebFeature::kVerticalScrollbarThumbScrollingWithMouse));
 
   // Hovering over the vertical scrollbar won't trigger the UseCounter.
   HandleMouseMoveEvent(195, 5);
-  EXPECT_FALSE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kVerticalScrollbarThumbScrollingWithMouse));
+  EXPECT_FALSE(GetDocument().IsUseCounted(
+      WebFeature::kVerticalScrollbarThumbScrollingWithMouse));
 
   // Hovering over the horizontal scrollbar won't trigger the UseCounter.
   HandleMouseMoveEvent(5, 195);
-  EXPECT_FALSE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kHorizontalScrollbarThumbScrollingWithMouse));
+  EXPECT_FALSE(GetDocument().IsUseCounted(
+      WebFeature::kHorizontalScrollbarThumbScrollingWithMouse));
 
   // Clicking on the vertical scrollbar won't trigger the UseCounter.
   HandleMousePressEvent(195, 175);
   EXPECT_EQ(vertical_scrollbar->PressedPart(),
             ScrollbarPart::kForwardTrackPart);
   HandleMouseReleaseEvent(195, 175);
-  EXPECT_FALSE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kVerticalScrollbarThumbScrollingWithMouse));
+  EXPECT_FALSE(GetDocument().IsUseCounted(
+      WebFeature::kVerticalScrollbarThumbScrollingWithMouse));
 
   // Clicking on the horizontal scrollbar won't trigger the UseCounter.
   HandleMousePressEvent(175, 195);
   EXPECT_EQ(horizontal_scrollbar->PressedPart(),
             ScrollbarPart::kForwardTrackPart);
   HandleMouseReleaseEvent(175, 195);
-  EXPECT_FALSE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kHorizontalScrollbarThumbScrollingWithMouse));
+  EXPECT_FALSE(GetDocument().IsUseCounted(
+      WebFeature::kHorizontalScrollbarThumbScrollingWithMouse));
 
   // Clicking outside the scrollbar and then releasing over the thumb of the
   // vertical scrollbar won't trigger the UseCounter.
   HandleMousePressEvent(50, 50);
   HandleMouseMoveEvent(195, 5);
   HandleMouseReleaseEvent(195, 5);
-  EXPECT_FALSE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kVerticalScrollbarThumbScrollingWithMouse));
+  EXPECT_FALSE(GetDocument().IsUseCounted(
+      WebFeature::kVerticalScrollbarThumbScrollingWithMouse));
 
   // Clicking outside the scrollbar and then releasing over the thumb of the
   // horizontal scrollbar won't trigger the UseCounter.
   HandleMousePressEvent(50, 50);
   HandleMouseMoveEvent(5, 195);
   HandleMouseReleaseEvent(5, 195);
-  EXPECT_FALSE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kHorizontalScrollbarThumbScrollingWithMouse));
+  EXPECT_FALSE(GetDocument().IsUseCounted(
+      WebFeature::kHorizontalScrollbarThumbScrollingWithMouse));
 }
 
 TEST_F(ScrollbarsTest, UseCounterPositiveWhenThumbIsScrolledWithMouse) {
@@ -2345,15 +2345,15 @@
   HandleMousePressEvent(195, 5);
   EXPECT_EQ(vertical_scrollbar->PressedPart(), ScrollbarPart::kThumbPart);
   HandleMouseReleaseEvent(195, 5);
-  EXPECT_TRUE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kVerticalScrollbarThumbScrollingWithMouse));
+  EXPECT_TRUE(GetDocument().IsUseCounted(
+      WebFeature::kVerticalScrollbarThumbScrollingWithMouse));
 
   // Clicking the thumb on the horizontal scrollbar will trigger the UseCounter.
   HandleMousePressEvent(5, 195);
   EXPECT_EQ(horizontal_scrollbar->PressedPart(), ScrollbarPart::kThumbPart);
   HandleMouseReleaseEvent(5, 195);
-  EXPECT_TRUE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kHorizontalScrollbarThumbScrollingWithMouse));
+  EXPECT_TRUE(GetDocument().IsUseCounted(
+      WebFeature::kHorizontalScrollbarThumbScrollingWithMouse));
 }
 
 TEST_F(ScrollbarsTest, UseCounterNegativeWhenThumbIsNotScrolledWithTouch) {
@@ -2388,8 +2388,8 @@
             ScrollbarPart::kForwardTrackPart);
   WebView().MainFrameWidget()->HandleInputEvent(GenerateTouchGestureEvent(
       WebInputEvent::kGestureTapCancel, IntPoint(195, 175)));
-  EXPECT_FALSE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kVerticalScrollbarThumbScrollingWithTouch));
+  EXPECT_FALSE(GetDocument().IsUseCounted(
+      WebFeature::kVerticalScrollbarThumbScrollingWithTouch));
 
   // Tapping on the horizontal scrollbar won't trigger the UseCounter.
   WebView().MainFrameWidget()->HandleInputEvent(GenerateTouchGestureEvent(
@@ -2398,8 +2398,8 @@
             ScrollbarPart::kForwardTrackPart);
   WebView().MainFrameWidget()->HandleInputEvent(GenerateTouchGestureEvent(
       WebInputEvent::kGestureTapCancel, IntPoint(175, 195)));
-  EXPECT_FALSE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kHorizontalScrollbarThumbScrollingWithTouch));
+  EXPECT_FALSE(GetDocument().IsUseCounted(
+      WebFeature::kHorizontalScrollbarThumbScrollingWithTouch));
 
   // Tapping outside the scrollbar and then releasing over the thumb of the
   // vertical scrollbar won't trigger the UseCounter.
@@ -2407,8 +2407,8 @@
       WebInputEvent::kGestureTapDown, IntPoint(50, 50)));
   WebView().MainFrameWidget()->HandleInputEvent(GenerateTouchGestureEvent(
       WebInputEvent::kGestureTapCancel, IntPoint(195, 5)));
-  EXPECT_FALSE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kVerticalScrollbarThumbScrollingWithTouch));
+  EXPECT_FALSE(GetDocument().IsUseCounted(
+      WebFeature::kVerticalScrollbarThumbScrollingWithTouch));
 
   // Tapping outside the scrollbar and then releasing over the thumb of the
   // horizontal scrollbar won't trigger the UseCounter.
@@ -2416,8 +2416,8 @@
       WebInputEvent::kGestureTapDown, IntPoint(50, 50)));
   WebView().MainFrameWidget()->HandleInputEvent(GenerateTouchGestureEvent(
       WebInputEvent::kGestureTapCancel, IntPoint(5, 195)));
-  EXPECT_FALSE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kHorizontalScrollbarThumbScrollingWithTouch));
+  EXPECT_FALSE(GetDocument().IsUseCounted(
+      WebFeature::kHorizontalScrollbarThumbScrollingWithTouch));
 }
 
 TEST_F(ScrollbarsTest, UseCounterPositiveWhenThumbIsScrolledWithTouch) {
@@ -2451,8 +2451,8 @@
   EXPECT_EQ(vertical_scrollbar->PressedPart(), ScrollbarPart::kThumbPart);
   WebView().MainFrameWidget()->HandleInputEvent(GenerateTouchGestureEvent(
       WebInputEvent::kGestureTapCancel, IntPoint(195, 5)));
-  EXPECT_TRUE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kVerticalScrollbarThumbScrollingWithTouch));
+  EXPECT_TRUE(GetDocument().IsUseCounted(
+      WebFeature::kVerticalScrollbarThumbScrollingWithTouch));
 
   // Clicking the thumb on the horizontal scrollbar will trigger the UseCounter.
   WebView().MainFrameWidget()->HandleInputEvent(GenerateTouchGestureEvent(
@@ -2460,8 +2460,8 @@
   EXPECT_EQ(horizontal_scrollbar->PressedPart(), ScrollbarPart::kThumbPart);
   WebView().MainFrameWidget()->HandleInputEvent(GenerateTouchGestureEvent(
       WebInputEvent::kGestureTapCancel, IntPoint(5, 195)));
-  EXPECT_TRUE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kHorizontalScrollbarThumbScrollingWithTouch));
+  EXPECT_TRUE(GetDocument().IsUseCounted(
+      WebFeature::kHorizontalScrollbarThumbScrollingWithTouch));
 }
 
 // For infinite scrolling page (load more content when scroll to bottom), user
diff --git a/third_party/blink/renderer/core/layout/shapes/shape_outside_info.cc b/third_party/blink/renderer/core/layout/shapes/shape_outside_info.cc
index 24db389..ce121a4 100644
--- a/third_party/blink/renderer/core/layout/shapes/shape_outside_info.cc
+++ b/third_party/blink/renderer/core/layout/shapes/shape_outside_info.cc
@@ -50,7 +50,7 @@
 
 void ShapeOutsideInfo::SetReferenceBoxLogicalSize(
     LayoutSize new_reference_box_logical_size) {
-  const Document& document = layout_box_.GetDocument();
+  Document& document = layout_box_.GetDocument();
   bool is_horizontal_writing_mode =
       layout_box_.ContainingBlock()->StyleRef().IsHorizontalWritingMode();
 
diff --git a/third_party/blink/renderer/core/layout/text_autosizer.cc b/third_party/blink/renderer/core/layout/text_autosizer.cc
index 87b231a..0030297f 100644
--- a/third_party/blink/renderer/core/layout/text_autosizer.cc
+++ b/third_party/blink/renderer/core/layout/text_autosizer.cc
@@ -498,7 +498,7 @@
   }
 
   if (page_info_.has_autosized_)
-    UseCounter::Count(*document_, WebFeature::kTextAutosizing);
+    document_->CountUse(WebFeature::kTextAutosizing);
 
   return multiplier;
 }
@@ -1155,7 +1155,7 @@
       view->Size().IsEmpty() || !IsCrossSite(*frame, frame->Tree().Top()))
     return;
 
-  UseCounter::Count(*document_, WebFeature::kTextAutosizedCrossSiteIframe);
+  document_->CountUse(WebFeature::kTextAutosizedCrossSiteIframe);
 }
 
 void TextAutosizer::ApplyMultiplier(LayoutObject* layout_object,
diff --git a/third_party/blink/renderer/core/layout/text_autosizer_test.cc b/third_party/blink/renderer/core/layout/text_autosizer_test.cc
index 5368206..aa7e849 100644
--- a/third_party/blink/renderer/core/layout/text_autosizer_test.cc
+++ b/third_party/blink/renderer/core/layout/text_autosizer_test.cc
@@ -1111,8 +1111,8 @@
   auto* child_frame = To<WebLocalFrameImpl>(MainFrame().FirstChild());
   auto* child_doc = child_frame->GetFrame()->GetDocument();
 
-  EXPECT_TRUE(UseCounter::IsCounted(*child_doc,
-                                    WebFeature::kTextAutosizedCrossSiteIframe));
+  EXPECT_TRUE(
+      child_doc->IsUseCounted(WebFeature::kTextAutosizedCrossSiteIframe));
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc
index 61c0739..2d51c91 100644
--- a/third_party/blink/renderer/core/loader/document_loader.cc
+++ b/third_party/blink/renderer/core/loader/document_loader.cc
@@ -571,7 +571,7 @@
   ResourceError resource_error = error.value();
   if (network_utils::IsCertificateTransparencyRequiredError(
           resource_error.ErrorCode())) {
-    GetUseCounter().Count(
+    GetUseCounterHelper().Count(
         WebFeature::kCertificateTransparencyRequiredErrorOnResourceLoad,
         GetFrame());
   }
@@ -789,7 +789,7 @@
   // Pre-commit state, count usage the use counter associated with "this"
   // (provisional document loader) instead of frame_'s document loader.
   if (response_.DidServiceWorkerNavigationPreload())
-    UseCounter::Count(this, WebFeature::kServiceWorkerNavigationPreload);
+    CountUse(WebFeature::kServiceWorkerNavigationPreload);
 
   if (response_.CurrentRequestUrl().ProtocolIs("ftp") &&
       response_.MimeType() == "text/vnd.chromium.ftp-dir") {
@@ -1191,7 +1191,7 @@
   if (!frame_->IsMainFrame() && response_.GetCTPolicyCompliance() ==
                                     ResourceResponse::kCTPolicyDoesNotComply) {
     // Exclude main-frame navigations; those are tracked elsewhere.
-    GetUseCounter().Count(
+    GetUseCounterHelper().Count(
         WebFeature::kCertificateTransparencyNonCompliantResourceInSubframe,
         GetFrame());
   }
@@ -1409,15 +1409,14 @@
                              PreloadHelper::kOnlyLoadNonMedia);
 
   frame_->GetPage()->DidCommitLoad(frame_);
-  GetUseCounter().DidCommitLoad(frame_);
+  GetUseCounterHelper().DidCommitLoad(frame_);
 
   // Report legacy TLS versions after Page::DidCommitLoad, because the latter
   // clears the console.
   if (response_.IsLegacyTLSVersion()) {
-    UseCounter::Count(this,
-                      frame_->Tree().Parent()
-                          ? WebFeature::kLegacyTLSVersionInSubframeMainResource
-                          : WebFeature::kLegacyTLSVersionInMainFrameResource);
+    CountUse(frame_->Tree().Parent()
+                 ? WebFeature::kLegacyTLSVersionInSubframeMainResource
+                 : WebFeature::kLegacyTLSVersionInMainFrameResource);
     GetLocalFrameClient().ReportLegacyTLSVersion(response_.CurrentRequestUrl());
     if (!frame_->Tree().Parent()) {
       ukm::builders::Net_LegacyTLSVersion(document->UkmSourceID())
@@ -1698,6 +1697,10 @@
   }
 }
 
+void DocumentLoader::CountUse(mojom::WebFeature feature) {
+  return use_counter_.Count(feature, GetFrame());
+}
+
 void DocumentLoader::ReportPreviewsIntervention() const {
   // Only send reports for main frames.
   if (!frame_->IsMainFrame())
diff --git a/third_party/blink/renderer/core/loader/document_loader.h b/third_party/blink/renderer/core/loader/document_loader.h
index efaa869..d2e03922 100644
--- a/third_party/blink/renderer/core/loader/document_loader.h
+++ b/third_party/blink/renderer/core/loader/document_loader.h
@@ -96,7 +96,10 @@
 // The DocumentLoader fetches a main resource and handles the result.
 class CORE_EXPORT DocumentLoader
     : public GarbageCollectedFinalized<DocumentLoader>,
+      public UseCounter,
       public WebNavigationBodyLoader::Client {
+  USING_GARBAGE_COLLECTED_MIXIN(DocumentLoader);
+
  public:
   DocumentLoader(LocalFrame*,
                  WebNavigationType navigation_type,
@@ -232,7 +235,7 @@
 
   void LoadFailed(const ResourceError&);
 
-  virtual void Trace(blink::Visitor*);
+  void Trace(blink::Visitor*) override;
 
   // For automation driver-initiated navigations over the devtools protocol,
   // |devtools_navigation_token_| is used to tag the navigation. This navigation
@@ -263,13 +266,16 @@
 
   bool IsListingFtpDirectory() const { return listing_ftp_directory_; }
 
-  UseCounter& GetUseCounter() { return use_counter_; }
+  UseCounterHelper& GetUseCounterHelper() { return use_counter_; }
   Dactyloscoper& GetDactyloscoper() { return dactyloscoper_; }
 
   int ErrorCode() const { return error_code_; }
 
   PrefetchedSignedExchangeManager* GetPrefetchedSignedExchangeManager() const;
 
+  // UseCounter
+  void CountUse(mojom::WebFeature) override;
+
  protected:
   bool had_transient_activation() const { return had_transient_activation_; }
 
@@ -473,12 +479,12 @@
   Member<SourceKeyedCachedMetadataHandler> cached_metadata_handler_;
   Member<PrefetchedSignedExchangeManager> prefetched_signed_exchange_manager_;
 
-  // This UseCounter tracks feature usage associated with the lifetime of the
-  // document load. Features recorded prior to commit will be recorded locally.
-  // Once commited, feature usage will be piped to the browser side page load
-  // metrics that aggregates usage from frames to one page load and report
-  // feature usage to UMA histograms per page load.
-  UseCounter use_counter_;
+  // This UseCounterHelper tracks feature usage associated with the lifetime of
+  // the document load. Features recorded prior to commit will be recorded
+  // locally. Once committed, feature usage will be piped to the browser side
+  // page load metrics that aggregates usage from frames to one page load and
+  // report feature usage to UMA histograms per page load.
+  UseCounterHelper use_counter_;
 
   Dactyloscoper dactyloscoper_;
 };
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context.cc b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
index b3d7a73..a833876 100644
--- a/third_party/blink/renderer/core/loader/frame_fetch_context.cc
+++ b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
@@ -769,7 +769,7 @@
   if (GetResourceFetcherProperties().IsDetached())
     return;
   if (DocumentLoader* loader = MasterDocumentLoader())
-    loader->GetUseCounter().Count(feature, GetFrame());
+    loader->GetUseCounterHelper().Count(feature, GetFrame());
 }
 
 void FrameFetchContext::CountDeprecation(WebFeature feature) const {
diff --git a/third_party/blink/renderer/core/loader/history_item.cc b/third_party/blink/renderer/core/loader/history_item.cc
index 2897841..974a37c6 100644
--- a/third_party/blink/renderer/core/loader/history_item.cc
+++ b/third_party/blink/renderer/core/loader/history_item.cc
@@ -152,8 +152,9 @@
 ResourceRequest HistoryItem::GenerateResourceRequest(
     mojom::FetchCacheMode cache_mode) {
   ResourceRequest request(url_string_);
-  request.SetReferrerString(referrer_.referrer);
-  request.SetReferrerPolicy(referrer_.referrer_policy);
+  // TODO(domfarolino): Stop storing ResourceRequest's generated referrer as a
+  // header and instead use a separate member. See https://crbug.com/850813.
+  request.SetHttpReferrer(referrer_);
   request.SetCacheMode(cache_mode);
   if (form_data_) {
     request.SetHttpMethod(http_names::kPOST);
diff --git a/third_party/blink/renderer/core/loader/modulescript/module_script_loader.cc b/third_party/blink/renderer/core/loader/modulescript/module_script_loader.cc
index 67e5e969..e79e350 100644
--- a/third_party/blink/renderer/core/loader/modulescript/module_script_loader.cc
+++ b/third_party/blink/renderer/core/loader/modulescript/module_script_loader.cc
@@ -159,8 +159,11 @@
   fetch_params.SetContentSecurityPolicyNonce(options_.Nonce());
 
   // [SMSR] "... its referrer policy to options's referrer policy." [spec text]
-  fetch_params.MutableResourceRequest().SetReferrerPolicy(
-      module_request.Options().GetReferrerPolicy());
+  // Note: For now this is done below with SetHttpReferrer()
+  network::mojom::ReferrerPolicy referrer_policy =
+      module_request.Options().GetReferrerPolicy();
+  if (referrer_policy == network::mojom::ReferrerPolicy::kDefault)
+    referrer_policy = fetch_client_settings_object.GetReferrerPolicy();
 
   // Step 5. "... mode is "cors", ..."
   // [SMSR] "... and its credentials mode to options's credentials mode."
@@ -170,8 +173,17 @@
       options_.CredentialsMode());
 
   // Step 5. "... referrer is referrer, ..." [spec text]
-  fetch_params.MutableResourceRequest().SetReferrerString(
-      module_request.ReferrerString());
+  // Note: For now this is done below with SetHttpReferrer()
+  String referrer_string = module_request.ReferrerString();
+  if (referrer_string == Referrer::ClientReferrerString())
+    referrer_string = fetch_client_settings_object.GetOutgoingReferrer();
+
+  // TODO(domfarolino): Stop storing ResourceRequest's referrer as a
+  // blink::Referrer (https://crbug.com/850813).
+  fetch_params.MutableResourceRequest().SetHttpReferrer(
+      SecurityPolicy::GenerateReferrer(referrer_policy,
+                                       fetch_params.GetResourceRequest().Url(),
+                                       referrer_string));
 
   // Priority Hints and a request's "importance" are currently non-standard, but
   // we can assume the following (see https://crbug.com/821464):
diff --git a/third_party/blink/renderer/core/loader/preload_helper.cc b/third_party/blink/renderer/core/loader/preload_helper.cc
index 33f5b7a..ac460df 100644
--- a/third_party/blink/renderer/core/loader/preload_helper.cc
+++ b/third_party/blink/renderer/core/loader/preload_helper.cc
@@ -99,6 +99,25 @@
   return media_values;
 }
 
+bool MediaMatches(const String& media, MediaValues* media_values) {
+  scoped_refptr<MediaQuerySet> media_queries = MediaQuerySet::Create(media);
+  MediaQueryEvaluator evaluator(*media_values);
+  return evaluator.Eval(*media_queries);
+}
+
+KURL GetBestFitImageURL(const Document& document,
+                        const KURL& base_url,
+                        MediaValues* media_values,
+                        const KURL& href,
+                        const String& image_srcset,
+                        const String& image_sizes) {
+  float source_size = SizesAttributeParser(media_values, image_sizes).length();
+  ImageCandidate candidate = BestFitSourceForImageAttributes(
+      media_values->DevicePixelRatio(), source_size, href, image_srcset);
+  return base_url.IsNull() ? document.CompleteURL(candidate.ToString())
+                           : KURL(base_url, candidate.ToString());
+}
+
 }  // namespace
 
 void PreloadHelper::DnsPrefetchIfNeeded(
@@ -195,12 +214,6 @@
   return base::nullopt;
 }
 
-static bool MediaMatches(const String& media, MediaValues* media_values) {
-  scoped_refptr<MediaQuerySet> media_queries = MediaQuerySet::Create(media);
-  MediaQueryEvaluator evaluator(*media_values);
-  return evaluator.Eval(*media_queries);
-}
-
 // |base_url| is used in Link HTTP Header based preloads to resolve relative
 // URLs in srcset, which should be based on the resource's URL, not the
 // document's base URL. If |base_url| is a null URL, relative URLs are resolved
@@ -223,13 +236,8 @@
   if (resource_type == ResourceType::kImage && !params.image_srcset.IsEmpty()) {
     UseCounter::Count(document, WebFeature::kLinkRelPreloadImageSrcset);
     media_values = CreateMediaValues(document, viewport_description);
-    float source_size =
-        SizesAttributeParser(media_values, params.image_sizes).length();
-    ImageCandidate candidate = BestFitSourceForImageAttributes(
-        media_values->DevicePixelRatio(), source_size, params.href,
-        params.image_srcset);
-    url = base_url.IsNull() ? document.CompleteURL(candidate.ToString())
-                            : KURL(base_url, candidate.ToString());
+    url = GetBestFitImageURL(document, base_url, media_values, params.href,
+                             params.image_srcset, params.image_sizes);
   } else {
     url = params.href;
   }
@@ -486,9 +494,23 @@
     if (alternate_resource_info && params.rel.IsLinkPreload()) {
       DCHECK(
           RuntimeEnabledFeatures::SignedExchangeSubresourcePrefetchEnabled());
-      // TODO(crbug.com/935267): Support image_srcset and image_sizes.
+      KURL url = params.href;
+      base::Optional<ResourceType> resource_type =
+          PreloadHelper::GetResourceTypeFromAsAttribute(params.as);
+      if (document && resource_type == ResourceType::kImage &&
+          !params.image_srcset.IsEmpty()) {
+        // |media_values| is created based on the viewport dimensions of the
+        // current page that prefetched SXGs, not on the viewport of the SXG
+        // content.
+        // TODO(crbug/935267): Consider supporting Viewport HTTP response
+        // header. https://discourse.wicg.io/t/proposal-viewport-http-header/
+        MediaValues* media_values =
+            CreateMediaValues(*document, viewport_description);
+        url = GetBestFitImageURL(*document, base_url, media_values, params.href,
+                                 params.image_srcset, params.image_sizes);
+      }
       const auto* alternative_resource =
-          alternate_resource_info->FindMatchingEntry(params.href);
+          alternate_resource_info->FindMatchingEntry(url);
       if (alternative_resource &&
           alternative_resource->alternative_url().IsValid()) {
         params.href = alternative_resource->alternative_url();
diff --git a/third_party/blink/renderer/core/loader/private/frame_client_hints_preferences_context.cc b/third_party/blink/renderer/core/loader/private/frame_client_hints_preferences_context.cc
index 04c56350..908dca81 100644
--- a/third_party/blink/renderer/core/loader/private/frame_client_hints_preferences_context.cc
+++ b/third_party/blink/renderer/core/loader/private/frame_client_hints_preferences_context.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/core/loader/private/frame_client_hints_preferences_context.h"
 
 #include "base/stl_util.h"
+#include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/frame/use_counter.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/loader/resource_load_observer_for_frame.cc b/third_party/blink/renderer/core/loader/resource_load_observer_for_frame.cc
index 593ef5b6..97373c4e7 100644
--- a/third_party/blink/renderer/core/loader/resource_load_observer_for_frame.cc
+++ b/third_party/blink/renderer/core/loader/resource_load_observer_for_frame.cc
@@ -257,8 +257,9 @@
 }
 
 void ResourceLoadObserverForFrame::CountUsage(WebFeature feature) {
-  frame_or_imported_document_->GetMasterDocumentLoader().GetUseCounter().Count(
-      feature, &frame_or_imported_document_->GetFrame());
+  frame_or_imported_document_->GetMasterDocumentLoader()
+      .GetUseCounterHelper()
+      .Count(feature, &frame_or_imported_document_->GetFrame());
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/loader/threadable_loader.cc b/third_party/blink/renderer/core/loader/threadable_loader.cc
index 74da9aff..24596cc 100644
--- a/third_party/blink/renderer/core/loader/threadable_loader.cc
+++ b/third_party/blink/renderer/core/loader/threadable_loader.cc
@@ -344,10 +344,10 @@
   if (GetSecurityOrigin())
     request.SetHTTPOrigin(GetSecurityOrigin());
 
-  if (override_referrer_) {
-    request.SetReferrerString(referrer_after_redirect_.referrer);
-    request.SetReferrerPolicy(referrer_after_redirect_.referrer_policy);
-  }
+  // TODO(domfarolino): Stop setting the HTTPReferrer header, and instead use
+  // ResourceRequest::referrer_. See https://crbug.com/850813.
+  if (override_referrer_)
+    request.SetHttpReferrer(referrer_after_redirect_);
 }
 
 void ThreadableLoader::LoadPreflightRequest(
diff --git a/third_party/blink/renderer/core/page/pointer_lock_controller.cc b/third_party/blink/renderer/core/page/pointer_lock_controller.cc
index cbc18b3..869c348 100644
--- a/third_party/blink/renderer/core/page/pointer_lock_controller.cc
+++ b/third_party/blink/renderer/core/page/pointer_lock_controller.cc
@@ -46,8 +46,8 @@
     return;
   }
 
-  UseCounter::CountCrossOriginIframe(
-      target->GetDocument(), WebFeature::kElementRequestPointerLockIframe);
+  target->GetDocument().CountUseOnlyInCrossOriginIframe(
+      WebFeature::kElementRequestPointerLockIframe);
   if (target->IsInShadowTree()) {
     UseCounter::Count(target->GetDocument(),
                       WebFeature::kElementRequestPointerLockInShadow);
diff --git a/third_party/blink/renderer/core/page/scrolling/root_scroller_test.cc b/third_party/blink/renderer/core/page/scrolling/root_scroller_test.cc
index 363e96b..edda635 100644
--- a/third_party/blink/renderer/core/page/scrolling/root_scroller_test.cc
+++ b/third_party/blink/renderer/core/page/scrolling/root_scroller_test.cc
@@ -1990,15 +1990,15 @@
   ASSERT_NE(container,
             GetDocument().GetRootScrollerController().EffectiveRootScroller());
 
-  EXPECT_FALSE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kActivatedImplicitRootScroller));
+  EXPECT_FALSE(
+      GetDocument().IsUseCounted(WebFeature::kActivatedImplicitRootScroller));
 
   container->style()->setProperty(&GetDocument(), "height", "150%", String(),
                                   ASSERT_NO_EXCEPTION);
   Compositor().BeginFrame();
 
-  EXPECT_FALSE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kActivatedImplicitRootScroller));
+  EXPECT_FALSE(
+      GetDocument().IsUseCounted(WebFeature::kActivatedImplicitRootScroller));
 }
 
 // Tests use counter for implicit root scroller. Ensure it's counted on a
@@ -2038,8 +2038,8 @@
   ASSERT_EQ(container,
             GetDocument().GetRootScrollerController().EffectiveRootScroller());
 
-  EXPECT_TRUE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kActivatedImplicitRootScroller));
+  EXPECT_TRUE(
+      GetDocument().IsUseCounted(WebFeature::kActivatedImplicitRootScroller));
 
   container->style()->setProperty(&GetDocument(), "height", "150%", String(),
                                   ASSERT_NO_EXCEPTION);
@@ -2048,8 +2048,8 @@
   ASSERT_NE(container,
             GetDocument().GetRootScrollerController().EffectiveRootScroller());
 
-  EXPECT_TRUE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kActivatedImplicitRootScroller));
+  EXPECT_TRUE(
+      GetDocument().IsUseCounted(WebFeature::kActivatedImplicitRootScroller));
 }
 
 // Tests use counter for implicit root scroller. Ensure it's counted on a
@@ -2089,8 +2089,8 @@
   ASSERT_NE(container,
             GetDocument().GetRootScrollerController().EffectiveRootScroller());
 
-  EXPECT_FALSE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kActivatedImplicitRootScroller));
+  EXPECT_FALSE(
+      GetDocument().IsUseCounted(WebFeature::kActivatedImplicitRootScroller));
 
   container->style()->setProperty(&GetDocument(), "height", "100%", String(),
                                   ASSERT_NO_EXCEPTION);
@@ -2099,8 +2099,8 @@
   ASSERT_EQ(container,
             GetDocument().GetRootScrollerController().EffectiveRootScroller());
 
-  EXPECT_TRUE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kActivatedImplicitRootScroller));
+  EXPECT_TRUE(
+      GetDocument().IsUseCounted(WebFeature::kActivatedImplicitRootScroller));
 }
 
 // Tests that if we have multiple valid candidates for implicit promotion, we
diff --git a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
index a509a45..49564f7b1 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
@@ -292,18 +292,18 @@
   // If the caret's node's fragment's containing block is this block, and
   // the paint action is PaintPhaseForeground, then paint the caret.
   if (paint_phase == PaintPhase::kForeground &&
-      box_fragment_.ShouldPaintCarets())
+      physical_box_fragment.ShouldPaintCarets())
     PaintCarets(paint_info, paint_offset);
 }
 
 void NGBoxFragmentPainter::PaintCarets(const PaintInfo& paint_info,
                                        const PhysicalOffset& paint_offset) {
-  LocalFrame* frame = box_fragment_.GetLayoutObject()->GetFrame();
-
-  if (box_fragment_.ShouldPaintCursorCaret())
+  const NGPhysicalBoxFragment& fragment = PhysicalFragment();
+  LocalFrame* frame = fragment.GetLayoutObject()->GetFrame();
+  if (fragment.ShouldPaintCursorCaret())
     frame->Selection().PaintCaret(paint_info.context, paint_offset);
 
-  if (box_fragment_.ShouldPaintDragCaret()) {
+  if (fragment.ShouldPaintDragCaret()) {
     frame->GetPage()->GetDragCaret().PaintDragCaret(frame, paint_info.context,
                                                     paint_offset);
   }
diff --git a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
index 59b2d49..0a77c13 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
@@ -1120,22 +1120,6 @@
   return nullptr;
 }
 
-bool NGPaintFragment::ShouldPaintCursorCaret() const {
-  // TODO(xiaochengh): Merge cursor caret painting functions from LayoutBlock to
-  // FrameSelection.
-  if (!GetLayoutObject()->IsLayoutBlock())
-    return false;
-  return To<LayoutBlock>(GetLayoutObject())->ShouldPaintCursorCaret();
-}
-
-bool NGPaintFragment::ShouldPaintDragCaret() const {
-  // TODO(xiaochengh): Merge drag caret painting functions from LayoutBlock to
-  // DragCaret.
-  if (!GetLayoutObject()->IsLayoutBlock())
-    return false;
-  return To<LayoutBlock>(GetLayoutObject())->ShouldPaintDragCaret();
-}
-
 String NGPaintFragment::DebugName() const {
   StringBuilder name;
 
diff --git a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h
index 1556d8c..3ad12a0 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h
+++ b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h
@@ -213,14 +213,6 @@
   // from GetNode() when this fragment is content of a pseudo node.
   Node* NodeForHitTest() const;
 
-  // Utility functions for caret painting. Note that carets are painted as part
-  // of the containing block's foreground.
-  bool ShouldPaintCursorCaret() const;
-  bool ShouldPaintDragCaret() const;
-  bool ShouldPaintCarets() const {
-    return ShouldPaintCursorCaret() || ShouldPaintDragCaret();
-  }
-
   // Returns true when associated fragment of |layout_object| has line box.
   static bool TryMarkFirstLineBoxDirtyFor(const LayoutObject& layout_object);
   static bool TryMarkLastLineBoxDirtyFor(const LayoutObject& layout_object);
diff --git a/third_party/blink/renderer/core/paint/theme_painter.cc b/third_party/blink/renderer/core/paint/theme_painter.cc
index 217a6d6..0a907d2 100644
--- a/third_party/blink/renderer/core/paint/theme_painter.cc
+++ b/third_party/blink/renderer/core/paint/theme_painter.cc
@@ -93,14 +93,14 @@
 ThemePainter::ThemePainter() = default;
 
 #define COUNT_APPEARANCE(doc, feature) \
-  UseCounter::Count(doc, WebFeature::kCSSValueAppearance##feature##Rendered)
+  doc.CountUse(WebFeature::kCSSValueAppearance##feature##Rendered)
 
 // Returns true; Needs CSS painting and/or PaintBorderOnly().
 bool ThemePainter::Paint(const LayoutObject& o,
                          const PaintInfo& paint_info,
                          const IntRect& r) {
   const Node* node = o.GetNode();
-  const auto& doc = o.GetDocument();
+  Document& doc = o.GetDocument();
   const ComputedStyle& style = o.StyleRef();
   ControlPart part = o.StyleRef().Appearance();
 
diff --git a/third_party/blink/renderer/core/svg/graphics/svg_image.cc b/third_party/blink/renderer/core/svg/graphics/svg_image.cc
index fb103a0a..1477639e 100644
--- a/third_party/blink/renderer/core/svg/graphics/svg_image.cc
+++ b/third_party/blink/renderer/core/svg/graphics/svg_image.cc
@@ -690,8 +690,7 @@
 void SVGImage::UpdateUseCounters(const Document& document) const {
   if (SVGSVGElement* root_element = SvgRootElement(page_.Get())) {
     if (root_element->TimeContainer()->HasAnimations()) {
-      UseCounter::Count(document,
-                        WebFeature::kSVGSMILAnimationInImageRegardlessOfCache);
+      document.CountUse(WebFeature::kSVGSMILAnimationInImageRegardlessOfCache);
     }
   }
 }
diff --git a/third_party/blink/renderer/core/testing/internals.cc b/third_party/blink/renderer/core/testing/internals.cc
index 291b86b..af0c14cb 100644
--- a/third_party/blink/renderer/core/testing/internals.cc
+++ b/third_party/blink/renderer/core/testing/internals.cc
@@ -187,10 +187,10 @@
 
 namespace {
 
-class UseCounterObserverImpl final : public UseCounter::Observer {
-
+class UseCounterHelperObserverImpl final : public UseCounterHelper::Observer {
  public:
-  UseCounterObserverImpl(ScriptPromiseResolver* resolver, WebFeature feature)
+  UseCounterHelperObserverImpl(ScriptPromiseResolver* resolver,
+                               WebFeature feature)
       : resolver_(resolver), feature_(feature) {}
 
   bool OnCountFeature(WebFeature feature) final {
@@ -201,14 +201,14 @@
   }
 
   void Trace(blink::Visitor* visitor) override {
-    UseCounter::Observer::Trace(visitor);
+    UseCounterHelper::Observer::Trace(visitor);
     visitor->Trace(resolver_);
   }
 
  private:
   Member<ScriptPromiseResolver> resolver_;
   WebFeature feature_;
-  DISALLOW_COPY_AND_ASSIGN(UseCounterObserverImpl);
+  DISALLOW_COPY_AND_ASSIGN(UseCounterHelperObserverImpl);
 };
 
 }  // namespace
@@ -3193,23 +3193,25 @@
 bool Internals::isUseCounted(Document* document, uint32_t feature) {
   if (feature >= static_cast<int32_t>(WebFeature::kNumberOfFeatures))
     return false;
-  return UseCounter::IsCounted(*document, static_cast<WebFeature>(feature));
+  return document->IsUseCounted(static_cast<WebFeature>(feature));
 }
 
 bool Internals::isCSSPropertyUseCounted(Document* document,
                                         const String& property_name) {
-  return UseCounter::IsCounted(*document, property_name);
+  return document->IsUseCounted(unresolvedCSSPropertyID(property_name),
+                                UseCounterHelper::CSSPropertyType::kDefault);
 }
 
 bool Internals::isAnimatedCSSPropertyUseCounted(Document* document,
                                                 const String& property_name) {
-  return UseCounter::IsCountedAnimatedCSS(*document, property_name);
+  return document->IsUseCounted(unresolvedCSSPropertyID(property_name),
+                                UseCounterHelper::CSSPropertyType::kAnimation);
 }
 
 void Internals::clearUseCounter(Document* document, uint32_t feature) {
   if (feature >= static_cast<int32_t>(WebFeature::kNumberOfFeatures))
     return;
-  UseCounter::ClearCountForTesting(*document, static_cast<WebFeature>(feature));
+  document->ClearUseCounterForTesting(static_cast<WebFeature>(feature));
 }
 
 Vector<String> Internals::getCSSPropertyLonghands() const {
@@ -3255,7 +3257,7 @@
   }
 
   WebFeature use_counter_feature = static_cast<WebFeature>(feature);
-  if (UseCounter::IsCounted(*document, use_counter_feature)) {
+  if (document->IsUseCounted(use_counter_feature)) {
     resolver->Resolve();
     return promise;
   }
@@ -3266,8 +3268,8 @@
     return promise;
   }
 
-  loader->GetUseCounter().AddObserver(
-      MakeGarbageCollected<UseCounterObserverImpl>(
+  loader->GetUseCounterHelper().AddObserver(
+      MakeGarbageCollected<UseCounterHelperObserverImpl>(
           resolver, static_cast<WebFeature>(use_counter_feature)));
   return promise;
 }
diff --git a/third_party/blink/renderer/core/testing/null_execution_context.h b/third_party/blink/renderer/core/testing/null_execution_context.h
index a87d362bd..9ecfd11 100644
--- a/third_party/blink/renderer/core/testing/null_execution_context.h
+++ b/third_party/blink/renderer/core/testing/null_execution_context.h
@@ -65,6 +65,8 @@
   FrameOrWorkerScheduler* GetScheduler() override;
   scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner(TaskType) override;
 
+  void CountUse(mojom::WebFeature) override {}
+
   using SecurityContext::GetSecurityOrigin;
   using SecurityContext::GetContentSecurityPolicy;
 
diff --git a/third_party/blink/renderer/core/timing/window_performance.cc b/third_party/blink/renderer/core/timing/window_performance.cc
index 8034545..7084416 100644
--- a/third_party/blink/renderer/core/timing/window_performance.cc
+++ b/third_party/blink/renderer/core/timing/window_performance.cc
@@ -184,7 +184,7 @@
   WebVector<WebServerTimingInfo> server_timing =
       PerformanceServerTiming::ParseServerTiming(*info);
   if (!server_timing.empty())
-    UseCounter::Count(document_loader, WebFeature::kPerformanceServerTiming);
+    document_loader->CountUse(WebFeature::kPerformanceServerTiming);
 
   return MakeGarbageCollected<PerformanceNavigationTiming>(
       GetFrame(), info, time_origin_, server_timing);
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 ec90d54a..53a84e3 100644
--- a/third_party/blink/renderer/core/workers/dedicated_worker_test.cc
+++ b/third_party/blink/renderer/core/workers/dedicated_worker_test.cc
@@ -223,13 +223,13 @@
 
   // API use on the DedicatedWorkerGlobalScope should be recorded in UseCounter
   // on the Document.
-  EXPECT_FALSE(UseCounter::IsCounted(GetDocument(), kFeature1));
+  EXPECT_FALSE(GetDocument().IsUseCounted(kFeature1));
   PostCrossThreadTask(
       *GetWorkerThread()->GetTaskRunner(TaskType::kInternalTest), FROM_HERE,
       CrossThreadBindOnce(&DedicatedWorkerThreadForTest::CountFeature,
                           CrossThreadUnretained(GetWorkerThread()), kFeature1));
   test::EnterRunLoop();
-  EXPECT_TRUE(UseCounter::IsCounted(GetDocument(), kFeature1));
+  EXPECT_TRUE(GetDocument().IsUseCounted(kFeature1));
 
   // API use should be reported to the Document only one time. See comments in
   // DedicatedWorkerObjectProxyForTest::CountFeature.
@@ -244,13 +244,13 @@
 
   // Deprecated API use on the DedicatedWorkerGlobalScope should be recorded in
   // UseCounter on the Document.
-  EXPECT_FALSE(UseCounter::IsCounted(GetDocument(), kFeature2));
+  EXPECT_FALSE(GetDocument().IsUseCounted(kFeature2));
   PostCrossThreadTask(
       *GetWorkerThread()->GetTaskRunner(TaskType::kInternalTest), FROM_HERE,
       CrossThreadBindOnce(&DedicatedWorkerThreadForTest::CountDeprecation,
                           CrossThreadUnretained(GetWorkerThread()), kFeature2));
   test::EnterRunLoop();
-  EXPECT_TRUE(UseCounter::IsCounted(GetDocument(), kFeature2));
+  EXPECT_TRUE(GetDocument().IsUseCounted(kFeature2));
 
   // API use should be reported to the Document only one time. See comments in
   // DedicatedWorkerObjectProxyForTest::CountDeprecation.
diff --git a/third_party/blink/renderer/core/workers/main_thread_worklet_test.cc b/third_party/blink/renderer/core/workers/main_thread_worklet_test.cc
index 04961c6..1aca5cd 100644
--- a/third_party/blink/renderer/core/workers/main_thread_worklet_test.cc
+++ b/third_party/blink/renderer/core/workers/main_thread_worklet_test.cc
@@ -125,9 +125,9 @@
 
   // API use on WorkletGlobalScope for the main thread should be recorded in
   // UseCounter on the Document.
-  EXPECT_FALSE(UseCounter::IsCounted(GetDocument(), kFeature1));
+  EXPECT_FALSE(GetDocument().IsUseCounted(kFeature1));
   UseCounter::Count(global_scope_, kFeature1);
-  EXPECT_TRUE(UseCounter::IsCounted(GetDocument(), kFeature1));
+  EXPECT_TRUE(GetDocument().IsUseCounted(kFeature1));
 
   // API use should be reported to the Document only one time. See comments in
   // MainThreadWorkletReportingProxyForTest::ReportFeature.
@@ -138,9 +138,9 @@
 
   // Deprecated API use on WorkletGlobalScope for the main thread should be
   // recorded in UseCounter on the Document.
-  EXPECT_FALSE(UseCounter::IsCounted(GetDocument(), kFeature2));
+  EXPECT_FALSE(GetDocument().IsUseCounted(kFeature2));
   Deprecation::CountDeprecation(global_scope_, kFeature2);
-  EXPECT_TRUE(UseCounter::IsCounted(GetDocument(), kFeature2));
+  EXPECT_TRUE(GetDocument().IsUseCounted(kFeature2));
 
   // API use should be reported to the Document only one time. See comments in
   // MainThreadWorkletReportingProxyForTest::ReportDeprecation.
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 d75f930..96582d2 100644
--- a/third_party/blink/renderer/core/workers/threaded_worklet_test.cc
+++ b/third_party/blink/renderer/core/workers/threaded_worklet_test.cc
@@ -317,13 +317,13 @@
 
   // API use on the threaded WorkletGlobalScope should be recorded in UseCounter
   // on the Document.
-  EXPECT_FALSE(UseCounter::IsCounted(GetDocument(), kFeature1));
+  EXPECT_FALSE(GetDocument().IsUseCounted(kFeature1));
   PostCrossThreadTask(
       *GetWorkerThread()->GetTaskRunner(TaskType::kInternalTest), FROM_HERE,
       CrossThreadBindOnce(&ThreadedWorkletThreadForTest::CountFeature,
                           CrossThreadUnretained(GetWorkerThread()), kFeature1));
   test::EnterRunLoop();
-  EXPECT_TRUE(UseCounter::IsCounted(GetDocument(), kFeature1));
+  EXPECT_TRUE(GetDocument().IsUseCounted(kFeature1));
 
   // API use should be reported to the Document only one time. See comments in
   // ThreadedWorkletObjectProxyForTest::CountFeature.
@@ -338,13 +338,13 @@
 
   // Deprecated API use on the threaded WorkletGlobalScope should be recorded in
   // UseCounter on the Document.
-  EXPECT_FALSE(UseCounter::IsCounted(GetDocument(), kFeature2));
+  EXPECT_FALSE(GetDocument().IsUseCounted(kFeature2));
   PostCrossThreadTask(
       *GetWorkerThread()->GetTaskRunner(TaskType::kInternalTest), FROM_HERE,
       CrossThreadBindOnce(&ThreadedWorkletThreadForTest::CountDeprecation,
                           CrossThreadUnretained(GetWorkerThread()), kFeature2));
   test::EnterRunLoop();
-  EXPECT_TRUE(UseCounter::IsCounted(GetDocument(), kFeature2));
+  EXPECT_TRUE(GetDocument().IsUseCounted(kFeature2));
 
   // API use should be reported to the Document only one time. See comments in
   // ThreadedWorkletObjectProxyForTest::CountDeprecation.
diff --git a/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h b/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h
index 3f5399a..6e94c0b 100644
--- a/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h
+++ b/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h
@@ -76,6 +76,9 @@
   // SecurityContext
   void DidUpdateSecurityOrigin() final {}
 
+  // UseCounter
+  void CountUse(WebFeature feature) final { CountFeature(feature); }
+
   // Returns true when the WorkerOrWorkletGlobalScope is closing (e.g. via
   // WorkerGlobalScope#close() method). If this returns true, the worker is
   // going to be shutdown after the current task execution. Globals that
@@ -89,6 +92,7 @@
   void SetModulator(Modulator*);
 
   // Called from UseCounter to record API use in this execution context.
+  // TODO(yhirano): Unify this with CountUse.
   void CountFeature(WebFeature);
 
   // Called from UseCounter to record deprecated API use in this execution
diff --git a/third_party/blink/renderer/modules/BUILD.gn b/third_party/blink/renderer/modules/BUILD.gn
index 89db140..1196b96c 100644
--- a/third_party/blink/renderer/modules/BUILD.gn
+++ b/third_party/blink/renderer/modules/BUILD.gn
@@ -373,6 +373,7 @@
     "screen_orientation/screen_orientation_controller_impl_test.cc",
     "service_worker/service_worker_container_test.cc",
     "service_worker/service_worker_installed_scripts_manager_test.cc",
+    "service_worker/service_worker_timeout_timer_test.cc",
     "service_worker/thread_safe_script_container_test.cc",
     "service_worker/web_embedded_worker_impl_test.cc",
     "wake_lock/wake_lock_controller_test.cc",
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.cc b/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.cc
index e1d0cb0e8d..8a8f297 100644
--- a/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.cc
+++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.cc
@@ -9,7 +9,6 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/optional.h"
 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
-#include "third_party/blink/public/platform/modules/background_fetch/web_background_fetch_registration.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/core/dom/events/event.h"
 #include "third_party/blink/renderer/core/fetch/request.h"
@@ -45,26 +44,20 @@
       observer_binding_(this) {}
 
 BackgroundFetchRegistration::BackgroundFetchRegistration(
-    ServiceWorkerRegistration* registration,
-    WebBackgroundFetchRegistration web_registration)
-    : developer_id_(std::move(web_registration.developer_id)),
-      upload_total_(web_registration.upload_total),
-      uploaded_(web_registration.uploaded),
-      download_total_(web_registration.download_total),
-      downloaded_(web_registration.downloaded),
-      result_(web_registration.result),
-      failure_reason_(web_registration.failure_reason),
+    ServiceWorkerRegistration* service_worker_registration,
+    mojom::blink::BackgroundFetchRegistrationPtr registration)
+    : developer_id_(registration->registration_data->developer_id),
+      upload_total_(registration->registration_data->upload_total),
+      uploaded_(registration->registration_data->uploaded),
+      download_total_(registration->registration_data->download_total),
+      downloaded_(registration->registration_data->downloaded),
+      result_(registration->registration_data->result),
+      failure_reason_(registration->registration_data->failure_reason),
       observer_binding_(this) {
-  DCHECK(registration);
-
-  mojom::blink::BackgroundFetchRegistrationServicePtrInfo
-      registration_service_info(
-          std::move(web_registration.registration_service_handle),
-          web_registration.registration_service_version);
-  DCHECK(registration_service_info);
-
-  Initialize(registration, mojom::blink::BackgroundFetchRegistrationServicePtr(
-                               std::move(registration_service_info)));
+  DCHECK(service_worker_registration);
+  Initialize(service_worker_registration,
+             mojom::blink::BackgroundFetchRegistrationServicePtr(
+                 std::move(registration->registration_interface)));
 }
 
 BackgroundFetchRegistration::~BackgroundFetchRegistration() = default;
@@ -268,7 +261,9 @@
   to_return.ReserveInitialCapacity(settled_fetches.size());
 
   for (auto& fetch : settled_fetches) {
-    Request* request = Request::Create(script_state, *(fetch->request));
+    Request* request =
+        Request::Create(script_state, *(fetch->request),
+                        Request::ForServiceWorkerFetchEvent::kFalse);
     auto* record =
         MakeGarbageCollected<BackgroundFetchRecord>(request, script_state);
 
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.h b/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.h
index e008b79..2ecb70a 100644
--- a/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.h
+++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.h
@@ -23,7 +23,6 @@
 class ScriptState;
 class ServiceWorkerRegistration;
 class RequestOrUSVString;
-struct WebBackgroundFetchRegistration;
 
 // Represents an individual Background Fetch registration. Gives developers
 // access to its properties, options, and enables them to abort the fetch.
@@ -45,8 +44,9 @@
       mojom::BackgroundFetchResult result,
       mojom::BackgroundFetchFailureReason failure_reason);
 
-  BackgroundFetchRegistration(ServiceWorkerRegistration* registration,
-                              WebBackgroundFetchRegistration web_registration);
+  BackgroundFetchRegistration(
+      ServiceWorkerRegistration* service_worker_registration,
+      mojom::blink::BackgroundFetchRegistrationPtr registration);
 
   ~BackgroundFetchRegistration() override;
 
diff --git a/third_party/blink/renderer/modules/battery/navigator_battery.cc b/third_party/blink/renderer/modules/battery/navigator_battery.cc
index 709d8e8..da14978 100644
--- a/third_party/blink/renderer/modules/battery/navigator_battery.cc
+++ b/third_party/blink/renderer/modules/battery/navigator_battery.cc
@@ -6,6 +6,7 @@
 
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/use_counter.h"
 #include "third_party/blink/renderer/modules/battery/battery_manager.h"
 
@@ -29,8 +30,8 @@
     if (frame) {
       if (!context->IsSecureContext())
         UseCounter::Count(document, WebFeature::kBatteryStatusInsecureOrigin);
-      UseCounter::CountIfFeatureWouldBeBlockedByFeaturePolicy(
-          *frame, WebFeature::kBatteryStatusCrossOrigin,
+      frame->CountUseIfFeatureWouldBeBlockedByFeaturePolicy(
+          WebFeature::kBatteryStatusCrossOrigin,
           WebFeature::kBatteryStatusSameOriginABA);
     }
   }
diff --git a/third_party/blink/renderer/modules/cache_storage/cache.cc b/third_party/blink/renderer/modules/cache_storage/cache.cc
index 63be8d69..0913ea9 100644
--- a/third_party/blink/renderer/modules/cache_storage/cache.cc
+++ b/third_party/blink/renderer/modules/cache_storage/cache.cc
@@ -1113,8 +1113,9 @@
               HeapVector<Member<Request>> requests;
               requests.ReserveInitialCapacity(result->get_keys().size());
               for (auto& request : result->get_keys()) {
-                requests.push_back(
-                    Request::Create(resolver->GetScriptState(), *request));
+                requests.push_back(Request::Create(
+                    resolver->GetScriptState(), *request,
+                    Request::ForServiceWorkerFetchEvent::kFalse));
               }
               resolver->Resolve(requests);
             }
diff --git a/third_party/blink/renderer/modules/crypto/crypto_histograms.cc b/third_party/blink/renderer/modules/crypto/crypto_histograms.cc
index b5baa13..539f4d02 100644
--- a/third_party/blink/renderer/modules/crypto/crypto_histograms.cc
+++ b/third_party/blink/renderer/modules/crypto/crypto_histograms.cc
@@ -8,6 +8,7 @@
 #include "third_party/blink/public/platform/web_crypto_algorithm.h"
 #include "third_party/blink/public/platform/web_crypto_algorithm_params.h"
 #include "third_party/blink/public/platform/web_crypto_key_algorithm.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/frame/use_counter.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/modules/device_orientation/device_motion_controller.cc b/third_party/blink/renderer/modules/device_orientation/device_motion_controller.cc
index 90fdf66..ec9f9a0 100644
--- a/third_party/blink/renderer/modules/device_orientation/device_motion_controller.cc
+++ b/third_party/blink/renderer/modules/device_orientation/device_motion_controller.cc
@@ -43,23 +43,11 @@
   if (event_type != EventTypeName())
     return;
 
+  // TOOD(crbug.com/932078): Investigate if this ever called with no |frame|.
   LocalFrame* frame = GetDocument().GetFrame();
   if (frame) {
-    if (GetDocument().IsSecureContext()) {
-      UseCounter::Count(GetDocument(), WebFeature::kDeviceMotionSecureOrigin);
-    } else {
-      Deprecation::CountDeprecation(GetDocument(),
-                                    WebFeature::kDeviceMotionInsecureOrigin);
-      HostsUsingFeatures::CountAnyWorld(
-          GetDocument(),
-          HostsUsingFeatures::Feature::kDeviceMotionInsecureHost);
-      if (frame->GetSettings()->GetStrictPowerfulFeatureRestrictions())
-        return;
-      if (RuntimeEnabledFeatures::
-              RestrictDeviceSensorEventsToSecureContextsEnabled()) {
-        return;
-      }
-    }
+    SECURITY_CHECK(GetDocument().IsSecureContext());
+    UseCounter::Count(GetDocument(), WebFeature::kDeviceMotionSecureOrigin);
   }
 
   if (!has_event_listener_) {
diff --git a/third_party/blink/renderer/modules/device_orientation/device_motion_event.idl b/third_party/blink/renderer/modules/device_orientation/device_motion_event.idl
index c74cb7b..cb204f8 100644
--- a/third_party/blink/renderer/modules/device_orientation/device_motion_event.idl
+++ b/third_party/blink/renderer/modules/device_orientation/device_motion_event.idl
@@ -27,7 +27,7 @@
 
 [
     Constructor(DOMString type, optional DeviceMotionEventInit eventInitDict),
-    Exposed=Window, SecureContext=RestrictDeviceSensorEventsToSecureContexts
+    Exposed=Window, SecureContext
 ] interface DeviceMotionEvent : Event {
     readonly attribute DeviceMotionEventAcceleration? acceleration;
     readonly attribute DeviceMotionEventAcceleration? accelerationIncludingGravity;
diff --git a/third_party/blink/renderer/modules/device_orientation/device_motion_event_acceleration.idl b/third_party/blink/renderer/modules/device_orientation/device_motion_event_acceleration.idl
index cf3cd8c..36728c11 100644
--- a/third_party/blink/renderer/modules/device_orientation/device_motion_event_acceleration.idl
+++ b/third_party/blink/renderer/modules/device_orientation/device_motion_event_acceleration.idl
@@ -25,7 +25,7 @@
 
 // https://w3c.github.io/deviceorientation/spec-source-orientation.html#devicemotion
 
-[SecureContext=RestrictDeviceSensorEventsToSecureContexts]
+[SecureContext]
 interface DeviceMotionEventAcceleration {
     readonly attribute double? x;
     readonly attribute double? y;
diff --git a/third_party/blink/renderer/modules/device_orientation/device_motion_event_rotation_rate.idl b/third_party/blink/renderer/modules/device_orientation/device_motion_event_rotation_rate.idl
index 9f0349a..95bf6f5 100644
--- a/third_party/blink/renderer/modules/device_orientation/device_motion_event_rotation_rate.idl
+++ b/third_party/blink/renderer/modules/device_orientation/device_motion_event_rotation_rate.idl
@@ -25,7 +25,7 @@
 
 // https://w3c.github.io/deviceorientation/spec-source-orientation.html#devicemotion
 
-[SecureContext=RestrictDeviceSensorEventsToSecureContexts]
+[SecureContext]
 interface DeviceMotionEventRotationRate {
     readonly attribute double? alpha;
     readonly attribute double? beta;
diff --git a/third_party/blink/renderer/modules/device_orientation/device_orientation_absolute_controller.cc b/third_party/blink/renderer/modules/device_orientation/device_orientation_absolute_controller.cc
index b00d2e7..629895ed 100644
--- a/third_party/blink/renderer/modules/device_orientation/device_orientation_absolute_controller.cc
+++ b/third_party/blink/renderer/modules/device_orientation/device_orientation_absolute_controller.cc
@@ -39,23 +39,12 @@
   if (event_type != EventTypeName())
     return;
 
+  // TOOD(crbug.com/932078): Investigate if this ever called with no |frame|.
   LocalFrame* frame = GetDocument().GetFrame();
   if (frame) {
-    if (GetDocument().IsSecureContext()) {
-      UseCounter::Count(GetDocument(),
-                        WebFeature::kDeviceOrientationAbsoluteSecureOrigin);
-    } else {
-      Deprecation::CountDeprecation(
-          GetDocument(), WebFeature::kDeviceOrientationAbsoluteInsecureOrigin);
-      // TODO: add rappor logging of insecure origins as in
-      // DeviceOrientationController.
-      if (frame->GetSettings()->GetStrictPowerfulFeatureRestrictions())
-        return;
-      if (RuntimeEnabledFeatures::
-              RestrictDeviceSensorEventsToSecureContextsEnabled()) {
-        return;
-      }
-    }
+    SECURITY_CHECK(GetDocument().IsSecureContext());
+    UseCounter::Count(GetDocument(),
+                      WebFeature::kDeviceOrientationAbsoluteSecureOrigin);
   }
 
   if (!has_event_listener_) {
diff --git a/third_party/blink/renderer/modules/device_orientation/device_orientation_controller.cc b/third_party/blink/renderer/modules/device_orientation/device_orientation_controller.cc
index 7f7c59e..2290173 100644
--- a/third_party/blink/renderer/modules/device_orientation/device_orientation_controller.cc
+++ b/third_party/blink/renderer/modules/device_orientation/device_orientation_controller.cc
@@ -54,27 +54,16 @@
   if (event_type != EventTypeName())
     return;
 
+  // TOOD(crbug.com/932078): Investigate if this ever called with no |frame|.
   LocalFrame* frame = GetDocument().GetFrame();
   if (frame) {
-    if (GetDocument().IsSecureContext()) {
-      UseCounter::Count(GetDocument(),
-                        WebFeature::kDeviceOrientationSecureOrigin);
-    } else {
-      Deprecation::CountDeprecation(
-          GetDocument(), WebFeature::kDeviceOrientationInsecureOrigin);
-      HostsUsingFeatures::CountAnyWorld(
-          GetDocument(),
-          HostsUsingFeatures::Feature::kDeviceOrientationInsecureHost);
-      if (GetDocument()
-              .GetFrame()
-              ->GetSettings()
-              ->GetStrictPowerfulFeatureRestrictions())
-        return;
-      if (RuntimeEnabledFeatures::
-              RestrictDeviceSensorEventsToSecureContextsEnabled()) {
-        return;
-      }
-    }
+    // TODO(crbug.com/967734): MediaControlsOrientationLock calls into this
+    // from potentially non-secure contexts. Do a no-op instead of crashing.
+    if (!GetDocument().IsSecureContext())
+      return;
+
+    UseCounter::Count(GetDocument(),
+                      WebFeature::kDeviceOrientationSecureOrigin);
   }
 
   if (!has_event_listener_) {
diff --git a/third_party/blink/renderer/modules/device_orientation/device_orientation_event.idl b/third_party/blink/renderer/modules/device_orientation/device_orientation_event.idl
index 7577eba..1a94e101 100644
--- a/third_party/blink/renderer/modules/device_orientation/device_orientation_event.idl
+++ b/third_party/blink/renderer/modules/device_orientation/device_orientation_event.idl
@@ -27,7 +27,7 @@
 
 [
     Constructor(DOMString type, optional DeviceOrientationEventInit eventInitDict),
-    Exposed=Window, SecureContext=RestrictDeviceSensorEventsToSecureContexts
+    Exposed=Window, SecureContext
 ] interface DeviceOrientationEvent : Event {
     readonly attribute double? alpha;
     readonly attribute double? beta;
diff --git a/third_party/blink/renderer/modules/device_orientation/window_device_motion.idl b/third_party/blink/renderer/modules/device_orientation/window_device_motion.idl
index 15130d8..70e81929 100644
--- a/third_party/blink/renderer/modules/device_orientation/window_device_motion.idl
+++ b/third_party/blink/renderer/modules/device_orientation/window_device_motion.idl
@@ -5,5 +5,5 @@
 [
     ImplementedAs=DOMWindowDeviceMotion
 ] partial interface Window {
-    attribute EventHandler ondevicemotion;
+    [SecureContext] attribute EventHandler ondevicemotion;
 };
diff --git a/third_party/blink/renderer/modules/device_orientation/window_device_orientation.idl b/third_party/blink/renderer/modules/device_orientation/window_device_orientation.idl
index b8fc188..503181fb 100644
--- a/third_party/blink/renderer/modules/device_orientation/window_device_orientation.idl
+++ b/third_party/blink/renderer/modules/device_orientation/window_device_orientation.idl
@@ -5,6 +5,6 @@
 [
     ImplementedAs=DOMWindowDeviceOrientation
 ] partial interface Window {
-    attribute EventHandler ondeviceorientation;
-    attribute EventHandler ondeviceorientationabsolute;
+    [SecureContext] attribute EventHandler ondeviceorientation;
+    [SecureContext] attribute EventHandler ondeviceorientationabsolute;
 };
diff --git a/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc b/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc
index ab85f81..12f7156 100644
--- a/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc
+++ b/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc
@@ -158,8 +158,8 @@
   }
 
   UseCounter::Count(*document, WebFeature::kEncryptedMediaSecureOrigin);
-  UseCounter::CountCrossOriginIframe(
-      *document, WebFeature::kEncryptedMediaCrossOriginIframe);
+  document->CountUseOnlyInCrossOriginIframe(
+      WebFeature::kEncryptedMediaCrossOriginIframe);
 
   // 4. Let origin be the origin of document.
   //    (Passed with the execution context.)
diff --git a/third_party/blink/renderer/modules/geolocation/geolocation.cc b/third_party/blink/renderer/modules/geolocation/geolocation.cc
index c37d3cb1..3fb54af 100644
--- a/third_party/blink/renderer/modules/geolocation/geolocation.cc
+++ b/third_party/blink/renderer/modules/geolocation/geolocation.cc
@@ -152,8 +152,8 @@
   String insecure_origin_msg;
   if (document->IsSecureContext(insecure_origin_msg)) {
     UseCounter::Count(document, WebFeature::kGeolocationSecureOrigin);
-    UseCounter::CountCrossOriginIframe(
-        *document, WebFeature::kGeolocationSecureOriginIframe);
+    document->CountUseOnlyInCrossOriginIframe(
+        WebFeature::kGeolocationSecureOriginIframe);
   } else if (GetFrame()
                  ->GetSettings()
                  ->GetAllowGeolocationOnInsecureOrigins()) {
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_display_cutout_delegate_test.cc b/third_party/blink/renderer/modules/media_controls/media_controls_display_cutout_delegate_test.cc
index cf72f74b..b837ebb 100644
--- a/third_party/blink/renderer/modules/media_controls/media_controls_display_cutout_delegate_test.cc
+++ b/third_party/blink/renderer/modules/media_controls/media_controls_display_cutout_delegate_test.cc
@@ -192,8 +192,8 @@
   EXPECT_EQ(mojom::ViewportFit::kAuto, CurrentViewportFit());
 
   // Make sure we recorded a UseCounter metric.
-  EXPECT_TRUE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kMediaControlsDisplayCutoutGesture));
+  EXPECT_TRUE(GetDocument().IsUseCounted(
+      WebFeature::kMediaControlsDisplayCutoutGesture));
 }
 
 TEST_F(MediaControlsDisplayCutoutDelegateTest, ContractingGesture) {
@@ -209,8 +209,8 @@
   EXPECT_EQ(mojom::ViewportFit::kAuto, CurrentViewportFit());
 
   // Make sure we recorded a UseCounter metric.
-  EXPECT_TRUE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kMediaControlsDisplayCutoutGesture));
+  EXPECT_TRUE(GetDocument().IsUseCounted(
+      WebFeature::kMediaControlsDisplayCutoutGesture));
 }
 
 TEST_F(MediaControlsDisplayCutoutDelegateTest, ContractingGesture_Noop) {
@@ -235,8 +235,8 @@
   EXPECT_EQ(mojom::ViewportFit::kAuto, CurrentViewportFit());
 
   // Make sure we recorded a UseCounter metric.
-  EXPECT_TRUE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kMediaControlsDisplayCutoutGesture));
+  EXPECT_TRUE(GetDocument().IsUseCounted(
+      WebFeature::kMediaControlsDisplayCutoutGesture));
 }
 
 TEST_F(MediaControlsDisplayCutoutDelegateTest, ExpandingGesture_DoubleNoop) {
@@ -270,8 +270,8 @@
 }
 
 TEST_F(MediaControlsDisplayCutoutDelegateTest, MetricsNoop) {
-  EXPECT_FALSE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kMediaControlsDisplayCutoutGesture));
+  EXPECT_FALSE(GetDocument().IsUseCounted(
+      WebFeature::kMediaControlsDisplayCutoutGesture));
 }
 
 TEST_F(MediaControlsDisplayCutoutDelegateTest, NoFullscreen_Noop) {
diff --git a/third_party/blink/renderer/modules/mediastream/media_constraints_impl.cc b/third_party/blink/renderer/modules/mediastream/media_constraints_impl.cc
index 8a3a57d..296d7d6 100644
--- a/third_party/blink/renderer/modules/mediastream/media_constraints_impl.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_constraints_impl.cc
@@ -648,10 +648,6 @@
     CopyStringConstraint(constraints_in->resizeMode(), naked_treatment,
                          constraint_buffer.resize_mode);
   }
-  if (constraints_in->hasVolume()) {
-    CopyDoubleConstraint(constraints_in->volume(), naked_treatment,
-                         constraint_buffer.volume);
-  }
   if (constraints_in->hasSampleRate()) {
     CopyLongConstraint(constraints_in->sampleRate(), naked_treatment,
                        constraint_buffer.sample_rate);
@@ -903,8 +899,6 @@
     output->setFacingMode(ConvertString(input.facing_mode, naked_treatment));
   if (!input.resize_mode.IsEmpty())
     output->setResizeMode(ConvertString(input.resize_mode, naked_treatment));
-  if (!input.volume.IsEmpty())
-    output->setVolume(ConvertDouble(input.volume, naked_treatment));
   if (!input.sample_rate.IsEmpty())
     output->setSampleRate(ConvertLong(input.sample_rate, naked_treatment));
   if (!input.sample_size.IsEmpty())
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_track.cc b/third_party/blink/renderer/modules/mediastream/media_stream_track.cc
index 10ad386..1091df9 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_track.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_track.cc
@@ -92,8 +92,7 @@
          constraint_set->hasFrameRate() || constraint_set->hasGroupId() ||
          constraint_set->hasHeight() || constraint_set->hasLatency() ||
          constraint_set->hasSampleRate() || constraint_set->hasSampleSize() ||
-         constraint_set->hasVideoKind() || constraint_set->hasVolume() ||
-         constraint_set->hasWidth();
+         constraint_set->hasVideoKind() || constraint_set->hasWidth();
 }
 
 bool ConstraintSetHasImageAndNonImageCapture(
@@ -517,8 +516,6 @@
     settings->setChannelCount(platform_settings.channel_count);
   if (platform_settings.HasLatency())
     settings->setLatency(platform_settings.latency);
-  if (platform_settings.HasVolume())
-    settings->setVolume(platform_settings.volume);
 
   if (image_capture_)
     image_capture_->GetMediaTrackSettings(settings);
diff --git a/third_party/blink/renderer/modules/mediastream/media_track_constraint_set.idl b/third_party/blink/renderer/modules/mediastream/media_track_constraint_set.idl
index 899eee12..1416db5 100644
--- a/third_party/blink/renderer/modules/mediastream/media_track_constraint_set.idl
+++ b/third_party/blink/renderer/modules/mediastream/media_track_constraint_set.idl
@@ -17,7 +17,6 @@
     ConstrainDouble frameRate;
     ConstrainDOMString facingMode;
     ConstrainDOMString resizeMode;
-    ConstrainDouble volume;
     ConstrainLong sampleRate;
     ConstrainLong sampleSize;
     ConstrainBoolean echoCancellation;
diff --git a/third_party/blink/renderer/modules/mediastream/media_track_settings.idl b/third_party/blink/renderer/modules/mediastream/media_track_settings.idl
index 3a08dbc..420d200 100644
--- a/third_party/blink/renderer/modules/mediastream/media_track_settings.idl
+++ b/third_party/blink/renderer/modules/mediastream/media_track_settings.idl
@@ -11,7 +11,6 @@
     double frameRate;
     DOMString facingMode;
     DOMString resizeMode;
-    double volume;
     long sampleRate;
     long sampleSize;
     boolean echoCancellation;
diff --git a/third_party/blink/renderer/modules/mediastream/media_track_supported_constraints.idl b/third_party/blink/renderer/modules/mediastream/media_track_supported_constraints.idl
index cb7da5a9..eda363d 100644
--- a/third_party/blink/renderer/modules/mediastream/media_track_supported_constraints.idl
+++ b/third_party/blink/renderer/modules/mediastream/media_track_supported_constraints.idl
@@ -14,7 +14,6 @@
     boolean frameRate = true;
     boolean facingMode = true;
     boolean resizeMode = true;
-    boolean volume = true;
     boolean sampleRate = true;
     boolean sampleSize = true;
     boolean echoCancellation = true;
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_request.cc b/third_party/blink/renderer/modules/mediastream/user_media_request.cc
index a6e9eb4b..8e01c44 100644
--- a/third_party/blink/renderer/modules/mediastream/user_media_request.cc
+++ b/third_party/blink/renderer/modules/mediastream/user_media_request.cc
@@ -473,8 +473,8 @@
 
   if (document->IsSecureContext(error_message)) {
     UseCounter::Count(document, WebFeature::kGetUserMediaSecureOrigin);
-    UseCounter::CountCrossOriginIframe(
-        *document, WebFeature::kGetUserMediaSecureOriginIframe);
+    document->CountUseOnlyInCrossOriginIframe(
+        WebFeature::kGetUserMediaSecureOriginIframe);
 
     // Feature policy deprecation messages.
     if (Audio()) {
diff --git a/third_party/blink/renderer/modules/notifications/notification.cc b/third_party/blink/renderer/modules/notifications/notification.cc
index 48cd0f6..36c8d3a 100644
--- a/third_party/blink/renderer/modules/notifications/notification.cc
+++ b/third_party/blink/renderer/modules/notifications/notification.cc
@@ -99,8 +99,8 @@
   if (context->IsSecureContext()) {
     UseCounter::Count(context, WebFeature::kNotificationSecureOrigin);
     if (document) {
-      UseCounter::CountCrossOriginIframe(
-          *document, WebFeature::kNotificationAPISecureOriginIframe);
+      document->CountUseOnlyInCrossOriginIframe(
+          WebFeature::kNotificationAPISecureOriginIframe);
     }
   } else {
     Deprecation::CountDeprecation(context,
diff --git a/third_party/blink/renderer/modules/payments/abort_payment_respond_with_observer.cc b/third_party/blink/renderer/modules/payments/abort_payment_respond_with_observer.cc
index 3d86413..09864831 100644
--- a/third_party/blink/renderer/modules/payments/abort_payment_respond_with_observer.cc
+++ b/third_party/blink/renderer/modules/payments/abort_payment_respond_with_observer.cc
@@ -8,7 +8,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/modules/payments/payment_handler_utils.h"
-#include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.h"
+#include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h"
 #include "third_party/blink/renderer/modules/service_worker/wait_until_observer.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "v8/include/v8.h"
@@ -26,7 +26,7 @@
   PaymentHandlerUtils::ReportResponseError(GetExecutionContext(),
                                            "AbortPaymentEvent", error);
 
-  ServiceWorkerGlobalScopeClient::From(GetExecutionContext())
+  To<ServiceWorkerGlobalScope>(GetExecutionContext())
       ->RespondToAbortPaymentEvent(event_id_, false);
 }
 
@@ -46,13 +46,13 @@
     return;
   }
 
-  ServiceWorkerGlobalScopeClient::From(GetExecutionContext())
+  To<ServiceWorkerGlobalScope>(GetExecutionContext())
       ->RespondToAbortPaymentEvent(event_id_, response);
 }
 
 void AbortPaymentRespondWithObserver::OnNoResponse() {
   DCHECK(GetExecutionContext());
-  ServiceWorkerGlobalScopeClient::From(GetExecutionContext())
+  To<ServiceWorkerGlobalScope>(GetExecutionContext())
       ->RespondToAbortPaymentEvent(event_id_, false);
 }
 
diff --git a/third_party/blink/renderer/modules/payments/can_make_payment_respond_with_observer.cc b/third_party/blink/renderer/modules/payments/can_make_payment_respond_with_observer.cc
index 0a61048..88492f7 100644
--- a/third_party/blink/renderer/modules/payments/can_make_payment_respond_with_observer.cc
+++ b/third_party/blink/renderer/modules/payments/can_make_payment_respond_with_observer.cc
@@ -8,7 +8,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/modules/payments/payment_handler_utils.h"
-#include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.h"
+#include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h"
 #include "third_party/blink/renderer/modules/service_worker/wait_until_observer.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "v8/include/v8.h"
@@ -26,7 +26,7 @@
   PaymentHandlerUtils::ReportResponseError(GetExecutionContext(),
                                            "CanMakePaymentEvent", error);
 
-  ServiceWorkerGlobalScopeClient::From(GetExecutionContext())
+  To<ServiceWorkerGlobalScope>(GetExecutionContext())
       ->RespondToCanMakePaymentEvent(event_id_, false);
 }
 
@@ -46,13 +46,13 @@
     return;
   }
 
-  ServiceWorkerGlobalScopeClient::From(GetExecutionContext())
+  To<ServiceWorkerGlobalScope>(GetExecutionContext())
       ->RespondToCanMakePaymentEvent(event_id_, response);
 }
 
 void CanMakePaymentRespondWithObserver::OnNoResponse() {
   DCHECK(GetExecutionContext());
-  ServiceWorkerGlobalScopeClient::From(GetExecutionContext())
+  To<ServiceWorkerGlobalScope>(GetExecutionContext())
       ->RespondToCanMakePaymentEvent(event_id_, true);
 }
 
diff --git a/third_party/blink/renderer/modules/payments/payment_event_data_conversion.cc b/third_party/blink/renderer/modules/payments/payment_event_data_conversion.cc
index 877ffc5..6d65245 100644
--- a/third_party/blink/renderer/modules/payments/payment_event_data_conversion.cc
+++ b/third_party/blink/renderer/modules/payments/payment_event_data_conversion.cc
@@ -4,8 +4,6 @@
 
 #include "third_party/blink/renderer/modules/payments/payment_event_data_conversion.h"
 
-#include "third_party/blink/public/platform/modules/payments/web_payment_method_data.h"
-#include "third_party/blink/public/platform/modules/payments/web_payment_request_event_data.h"
 #include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
 #include "third_party/blink/renderer/modules/payments/can_make_payment_event_init.h"
 #include "third_party/blink/renderer/modules/payments/payment_currency_amount.h"
@@ -19,37 +17,41 @@
 namespace {
 
 PaymentCurrencyAmount* ToPaymentCurrencyAmount(
-    const WebPaymentCurrencyAmount& web_amount) {
+    payments::mojom::blink::PaymentCurrencyAmountPtr data) {
   PaymentCurrencyAmount* amount = PaymentCurrencyAmount::Create();
-  amount->setCurrency(web_amount.currency);
-  amount->setValue(web_amount.value);
+  if (!data)
+    return amount;
+  amount->setCurrency(data->currency);
+  amount->setValue(data->value);
   return amount;
 }
 
-PaymentItem* ToPaymentItem(const WebPaymentItem& web_item) {
+PaymentItem* ToPaymentItem(payments::mojom::blink::PaymentItemPtr data) {
   PaymentItem* item = PaymentItem::Create();
-  item->setLabel(web_item.label);
-  item->setAmount(ToPaymentCurrencyAmount(web_item.amount));
-  item->setPending(web_item.pending);
+  if (!data)
+    return item;
+  item->setLabel(data->label);
+  item->setAmount(ToPaymentCurrencyAmount(std::move(data->amount)));
+  item->setPending(data->pending);
   return item;
 }
 
 PaymentDetailsModifier* ToPaymentDetailsModifier(
     ScriptState* script_state,
-    const WebPaymentDetailsModifier& web_modifier) {
+    payments::mojom::blink::PaymentDetailsModifierPtr data) {
+  DCHECK(data);
   PaymentDetailsModifier* modifier = PaymentDetailsModifier::Create();
-  modifier->setSupportedMethod(web_modifier.supported_method);
-  modifier->setTotal(ToPaymentItem(web_modifier.total));
+  modifier->setSupportedMethod(data->method_data->supported_method);
+  modifier->setTotal(ToPaymentItem(std::move(data->total)));
   HeapVector<Member<PaymentItem>> additional_display_items;
-  for (const auto& web_item : web_modifier.additional_display_items) {
-    additional_display_items.push_back(ToPaymentItem(web_item));
-  }
+  for (auto& item : data->additional_display_items)
+    additional_display_items.push_back(ToPaymentItem(std::move(item)));
   modifier->setAdditionalDisplayItems(additional_display_items);
   return modifier;
 }
 
 ScriptValue StringDataToScriptValue(ScriptState* script_state,
-                                    const WebString& stringified_data) {
+                                    const String& stringified_data) {
   if (!script_state->ContextIsValid())
     return ScriptValue();
 
@@ -65,11 +67,12 @@
 
 PaymentMethodData* ToPaymentMethodData(
     ScriptState* script_state,
-    const WebPaymentMethodData& web_method_data) {
+    payments::mojom::blink::PaymentMethodDataPtr data) {
+  DCHECK(data);
   PaymentMethodData* method_data = PaymentMethodData::Create();
-  method_data->setSupportedMethod(web_method_data.supported_method);
+  method_data->setSupportedMethod(data->supported_method);
   method_data->setData(
-      StringDataToScriptValue(script_state, web_method_data.stringified_data));
+      StringDataToScriptValue(script_state, data->stringified_data));
   return method_data;
 }
 
@@ -77,57 +80,63 @@
 
 PaymentRequestEventInit* PaymentEventDataConversion::ToPaymentRequestEventInit(
     ScriptState* script_state,
-    const WebPaymentRequestEventData& web_event_data) {
+    payments::mojom::blink::PaymentRequestEventDataPtr event_data) {
   DCHECK(script_state);
+  DCHECK(event_data);
 
-  PaymentRequestEventInit* event_data = PaymentRequestEventInit::Create();
+  PaymentRequestEventInit* event_init = PaymentRequestEventInit::Create();
   if (!script_state->ContextIsValid())
-    return event_data;
+    return event_init;
 
   ScriptState::Scope scope(script_state);
 
-  event_data->setTopOrigin(web_event_data.top_origin);
-  event_data->setPaymentRequestOrigin(web_event_data.payment_request_origin);
-  event_data->setPaymentRequestId(web_event_data.payment_request_id);
+  event_init->setTopOrigin(event_data->top_origin.GetString());
+  event_init->setPaymentRequestOrigin(
+      event_data->payment_request_origin.GetString());
+  event_init->setPaymentRequestId(event_data->payment_request_id);
   HeapVector<Member<PaymentMethodData>> method_data;
-  for (const auto& md : web_event_data.method_data) {
-    method_data.push_back(ToPaymentMethodData(script_state, md));
+  for (auto& md : event_data->method_data) {
+    method_data.push_back(ToPaymentMethodData(script_state, std::move(md)));
   }
-  event_data->setMethodData(method_data);
-  event_data->setTotal(ToPaymentCurrencyAmount(web_event_data.total));
+  event_init->setMethodData(method_data);
+  event_init->setTotal(ToPaymentCurrencyAmount(std::move(event_data->total)));
   HeapVector<Member<PaymentDetailsModifier>> modifiers;
-  for (const auto& modifier : web_event_data.modifiers) {
-    modifiers.push_back(ToPaymentDetailsModifier(script_state, modifier));
+  for (auto& modifier : event_data->modifiers) {
+    modifiers.push_back(
+        ToPaymentDetailsModifier(script_state, std::move(modifier)));
   }
-  event_data->setModifiers(modifiers);
-  event_data->setInstrumentKey(web_event_data.instrument_key);
-  return event_data;
+  event_init->setModifiers(modifiers);
+  event_init->setInstrumentKey(event_data->instrument_key);
+  return event_init;
 }
 
 CanMakePaymentEventInit* PaymentEventDataConversion::ToCanMakePaymentEventInit(
     ScriptState* script_state,
-    const WebCanMakePaymentEventData& web_event_data) {
+    payments::mojom::blink::CanMakePaymentEventDataPtr event_data) {
   DCHECK(script_state);
+  DCHECK(event_data);
 
-  CanMakePaymentEventInit* event_data = CanMakePaymentEventInit::Create();
+  CanMakePaymentEventInit* event_init = CanMakePaymentEventInit::Create();
   if (!script_state->ContextIsValid())
-    return event_data;
+    return event_init;
 
   ScriptState::Scope scope(script_state);
 
-  event_data->setTopOrigin(web_event_data.top_origin);
-  event_data->setPaymentRequestOrigin(web_event_data.payment_request_origin);
+  event_init->setTopOrigin(event_data->top_origin.GetString());
+  event_init->setPaymentRequestOrigin(
+      event_data->payment_request_origin.GetString());
   HeapVector<Member<PaymentMethodData>> method_data;
-  for (const auto& md : web_event_data.method_data) {
-    method_data.push_back(ToPaymentMethodData(script_state, md));
+  for (auto& md : event_data->method_data) {
+    method_data.push_back(ToPaymentMethodData(script_state, std::move(md)));
   }
-  event_data->setMethodData(method_data);
+  event_init->setMethodData(method_data);
   HeapVector<Member<PaymentDetailsModifier>> modifiers;
-  for (const auto& modifier : web_event_data.modifiers) {
-    modifiers.push_back(ToPaymentDetailsModifier(script_state, modifier));
+  for (auto& modifier : event_data->modifiers) {
+    modifiers.push_back(
+        ToPaymentDetailsModifier(script_state, std::move(modifier)));
   }
-  event_data->setModifiers(modifiers);
-  return event_data;
+  event_init->setModifiers(modifiers);
+  return event_init;
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/payments/payment_event_data_conversion.h b/third_party/blink/renderer/modules/payments/payment_event_data_conversion.h
index e8643e7c..c6c1deb 100644
--- a/third_party/blink/renderer/modules/payments/payment_event_data_conversion.h
+++ b/third_party/blink/renderer/modules/payments/payment_event_data_conversion.h
@@ -5,6 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PAYMENTS_PAYMENT_EVENT_DATA_CONVERSION_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_PAYMENTS_PAYMENT_EVENT_DATA_CONVERSION_H_
 
+#include "third_party/blink/public/mojom/payments/payment_app.mojom-blink.h"
 #include "third_party/blink/renderer/modules/payments/can_make_payment_event_init.h"
 #include "third_party/blink/renderer/modules/payments/payment_request_event_init.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
@@ -14,8 +15,6 @@
 class CanMakePaymentEventInit;
 class PaymentRequestEventInit;
 class ScriptState;
-struct WebCanMakePaymentEventData;
-struct WebPaymentRequestEventData;
 
 class MODULES_EXPORT PaymentEventDataConversion {
   STATIC_ONLY(PaymentEventDataConversion);
@@ -23,10 +22,10 @@
  public:
   static CanMakePaymentEventInit* ToCanMakePaymentEventInit(
       ScriptState*,
-      const WebCanMakePaymentEventData&);
+      payments::mojom::blink::CanMakePaymentEventDataPtr);
   static PaymentRequestEventInit* ToPaymentRequestEventInit(
       ScriptState*,
-      const WebPaymentRequestEventData&);
+      payments::mojom::blink::PaymentRequestEventDataPtr);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/payments/payment_event_data_conversion_test.cc b/third_party/blink/renderer/modules/payments/payment_event_data_conversion_test.cc
index a1db5a3..150e10dc 100644
--- a/third_party/blink/renderer/modules/payments/payment_event_data_conversion_test.cc
+++ b/third_party/blink/renderer/modules/payments/payment_event_data_conversion_test.cc
@@ -6,7 +6,6 @@
 
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/platform/modules/payments/web_payment_request_event_data.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
@@ -15,56 +14,61 @@
 namespace blink {
 namespace {
 
-static WebPaymentCurrencyAmount CreateWebPaymentCurrencyAmountForTest() {
-  WebPaymentCurrencyAmount web_currency_amount;
-  web_currency_amount.currency = WebString::FromUTF8("USD");
-  web_currency_amount.value = WebString::FromUTF8("9.99");
-  return web_currency_amount;
+static payments::mojom::blink::PaymentCurrencyAmountPtr
+CreatePaymentCurrencyAmountForTest() {
+  auto currency_amount = payments::mojom::blink::PaymentCurrencyAmount::New();
+  currency_amount->currency = String::FromUTF8("USD");
+  currency_amount->value = String::FromUTF8("9.99");
+  return currency_amount;
 }
 
-static WebPaymentMethodData CreateWebPaymentMethodDataForTest() {
-  WebPaymentMethodData web_method_data;
-  web_method_data.supported_method = "foo";
-  web_method_data.stringified_data = "{\"merchantId\":\"12345\"}";
-  return web_method_data;
+static payments::mojom::blink::PaymentMethodDataPtr
+CreatePaymentMethodDataForTest() {
+  auto method_data = payments::mojom::blink::PaymentMethodData::New();
+  method_data->supported_method = String::FromUTF8("foo");
+  method_data->stringified_data =
+      String::FromUTF8("{\"merchantId\":\"12345\"}");
+  return method_data;
 }
 
-static WebCanMakePaymentEventData CreateWebCanMakePaymentEventDataForTest() {
-  WebCanMakePaymentEventData web_data;
-  web_data.top_origin = WebString::FromUTF8("https://example.com");
-  web_data.payment_request_origin = WebString::FromUTF8("https://example.com");
-  Vector<WebPaymentMethodData> method_data;
-  method_data.push_back(CreateWebPaymentMethodDataForTest());
-  web_data.method_data = WebVector<WebPaymentMethodData>(method_data);
-  return web_data;
+static payments::mojom::blink::CanMakePaymentEventDataPtr
+CreateCanMakePaymentEventDataForTest() {
+  auto event_data = payments::mojom::blink::CanMakePaymentEventData::New();
+  event_data->top_origin = KURL("https://example.com");
+  event_data->payment_request_origin = KURL("https://example.com");
+  Vector<payments::mojom::blink::PaymentMethodDataPtr> method_data;
+  method_data.push_back(CreatePaymentMethodDataForTest());
+  event_data->method_data = std::move(method_data);
+  return event_data;
 }
 
-static WebPaymentRequestEventData CreateWebPaymentRequestEventDataForTest() {
-  WebPaymentRequestEventData web_data;
-  web_data.top_origin = WebString::FromUTF8("https://example.com");
-  web_data.payment_request_origin = WebString::FromUTF8("https://example.com");
-  web_data.payment_request_id = WebString::FromUTF8("payment-request-id");
-  Vector<WebPaymentMethodData> method_data;
-  method_data.push_back(CreateWebPaymentMethodDataForTest());
-  web_data.method_data = WebVector<WebPaymentMethodData>(method_data);
-  web_data.total = CreateWebPaymentCurrencyAmountForTest();
-  web_data.instrument_key = WebString::FromUTF8("payment-instrument-key");
-  return web_data;
+static payments::mojom::blink::PaymentRequestEventDataPtr
+CreatePaymentRequestEventDataForTest() {
+  auto event_data = payments::mojom::blink::PaymentRequestEventData::New();
+  event_data->top_origin = KURL("https://example.com");
+  event_data->payment_request_origin = KURL("https://example.com");
+  event_data->payment_request_id = String::FromUTF8("payment-request-id");
+  Vector<payments::mojom::blink::PaymentMethodDataPtr> method_data;
+  method_data.push_back(CreatePaymentMethodDataForTest());
+  event_data->method_data = std::move(method_data);
+  event_data->total = CreatePaymentCurrencyAmountForTest();
+  event_data->instrument_key = String::FromUTF8("payment-instrument-key");
+  return event_data;
 }
 
 TEST(PaymentEventDataConversionTest, ToCanMakePaymentEventData) {
   V8TestingScope scope;
-  WebCanMakePaymentEventData web_data =
-      CreateWebCanMakePaymentEventDataForTest();
+  payments::mojom::blink::CanMakePaymentEventDataPtr event_data =
+      CreateCanMakePaymentEventDataForTest();
   CanMakePaymentEventInit* data =
       PaymentEventDataConversion::ToCanMakePaymentEventInit(
-          scope.GetScriptState(), web_data);
+          scope.GetScriptState(), std::move(event_data));
 
   ASSERT_TRUE(data->hasTopOrigin());
-  EXPECT_EQ("https://example.com", data->topOrigin());
+  EXPECT_EQ(KURL("https://example.com"), KURL(data->topOrigin()));
 
   ASSERT_TRUE(data->hasPaymentRequestOrigin());
-  EXPECT_EQ("https://example.com", data->paymentRequestOrigin());
+  EXPECT_EQ(KURL("https://example.com"), KURL(data->paymentRequestOrigin()));
 
   ASSERT_TRUE(data->hasMethodData());
   ASSERT_EQ(1UL, data->methodData().size());
@@ -83,17 +87,17 @@
 
 TEST(PaymentEventDataConversionTest, ToPaymentRequestEventData) {
   V8TestingScope scope;
-  WebPaymentRequestEventData web_data =
-      CreateWebPaymentRequestEventDataForTest();
+  payments::mojom::blink::PaymentRequestEventDataPtr event_data =
+      CreatePaymentRequestEventDataForTest();
   PaymentRequestEventInit* data =
       PaymentEventDataConversion::ToPaymentRequestEventInit(
-          scope.GetScriptState(), web_data);
+          scope.GetScriptState(), std::move(event_data));
 
   ASSERT_TRUE(data->hasTopOrigin());
-  EXPECT_EQ("https://example.com", data->topOrigin());
+  EXPECT_EQ(KURL("https://example.com"), KURL(data->topOrigin()));
 
   ASSERT_TRUE(data->hasPaymentRequestOrigin());
-  EXPECT_EQ("https://example.com", data->paymentRequestOrigin());
+  EXPECT_EQ(KURL("https://example.com"), KURL(data->paymentRequestOrigin()));
 
   ASSERT_TRUE(data->hasPaymentRequestId());
   EXPECT_EQ("payment-request-id", data->paymentRequestId());
diff --git a/third_party/blink/renderer/modules/payments/payment_request_respond_with_observer.cc b/third_party/blink/renderer/modules/payments/payment_request_respond_with_observer.cc
index 496c4b1..1806255 100644
--- a/third_party/blink/renderer/modules/payments/payment_request_respond_with_observer.cc
+++ b/third_party/blink/renderer/modules/payments/payment_request_respond_with_observer.cc
@@ -4,7 +4,6 @@
 
 #include "third_party/blink/renderer/modules/payments/payment_request_respond_with_observer.h"
 
-#include "third_party/blink/public/platform/modules/payments/web_payment_handler_response.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_payment_handler_response.h"
@@ -12,7 +11,7 @@
 #include "third_party/blink/renderer/core/inspector/console_message.h"
 #include "third_party/blink/renderer/modules/payments/payment_handler_response.h"
 #include "third_party/blink/renderer/modules/payments/payment_handler_utils.h"
-#include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.h"
+#include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h"
 #include "third_party/blink/renderer/modules/service_worker/wait_until_observer.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "v8/include/v8.h"
@@ -32,9 +31,10 @@
   PaymentHandlerUtils::ReportResponseError(GetExecutionContext(),
                                            "PaymentRequestEvent", error);
 
-  WebPaymentHandlerResponse web_data;
-  ServiceWorkerGlobalScopeClient::From(GetExecutionContext())
-      ->RespondToPaymentRequestEvent(event_id_, web_data);
+  To<ServiceWorkerGlobalScope>(GetExecutionContext())
+      ->RespondToPaymentRequestEvent(
+          event_id_,
+          payments::mojom::blink::PaymentHandlerResponse::New("", ""));
 }
 
 void PaymentRequestRespondWithObserver::OnResponseFulfilled(
@@ -66,9 +66,6 @@
     return;
   }
 
-  WebPaymentHandlerResponse web_data;
-  web_data.method_name = response->methodName();
-
   v8::Local<v8::String> details_value;
   if (!v8::JSON::Stringify(response->details().GetContext(),
                            response->details().V8Value().As<v8::Object>())
@@ -81,15 +78,18 @@
     OnResponseRejected(mojom::ServiceWorkerResponseError::kUnknown);
     return;
   }
-  web_data.stringified_details = ToCoreString(details_value);
-  ServiceWorkerGlobalScopeClient::From(GetExecutionContext())
-      ->RespondToPaymentRequestEvent(event_id_, web_data);
+  To<ServiceWorkerGlobalScope>(GetExecutionContext())
+      ->RespondToPaymentRequestEvent(
+          event_id_, payments::mojom::blink::PaymentHandlerResponse::New(
+                         response->methodName(), ToCoreString(details_value)));
 }
 
 void PaymentRequestRespondWithObserver::OnNoResponse() {
   DCHECK(GetExecutionContext());
-  ServiceWorkerGlobalScopeClient::From(GetExecutionContext())
-      ->RespondToPaymentRequestEvent(event_id_, WebPaymentHandlerResponse());
+  To<ServiceWorkerGlobalScope>(GetExecutionContext())
+      ->RespondToPaymentRequestEvent(
+          event_id_,
+          payments::mojom::blink::PaymentHandlerResponse::New("", ""));
 }
 
 PaymentRequestRespondWithObserver::PaymentRequestRespondWithObserver(
diff --git a/third_party/blink/renderer/modules/service_worker/BUILD.gn b/third_party/blink/renderer/modules/service_worker/BUILD.gn
index 394ed3c..21a49cfc 100644
--- a/third_party/blink/renderer/modules/service_worker/BUILD.gn
+++ b/third_party/blink/renderer/modules/service_worker/BUILD.gn
@@ -6,6 +6,8 @@
 
 blink_modules_sources("service_worker") {
   sources = [
+    "controller_service_worker.cc",
+    "controller_service_worker.h",
     "extendable_event.cc",
     "extendable_event.h",
     "extendable_message_event.cc",
@@ -52,6 +54,8 @@
     "service_worker_script_cached_metadata_handler.h",
     "service_worker_thread.cc",
     "service_worker_thread.h",
+    "service_worker_timeout_timer.cc",
+    "service_worker_timeout_timer.h",
     "service_worker_window_client.cc",
     "service_worker_window_client.h",
     "thread_safe_script_container.cc",
diff --git a/third_party/blink/renderer/modules/service_worker/DEPS b/third_party/blink/renderer/modules/service_worker/DEPS
index 16135b6..a5c5adf5 100644
--- a/third_party/blink/renderer/modules/service_worker/DEPS
+++ b/third_party/blink/renderer/modules/service_worker/DEPS
@@ -12,19 +12,24 @@
 ]
 
 specific_include_rules = {
-    "service_worker_global_scope_proxy\.cc": [
+    "service_worker_global_scope\.cc": [
         "+third_party/blink/renderer/modules/background_fetch",
         "+third_party/blink/renderer/modules/background_sync",
         "+third_party/blink/renderer/modules/cookie_store",
-        "+third_party/blink/renderer/modules/exported",
         "+third_party/blink/renderer/modules/notifications",
         "+third_party/blink/renderer/modules/payments",
         "+third_party/blink/renderer/modules/push_messaging",
     ],
+    "service_worker_global_scope_proxy\.cc": [
+        "+third_party/blink/renderer/modules/exported",
+    ],
     "service_worker_installed_scripts_manager_test\.cc": [
         "+base/run_loop.h",
         "+mojo/public/cpp/bindings/binding.h",
     ],
+    "service_worker_timeout_timer_test\.cc": [
+        "+base/test/test_mock_time_task_runner.h",
+    ],
     "web_embedded_worker_impl_test\.cc": [
         "+third_party/blink/renderer/modules/exported",
     ],
diff --git a/third_party/blink/renderer/modules/service_worker/controller_service_worker.cc b/third_party/blink/renderer/modules/service_worker/controller_service_worker.cc
new file mode 100644
index 0000000..a25b5021
--- /dev/null
+++ b/third_party/blink/renderer/modules/service_worker/controller_service_worker.cc
@@ -0,0 +1,38 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/service_worker/controller_service_worker.h"
+
+#include "base/sequenced_task_runner.h"
+#include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h"
+
+namespace blink {
+
+ControllerServiceWorker::ControllerServiceWorker(
+    mojom::blink::ControllerServiceWorkerRequest request,
+    ServiceWorkerGlobalScope* service_worker_global_scope,
+    scoped_refptr<base::SequencedTaskRunner> task_runner)
+    : service_worker_global_scope_(service_worker_global_scope),
+      task_runner_(std::move(task_runner)) {
+  bindings_.AddBinding(this, std::move(request), task_runner_);
+}
+
+ControllerServiceWorker::~ControllerServiceWorker() = default;
+
+void ControllerServiceWorker::DispatchFetchEvent(
+    mojom::blink::DispatchFetchEventParamsPtr params,
+    mojom::blink::ServiceWorkerFetchResponseCallbackPtr response_callback,
+    DispatchFetchEventCallback callback) {
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
+  service_worker_global_scope_->DispatchOrQueueFetchEvent(
+      std::move(params), std::move(response_callback), std::move(callback));
+}
+
+void ControllerServiceWorker::Clone(
+    mojom::blink::ControllerServiceWorkerRequest request) {
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
+  bindings_.AddBinding(this, std::move(request), task_runner_);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/modules/service_worker/controller_service_worker.h b/third_party/blink/renderer/modules/service_worker/controller_service_worker.h
new file mode 100644
index 0000000..8db6c9e8
--- /dev/null
+++ b/third_party/blink/renderer/modules/service_worker/controller_service_worker.h
@@ -0,0 +1,66 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_CONTROLLER_SERVICE_WORKER_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_CONTROLLER_SERVICE_WORKER_H_
+
+#include <utility>
+
+#include "base/macros.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "third_party/blink/public/mojom/service_worker/controller_service_worker.mojom-blink.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
+
+namespace base {
+class SequencedTaskRunner;
+}
+
+namespace blink {
+
+class ServiceWorkerGlobalScope;
+
+// An instance of this class is created on the service worker thread
+// for its owner ServiceWorkerGlobalScope.
+// This implements mojom::blink::ControllerServiceWorker and its Mojo endpoint
+// is connected by each controllee and also by the ServiceWorkerProviderHost
+// in the browser process.
+// Subresource requests made by the controllees are sent to this class as
+// Fetch events via the Mojo endpoints.
+//
+// TODO(kinuko): Implement self-killing timer, that does something similar to
+// what ServiceWorkerVersion::StopWorkerIfIdle did in the browser process in
+// the non-S13n codepath.
+class ControllerServiceWorker : public mojom::blink::ControllerServiceWorker {
+ public:
+  ControllerServiceWorker(mojom::blink::ControllerServiceWorkerRequest request,
+                          ServiceWorkerGlobalScope* service_worker_global_scope,
+                          scoped_refptr<base::SequencedTaskRunner> task_runner);
+  ~ControllerServiceWorker() override;
+
+  // mojom::blink::ControllerServiceWorker:
+  void DispatchFetchEvent(
+      mojom::blink::DispatchFetchEventParamsPtr params,
+      mojom::blink::ServiceWorkerFetchResponseCallbackPtr response_callback,
+      DispatchFetchEventCallback callback) override;
+  void Clone(mojom::blink::ControllerServiceWorkerRequest request) override;
+
+ private:
+  // Connected by the ServiceWorkerProviderHost in the browser process
+  // and by the controllees.
+  mojo::BindingSet<mojom::blink::ControllerServiceWorker> bindings_;
+
+  // |service_worker_global_scope_| is guaranteed to outlive |this| because
+  // |service_worker_global_scope_| owns |this|, we just use WeakPersistent
+  // rather than a raw pointer here because a non-garbage-collected class should
+  // not store a raw pointer to an on-heap object.
+  WeakPersistent<ServiceWorkerGlobalScope> service_worker_global_scope_;
+
+  scoped_refptr<base::SequencedTaskRunner> task_runner_;
+
+  DISALLOW_COPY_AND_ASSIGN(ControllerServiceWorker);
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_CONTROLLER_SERVICE_WORKER_H_
diff --git a/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc b/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc
index 9fed381..99621b1 100644
--- a/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc
+++ b/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc
@@ -13,7 +13,7 @@
 #include "services/network/public/mojom/fetch_api.mojom-blink.h"
 #include "third_party/blink/public/mojom/devtools/console_message.mojom-shared.h"
 #include "third_party/blink/public/mojom/loader/request_context_frame_type.mojom-blink.h"
-#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_response.h"
+#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_stream_handle.h"
 #include "third_party/blink/public/platform/task_type.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
@@ -21,7 +21,7 @@
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/fetch/body_stream_buffer.h"
 #include "third_party/blink/renderer/core/inspector/console_message.h"
-#include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.h"
+#include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h"
 #include "third_party/blink/renderer/modules/service_worker/wait_until_observer.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/loader/fetch/bytes_consumer.h"
@@ -122,7 +122,7 @@
 }
 
 // Notifies the result of FetchDataLoader to |handle_|. |handle_| pass through
-// the result to its observer which is outside of blink.
+// the result to its observer.
 class FetchLoaderClient final
     : public GarbageCollectedFinalized<FetchLoaderClient>,
       public FetchDataLoader::Client {
@@ -221,13 +221,14 @@
                              mojom::ConsoleMessageLevel::kWarning,
                              GetMessageForResponseError(error, request_url_)));
 
-  // The default value of WebServiceWorkerResponse's status is 0, which maps
-  // to a network error.
-  WebServiceWorkerResponse web_response;
-  web_response.SetError(error);
-  ServiceWorkerGlobalScopeClient::From(GetExecutionContext())
-      ->RespondToFetchEvent(event_id_, web_response, event_dispatch_time_,
-                            base::TimeTicks::Now());
+  // The default value of FetchAPIResponse's status is 0, which maps to a
+  // network error.
+  auto response = mojom::blink::FetchAPIResponse::New();
+  response->status_text = "";
+  response->error = error;
+  To<ServiceWorkerGlobalScope>(GetExecutionContext())
+      ->RespondToFetchEvent(event_id_, std::move(response),
+                            event_dispatch_time_, base::TimeTicks::Now());
 }
 
 void FetchRespondWithObserver::OnResponseFulfilled(
@@ -313,8 +314,8 @@
     return;
   }
 
-  WebServiceWorkerResponse web_response;
-  response->PopulateWebServiceWorkerResponse(web_response);
+  mojom::blink::FetchAPIResponsePtr fetch_api_response =
+      response->PopulateFetchAPIResponse();
 
   BodyStreamBuffer* buffer = response->InternalBodyBuffer();
   if (buffer) {
@@ -328,10 +329,10 @@
     }
     if (blob_data_handle) {
       // Handle the blob response body.
-      web_response.SetBlobDataHandle(blob_data_handle);
-      ServiceWorkerGlobalScopeClient::From(GetExecutionContext())
-          ->RespondToFetchEvent(event_id_, web_response, event_dispatch_time_,
-                                base::TimeTicks::Now());
+      fetch_api_response->blob = blob_data_handle;
+      To<ServiceWorkerGlobalScope>(GetExecutionContext())
+          ->RespondToFetchEvent(event_id_, std::move(fetch_api_response),
+                                event_dispatch_time_, base::TimeTicks::Now());
       return;
     }
 
@@ -353,22 +354,23 @@
       return;
     }
 
-    ServiceWorkerGlobalScopeClient::From(GetExecutionContext())
+    To<ServiceWorkerGlobalScope>(GetExecutionContext())
         ->RespondToFetchEventWithResponseStream(
-            event_id_, web_response, fetch_loader_client->Handle(),
-            event_dispatch_time_, base::TimeTicks::Now());
+            event_id_, std::move(fetch_api_response),
+            fetch_loader_client->Handle(), event_dispatch_time_,
+            base::TimeTicks::Now());
 
     fetch_loader_client->SetStarted();
     return;
   }
-  ServiceWorkerGlobalScopeClient::From(GetExecutionContext())
-      ->RespondToFetchEvent(event_id_, web_response, event_dispatch_time_,
-                            base::TimeTicks::Now());
+  To<ServiceWorkerGlobalScope>(GetExecutionContext())
+      ->RespondToFetchEvent(event_id_, std::move(fetch_api_response),
+                            event_dispatch_time_, base::TimeTicks::Now());
 }
 
 void FetchRespondWithObserver::OnNoResponse() {
   DCHECK(GetExecutionContext());
-  ServiceWorkerGlobalScopeClient::From(GetExecutionContext())
+  To<ServiceWorkerGlobalScope>(GetExecutionContext())
       ->RespondToFetchEventWithNoResponse(event_id_, event_dispatch_time_,
                                           base::TimeTicks::Now());
 }
diff --git a/third_party/blink/renderer/modules/service_worker/respond_with_observer.cc b/third_party/blink/renderer/modules/service_worker/respond_with_observer.cc
index d1082d4..30e962d 100644
--- a/third_party/blink/renderer/modules/service_worker/respond_with_observer.cc
+++ b/third_party/blink/renderer/modules/service_worker/respond_with_observer.cc
@@ -4,7 +4,6 @@
 
 #include "third_party/blink/renderer/modules/service_worker/respond_with_observer.h"
 
-#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_response.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_function.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_client.cc b/third_party/blink/renderer/modules/service_worker/service_worker_client.cc
index 91a9524..870189b 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_client.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_client.cc
@@ -22,21 +22,10 @@
 namespace blink {
 
 ServiceWorkerClient* ServiceWorkerClient::Create(
-    const WebServiceWorkerClientInfo& info) {
-  return MakeGarbageCollected<ServiceWorkerClient>(info);
-}
-
-ServiceWorkerClient* ServiceWorkerClient::Create(
     const mojom::blink::ServiceWorkerClientInfo& info) {
   return MakeGarbageCollected<ServiceWorkerClient>(info);
 }
 
-ServiceWorkerClient::ServiceWorkerClient(const WebServiceWorkerClientInfo& info)
-    : uuid_(info.uuid),
-      url_(info.url.GetString()),
-      type_(info.client_type),
-      frame_type_(info.frame_type) {}
-
 ServiceWorkerClient::ServiceWorkerClient(
     const mojom::blink::ServiceWorkerClientInfo& info)
     : uuid_(info.client_uuid),
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_client.h b/third_party/blink/renderer/modules/service_worker/service_worker_client.h
index a19e4653..438c591 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_client.h
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_client.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 #include "third_party/blink/public/mojom/service_worker/service_worker_client.mojom-blink.h"
-#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_clients_info.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
@@ -23,11 +22,9 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static ServiceWorkerClient* Create(const WebServiceWorkerClientInfo&);
   static ServiceWorkerClient* Create(
       const mojom::blink::ServiceWorkerClientInfo&);
 
-  explicit ServiceWorkerClient(const WebServiceWorkerClientInfo&);
   explicit ServiceWorkerClient(const mojom::blink::ServiceWorkerClientInfo&);
   ~ServiceWorkerClient() override;
 
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_clients.cc b/third_party/blink/renderer/modules/service_worker/service_worker_clients.cc
index 3bb8e2a..144f7a5 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_clients.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_clients.cc
@@ -10,7 +10,6 @@
 #include "base/memory/ptr_util.h"
 #include "base/memory/scoped_refptr.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_client.mojom-blink.h"
-#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_clients_info.h"
 #include "third_party/blink/renderer/bindings/core/v8/callback_promise_adapter.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_clients.h b/third_party/blink/renderer/modules/service_worker/service_worker_clients.h
index aab19e2..ccd60ed1 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_clients.h
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_clients.h
@@ -5,7 +5,6 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_SERVICE_WORKER_CLIENTS_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_SERVICE_WORKER_CLIENTS_H_
 
-#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_clients_info.h"
 #include "third_party/blink/renderer/modules/service_worker/client_query_options.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_container_test.cc b/third_party/blink/renderer/modules/service_worker/service_worker_container_test.cc
index 57d91f60..6c04a4a 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_container_test.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_container_test.cc
@@ -8,7 +8,6 @@
 #include <utility>
 
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_clients_info.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_provider.h"
 #include "third_party/blink/public/platform/web_url.h"
 #include "third_party/blink/renderer/bindings/core/v8/dictionary.h"
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 38c95575..7de6361 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
@@ -37,6 +37,8 @@
 #include "base/memory/ptr_util.h"
 #include "base/numerics/safe_conversions.h"
 #include "third_party/blink/public/common/features.h"
+#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_error.h"
+#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_stream_handle.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/web_url.h"
 #include "third_party/blink/renderer/bindings/core/v8/callback_promise_adapter.h"
@@ -53,6 +55,7 @@
 #include "third_party/blink/renderer/core/inspector/worker_thread_debugger.h"
 #include "third_party/blink/renderer/core/loader/threadable_loader.h"
 #include "third_party/blink/renderer/core/loader/worker_resource_timing_notifier_impl.h"
+#include "third_party/blink/renderer/core/messaging/blink_transferable_message.h"
 #include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h"
 #include "third_party/blink/renderer/core/probe/core_probes.h"
 #include "third_party/blink/renderer/core/trustedtypes/trusted_script_url.h"
@@ -61,18 +64,49 @@
 #include "third_party/blink/renderer/core/workers/worker_classic_script_loader.h"
 #include "third_party/blink/renderer/core/workers/worker_clients.h"
 #include "third_party/blink/renderer/core/workers/worker_reporting_proxy.h"
+#include "third_party/blink/renderer/modules/background_fetch/background_fetch_event.h"
+#include "third_party/blink/renderer/modules/background_fetch/background_fetch_event_init.h"
+#include "third_party/blink/renderer/modules/background_fetch/background_fetch_registration.h"
+#include "third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.h"
+#include "third_party/blink/renderer/modules/background_sync/periodic_sync_event.h"
+#include "third_party/blink/renderer/modules/background_sync/sync_event.h"
+#include "third_party/blink/renderer/modules/cookie_store/cookie_change_event.h"
+#include "third_party/blink/renderer/modules/cookie_store/extendable_cookie_change_event.h"
 #include "third_party/blink/renderer/modules/event_target_modules.h"
+#include "third_party/blink/renderer/modules/notifications/notification.h"
+#include "third_party/blink/renderer/modules/notifications/notification_event.h"
+#include "third_party/blink/renderer/modules/notifications/notification_event_init.h"
+#include "third_party/blink/renderer/modules/payments/abort_payment_event.h"
+#include "third_party/blink/renderer/modules/payments/abort_payment_respond_with_observer.h"
+#include "third_party/blink/renderer/modules/payments/can_make_payment_event.h"
+#include "third_party/blink/renderer/modules/payments/can_make_payment_respond_with_observer.h"
+#include "third_party/blink/renderer/modules/payments/payment_event_data_conversion.h"
+#include "third_party/blink/renderer/modules/payments/payment_request_event.h"
+#include "third_party/blink/renderer/modules/payments/payment_request_event_init.h"
+#include "third_party/blink/renderer/modules/payments/payment_request_respond_with_observer.h"
+#include "third_party/blink/renderer/modules/push_messaging/push_event.h"
+#include "third_party/blink/renderer/modules/push_messaging/push_message_data.h"
+#include "third_party/blink/renderer/modules/service_worker/controller_service_worker.h"
+#include "third_party/blink/renderer/modules/service_worker/extendable_event.h"
+#include "third_party/blink/renderer/modules/service_worker/extendable_message_event.h"
+#include "third_party/blink/renderer/modules/service_worker/fetch_event.h"
+#include "third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.h"
+#include "third_party/blink/renderer/modules/service_worker/install_event.h"
 #include "third_party/blink/renderer/modules/service_worker/respond_with_observer.h"
 #include "third_party/blink/renderer/modules/service_worker/service_worker.h"
+#include "third_party/blink/renderer/modules/service_worker/service_worker_client.h"
 #include "third_party/blink/renderer/modules/service_worker/service_worker_clients.h"
 #include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.h"
 #include "third_party/blink/renderer/modules/service_worker/service_worker_module_tree_client.h"
 #include "third_party/blink/renderer/modules/service_worker/service_worker_registration.h"
 #include "third_party/blink/renderer/modules/service_worker/service_worker_script_cached_metadata_handler.h"
 #include "third_party/blink/renderer/modules/service_worker/service_worker_thread.h"
+#include "third_party/blink/renderer/modules/service_worker/service_worker_timeout_timer.h"
+#include "third_party/blink/renderer/modules/service_worker/service_worker_window_client.h"
 #include "third_party/blink/renderer/modules/service_worker/wait_until_observer.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
+#include "third_party/blink/renderer/platform/cross_thread_functional.h"
 #include "third_party/blink/renderer/platform/histogram.h"
 #include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h"
 #include "third_party/blink/renderer/platform/loader/fetch/memory_cache.h"
@@ -87,6 +121,33 @@
 
 namespace {
 
+constexpr char kServiceWorkerGlobalScopeTraceScope[] =
+    "ServiceWorkerGlobalScope";
+
+class StreamHandleListener : public WebServiceWorkerStreamHandle::Listener {
+ public:
+  StreamHandleListener(
+      mojom::blink::ServiceWorkerStreamCallbackPtr callback_ptr,
+      std::unique_ptr<ServiceWorkerTimeoutTimer::StayAwakeToken> token)
+      : callback_ptr_(std::move(callback_ptr)), token_(std::move(token)) {}
+
+  ~StreamHandleListener() override {}
+
+  void OnAborted() override {
+    callback_ptr_->OnAborted();
+    token_.reset();
+  }
+
+  void OnCompleted() override {
+    callback_ptr_->OnCompleted();
+    token_.reset();
+  }
+
+ private:
+  mojom::blink::ServiceWorkerStreamCallbackPtr callback_ptr_;
+  std::unique_ptr<ServiceWorkerTimeoutTimer::StayAwakeToken> token_;
+};
+
 void DidSkipWaiting(ScriptPromiseResolver* resolver, bool success) {
   if (!resolver->GetExecutionContext() ||
       resolver->GetExecutionContext()->IsContextDestroyed())
@@ -97,6 +158,47 @@
   resolver->Resolve();
 }
 
+// Creates a callback which takes an |event_id| and |status|, which calls the
+// given event's callback with the given status and removes it from |map|.
+template <typename MapType, typename... Args>
+ServiceWorkerTimeoutTimer::AbortCallback CreateAbortCallback(MapType* map,
+                                                             Args&&... args) {
+  return WTF::Bind(
+      [](MapType* map, Args&&... args, int event_id,
+         mojom::blink::ServiceWorkerEventStatus status) {
+        auto iter = map->find(event_id);
+        DCHECK(iter != map->end());
+        std::move(iter->value).Run(status, std::forward<Args>(args)...);
+        map->erase(iter);
+      },
+      WTF::Unretained(map), std::forward<Args>(args)...);
+}
+
+// Finds an event callback keyed by |event_id| from |map|, and runs the callback
+// with |args|. Returns true if the callback was found and called, otherwise
+// returns false.
+template <typename MapType, typename... Args>
+bool RunEventCallback(MapType* map,
+                      ServiceWorkerTimeoutTimer* timer,
+                      int event_id,
+                      Args&&... args) {
+  auto iter = map->find(event_id);
+  // The event may have been aborted.
+  if (iter == map->end())
+    return false;
+  std::move(iter->value).Run(std::forward<Args>(args)...);
+  map->erase(iter);
+  timer->EndEvent(event_id);
+  return true;
+}
+
+template <typename T>
+static std::string MojoEnumToString(T mojo_enum) {
+  std::ostringstream oss;
+  oss << mojo_enum;
+  return oss.str();
+}
+
 }  // namespace
 
 ServiceWorkerGlobalScope* ServiceWorkerGlobalScope::Create(
@@ -157,14 +259,17 @@
     mojom::blink::CacheStoragePtrInfo cache_storage_info,
     base::TimeTicks time_origin)
     : WorkerGlobalScope(std::move(creation_params), thread, time_origin),
-      cache_storage_info_(std::move(cache_storage_info)) {}
+      cache_storage_info_(std::move(cache_storage_info)),
+      binding_(this) {
+  // Create the idle timer. At this point the timer is not started. It will be
+  // started by DidEvaluateScript().
+  timeout_timer_ =
+      std::make_unique<ServiceWorkerTimeoutTimer>(WTF::BindRepeating(
+          &ServiceWorkerGlobalScope::OnIdleTimeout, WrapWeakPersistent(this)));
+}
 
 ServiceWorkerGlobalScope::~ServiceWorkerGlobalScope() = default;
 
-void ServiceWorkerGlobalScope::ReadyToEvaluateScript() {
-  ReadyToRunClassicScript();
-}
-
 bool ServiceWorkerGlobalScope::ShouldInstallV8Extensions() const {
   return Platform::Current()->AllowScriptExtensionForServiceWorker(
       WebSecurityOrigin(GetSecurityOrigin()));
@@ -301,6 +406,9 @@
   DCHECK(IsContextThread());
   ServiceWorkerGlobalScopeClient::From(GetExecutionContext())
       ->WillDestroyWorkerContext();
+  timeout_timer_.reset();
+  binding_.Close();
+  controller_.reset();
   WorkerGlobalScope::Dispose();
 }
 
@@ -335,6 +443,8 @@
   DCHECK(!did_evaluate_script_);
   did_evaluate_script_ = true;
 
+  timeout_timer_->Start();
+
   // Skip recording UMAs for module scripts because there're no ways to get the
   // number of static-imported scripts and the total size of the imported
   // scripts.
@@ -529,38 +639,104 @@
   return resolver->Promise();
 }
 
-void ServiceWorkerGlobalScope::BindServiceWorkerHost(
-    mojom::blink::ServiceWorkerHostAssociatedPtrInfo service_worker_host) {
-  ServiceWorkerGlobalScopeClient::From(GetExecutionContext())
-      ->BindServiceWorkerHost(std::move(service_worker_host),
-                              GetTaskRunner(TaskType::kInternalIPC));
-}
-
-void ServiceWorkerGlobalScope::SetRegistration(
-    WebServiceWorkerRegistrationObjectInfo info) {
-  if (!GetExecutionContext())
-    return;
-  registration_ = MakeGarbageCollected<ServiceWorkerRegistration>(
-      GetExecutionContext(), std::move(info));
-}
-
-void ServiceWorkerGlobalScope::SetFetchHandlerExistence(
-    FetchHandlerExistence fetch_handler_existence) {
+void ServiceWorkerGlobalScope::BindServiceWorker(
+    mojom::blink::ServiceWorkerRequest request) {
   DCHECK(IsContextThread());
-  if (fetch_handler_existence == FetchHandlerExistence::EXISTS &&
-      base::FeatureList::IsEnabled(
-          features::kServiceWorkerIsolateInForeground)) {
-    GetThread()->GetIsolate()->IsolateInForegroundNotification();
+  DCHECK(!binding_.is_bound());
+  // TODO(falken): Consider adding task types for "the handle fetch task source"
+  // and "handle functional event task source" defined in the service worker
+  // spec and use them when dispatching events.
+  binding_.Bind(std::move(request),
+                GetThread()->GetTaskRunner(TaskType::kInternalDefault));
+}
+
+void ServiceWorkerGlobalScope::BindControllerServiceWorker(
+    mojom::blink::ControllerServiceWorkerRequest request) {
+  DCHECK(IsContextThread());
+  DCHECK(!controller_);
+  // TODO(falken): Consider adding task types for "the handle fetch task source"
+  // and "handle functional event task source" defined in the service worker
+  // spec and use them when dispatching events.
+  controller_ = std::make_unique<ControllerServiceWorker>(
+      std::move(request), this,
+      GetThread()->GetTaskRunner(TaskType::kInternalDefault));
+}
+
+void ServiceWorkerGlobalScope::OnNavigationPreloadResponse(
+    int fetch_event_id,
+    std::unique_ptr<WebURLResponse> response,
+    mojo::ScopedDataPipeConsumerHandle data_pipe) {
+  DCHECK(IsContextThread());
+  auto it = pending_preload_fetch_events_.find(fetch_event_id);
+  DCHECK(it != pending_preload_fetch_events_.end());
+  FetchEvent* fetch_event = it->value.Get();
+  DCHECK(fetch_event);
+  fetch_event->OnNavigationPreloadResponse(ScriptController()->GetScriptState(),
+                                           std::move(response),
+                                           std::move(data_pipe));
+}
+
+void ServiceWorkerGlobalScope::OnNavigationPreloadError(
+    int fetch_event_id,
+    std::unique_ptr<WebServiceWorkerError> error) {
+  DCHECK(IsContextThread());
+  FetchEvent* fetch_event = pending_preload_fetch_events_.Take(fetch_event_id);
+  DCHECK(fetch_event);
+  // Display an error message to the console, preferring the unsanitized one if
+  // available.
+  const WebString& error_message = error->unsanitized_message.IsEmpty()
+                                       ? error->message
+                                       : error->unsanitized_message;
+  if (!error_message.IsEmpty()) {
+    AddConsoleMessage(ConsoleMessage::Create(
+        mojom::ConsoleMessageSource::kWorker,
+        mojom::ConsoleMessageLevel::kError, error_message));
   }
+  // Reject the preloadResponse promise.
+  fetch_event->OnNavigationPreloadError(ScriptController()->GetScriptState(),
+                                        std::move(error));
+}
+
+void ServiceWorkerGlobalScope::OnNavigationPreloadComplete(
+    int fetch_event_id,
+    TimeTicks completion_time,
+    int64_t encoded_data_length,
+    int64_t encoded_body_length,
+    int64_t decoded_body_length) {
+  DCHECK(IsContextThread());
+  FetchEvent* fetch_event = pending_preload_fetch_events_.Take(fetch_event_id);
+  DCHECK(fetch_event);
+  fetch_event->OnNavigationPreloadComplete(
+      this, completion_time, encoded_data_length, encoded_body_length,
+      decoded_body_length);
+}
+
+void ServiceWorkerGlobalScope::DispatchOrQueueFetchEvent(
+    mojom::blink::DispatchFetchEventParamsPtr params,
+    mojom::blink::ServiceWorkerFetchResponseCallbackPtr response_callback,
+    DispatchFetchEventCallback callback) {
+  DCHECK(IsContextThread());
+  TRACE_EVENT2("ServiceWorker",
+               "ServiceWorkerGlobalScope::DispatchOrQueueFetchEvent", "url",
+               params->request->url.ElidedString().Utf8().data(), "queued",
+               RequestedTermination() ? "true" : "false");
+  if (RequestedTermination()) {
+    timeout_timer_->PushPendingTask(WTF::Bind(
+        &ServiceWorkerGlobalScope::DispatchFetchEvent, WrapWeakPersistent(this),
+        std::move(params), std::move(response_callback), std::move(callback)));
+    return;
+  }
+  DispatchFetchEvent(std::move(params), std::move(response_callback),
+                     std::move(callback));
 }
 
 ServiceWorker* ServiceWorkerGlobalScope::GetOrCreateServiceWorker(
     WebServiceWorkerObjectInfo info) {
   if (info.version_id == mojom::blink::kInvalidServiceWorkerVersionId)
     return nullptr;
-  ServiceWorker* worker = service_worker_objects_.at(info.version_id);
+  ::blink::ServiceWorker* worker = service_worker_objects_.at(info.version_id);
   if (!worker) {
-    worker = ServiceWorker::Create(this, std::move(info));
+    worker = ::blink::ServiceWorker::Create(this, std::move(info));
     service_worker_objects_.Set(info.version_id, worker);
   }
   return worker;
@@ -615,6 +791,7 @@
   visitor->Trace(clients_);
   visitor->Trace(registration_);
   visitor->Trace(service_worker_objects_);
+  visitor->Trace(pending_preload_fetch_events_);
   WorkerGlobalScope::Trace(visitor);
 }
 
@@ -694,6 +871,376 @@
   }
 }
 
+void ServiceWorkerGlobalScope::DidHandleInstallEvent(
+    int install_event_id,
+    mojom::ServiceWorkerEventStatus status) {
+  DCHECK(IsContextThread());
+  SetFetchHandlerExistence(HasEventListeners(event_type_names::kFetch)
+                               ? FetchHandlerExistence::EXISTS
+                               : FetchHandlerExistence::DOES_NOT_EXIST);
+  TRACE_EVENT_WITH_FLOW1(
+      "ServiceWorker", "ServiceWorkerGlobalScope::DidHandleInstallEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(install_event_id)),
+      TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status));
+  RunEventCallback(&install_event_callbacks_, timeout_timer_.get(),
+                   install_event_id, status,
+                   HasEventListeners(event_type_names::kFetch));
+}
+
+void ServiceWorkerGlobalScope::DidHandleActivateEvent(
+    int event_id,
+    mojom::ServiceWorkerEventStatus status) {
+  DCHECK(IsContextThread());
+  TRACE_EVENT_WITH_FLOW1(
+      "ServiceWorker", "ServiceWorkerGlobalScope::DidHandleActivateEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status));
+  RunEventCallback(&activate_event_callbacks_, timeout_timer_.get(), event_id,
+                   status);
+}
+
+void ServiceWorkerGlobalScope::DidHandleBackgroundFetchAbortEvent(
+    int event_id,
+    mojom::ServiceWorkerEventStatus status) {
+  DCHECK(IsContextThread());
+  TRACE_EVENT_WITH_FLOW1(
+      "ServiceWorker",
+      "ServiceWorkerGlobalScope::DidHandleBackgroundFetchAbortEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status));
+  RunEventCallback(&background_fetch_abort_event_callbacks_,
+                   timeout_timer_.get(), event_id, status);
+}
+
+void ServiceWorkerGlobalScope::DidHandleBackgroundFetchClickEvent(
+    int event_id,
+    mojom::ServiceWorkerEventStatus status) {
+  DCHECK(IsContextThread());
+  TRACE_EVENT_WITH_FLOW1(
+      "ServiceWorker",
+      "ServiceWorkerGlobalScope::DidHandleBackgroundFetchClickEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status));
+  RunEventCallback(&background_fetch_click_event_callbacks_,
+                   timeout_timer_.get(), event_id, status);
+}
+
+void ServiceWorkerGlobalScope::DidHandleBackgroundFetchFailEvent(
+    int event_id,
+    mojom::ServiceWorkerEventStatus status) {
+  TRACE_EVENT_WITH_FLOW1(
+      "ServiceWorker",
+      "ServiceWorkerGlobalScope::DidHandleBackgroundFetchFailEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status));
+  RunEventCallback(&background_fetch_fail_event_callbacks_,
+                   timeout_timer_.get(), event_id, status);
+}
+
+void ServiceWorkerGlobalScope::DidHandleBackgroundFetchSuccessEvent(
+    int event_id,
+    mojom::ServiceWorkerEventStatus status) {
+  DCHECK(IsContextThread());
+  TRACE_EVENT_WITH_FLOW1(
+      "ServiceWorker",
+      "ServiceWorkerGlobalScope::DidHandleBackgroundFetchSuccessEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status));
+  RunEventCallback(&background_fetched_event_callbacks_, timeout_timer_.get(),
+                   event_id, status);
+}
+
+void ServiceWorkerGlobalScope::DidHandleExtendableMessageEvent(
+    int event_id,
+    mojom::ServiceWorkerEventStatus status) {
+  DCHECK(IsContextThread());
+  TRACE_EVENT_WITH_FLOW1(
+      "ServiceWorker",
+      "ServiceWorkerGlobalScope::DidHandleExtendableMessageEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status));
+  RunEventCallback(&message_event_callbacks_, timeout_timer_.get(), event_id,
+                   status);
+}
+
+void ServiceWorkerGlobalScope::RespondToFetchEventWithNoResponse(
+    int fetch_event_id,
+    base::TimeTicks event_dispatch_time,
+    base::TimeTicks respond_with_settled_time) {
+  DCHECK(IsContextThread());
+  TRACE_EVENT_WITH_FLOW0(
+      "ServiceWorker",
+      "ServiceWorkerGlobalScope::RespondToFetchEventWithNoResponse",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(fetch_event_id)),
+      TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
+  DCHECK(fetch_response_callbacks_.Contains(fetch_event_id));
+  mojom::blink::ServiceWorkerFetchResponseCallbackPtr response_callback =
+      fetch_response_callbacks_.Take(fetch_event_id);
+
+  auto timing = mojom::blink::ServiceWorkerFetchEventTiming::New();
+  timing->dispatch_event_time = event_dispatch_time;
+  timing->respond_with_settled_time = respond_with_settled_time;
+
+  response_callback->OnFallback(std::move(timing));
+}
+
+void ServiceWorkerGlobalScope::RespondToFetchEvent(
+    int fetch_event_id,
+    mojom::blink::FetchAPIResponsePtr response,
+    base::TimeTicks event_dispatch_time,
+    base::TimeTicks respond_with_settled_time) {
+  DCHECK(IsContextThread());
+  TRACE_EVENT_WITH_FLOW0(
+      "ServiceWorker", "ServiceWorkerGlobalScope::RespondToFetchEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(fetch_event_id)),
+      TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
+  DCHECK(fetch_response_callbacks_.Contains(fetch_event_id));
+
+  mojom::blink::ServiceWorkerFetchResponseCallbackPtr response_callback =
+      fetch_response_callbacks_.Take(fetch_event_id);
+
+  auto timing = mojom::blink::ServiceWorkerFetchEventTiming::New();
+  timing->dispatch_event_time = event_dispatch_time;
+  timing->respond_with_settled_time = respond_with_settled_time;
+
+  response_callback->OnResponse(std::move(response), std::move(timing));
+}
+
+void ServiceWorkerGlobalScope::RespondToFetchEventWithResponseStream(
+    int fetch_event_id,
+    mojom::blink::FetchAPIResponsePtr response,
+    blink::WebServiceWorkerStreamHandle* web_body_as_stream,
+    base::TimeTicks event_dispatch_time,
+    base::TimeTicks respond_with_settled_time) {
+  DCHECK(IsContextThread());
+  TRACE_EVENT_WITH_FLOW0(
+      "ServiceWorker",
+      "ServiceWorkerGlobalScope::RespondToFetchEventWithResponseStream",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(fetch_event_id)),
+      TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
+  DCHECK(fetch_response_callbacks_.Contains(fetch_event_id));
+  mojom::blink::ServiceWorkerFetchResponseCallbackPtr response_callback =
+      fetch_response_callbacks_.Take(fetch_event_id);
+  auto body_as_stream = mojom::blink::ServiceWorkerStreamHandle::New();
+  mojom::blink::ServiceWorkerStreamCallbackPtr callback_ptr;
+  body_as_stream->callback_request = mojo::MakeRequest(&callback_ptr);
+  body_as_stream->stream = web_body_as_stream->DrainStreamDataPipe();
+  DCHECK(body_as_stream->stream.is_valid());
+
+  web_body_as_stream->SetListener(std::make_unique<StreamHandleListener>(
+      std::move(callback_ptr), timeout_timer_->CreateStayAwakeToken()));
+
+  auto timing = mojom::blink::ServiceWorkerFetchEventTiming::New();
+  timing->dispatch_event_time = event_dispatch_time;
+  timing->respond_with_settled_time = respond_with_settled_time;
+
+  response_callback->OnResponseStream(
+      std::move(response), std::move(body_as_stream), std::move(timing));
+}
+
+void ServiceWorkerGlobalScope::DidHandleFetchEvent(
+    int event_id,
+    mojom::ServiceWorkerEventStatus status) {
+  DCHECK(IsContextThread());
+  // This TRACE_EVENT is used for perf benchmark to confirm if all of fetch
+  // events have completed. (crbug.com/736697)
+  TRACE_EVENT_WITH_FLOW1(
+      "ServiceWorker", "ServiceWorkerGlobalScope::DidHandleFetchEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status));
+  if (!RunEventCallback(&fetch_event_callbacks_, timeout_timer_.get(), event_id,
+                        status)) {
+    // The event may have been aborted. Its response callback also needs to be
+    // deleted.
+    fetch_response_callbacks_.erase(event_id);
+  } else {
+    // |fetch_response_callback| should be used before settling a promise for
+    // waitUntil().
+    DCHECK(!fetch_response_callbacks_.Contains(event_id));
+  }
+}
+
+void ServiceWorkerGlobalScope::DidHandleNotificationClickEvent(
+    int event_id,
+    mojom::ServiceWorkerEventStatus status) {
+  DCHECK(IsContextThread());
+  TRACE_EVENT_WITH_FLOW1(
+      "ServiceWorker",
+      "ServiceWorkerGlobalScope::DidHandleNotificationClickEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status));
+  RunEventCallback(&notification_click_event_callbacks_, timeout_timer_.get(),
+                   event_id, status);
+}
+
+void ServiceWorkerGlobalScope::DidHandleNotificationCloseEvent(
+    int event_id,
+    mojom::ServiceWorkerEventStatus status) {
+  DCHECK(IsContextThread());
+  TRACE_EVENT_WITH_FLOW1(
+      "ServiceWorker",
+      "ServiceWorkerGlobalScope::DidHandleNotificationCloseEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status));
+  RunEventCallback(&notification_close_event_callbacks_, timeout_timer_.get(),
+                   event_id, status);
+}
+
+void ServiceWorkerGlobalScope::DidHandlePushEvent(
+    int event_id,
+    mojom::ServiceWorkerEventStatus status) {
+  DCHECK(IsContextThread());
+  TRACE_EVENT_WITH_FLOW1(
+      "ServiceWorker", "ServiceWorkerGlobalScope::DidHandlePushEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status));
+  RunEventCallback(&push_event_callbacks_, timeout_timer_.get(), event_id,
+                   status);
+}
+
+void ServiceWorkerGlobalScope::DidHandleSyncEvent(
+    int event_id,
+    mojom::ServiceWorkerEventStatus status) {
+  DCHECK(IsContextThread());
+  TRACE_EVENT_WITH_FLOW1(
+      "ServiceWorker", "ServiceWorkerGlobalScope::DidHandleSyncEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status));
+  RunEventCallback(&sync_event_callbacks_, timeout_timer_.get(), event_id,
+                   status);
+}
+
+void ServiceWorkerGlobalScope::DidHandlePeriodicSyncEvent(
+    int event_id,
+    mojom::ServiceWorkerEventStatus status) {
+  DCHECK(IsContextThread());
+  TRACE_EVENT_WITH_FLOW1(
+      "ServiceWorker", "ServiceWorkerGlobalScope::DidHandlePeriodicSyncEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status));
+  RunEventCallback(&periodic_sync_event_callbacks_, timeout_timer_.get(),
+                   event_id, status);
+}
+
+void ServiceWorkerGlobalScope::RespondToAbortPaymentEvent(
+    int event_id,
+    bool payment_aborted) {
+  DCHECK(IsContextThread());
+  TRACE_EVENT_WITH_FLOW0(
+      "ServiceWorker", "ServiceWorkerGlobalScope::RespondToAbortPaymentEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
+  DCHECK(abort_payment_result_callbacks_.Contains(event_id));
+  payments::mojom::blink::PaymentHandlerResponseCallbackPtr result_callback =
+      abort_payment_result_callbacks_.Take(event_id);
+  result_callback->OnResponseForAbortPayment(payment_aborted);
+}
+
+void ServiceWorkerGlobalScope::DidHandleAbortPaymentEvent(
+    int event_id,
+    mojom::ServiceWorkerEventStatus status) {
+  DCHECK(IsContextThread());
+  TRACE_EVENT_WITH_FLOW1(
+      "ServiceWorker", "ServiceWorkerGlobalScope::DidHandleAbortPaymentEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status));
+  if (RunEventCallback(&abort_payment_event_callbacks_, timeout_timer_.get(),
+                       event_id, status)) {
+    abort_payment_result_callbacks_.erase(event_id);
+  }
+}
+
+void ServiceWorkerGlobalScope::RespondToCanMakePaymentEvent(
+    int event_id,
+    bool can_make_payment) {
+  DCHECK(IsContextThread());
+  TRACE_EVENT_WITH_FLOW0(
+      "ServiceWorker", "ServiceWorkerGlobalScope::RespondToCanMakePaymentEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
+  DCHECK(can_make_payment_result_callbacks_.Contains(event_id));
+  payments::mojom::blink::PaymentHandlerResponseCallbackPtr result_callback =
+      can_make_payment_result_callbacks_.Take(event_id);
+  result_callback->OnResponseForCanMakePayment(can_make_payment);
+}
+
+void ServiceWorkerGlobalScope::DidHandleCanMakePaymentEvent(
+    int event_id,
+    mojom::ServiceWorkerEventStatus status) {
+  DCHECK(IsContextThread());
+  TRACE_EVENT_WITH_FLOW1(
+      "ServiceWorker", "ServiceWorkerGlobalScope::DidHandleCanMakePaymentEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status));
+  if (RunEventCallback(&can_make_payment_event_callbacks_, timeout_timer_.get(),
+                       event_id, status)) {
+    can_make_payment_result_callbacks_.erase(event_id);
+  }
+}
+
+void ServiceWorkerGlobalScope::RespondToPaymentRequestEvent(
+    int payment_event_id,
+    payments::mojom::blink::PaymentHandlerResponsePtr response) {
+  DCHECK(IsContextThread());
+  TRACE_EVENT_WITH_FLOW0(
+      "ServiceWorker", "ServiceWorkerGlobalScope::RespondToPaymentRequestEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(payment_event_id)),
+      TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
+  DCHECK(payment_response_callbacks_.Contains(payment_event_id));
+  payments::mojom::blink::PaymentHandlerResponseCallbackPtr response_callback =
+      payment_response_callbacks_.Take(payment_event_id);
+  response_callback->OnResponseForPaymentRequest(std::move(response));
+}
+
+void ServiceWorkerGlobalScope::DidHandlePaymentRequestEvent(
+    int payment_event_id,
+    mojom::ServiceWorkerEventStatus status) {
+  DCHECK(IsContextThread());
+  TRACE_EVENT_WITH_FLOW1(
+      "ServiceWorker", "ServiceWorkerGlobalScope::DidHandlePaymentRequestEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(payment_event_id)),
+      TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status));
+  if (RunEventCallback(&payment_request_event_callbacks_, timeout_timer_.get(),
+                       payment_event_id, status)) {
+    payment_response_callbacks_.erase(payment_event_id);
+  }
+}
+
+void ServiceWorkerGlobalScope::DidHandleCookieChangeEvent(
+    int event_id,
+    mojom::ServiceWorkerEventStatus status) {
+  DCHECK(IsContextThread());
+  TRACE_EVENT_WITH_FLOW1(
+      "ServiceWorker", "ServiceWorkerGlobalScope::DidHandleCookieChangeEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_IN, "status", MojoEnumToString(status));
+  RunEventCallback(&cookie_change_event_callbacks_, timeout_timer_.get(),
+                   event_id, status);
+}
+
 void ServiceWorkerGlobalScope::SetIsInstalling(bool is_installing) {
   is_installing_ = is_installing;
   if (is_installing)
@@ -732,13 +1279,637 @@
 }
 
 int ServiceWorkerGlobalScope::WillStartTask() {
-  return ServiceWorkerGlobalScopeClient::From(GetExecutionContext())
-      ->WillStartTask();
+  DCHECK(IsContextThread());
+  DCHECK(timeout_timer_);
+  return timeout_timer_->StartEvent(base::DoNothing());
 }
 
 void ServiceWorkerGlobalScope::DidEndTask(int task_id) {
+  DCHECK(IsContextThread());
+  DCHECK(timeout_timer_);
+  // Check if the task is still alive, since the timeout timer might have
+  // already timed it out (which calls the abort callback passed to StartEvent()
+  // but that does nothing, since we just check HasEvent() here instead of
+  // maintaining our own set of started events).
+  if (timeout_timer_->HasEvent(task_id))
+    timeout_timer_->EndEvent(task_id);
+}
+
+void ServiceWorkerGlobalScope::OnIdleTimeout() {
+  DCHECK(IsContextThread());
+  // RequestedTermination() returns true if ServiceWorkerTimeoutTimer agrees
+  // we should request the host to terminate this worker now.
+  DCHECK(RequestedTermination());
+  // We use CrossThreadBindOnce() here because the callback may be destroyed on
+  // the main thread if the worker thread has already terminated.
   ServiceWorkerGlobalScopeClient::From(GetExecutionContext())
-      ->DidEndTask(task_id);
+      ->RequestTermination(ConvertToBaseOnceCallback(
+          CrossThreadBindOnce(&ServiceWorkerGlobalScope::OnRequestedTermination,
+                              WrapCrossThreadWeakPersistent(this))));
+}
+
+void ServiceWorkerGlobalScope::OnRequestedTermination(bool will_be_terminated) {
+  DCHECK(IsContextThread());
+  // This worker will be terminated soon. Ignore the message.
+  if (will_be_terminated)
+    return;
+
+  // Dispatch a dummy event to run all of queued tasks. This updates the
+  // idle timer too.
+  const int event_id = timeout_timer_->StartEvent(base::DoNothing());
+  timeout_timer_->EndEvent(event_id);
+}
+
+bool ServiceWorkerGlobalScope::RequestedTermination() const {
+  DCHECK(IsContextThread());
+  return timeout_timer_->did_idle_timeout();
+}
+
+void ServiceWorkerGlobalScope::DispatchExtendableMessageEventInternal(
+    int event_id,
+    mojom::blink::ExtendableMessageEventPtr event) {
+  BlinkTransferableMessage msg = std::move(event->message);
+  MessagePortArray* ports =
+      MessagePort::EntanglePorts(*this, std::move(msg.ports));
+  String origin;
+  if (!event->source_origin->IsOpaque())
+    origin = event->source_origin->ToString();
+  WaitUntilObserver* observer =
+      WaitUntilObserver::Create(this, WaitUntilObserver::kMessage, event_id);
+
+  if (event->source_info_for_client) {
+    mojom::blink::ServiceWorkerClientInfoPtr client_info =
+        std::move(event->source_info_for_client);
+    DCHECK(!client_info->client_uuid.IsEmpty());
+    ServiceWorkerClient* source = nullptr;
+    if (client_info->client_type == mojom::ServiceWorkerClientType::kWindow)
+      source = ServiceWorkerWindowClient::Create(*client_info);
+    else
+      source = ServiceWorkerClient::Create(*client_info);
+    Event* event_to_dispatch = ExtendableMessageEvent::Create(
+        std::move(msg.message), origin, ports, source, observer);
+    DispatchExtendableEvent(event_to_dispatch, observer);
+    return;
+  }
+
+  DCHECK_NE(event->source_info_for_service_worker->version_id,
+            mojom::blink::kInvalidServiceWorkerVersionId);
+  ::blink::ServiceWorker* source = ::blink::ServiceWorker::From(
+      GetExecutionContext(), std::move(event->source_info_for_service_worker));
+  Event* event_to_dispatch = ExtendableMessageEvent::Create(
+      std::move(msg.message), origin, ports, source, observer);
+  DispatchExtendableEvent(event_to_dispatch, observer);
+}
+
+void ServiceWorkerGlobalScope::SetFetchHandlerExistence(
+    FetchHandlerExistence fetch_handler_existence) {
+  DCHECK(IsContextThread());
+  if (fetch_handler_existence == FetchHandlerExistence::EXISTS &&
+      base::FeatureList::IsEnabled(
+          features::kServiceWorkerIsolateInForeground)) {
+    GetThread()->GetIsolate()->IsolateInForegroundNotification();
+  }
+}
+
+void ServiceWorkerGlobalScope::InitializeGlobalScope(
+    mojom::blink::ServiceWorkerHostAssociatedPtrInfo service_worker_host,
+    mojom::blink::ServiceWorkerRegistrationObjectInfoPtr registration_info,
+    mojom::blink::FetchHandlerExistence fetch_hander_existence) {
+  DCHECK(IsContextThread());
+
+  ServiceWorkerGlobalScopeClient::From(GetExecutionContext())
+      ->BindServiceWorkerHost(std::move(service_worker_host),
+                              GetTaskRunner(TaskType::kInternalIPC));
+
+  // Set ServiceWorkerGlobalScope#registration.
+  DCHECK_NE(registration_info->registration_id,
+            mojom::blink::kInvalidServiceWorkerRegistrationId);
+  DCHECK(registration_info->host_ptr_info.is_valid());
+  DCHECK(registration_info->request.is_pending());
+  registration_ = MakeGarbageCollected<ServiceWorkerRegistration>(
+      GetExecutionContext(), std::move(registration_info));
+
+  SetFetchHandlerExistence(fetch_hander_existence);
+
+  ReadyToRunClassicScript();
+}
+
+void ServiceWorkerGlobalScope::DispatchInstallEvent(
+    DispatchInstallEventCallback callback) {
+  DCHECK(IsContextThread());
+  int event_id = timeout_timer_->StartEvent(CreateAbortCallback(
+      &install_event_callbacks_, false /* has_fetch_handler */));
+  install_event_callbacks_.Set(event_id, std::move(callback));
+  TRACE_EVENT_WITH_FLOW0(
+      "ServiceWorker", "ServiceWorkerGlobalScope::DispatchInstallEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_OUT);
+
+  WaitUntilObserver* observer =
+      WaitUntilObserver::Create(this, WaitUntilObserver::kInstall, event_id);
+  Event* event =
+      InstallEvent::Create(event_type_names::kInstall,
+                           ExtendableEventInit::Create(), event_id, observer);
+  SetIsInstalling(true);
+  DispatchExtendableEvent(event, observer);
+}
+
+void ServiceWorkerGlobalScope::DispatchActivateEvent(
+    DispatchActivateEventCallback callback) {
+  DCHECK(IsContextThread());
+  int event_id = timeout_timer_->StartEvent(
+      CreateAbortCallback(&activate_event_callbacks_));
+  activate_event_callbacks_.Set(event_id, std::move(callback));
+  TRACE_EVENT_WITH_FLOW0(
+      "ServiceWorker", "ServiceWorkerGlobalScope::DispatchActivateEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_OUT);
+
+  WaitUntilObserver* observer =
+      WaitUntilObserver::Create(this, WaitUntilObserver::kActivate, event_id);
+  Event* event = ExtendableEvent::Create(
+      event_type_names::kActivate, ExtendableEventInit::Create(), observer);
+  DispatchExtendableEvent(event, observer);
+}
+
+void ServiceWorkerGlobalScope::DispatchBackgroundFetchAbortEvent(
+    mojom::blink::BackgroundFetchRegistrationPtr registration,
+    DispatchBackgroundFetchAbortEventCallback callback) {
+  DCHECK(IsContextThread());
+  int event_id = timeout_timer_->StartEvent(
+      CreateAbortCallback(&background_fetch_abort_event_callbacks_));
+  background_fetch_abort_event_callbacks_.Set(event_id, std::move(callback));
+  TRACE_EVENT_WITH_FLOW0(
+      "ServiceWorker",
+      "ServiceWorkerGlobalScope::DispatchBackgroundFetchAbortEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_OUT);
+
+  WaitUntilObserver* observer = WaitUntilObserver::Create(
+      this, WaitUntilObserver::kBackgroundFetchAbort, event_id);
+  ScriptState* script_state = ScriptController()->GetScriptState();
+
+  // Do not remove this, |scope| is needed by
+  // BackgroundFetchEvent::Create which eventually calls ToV8.
+  ScriptState::Scope scope(script_state);
+
+  BackgroundFetchEventInit* init = BackgroundFetchEventInit::Create();
+  init->setRegistration(MakeGarbageCollected<BackgroundFetchRegistration>(
+      registration_, std::move(registration)));
+
+  BackgroundFetchEvent* event = BackgroundFetchEvent::Create(
+      event_type_names::kBackgroundfetchabort, init, observer);
+
+  DispatchExtendableEvent(event, observer);
+}
+
+void ServiceWorkerGlobalScope::DispatchBackgroundFetchClickEvent(
+    mojom::blink::BackgroundFetchRegistrationPtr registration,
+    DispatchBackgroundFetchClickEventCallback callback) {
+  DCHECK(IsContextThread());
+  int event_id = timeout_timer_->StartEvent(
+      CreateAbortCallback(&background_fetch_click_event_callbacks_));
+  background_fetch_click_event_callbacks_.Set(event_id, std::move(callback));
+  TRACE_EVENT_WITH_FLOW0(
+      "ServiceWorker",
+      "ServiceWorkerGlobalScope::DispatchBackgroundFetchClickEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_OUT);
+
+  WaitUntilObserver* observer = WaitUntilObserver::Create(
+      this, WaitUntilObserver::kBackgroundFetchClick, event_id);
+
+  BackgroundFetchEventInit* init = BackgroundFetchEventInit::Create();
+  init->setRegistration(MakeGarbageCollected<BackgroundFetchRegistration>(
+      registration_, std::move(registration)));
+
+  BackgroundFetchEvent* event = BackgroundFetchEvent::Create(
+      event_type_names::kBackgroundfetchclick, init, observer);
+
+  DispatchExtendableEvent(event, observer);
+}
+
+void ServiceWorkerGlobalScope::DispatchBackgroundFetchFailEvent(
+    mojom::blink::BackgroundFetchRegistrationPtr registration,
+    DispatchBackgroundFetchFailEventCallback callback) {
+  DCHECK(IsContextThread());
+  int event_id = timeout_timer_->StartEvent(
+      CreateAbortCallback(&background_fetch_fail_event_callbacks_));
+  background_fetch_fail_event_callbacks_.Set(event_id, std::move(callback));
+  TRACE_EVENT_WITH_FLOW0(
+      "ServiceWorker",
+      "ServiceWorkerGlobalScope::DispatchBackgroundFetchFailEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_OUT);
+
+  WaitUntilObserver* observer = WaitUntilObserver::Create(
+      this, WaitUntilObserver::kBackgroundFetchFail, event_id);
+
+  ScriptState* script_state = ScriptController()->GetScriptState();
+
+  // Do not remove this, |scope| is needed by
+  // BackgroundFetchSettledEvent::Create which eventually calls ToV8.
+  ScriptState::Scope scope(script_state);
+
+  BackgroundFetchEventInit* init = BackgroundFetchEventInit::Create();
+  init->setRegistration(MakeGarbageCollected<BackgroundFetchRegistration>(
+      registration_, std::move(registration)));
+
+  BackgroundFetchUpdateUIEvent* event = BackgroundFetchUpdateUIEvent::Create(
+      event_type_names::kBackgroundfetchfail, init, observer, registration_);
+
+  DispatchExtendableEvent(event, observer);
+}
+
+void ServiceWorkerGlobalScope::DispatchBackgroundFetchSuccessEvent(
+    mojom::blink::BackgroundFetchRegistrationPtr registration,
+    DispatchBackgroundFetchSuccessEventCallback callback) {
+  DCHECK(IsContextThread());
+  int event_id = timeout_timer_->StartEvent(
+      CreateAbortCallback(&background_fetched_event_callbacks_));
+  background_fetched_event_callbacks_.Set(event_id, std::move(callback));
+  TRACE_EVENT_WITH_FLOW0(
+      "ServiceWorker",
+      "ServiceWorkerGlobalScope::DispatchBackgroundFetchSuccessEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_OUT);
+
+  WaitUntilObserver* observer = WaitUntilObserver::Create(
+      this, WaitUntilObserver::kBackgroundFetchSuccess, event_id);
+
+  ScriptState* script_state = ScriptController()->GetScriptState();
+
+  // Do not remove this, |scope| is needed by
+  // BackgroundFetchSettledEvent::Create which eventually calls ToV8.
+  ScriptState::Scope scope(script_state);
+
+  BackgroundFetchEventInit* init = BackgroundFetchEventInit::Create();
+  init->setRegistration(MakeGarbageCollected<BackgroundFetchRegistration>(
+      registration_, std::move(registration)));
+
+  BackgroundFetchUpdateUIEvent* event = BackgroundFetchUpdateUIEvent::Create(
+      event_type_names::kBackgroundfetchsuccess, init, observer, registration_);
+
+  DispatchExtendableEvent(event, observer);
+}
+
+void ServiceWorkerGlobalScope::DispatchExtendableMessageEvent(
+    mojom::blink::ExtendableMessageEventPtr event,
+    DispatchExtendableMessageEventCallback callback) {
+  DCHECK(IsContextThread());
+  int event_id = timeout_timer_->StartEvent(
+      CreateAbortCallback(&message_event_callbacks_));
+  message_event_callbacks_.Set(event_id, std::move(callback));
+  TRACE_EVENT_WITH_FLOW0(
+      "ServiceWorker",
+      "ServiceWorkerGlobalScope::DispatchExtendableMessageEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_OUT);
+  DispatchExtendableMessageEventInternal(event_id, std::move(event));
+}
+
+void ServiceWorkerGlobalScope::DispatchExtendableMessageEventWithCustomTimeout(
+    mojom::blink::ExtendableMessageEventPtr event,
+    base::TimeDelta timeout,
+    DispatchExtendableMessageEventCallback callback) {
+  DCHECK(IsContextThread());
+  int event_id = timeout_timer_->StartEventWithCustomTimeout(
+      CreateAbortCallback(&message_event_callbacks_), timeout);
+  message_event_callbacks_.Set(event_id, std::move(callback));
+  TRACE_EVENT_WITH_FLOW0(
+      "ServiceWorker",
+      "ServiceWorkerGlobalScope::"
+      "DispatchExtendableMessageEventWithCustomTimeout",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_OUT);
+  DispatchExtendableMessageEventInternal(event_id, std::move(event));
+}
+
+void ServiceWorkerGlobalScope::DispatchFetchEvent(
+    mojom::blink::DispatchFetchEventParamsPtr params,
+    mojom::blink::ServiceWorkerFetchResponseCallbackPtr response_callback,
+    DispatchFetchEventCallback callback) {
+  DCHECK(IsContextThread());
+  int event_id =
+      timeout_timer_->StartEvent(CreateAbortCallback(&fetch_event_callbacks_));
+  fetch_event_callbacks_.Set(event_id, std::move(callback));
+  fetch_response_callbacks_.Set(event_id, std::move(response_callback));
+
+  // This TRACE_EVENT is used for perf benchmark to confirm if all of fetch
+  // events have completed. (crbug.com/736697)
+  TRACE_EVENT_WITH_FLOW1(
+      "ServiceWorker", "ServiceWorkerGlobalScope::DispatchFetchEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_OUT, "url",
+      params->request->url.ElidedString().Utf8().data());
+
+  // Set up for navigation preload (FetchEvent#preloadResponse) if needed.
+  const bool navigation_preload_sent = !!params->preload_handle;
+  if (navigation_preload_sent) {
+    ServiceWorkerGlobalScopeClient::From(GetExecutionContext())
+        ->SetupNavigationPreload(event_id, params->request->url,
+                                 std::move(params->preload_handle));
+  }
+
+  mojom::blink::FetchAPIRequest& fetch_request = *params->request;
+  ScriptState::Scope scope(ScriptController()->GetScriptState());
+  WaitUntilObserver* wait_until_observer =
+      WaitUntilObserver::Create(this, WaitUntilObserver::kFetch, event_id);
+  FetchRespondWithObserver* respond_with_observer =
+      FetchRespondWithObserver::Create(
+          this, event_id, fetch_request.url, fetch_request.mode,
+          fetch_request.redirect_mode, fetch_request.frame_type,
+          fetch_request.request_context_type, wait_until_observer);
+  Request* request =
+      Request::Create(ScriptController()->GetScriptState(), fetch_request,
+                      Request::ForServiceWorkerFetchEvent::kTrue);
+  request->getHeaders()->SetGuard(Headers::kImmutableGuard);
+  FetchEventInit* event_init = FetchEventInit::Create();
+  event_init->setCancelable(true);
+  event_init->setRequest(request);
+  event_init->setClientId(
+      fetch_request.is_main_resource_load ? String() : params->client_id);
+  event_init->setResultingClientId(
+      !fetch_request.is_main_resource_load ? String() : params->client_id);
+  event_init->setIsReload(fetch_request.is_reload);
+  ScriptState* script_state = ScriptController()->GetScriptState();
+  FetchEvent* fetch_event = FetchEvent::Create(
+      script_state, event_type_names::kFetch, event_init, respond_with_observer,
+      wait_until_observer, navigation_preload_sent);
+  if (navigation_preload_sent) {
+    // Keep |fetchEvent| until OnNavigationPreloadComplete() or
+    // onNavigationPreloadError() will be called.
+    pending_preload_fetch_events_.insert(event_id, fetch_event);
+  }
+
+  DispatchExtendableEventWithRespondWith(fetch_event, wait_until_observer,
+                                         respond_with_observer);
+}
+
+void ServiceWorkerGlobalScope::DispatchNotificationClickEvent(
+    const String& notification_id,
+    mojom::blink::NotificationDataPtr notification_data,
+    int action_index,
+    const String& reply,
+    DispatchNotificationClickEventCallback callback) {
+  DCHECK(IsContextThread());
+  int event_id = timeout_timer_->StartEvent(
+      CreateAbortCallback(&notification_click_event_callbacks_));
+  notification_click_event_callbacks_.Set(event_id, std::move(callback));
+  TRACE_EVENT_WITH_FLOW0(
+      "ServiceWorker",
+      "ServiceWorkerGlobalScope::DispatchNotificationClickEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_OUT);
+
+  WaitUntilObserver* observer = WaitUntilObserver::Create(
+      this, WaitUntilObserver::kNotificationClick, event_id);
+  NotificationEventInit* event_init = NotificationEventInit::Create();
+  if (notification_data->actions.has_value() && 0 <= action_index &&
+      action_index < static_cast<int>(notification_data->actions->size())) {
+    event_init->setAction((*notification_data->actions)[action_index]->action);
+  }
+  event_init->setNotification(Notification::Create(
+      this, notification_id, std::move(notification_data), true /* showing */));
+  event_init->setReply(reply);
+  Event* event = NotificationEvent::Create(event_type_names::kNotificationclick,
+                                           event_init, observer);
+  DispatchExtendableEvent(event, observer);
+}
+
+void ServiceWorkerGlobalScope::DispatchNotificationCloseEvent(
+    const String& notification_id,
+    mojom::blink::NotificationDataPtr notification_data,
+    DispatchNotificationCloseEventCallback callback) {
+  DCHECK(IsContextThread());
+  int event_id = timeout_timer_->StartEvent(
+      CreateAbortCallback(&notification_close_event_callbacks_));
+  notification_close_event_callbacks_.Set(event_id, std::move(callback));
+  TRACE_EVENT_WITH_FLOW0(
+      "ServiceWorker",
+      "ServiceWorkerGlobalScope::DispatchNotificationCloseEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_OUT);
+  WaitUntilObserver* observer = WaitUntilObserver::Create(
+      this, WaitUntilObserver::kNotificationClose, event_id);
+  NotificationEventInit* event_init = NotificationEventInit::Create();
+  event_init->setAction(WTF::String());  // initialize as null.
+  event_init->setNotification(Notification::Create(this, notification_id,
+                                                   std::move(notification_data),
+                                                   false /* showing */));
+  Event* event = NotificationEvent::Create(event_type_names::kNotificationclose,
+                                           event_init, observer);
+  DispatchExtendableEvent(event, observer);
+}
+
+void ServiceWorkerGlobalScope::DispatchPushEvent(
+    const String& payload,
+    DispatchPushEventCallback callback) {
+  DCHECK(IsContextThread());
+  int event_id = timeout_timer_->StartEventWithCustomTimeout(
+      CreateAbortCallback(&push_event_callbacks_),
+      base::TimeDelta::FromSeconds(mojom::blink::kPushEventTimeoutSeconds));
+  push_event_callbacks_.Set(event_id, std::move(callback));
+  TRACE_EVENT_WITH_FLOW0(
+      "ServiceWorker", "ServiceWorkerGlobalScope::DispatchPushEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_OUT);
+
+  WaitUntilObserver* observer =
+      WaitUntilObserver::Create(this, WaitUntilObserver::kPush, event_id);
+  Event* event = PushEvent::Create(event_type_names::kPush,
+                                   PushMessageData::Create(payload), observer);
+  DispatchExtendableEvent(event, observer);
+}
+
+void ServiceWorkerGlobalScope::DispatchSyncEvent(
+    const String& tag,
+    bool last_chance,
+    base::TimeDelta timeout,
+    DispatchSyncEventCallback callback) {
+  DCHECK(IsContextThread());
+  int event_id = timeout_timer_->StartEventWithCustomTimeout(
+      CreateAbortCallback(&sync_event_callbacks_), timeout);
+  sync_event_callbacks_.Set(event_id, std::move(callback));
+  TRACE_EVENT_WITH_FLOW0(
+      "ServiceWorker", "ServiceWorkerGlobalScope::DispatchSyncEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_OUT);
+
+  WaitUntilObserver* observer =
+      WaitUntilObserver::Create(this, WaitUntilObserver::kSync, event_id);
+  Event* event =
+      SyncEvent::Create(event_type_names::kSync, tag, last_chance, observer);
+  DispatchExtendableEvent(event, observer);
+}
+
+void ServiceWorkerGlobalScope::DispatchPeriodicSyncEvent(
+    const String& tag,
+    base::TimeDelta timeout,
+    DispatchPeriodicSyncEventCallback callback) {
+  DCHECK(IsContextThread());
+  int event_id = timeout_timer_->StartEventWithCustomTimeout(
+      CreateAbortCallback(&periodic_sync_event_callbacks_), timeout);
+  periodic_sync_event_callbacks_.Set(event_id, std::move(callback));
+  TRACE_EVENT_WITH_FLOW0(
+      "ServiceWorker", "ServiceWorkerGlobalScope::DispatchPeriodicSyncEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_OUT);
+
+  WaitUntilObserver* observer = WaitUntilObserver::Create(
+      this, WaitUntilObserver::kPeriodicSync, event_id);
+  Event* event =
+      PeriodicSyncEvent::Create(event_type_names::kPeriodicsync, tag, observer);
+  DispatchExtendableEvent(event, observer);
+}
+
+void ServiceWorkerGlobalScope::DispatchAbortPaymentEvent(
+    payments::mojom::blink::PaymentHandlerResponseCallbackPtr response_callback,
+    DispatchAbortPaymentEventCallback callback) {
+  DCHECK(IsContextThread());
+  int event_id = timeout_timer_->StartEvent(
+      CreateAbortCallback(&abort_payment_event_callbacks_));
+  abort_payment_event_callbacks_.Set(event_id, std::move(callback));
+  abort_payment_result_callbacks_.Set(event_id, std::move(response_callback));
+  TRACE_EVENT_WITH_FLOW0(
+      "ServiceWorker", "ServiceWorkerGlobalScope::DispatchAbortPaymentEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_OUT);
+
+  WaitUntilObserver* wait_until_observer = WaitUntilObserver::Create(
+      this, WaitUntilObserver::kAbortPayment, event_id);
+  AbortPaymentRespondWithObserver* respond_with_observer =
+      MakeGarbageCollected<AbortPaymentRespondWithObserver>(
+          this, event_id, wait_until_observer);
+
+  Event* event = AbortPaymentEvent::Create(
+      event_type_names::kAbortpayment, ExtendableEventInit::Create(),
+      respond_with_observer, wait_until_observer);
+
+  DispatchExtendableEventWithRespondWith(event, wait_until_observer,
+                                         respond_with_observer);
+}
+
+void ServiceWorkerGlobalScope::DispatchCanMakePaymentEvent(
+    payments::mojom::blink::CanMakePaymentEventDataPtr event_data,
+    payments::mojom::blink::PaymentHandlerResponseCallbackPtr response_callback,
+    DispatchCanMakePaymentEventCallback callback) {
+  DCHECK(IsContextThread());
+  int event_id = timeout_timer_->StartEvent(
+      CreateAbortCallback(&can_make_payment_event_callbacks_));
+  can_make_payment_event_callbacks_.Set(event_id, std::move(callback));
+  can_make_payment_result_callbacks_.Set(event_id,
+                                         std::move(response_callback));
+  TRACE_EVENT_WITH_FLOW0(
+      "ServiceWorker", "ServiceWorkerGlobalScope::DispatchCanMakePaymentEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_OUT);
+
+  WaitUntilObserver* wait_until_observer = WaitUntilObserver::Create(
+      this, WaitUntilObserver::kCanMakePayment, event_id);
+  CanMakePaymentRespondWithObserver* respond_with_observer =
+      MakeGarbageCollected<CanMakePaymentRespondWithObserver>(
+          this, event_id, wait_until_observer);
+
+  Event* event = CanMakePaymentEvent::Create(
+      event_type_names::kCanmakepayment,
+      PaymentEventDataConversion::ToCanMakePaymentEventInit(
+          ScriptController()->GetScriptState(), std::move(event_data)),
+      respond_with_observer, wait_until_observer);
+
+  DispatchExtendableEventWithRespondWith(event, wait_until_observer,
+                                         respond_with_observer);
+}
+
+void ServiceWorkerGlobalScope::DispatchPaymentRequestEvent(
+    payments::mojom::blink::PaymentRequestEventDataPtr event_data,
+    payments::mojom::blink::PaymentHandlerResponseCallbackPtr response_callback,
+    DispatchPaymentRequestEventCallback callback) {
+  DCHECK(IsContextThread());
+  int event_id = timeout_timer_->StartEvent(
+      CreateAbortCallback(&payment_request_event_callbacks_));
+  payment_request_event_callbacks_.Set(event_id, std::move(callback));
+  payment_response_callbacks_.Set(event_id, std::move(response_callback));
+  TRACE_EVENT_WITH_FLOW0(
+      "ServiceWorker", "ServiceWorkerGlobalScope::DispatchPaymentRequestEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_OUT);
+
+  WaitUntilObserver* wait_until_observer = WaitUntilObserver::Create(
+      this, WaitUntilObserver::kPaymentRequest, event_id);
+  PaymentRequestRespondWithObserver* respond_with_observer =
+      PaymentRequestRespondWithObserver::Create(this, event_id,
+                                                wait_until_observer);
+  payments::mojom::blink::PaymentHandlerHostPtrInfo payment_handler_host =
+      std::move(event_data->payment_handler_host);
+  Event* event = PaymentRequestEvent::Create(
+      event_type_names::kPaymentrequest,
+      PaymentEventDataConversion::ToPaymentRequestEventInit(
+          ScriptController()->GetScriptState(), std::move(event_data)),
+      std::move(payment_handler_host), respond_with_observer,
+      wait_until_observer);
+
+  DispatchExtendableEventWithRespondWith(event, wait_until_observer,
+                                         respond_with_observer);
+}
+
+void ServiceWorkerGlobalScope::DispatchCookieChangeEvent(
+    const WebCanonicalCookie& cookie,
+    ::network::mojom::CookieChangeCause change_cause,
+    DispatchCookieChangeEventCallback callback) {
+  DCHECK(IsContextThread());
+  int event_id = timeout_timer_->StartEvent(
+      CreateAbortCallback(&cookie_change_event_callbacks_));
+  cookie_change_event_callbacks_.Set(event_id, std::move(callback));
+  TRACE_EVENT_WITH_FLOW0(
+      "ServiceWorker", "ServiceWorkerGlobalScope::DispatchCookieChangeEvent",
+      TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
+                          TRACE_ID_LOCAL(event_id)),
+      TRACE_EVENT_FLAG_FLOW_OUT);
+
+  WaitUntilObserver* observer = WaitUntilObserver::Create(
+      this, WaitUntilObserver::kCookieChange, event_id);
+
+  HeapVector<Member<CookieListItem>> changed;
+  HeapVector<Member<CookieListItem>> deleted;
+  CookieChangeEvent::ToEventInfo(cookie, change_cause, changed, deleted);
+  Event* event = ExtendableCookieChangeEvent::Create(
+      event_type_names::kCookiechange, std::move(changed), std::move(deleted),
+      observer);
+
+  // TODO(pwnall): Handle handle the case when
+  //               (changed.IsEmpty() && deleted.IsEmpty()).
+
+  // TODO(pwnall): Investigate dispatching this on cookieStore.
+  DispatchExtendableEvent(event, observer);
+}
+
+void ServiceWorkerGlobalScope::Ping(PingCallback callback) {
+  DCHECK(IsContextThread());
+  std::move(callback).Run();
+}
+
+void ServiceWorkerGlobalScope::SetIdleTimerDelayToZero() {
+  DCHECK(IsContextThread());
+  DCHECK(timeout_timer_);
+  timeout_timer_->SetIdleTimerDelayToZero();
 }
 
 }  // namespace blink
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 bd8b5d0..e31d1e2 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
@@ -31,7 +31,9 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_SERVICE_WORKER_GLOBAL_SCOPE_H_
 
 #include <memory>
+#include "mojo/public/cpp/bindings/binding.h"
 #include "third_party/blink/public/mojom/cache_storage/cache_storage.mojom-blink.h"
+#include "third_party/blink/public/mojom/service_worker/controller_service_worker.mojom-blink.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/request_or_usv_string.h"
 #include "third_party/blink/renderer/core/workers/worker_global_scope.h"
@@ -42,7 +44,9 @@
 
 namespace blink {
 
+class ControllerServiceWorker;
 class ExceptionState;
+class FetchEvent;
 class RespondWithObserver;
 class RequestInit;
 class ScriptPromise;
@@ -51,16 +55,21 @@
 class ServiceWorkerClients;
 class ServiceWorkerRegistration;
 class ServiceWorkerThread;
+class ServiceWorkerTimeoutTimer;
 class StringOrTrustedScriptURL;
 class WaitUntilObserver;
+class WebServiceWorkerStreamHandle;
+class WebURLResponse;
 class WorkerClassicScriptLoader;
 struct GlobalScopeCreationParams;
+struct WebServiceWorkerError;
 struct WebServiceWorkerObjectInfo;
-struct WebServiceWorkerRegistrationObjectInfo;
 
 typedef RequestOrUSVString RequestInfo;
 
-class MODULES_EXPORT ServiceWorkerGlobalScope final : public WorkerGlobalScope {
+class MODULES_EXPORT ServiceWorkerGlobalScope final
+    : public WorkerGlobalScope,
+      public mojom::blink::ServiceWorker {
   DEFINE_WRAPPERTYPEINFO();
 
  public:
@@ -137,14 +146,37 @@
 
   ScriptPromise skipWaiting(ScriptState*);
 
-  void BindServiceWorkerHost(mojom::blink::ServiceWorkerHostAssociatedPtrInfo);
+  void BindServiceWorker(mojom::blink::ServiceWorkerRequest);
+  void BindControllerServiceWorker(
+      mojom::blink::ControllerServiceWorkerRequest);
+  void OnNavigationPreloadResponse(
+      int fetch_event_id,
+      std::unique_ptr<WebURLResponse>,
+      mojo::ScopedDataPipeConsumerHandle data_pipe);
+  void OnNavigationPreloadError(int fetch_event_id,
+                                std::unique_ptr<WebServiceWorkerError>);
+  void OnNavigationPreloadComplete(int fetch_event_id,
+                                   TimeTicks completion_time,
+                                   int64_t encoded_data_length,
+                                   int64_t encoded_body_length,
+                                   int64_t decoded_body_length);
 
-  void SetRegistration(WebServiceWorkerRegistrationObjectInfo info);
-  void SetFetchHandlerExistence(FetchHandlerExistence fetch_handler_existence);
+  // Dispatches the fetch event if the worker is running normally, and queues it
+  // instead if the worker has already requested to be terminated by the
+  // browser. If queued, the event will be dispatched once the worker resumes
+  // normal operation (if the browser decides not to terminate it, and instead
+  // starts another event), or else is dropped if the worker is terminated.
+  //
+  // This method needs to be used only if the event comes directly from a
+  // client, which means it is coming through the ControllerServiceWorker.
+  void DispatchOrQueueFetchEvent(
+      mojom::blink::DispatchFetchEventParamsPtr params,
+      mojom::blink::ServiceWorkerFetchResponseCallbackPtr response_callback,
+      DispatchFetchEventCallback callback);
 
   // Returns the ServiceWorker object described by the given info. Creates a new
   // object if needed, or else returns the existing one.
-  ServiceWorker* GetOrCreateServiceWorker(WebServiceWorkerObjectInfo);
+  ::blink::ServiceWorker* GetOrCreateServiceWorker(WebServiceWorkerObjectInfo);
 
   // EventTarget
   const AtomicString& InterfaceName() const override;
@@ -159,16 +191,94 @@
   bool IsInstalling() const { return is_installing_; }
   void SetIsInstalling(bool is_installing);
 
-  // Script evaluation does not start until this function is called.
-  void ReadyToEvaluateScript();
-
   void CountCacheStorageInstalledScript(uint64_t script_size,
                                         uint64_t script_metadata_size);
 
+  void DidHandleInstallEvent(int install_event_id,
+                             mojom::ServiceWorkerEventStatus);
+  void DidHandleActivateEvent(int event_id, mojom::ServiceWorkerEventStatus);
+  void DidHandleBackgroundFetchAbortEvent(int event_id,
+                                          mojom::ServiceWorkerEventStatus);
+  void DidHandleBackgroundFetchClickEvent(int event_id,
+                                          mojom::ServiceWorkerEventStatus);
+  void DidHandleBackgroundFetchFailEvent(int event_id,
+                                         mojom::ServiceWorkerEventStatus);
+  void DidHandleBackgroundFetchSuccessEvent(int event_id,
+                                            mojom::ServiceWorkerEventStatus);
+  void DidHandleExtendableMessageEvent(int event_id,
+                                       mojom::ServiceWorkerEventStatus);
+
+  // RespondToFetchEvent* will be called after the service worker returns a
+  // response to a FetchEvent, and DidHandleFetchEvent will be called after the
+  // end of FetchEvent's lifecycle. |fetch_event_id| is the id that was passed
+  // to DispatchFetchEvent.
+
+  // Used when respondWith() is not called. Tells the browser to fall back to
+  // native fetch.
+  void RespondToFetchEventWithNoResponse(
+      int fetch_event_id,
+      base::TimeTicks event_dispatch_time,
+      base::TimeTicks respond_with_settled_time);
+  // Responds to the fetch event with |response|.
+  void RespondToFetchEvent(int fetch_event_id,
+                           mojom::blink::FetchAPIResponsePtr,
+                           base::TimeTicks event_dispatch_time,
+                           base::TimeTicks respond_with_settled_time);
+  // Responds to the fetch event with |response|, where body is
+  // |body_as_stream|.
+  void RespondToFetchEventWithResponseStream(
+      int fetch_event_id,
+      mojom::blink::FetchAPIResponsePtr,
+      WebServiceWorkerStreamHandle*,
+      base::TimeTicks event_dispatch_time,
+      base::TimeTicks respond_with_settled_time);
+
+  // RespondToAbortPaymentEvent will be called after the service worker
+  // returns a response to a AbortPaymentEvent, and DidHandleAbortPaymentEvent
+  // will be called after the end of AbortPaymentEvent's lifecycle.
+  // |event_id| is the id that was passed to DispatchAbortPaymentEvent.
+  void RespondToAbortPaymentEvent(int event_id, bool abort_payment);
+  // RespondToCanMakePaymentEvent will be called after the service worker
+  // returns a response to a CanMakePaymentEvent, and
+  // DidHandleCanMakePaymentEvent will be called after the end of
+  // CanMakePaymentEvent's lifecycle. |event_id| is the id that was passed
+  // to DispatchCanMakePaymentEvent.
+  void RespondToCanMakePaymentEvent(int event_id, bool can_make_payment);
+  // RespondToPaymentRequestEvent will be called after the service worker
+  // returns a response to a PaymentRequestEvent, and
+  // DidHandlePaymentRequestEvent will be called after the end of
+  // PaymentRequestEvent's lifecycle. |event_id| is the id that was passed
+  // to DispatchPaymentRequestEvent.
+  void RespondToPaymentRequestEvent(
+      int event_id,
+      payments::mojom::blink::PaymentHandlerResponsePtr);
+  void DidHandleFetchEvent(int fetch_event_id, mojom::ServiceWorkerEventStatus);
+  void DidHandleNotificationClickEvent(int event_id,
+                                       mojom::ServiceWorkerEventStatus);
+  void DidHandleNotificationCloseEvent(int event_id,
+                                       mojom::ServiceWorkerEventStatus);
+  void DidHandlePushEvent(int push_event_id, mojom::ServiceWorkerEventStatus);
+  void DidHandleSyncEvent(int sync_event_id, mojom::ServiceWorkerEventStatus);
+  void DidHandlePeriodicSyncEvent(int event_id,
+                                  mojom::ServiceWorkerEventStatus status);
+  void DidHandleAbortPaymentEvent(int abort_payment_event_id,
+                                  mojom::ServiceWorkerEventStatus);
+  void DidHandleCanMakePaymentEvent(int payment_request_event_id,
+                                    mojom::ServiceWorkerEventStatus);
+  void DidHandlePaymentRequestEvent(int payment_request_event_id,
+                                    mojom::ServiceWorkerEventStatus);
+  void DidHandleCookieChangeEvent(int event_id,
+                                  mojom::ServiceWorkerEventStatus);
+
   mojom::blink::CacheStoragePtrInfo TakeCacheStorage();
 
-  // See the functions of the same name in WebServiceWorkerContextClient.
+  // Called when a task is going to be scheduled on the service worker.
+  // The service worker shouldn't request to be terminated until the task is
+  // finished. Returns an id for the task. The caller must call DidEndTask()
+  // with the returned id to notify that the task is finished.
   int WillStartTask();
+  // Called when a task is finished. |task_id| must be a return value of
+  // WillStartTask().
   void DidEndTask(int task_id);
 
   DEFINE_ATTRIBUTE_EVENT_LISTENER(install, kInstall)
@@ -212,12 +322,99 @@
   // number of scripts and the total bytes of scripts.
   void CountScriptInternal(size_t script_size, size_t cached_metadata_size);
 
+  // Called by ServiceWorkerTimeoutTimer when a certain time has passed since
+  // the last task finished.
+  void OnIdleTimeout();
+
+  void OnRequestedTermination(bool will_be_terminated);
+
+  // Returns true if the worker has requested to be terminated by the browser
+  // process. It does this due to idle timeout.
+  bool RequestedTermination() const;
+
+  void DispatchExtendableMessageEventInternal(
+      int event_id,
+      mojom::blink::ExtendableMessageEventPtr event);
+
+  void SetFetchHandlerExistence(FetchHandlerExistence fetch_handler_existence);
+
+  // Implements mojom::blink::ServiceWorker.
+  void InitializeGlobalScope(
+      mojom::blink::ServiceWorkerHostAssociatedPtrInfo service_worker_host,
+      mojom::blink::ServiceWorkerRegistrationObjectInfoPtr registration_info,
+      mojom::blink::FetchHandlerExistence fetch_hander_existence) override;
+  void DispatchInstallEvent(DispatchInstallEventCallback callback) override;
+  void DispatchActivateEvent(DispatchActivateEventCallback callback) override;
+  void DispatchBackgroundFetchAbortEvent(
+      mojom::blink::BackgroundFetchRegistrationPtr registration,
+      DispatchBackgroundFetchAbortEventCallback callback) override;
+  void DispatchBackgroundFetchClickEvent(
+      mojom::blink::BackgroundFetchRegistrationPtr registration,
+      DispatchBackgroundFetchClickEventCallback callback) override;
+  void DispatchBackgroundFetchFailEvent(
+      mojom::blink::BackgroundFetchRegistrationPtr registration,
+      DispatchBackgroundFetchFailEventCallback callback) override;
+  void DispatchBackgroundFetchSuccessEvent(
+      mojom::blink::BackgroundFetchRegistrationPtr registration,
+      DispatchBackgroundFetchSuccessEventCallback callback) override;
+  void DispatchExtendableMessageEvent(
+      mojom::blink::ExtendableMessageEventPtr event,
+      DispatchExtendableMessageEventCallback callback) override;
+  void DispatchExtendableMessageEventWithCustomTimeout(
+      mojom::blink::ExtendableMessageEventPtr event,
+      base::TimeDelta timeout,
+      DispatchExtendableMessageEventCallback callback) override;
+  void DispatchFetchEvent(
+      mojom::blink::DispatchFetchEventParamsPtr params,
+      mojom::blink::ServiceWorkerFetchResponseCallbackPtr response_callback,
+      DispatchFetchEventCallback callback) override;
+  void DispatchNotificationClickEvent(
+      const String& notification_id,
+      mojom::blink::NotificationDataPtr notification_data,
+      int action_index,
+      const String& reply,
+      DispatchNotificationClickEventCallback callback) override;
+  void DispatchNotificationCloseEvent(
+      const String& notification_id,
+      mojom::blink::NotificationDataPtr notification_data,
+      DispatchNotificationCloseEventCallback callback) override;
+  void DispatchPushEvent(const String& payload,
+                         DispatchPushEventCallback callback) override;
+  void DispatchSyncEvent(const String& tag,
+                         bool last_chance,
+                         base::TimeDelta timeout,
+                         DispatchSyncEventCallback callback) override;
+  void DispatchPeriodicSyncEvent(
+      const String& tag,
+      base::TimeDelta timeout,
+      DispatchPeriodicSyncEventCallback callback) override;
+  void DispatchAbortPaymentEvent(
+      payments::mojom::blink::PaymentHandlerResponseCallbackPtr
+          response_callback,
+      DispatchAbortPaymentEventCallback callback) override;
+  void DispatchCanMakePaymentEvent(
+      payments::mojom::blink::CanMakePaymentEventDataPtr event_data,
+      payments::mojom::blink::PaymentHandlerResponseCallbackPtr
+          response_callback,
+      DispatchCanMakePaymentEventCallback callback) override;
+  void DispatchPaymentRequestEvent(
+      payments::mojom::blink::PaymentRequestEventDataPtr event_data,
+      payments::mojom::blink::PaymentHandlerResponseCallbackPtr
+          response_callback,
+      DispatchPaymentRequestEventCallback callback) override;
+  void DispatchCookieChangeEvent(
+      const WebCanonicalCookie& cookie,
+      ::network::mojom::blink::CookieChangeCause cause,
+      DispatchCookieChangeEventCallback callback) override;
+  void Ping(PingCallback callback) override;
+  void SetIdleTimerDelayToZero() override;
+
   Member<ServiceWorkerClients> clients_;
   Member<ServiceWorkerRegistration> registration_;
   // Map from service worker version id to JavaScript ServiceWorker object in
   // current execution context.
   HeapHashMap<int64_t,
-              WeakMember<ServiceWorker>,
+              WeakMember<::blink::ServiceWorker>,
               WTF::IntHash<int64_t>,
               WTF::UnsignedWithZeroKeyHashTraits<int64_t>>
       service_worker_objects_;
@@ -234,6 +431,64 @@
   // doesn't need to be used. Taken at the initial call to
   // ServiceWorkerGlobalScope#caches.
   mojom::blink::CacheStoragePtrInfo cache_storage_info_;
+
+  mojo::Binding<mojom::blink::ServiceWorker> binding_;
+
+  // Maps for inflight event callbacks.
+  // These are mapped from an event id issued from ServiceWorkerTimeoutTimer to
+  // the Mojo callback to notify the end of the event.
+  HashMap<int, DispatchInstallEventCallback> install_event_callbacks_;
+  HashMap<int, DispatchActivateEventCallback> activate_event_callbacks_;
+  HashMap<int, DispatchBackgroundFetchAbortEventCallback>
+      background_fetch_abort_event_callbacks_;
+  HashMap<int, DispatchBackgroundFetchClickEventCallback>
+      background_fetch_click_event_callbacks_;
+  HashMap<int, DispatchBackgroundFetchFailEventCallback>
+      background_fetch_fail_event_callbacks_;
+  HashMap<int, DispatchBackgroundFetchSuccessEventCallback>
+      background_fetched_event_callbacks_;
+  HashMap<int, DispatchSyncEventCallback> sync_event_callbacks_;
+  HashMap<int, DispatchPeriodicSyncEventCallback>
+      periodic_sync_event_callbacks_;
+  HashMap<int, payments::mojom::blink::PaymentHandlerResponseCallbackPtr>
+      abort_payment_result_callbacks_;
+  HashMap<int, DispatchCanMakePaymentEventCallback>
+      abort_payment_event_callbacks_;
+  HashMap<int, DispatchCanMakePaymentEventCallback>
+      can_make_payment_event_callbacks_;
+  HashMap<int, DispatchPaymentRequestEventCallback>
+      payment_request_event_callbacks_;
+  HashMap<int, DispatchNotificationClickEventCallback>
+      notification_click_event_callbacks_;
+  HashMap<int, DispatchNotificationCloseEventCallback>
+      notification_close_event_callbacks_;
+  HashMap<int, DispatchPushEventCallback> push_event_callbacks_;
+  HashMap<int, DispatchFetchEventCallback> fetch_event_callbacks_;
+  HashMap<int, DispatchCookieChangeEventCallback>
+      cookie_change_event_callbacks_;
+  HashMap<int, DispatchExtendableMessageEventCallback> message_event_callbacks_;
+
+  // Maps for response callbacks.
+  // These are mapped from an event id to the Mojo interface pointer which is
+  // passed from the relevant DispatchSomeEvent() method.
+  HashMap<int, payments::mojom::blink::PaymentHandlerResponseCallbackPtr>
+      can_make_payment_result_callbacks_;
+  HashMap<int, payments::mojom::blink::PaymentHandlerResponseCallbackPtr>
+      payment_response_callbacks_;
+  HashMap<int, mojom::blink::ServiceWorkerFetchResponseCallbackPtr>
+      fetch_response_callbacks_;
+
+  HeapHashMap<int, Member<FetchEvent>> pending_preload_fetch_events_;
+
+  // Timer triggered when the service worker considers it should be stopped or
+  // an event should be aborted.
+  std::unique_ptr<ServiceWorkerTimeoutTimer> timeout_timer_;
+
+  // |controller_| should be destroyed before |timeout_timer_| since the pipe
+  // needs to be disconnected before callbacks passed by DispatchSomeEvent() get
+  // destructed, which may be stored in |timeout_timer_| as parameters of
+  // pending tasks added after a termination request.
+  std::unique_ptr<ControllerServiceWorker> controller_;
 };
 
 template <>
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.cc
index a4ec04b..d5973a7 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.cc
@@ -32,9 +32,7 @@
 
 #include <memory>
 #include <utility>
-#include "third_party/blink/public/platform/modules/payments/web_payment_handler_response.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_error.h"
-#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_response.h"
 #include "third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
@@ -147,154 +145,6 @@
       WTF::Bind(&DidNavigateOrOpenWindow, WrapPersistent(resolver)));
 }
 
-void ServiceWorkerGlobalScopeClient::DidHandleActivateEvent(
-    int event_id,
-    mojom::ServiceWorkerEventStatus status) {
-  client_.DidHandleActivateEvent(event_id, status);
-}
-
-void ServiceWorkerGlobalScopeClient::DidHandleBackgroundFetchAbortEvent(
-    int event_id,
-    mojom::ServiceWorkerEventStatus status) {
-  client_.DidHandleBackgroundFetchAbortEvent(event_id, status);
-}
-
-void ServiceWorkerGlobalScopeClient::DidHandleBackgroundFetchClickEvent(
-    int event_id,
-    mojom::ServiceWorkerEventStatus status) {
-  client_.DidHandleBackgroundFetchClickEvent(event_id, status);
-}
-
-void ServiceWorkerGlobalScopeClient::DidHandleBackgroundFetchFailEvent(
-    int event_id,
-    mojom::ServiceWorkerEventStatus status) {
-  client_.DidHandleBackgroundFetchFailEvent(event_id, status);
-}
-
-void ServiceWorkerGlobalScopeClient::DidHandleBackgroundFetchSuccessEvent(
-    int event_id,
-    mojom::ServiceWorkerEventStatus status) {
-  client_.DidHandleBackgroundFetchSuccessEvent(event_id, status);
-}
-
-void ServiceWorkerGlobalScopeClient::DidHandleCookieChangeEvent(
-    int event_id,
-    mojom::ServiceWorkerEventStatus status) {
-  client_.DidHandleCookieChangeEvent(event_id, status);
-}
-
-void ServiceWorkerGlobalScopeClient::DidHandleExtendableMessageEvent(
-    int event_id,
-    mojom::ServiceWorkerEventStatus status) {
-  client_.DidHandleExtendableMessageEvent(event_id, status);
-}
-
-void ServiceWorkerGlobalScopeClient::RespondToFetchEventWithNoResponse(
-    int fetch_event_id,
-    base::TimeTicks event_dispatch_time,
-    base::TimeTicks respond_with_settled_time) {
-  client_.RespondToFetchEventWithNoResponse(fetch_event_id, event_dispatch_time,
-                                            respond_with_settled_time);
-}
-
-void ServiceWorkerGlobalScopeClient::RespondToFetchEvent(
-    int fetch_event_id,
-    const WebServiceWorkerResponse& response,
-    base::TimeTicks event_dispatch_time,
-    base::TimeTicks respond_with_settled_time) {
-  client_.RespondToFetchEvent(fetch_event_id, response, event_dispatch_time,
-                              respond_with_settled_time);
-}
-
-void ServiceWorkerGlobalScopeClient::RespondToFetchEventWithResponseStream(
-    int fetch_event_id,
-    const WebServiceWorkerResponse& response,
-    WebServiceWorkerStreamHandle* stream_handle,
-    base::TimeTicks event_dispatch_time,
-    base::TimeTicks respond_with_settled_time) {
-  client_.RespondToFetchEventWithResponseStream(
-      fetch_event_id, response, stream_handle, event_dispatch_time,
-      respond_with_settled_time);
-}
-
-void ServiceWorkerGlobalScopeClient::RespondToAbortPaymentEvent(
-    int event_id,
-    bool abort_payment) {
-  client_.RespondToAbortPaymentEvent(event_id, abort_payment);
-}
-
-void ServiceWorkerGlobalScopeClient::RespondToCanMakePaymentEvent(
-    int event_id,
-    bool response) {
-  client_.RespondToCanMakePaymentEvent(event_id, response);
-}
-
-void ServiceWorkerGlobalScopeClient::RespondToPaymentRequestEvent(
-    int event_id,
-    const WebPaymentHandlerResponse& response) {
-  client_.RespondToPaymentRequestEvent(event_id, response);
-}
-
-void ServiceWorkerGlobalScopeClient::DidHandleFetchEvent(
-    int fetch_event_id,
-    mojom::ServiceWorkerEventStatus status) {
-  client_.DidHandleFetchEvent(fetch_event_id, status);
-}
-
-void ServiceWorkerGlobalScopeClient::DidHandleInstallEvent(
-    int install_event_id,
-    mojom::ServiceWorkerEventStatus status) {
-  client_.DidHandleInstallEvent(install_event_id, status);
-}
-
-void ServiceWorkerGlobalScopeClient::DidHandleNotificationClickEvent(
-    int event_id,
-    mojom::ServiceWorkerEventStatus status) {
-  client_.DidHandleNotificationClickEvent(event_id, status);
-}
-
-void ServiceWorkerGlobalScopeClient::DidHandleNotificationCloseEvent(
-    int event_id,
-    mojom::ServiceWorkerEventStatus status) {
-  client_.DidHandleNotificationCloseEvent(event_id, status);
-}
-
-void ServiceWorkerGlobalScopeClient::DidHandlePushEvent(
-    int push_event_id,
-    mojom::ServiceWorkerEventStatus status) {
-  client_.DidHandlePushEvent(push_event_id, status);
-}
-
-void ServiceWorkerGlobalScopeClient::DidHandleSyncEvent(
-    int sync_event_id,
-    mojom::ServiceWorkerEventStatus status) {
-  client_.DidHandleSyncEvent(sync_event_id, status);
-}
-
-void ServiceWorkerGlobalScopeClient::DidHandlePeriodicSyncEvent(
-    int periodic_sync_event_id,
-    mojom::ServiceWorkerEventStatus status) {
-  client_.DidHandlePeriodicSyncEvent(periodic_sync_event_id, status);
-}
-
-void ServiceWorkerGlobalScopeClient::DidHandleAbortPaymentEvent(
-    int abort_payment_event_id,
-    mojom::ServiceWorkerEventStatus status) {
-  client_.DidHandleAbortPaymentEvent(abort_payment_event_id, status);
-}
-
-void ServiceWorkerGlobalScopeClient::DidHandleCanMakePaymentEvent(
-    int payment_request_event_id,
-    mojom::ServiceWorkerEventStatus status) {
-  client_.DidHandleCanMakePaymentEvent(payment_request_event_id, status);
-}
-
-void ServiceWorkerGlobalScopeClient::DidHandlePaymentRequestEvent(
-    int payment_request_event_id,
-    mojom::ServiceWorkerEventStatus status) {
-  client_.DidHandlePaymentRequestEvent(payment_request_event_id, status);
-}
-
 void ServiceWorkerGlobalScopeClient::BindServiceWorkerHost(
     mojom::blink::ServiceWorkerHostAssociatedPtrInfo service_worker_host,
     scoped_refptr<base::SequencedTaskRunner> task_runner) {
@@ -304,18 +154,27 @@
                             std::move(task_runner));
 }
 
+void ServiceWorkerGlobalScopeClient::SetupNavigationPreload(
+    int fetch_event_id,
+    const KURL& url,
+    mojom::blink::FetchEventPreloadHandlePtr preload_handle) {
+  auto web_preload_handle = std::make_unique<WebFetchEventPreloadHandle>();
+  web_preload_handle->url_loader = preload_handle->url_loader.PassHandle();
+  web_preload_handle->url_loader_client_request =
+      preload_handle->url_loader_client_request.PassMessagePipe();
+  client_.SetupNavigationPreload(fetch_event_id, url,
+                                 std::move(web_preload_handle));
+}
+
+void ServiceWorkerGlobalScopeClient::RequestTermination(
+    base::OnceCallback<void(bool)> callback) {
+  client_.RequestTermination(std::move(callback));
+}
+
 void ServiceWorkerGlobalScopeClient::WillDestroyWorkerContext() {
   service_worker_host_.reset();
 }
 
-int ServiceWorkerGlobalScopeClient::WillStartTask() {
-  return client_.WillStartTask();
-}
-
-void ServiceWorkerGlobalScopeClient::DidEndTask(int task_id) {
-  client_.DidEndTask(task_id);
-}
-
 const char ServiceWorkerGlobalScopeClient::kSupplementName[] =
     "ServiceWorkerGlobalScopeClient";
 
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.h b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.h
index c0827a2..9dfa269 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.h
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.h
@@ -37,7 +37,6 @@
 #include "third_party/blink/public/common/messaging/transferable_message.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker.mojom-blink.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom-blink.h"
-#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_stream_handle.h"
 #include "third_party/blink/renderer/core/messaging/message_port.h"
 #include "third_party/blink/renderer/core/workers/worker_clients.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
@@ -45,16 +44,12 @@
 
 namespace blink {
 
-struct WebPaymentHandlerResponse;
 class ExecutionContext;
 class KURL;
 class ScriptPromiseResolver;
 class WebServiceWorkerContextClient;
-class WebServiceWorkerResponse;
 class WorkerClients;
 
-// See WebServiceWorkerContextClient for documentation for the methods in this
-// class.
 class MODULES_EXPORT ServiceWorkerGlobalScopeClient final
     : public GarbageCollectedFinalized<ServiceWorkerGlobalScopeClient>,
       public Supplement<WorkerClients> {
@@ -87,65 +82,18 @@
   void Focus(const String& client_uuid, FocusCallback);
   void Navigate(const String& client_uuid, const KURL&, ScriptPromiseResolver*);
 
-  void DidHandleActivateEvent(int event_id, mojom::ServiceWorkerEventStatus);
-  void DidHandleBackgroundFetchAbortEvent(int event_id,
-                                          mojom::ServiceWorkerEventStatus);
-  void DidHandleBackgroundFetchClickEvent(int event_id,
-                                          mojom::ServiceWorkerEventStatus);
-  void DidHandleBackgroundFetchFailEvent(int event_id,
-                                         mojom::ServiceWorkerEventStatus);
-  void DidHandleBackgroundFetchSuccessEvent(int event_id,
-                                            mojom::ServiceWorkerEventStatus);
-  void DidHandleCookieChangeEvent(int event_id,
-                                  mojom::ServiceWorkerEventStatus);
-  void DidHandleExtendableMessageEvent(int event_id,
-                                       mojom::ServiceWorkerEventStatus);
-  void RespondToFetchEventWithNoResponse(
-      int fetch_event_id,
-      base::TimeTicks event_dispatch_time,
-      base::TimeTicks respond_with_settled_time);
-  void RespondToFetchEvent(int fetch_event_id,
-                           const WebServiceWorkerResponse&,
-                           base::TimeTicks event_dispatch_time,
-                           base::TimeTicks respond_with_settled_time);
-  void RespondToFetchEventWithResponseStream(
-      int fetch_event_id,
-      const WebServiceWorkerResponse&,
-      WebServiceWorkerStreamHandle*,
-      base::TimeTicks event_dispatch_time,
-      base::TimeTicks respond_with_settled_time);
-  void RespondToAbortPaymentEvent(int event_id, bool abort_payment);
-  void RespondToCanMakePaymentEvent(int event_id, bool can_make_payment);
-  void RespondToPaymentRequestEvent(int event_id,
-                                    const WebPaymentHandlerResponse&);
-  void DidHandleFetchEvent(int fetch_event_id, mojom::ServiceWorkerEventStatus);
-  void DidHandleInstallEvent(int install_event_id,
-                             mojom::ServiceWorkerEventStatus);
-  void DidHandleNotificationClickEvent(int event_id,
-                                       mojom::ServiceWorkerEventStatus);
-  void DidHandleNotificationCloseEvent(int event_id,
-                                       mojom::ServiceWorkerEventStatus);
-  void DidHandlePushEvent(int push_event_id, mojom::ServiceWorkerEventStatus);
-  void DidHandleSyncEvent(int sync_event_id,
-                          mojom::ServiceWorkerEventStatus status);
-  void DidHandlePeriodicSyncEvent(int periodic_sync_event_id,
-                                  mojom::ServiceWorkerEventStatus status);
-  void DidHandleAbortPaymentEvent(int abort_payment_event_id,
-                                  mojom::ServiceWorkerEventStatus);
-  void DidHandleCanMakePaymentEvent(int payment_request_event_id,
-                                    mojom::ServiceWorkerEventStatus);
-  void DidHandlePaymentRequestEvent(int payment_request_event_id,
-                                    mojom::ServiceWorkerEventStatus);
-
+  // Called from ServiceWorkerGlobalScope.
   void BindServiceWorkerHost(
       mojom::blink::ServiceWorkerHostAssociatedPtrInfo service_worker_host,
       scoped_refptr<base::SequencedTaskRunner> task_runner);
+  void SetupNavigationPreload(
+      int fetch_event_id,
+      const KURL& url,
+      mojom::blink::FetchEventPreloadHandlePtr preload_handle);
+  void RequestTermination(base::OnceCallback<void(bool)> callback);
 
   void WillDestroyWorkerContext();
 
-  int WillStartTask();
-  void DidEndTask(int task_id);
-
   static ServiceWorkerGlobalScopeClient* From(ExecutionContext*);
 
   void Trace(blink::Visitor*) override;
@@ -155,8 +103,8 @@
 
   // Lives on the service worker thread, is bound by BindServiceWorkerHost()
   // which is triggered by the first Mojo call received on the service worker
-  // thread content::mojom::ServiceWorker::InitializeGlobalScope(), and is
-  // closed by WillDestroyWorkerContext().
+  // thread mojom::blink::ServiceWorker::InitializeGlobalScope(), and is closed
+  // by WillDestroyWorkerContext().
   mojom::blink::ServiceWorkerHostAssociatedPtr service_worker_host_;
 
   DISALLOW_COPY_AND_ASSIGN(ServiceWorkerGlobalScopeClient);
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
index 6c21f5af..2aa22ff 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
@@ -35,14 +35,9 @@
 
 #include "base/memory/ptr_util.h"
 #include "base/trace_event/trace_event.h"
-#include "third_party/blink/public/mojom/notifications/notification.mojom-blink.h"
-#include "third_party/blink/public/mojom/payments/payment_handler_host.mojom-blink.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_client.mojom-blink.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom-blink.h"
-#include "third_party/blink/public/platform/modules/notifications/web_notification_data.h"
-#include "third_party/blink/public/platform/modules/payments/web_payment_request_event_data.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_error.h"
-#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_request.h"
 #include "third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h"
 #include "third_party/blink/public/web/web_serialized_script_value.h"
 #include "third_party/blink/renderer/bindings/core/v8/source_location.h"
@@ -50,42 +45,13 @@
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/fetch/headers.h"
 #include "third_party/blink/renderer/core/inspector/console_message.h"
-#include "third_party/blink/renderer/core/messaging/blink_transferable_message.h"
 #include "third_party/blink/renderer/core/messaging/message_port.h"
 #include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
 #include "third_party/blink/renderer/core/workers/parent_execution_context_task_runners.h"
 #include "third_party/blink/renderer/core/workers/worker_global_scope.h"
 #include "third_party/blink/renderer/core/workers/worker_thread.h"
-#include "third_party/blink/renderer/modules/background_fetch/background_fetch_event.h"
-#include "third_party/blink/renderer/modules/background_fetch/background_fetch_event_init.h"
-#include "third_party/blink/renderer/modules/background_fetch/background_fetch_registration.h"
-#include "third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.h"
-#include "third_party/blink/renderer/modules/background_sync/periodic_sync_event.h"
-#include "third_party/blink/renderer/modules/background_sync/sync_event.h"
-#include "third_party/blink/renderer/modules/cookie_store/cookie_change_event.h"
-#include "third_party/blink/renderer/modules/cookie_store/extendable_cookie_change_event.h"
 #include "third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h"
-#include "third_party/blink/renderer/modules/notifications/notification.h"
-#include "third_party/blink/renderer/modules/notifications/notification_event.h"
-#include "third_party/blink/renderer/modules/notifications/notification_event_init.h"
-#include "third_party/blink/renderer/modules/payments/abort_payment_event.h"
-#include "third_party/blink/renderer/modules/payments/abort_payment_respond_with_observer.h"
-#include "third_party/blink/renderer/modules/payments/can_make_payment_event.h"
-#include "third_party/blink/renderer/modules/payments/can_make_payment_respond_with_observer.h"
-#include "third_party/blink/renderer/modules/payments/payment_event_data_conversion.h"
-#include "third_party/blink/renderer/modules/payments/payment_request_event.h"
-#include "third_party/blink/renderer/modules/payments/payment_request_event_init.h"
-#include "third_party/blink/renderer/modules/payments/payment_request_respond_with_observer.h"
-#include "third_party/blink/renderer/modules/push_messaging/push_event.h"
-#include "third_party/blink/renderer/modules/push_messaging/push_message_data.h"
-#include "third_party/blink/renderer/modules/service_worker/extendable_event.h"
-#include "third_party/blink/renderer/modules/service_worker/extendable_message_event.h"
-#include "third_party/blink/renderer/modules/service_worker/fetch_event.h"
-#include "third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.h"
-#include "third_party/blink/renderer/modules/service_worker/install_event.h"
-#include "third_party/blink/renderer/modules/service_worker/service_worker_client.h"
 #include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h"
-#include "third_party/blink/renderer/modules/service_worker/service_worker_window_client.h"
 #include "third_party/blink/renderer/modules/service_worker/wait_until_observer.h"
 #include "third_party/blink/renderer/platform/cross_thread_functional.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
@@ -93,71 +59,8 @@
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
 
-namespace mojo {
-
-namespace {
-
-blink::mojom::NotificationActionType ToMojomNotificationActionType(
-    blink::WebNotificationAction::Type input) {
-  switch (input) {
-    case blink::WebNotificationAction::kButton:
-      return blink::mojom::NotificationActionType::BUTTON;
-    case blink::WebNotificationAction::kText:
-      return blink::mojom::NotificationActionType::TEXT;
-  }
-
-  NOTREACHED();
-  return blink::mojom::NotificationActionType::BUTTON;
-}
-
-}  // namespace
-
-// Inside Blink we're using mojom structs to represent notification data, not
-// WebNotification{Action,Data}, however, we still need WebNotificationData to
-// carry data from Content into Blink, so, for now we need these type
-// converters. They would disappear once we eliminate the abstract interface
-// layer blink::WebServiceWorkerContextProxy via Onion Soup effort later.
-template <>
-struct TypeConverter<blink::mojom::blink::NotificationActionPtr,
-                     blink::WebNotificationAction> {
-  static blink::mojom::blink::NotificationActionPtr Convert(
-      const blink::WebNotificationAction& input) {
-    return blink::mojom::blink::NotificationAction::New(
-        ToMojomNotificationActionType(input.type), input.action, input.title,
-        input.icon, input.placeholder);
-  }
-};
-
-template <>
-struct TypeConverter<blink::mojom::blink::NotificationDataPtr,
-                     blink::WebNotificationData> {
-  static blink::mojom::blink::NotificationDataPtr Convert(
-      const blink::WebNotificationData& input) {
-    Vector<int32_t> vibration_pattern;
-    vibration_pattern.Append(input.vibrate.Data(),
-                             SafeCast<wtf_size_t>(input.vibrate.size()));
-
-    Vector<uint8_t> data;
-    data.Append(input.data.Data(), SafeCast<wtf_size_t>(input.data.size()));
-
-    Vector<blink::mojom::blink::NotificationActionPtr> actions;
-    for (const auto& web_action : input.actions) {
-      actions.push_back(
-          blink::mojom::blink::NotificationAction::From(web_action));
-    }
-
-    return blink::mojom::blink::NotificationData::New(
-        input.title, input.direction, input.lang, input.body, input.tag,
-        input.image, input.icon, input.badge, std::move(vibration_pattern),
-        input.timestamp, input.renotify, input.silent,
-        input.require_interaction, std::move(data), std::move(actions),
-        input.show_trigger_timestamp);
-  }
-};
-
-}  // namespace mojo
-
 namespace blink {
+
 ServiceWorkerGlobalScopeProxy* ServiceWorkerGlobalScopeProxy::Create(
     WebEmbeddedWorkerImpl& embedded_worker,
     WebServiceWorkerContextClient& client) {
@@ -175,244 +78,18 @@
   visitor->Trace(parent_execution_context_task_runners_);
 }
 
-void ServiceWorkerGlobalScopeProxy::BindServiceWorkerHost(
-    mojo::ScopedInterfaceEndpointHandle service_worker_host) {
+void ServiceWorkerGlobalScopeProxy::BindServiceWorker(
+    mojo::ScopedMessagePipeHandle request) {
   DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
-  WorkerGlobalScope()->BindServiceWorkerHost(
-      mojom::blink::ServiceWorkerHostAssociatedPtrInfo(
-          std::move(service_worker_host),
-          mojom::blink::ServiceWorkerHost::Version_));
+  WorkerGlobalScope()->BindServiceWorker(
+      mojom::blink::ServiceWorkerRequest(std::move(request)));
 }
 
-void ServiceWorkerGlobalScopeProxy::SetRegistration(
-    WebServiceWorkerRegistrationObjectInfo info) {
+void ServiceWorkerGlobalScopeProxy::BindControllerServiceWorker(
+    mojo::ScopedMessagePipeHandle request) {
   DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
-  WorkerGlobalScope()->SetRegistration(std::move(info));
-}
-
-void ServiceWorkerGlobalScopeProxy::SetFetchHandlerExistence(
-    FetchHandlerExistence fetch_handler_existence) {
-  WorkerGlobalScope()->SetFetchHandlerExistence(fetch_handler_existence);
-}
-
-void ServiceWorkerGlobalScopeProxy::ReadyToEvaluateScript() {
-  DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
-  WorkerGlobalScope()->ReadyToEvaluateScript();
-}
-
-void ServiceWorkerGlobalScopeProxy::DispatchBackgroundFetchAbortEvent(
-    int event_id,
-    WebBackgroundFetchRegistration registration) {
-  DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
-  WaitUntilObserver* observer = WaitUntilObserver::Create(
-      WorkerGlobalScope(), WaitUntilObserver::kBackgroundFetchAbort, event_id);
-
-  ScriptState* script_state =
-      WorkerGlobalScope()->ScriptController()->GetScriptState();
-
-  // Do not remove this, |scope| is needed by
-  // BackgroundFetchEvent::Create which eventually calls ToV8.
-  ScriptState::Scope scope(script_state);
-
-  BackgroundFetchEventInit* init = BackgroundFetchEventInit::Create();
-  init->setRegistration(MakeGarbageCollected<BackgroundFetchRegistration>(
-      WorkerGlobalScope()->registration() /* service_worker_registration */,
-      std::move(registration)));
-
-  BackgroundFetchEvent* event = BackgroundFetchEvent::Create(
-      event_type_names::kBackgroundfetchabort, init, observer);
-
-  WorkerGlobalScope()->DispatchExtendableEvent(event, observer);
-}
-
-void ServiceWorkerGlobalScopeProxy::DispatchBackgroundFetchClickEvent(
-    int event_id,
-    WebBackgroundFetchRegistration registration) {
-  DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
-  WaitUntilObserver* observer = WaitUntilObserver::Create(
-      WorkerGlobalScope(), WaitUntilObserver::kBackgroundFetchClick, event_id);
-
-  BackgroundFetchEventInit* init = BackgroundFetchEventInit::Create();
-  init->setRegistration(MakeGarbageCollected<BackgroundFetchRegistration>(
-      WorkerGlobalScope()->registration() /* service_worker_registration */,
-      std::move(registration)));
-
-  BackgroundFetchEvent* event = BackgroundFetchEvent::Create(
-      event_type_names::kBackgroundfetchclick, init, observer);
-
-  WorkerGlobalScope()->DispatchExtendableEvent(event, observer);
-}
-
-void ServiceWorkerGlobalScopeProxy::DispatchBackgroundFetchFailEvent(
-    int event_id,
-    WebBackgroundFetchRegistration registration) {
-  DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
-  WaitUntilObserver* observer = WaitUntilObserver::Create(
-      WorkerGlobalScope(), WaitUntilObserver::kBackgroundFetchFail, event_id);
-
-  ScriptState* script_state =
-      WorkerGlobalScope()->ScriptController()->GetScriptState();
-
-  // Do not remove this, |scope| is needed by
-  // BackgroundFetchSettledEvent::Create which eventually calls ToV8.
-  ScriptState::Scope scope(script_state);
-
-  BackgroundFetchEventInit* init = BackgroundFetchEventInit::Create();
-  init->setRegistration(MakeGarbageCollected<BackgroundFetchRegistration>(
-      WorkerGlobalScope()->registration() /* service_worker_registration */,
-      std::move(registration)));
-
-  BackgroundFetchUpdateUIEvent* event = BackgroundFetchUpdateUIEvent::Create(
-      event_type_names::kBackgroundfetchfail, init, observer,
-      worker_global_scope_->registration());
-
-  WorkerGlobalScope()->DispatchExtendableEvent(event, observer);
-}
-
-void ServiceWorkerGlobalScopeProxy::DispatchBackgroundFetchSuccessEvent(
-    int event_id,
-    WebBackgroundFetchRegistration registration) {
-  DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
-  WaitUntilObserver* observer = WaitUntilObserver::Create(
-      WorkerGlobalScope(), WaitUntilObserver::kBackgroundFetchSuccess,
-      event_id);
-
-  ScriptState* script_state =
-      WorkerGlobalScope()->ScriptController()->GetScriptState();
-
-  // Do not remove this, |scope| is needed by
-  // BackgroundFetchSettledEvent::Create which eventually calls ToV8.
-  ScriptState::Scope scope(script_state);
-
-  BackgroundFetchEventInit* init = BackgroundFetchEventInit::Create();
-  init->setRegistration(MakeGarbageCollected<BackgroundFetchRegistration>(
-      WorkerGlobalScope()->registration() /* service_worker_registration */,
-      std::move(registration)));
-
-  BackgroundFetchUpdateUIEvent* event = BackgroundFetchUpdateUIEvent::Create(
-      event_type_names::kBackgroundfetchsuccess, init, observer,
-      worker_global_scope_->registration());
-
-  WorkerGlobalScope()->DispatchExtendableEvent(event, observer);
-}
-
-void ServiceWorkerGlobalScopeProxy::DispatchActivateEvent(int event_id) {
-  DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
-  WaitUntilObserver* observer = WaitUntilObserver::Create(
-      WorkerGlobalScope(), WaitUntilObserver::kActivate, event_id);
-  Event* event = ExtendableEvent::Create(
-      event_type_names::kActivate, ExtendableEventInit::Create(), observer);
-  WorkerGlobalScope()->DispatchExtendableEvent(event, observer);
-}
-
-void ServiceWorkerGlobalScopeProxy::DispatchCookieChangeEvent(
-    int event_id,
-    const WebCanonicalCookie& cookie,
-    network::mojom::CookieChangeCause change_cause) {
-  DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
-  WaitUntilObserver* observer = WaitUntilObserver::Create(
-      WorkerGlobalScope(), WaitUntilObserver::kCookieChange, event_id);
-
-  HeapVector<Member<CookieListItem>> changed;
-  HeapVector<Member<CookieListItem>> deleted;
-  CookieChangeEvent::ToEventInfo(cookie, change_cause, changed, deleted);
-  Event* event = ExtendableCookieChangeEvent::Create(
-      event_type_names::kCookiechange, std::move(changed), std::move(deleted),
-      observer);
-
-  // TODO(pwnall): Handle handle the case when
-  //               (changed.IsEmpty() && deleted.IsEmpty()).
-
-  // TODO(pwnall): Investigate dispatching this on cookieStore.
-  WorkerGlobalScope()->DispatchExtendableEvent(event, observer);
-}
-
-void ServiceWorkerGlobalScopeProxy::DispatchExtendableMessageEvent(
-    int event_id,
-    TransferableMessage message,
-    const WebSecurityOrigin& source_origin,
-    const WebServiceWorkerClientInfo& client) {
-  DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
-  auto msg = ToBlinkTransferableMessage(std::move(message));
-  MessagePortArray* ports =
-      MessagePort::EntanglePorts(*worker_global_scope_, std::move(msg.ports));
-  String origin;
-  if (!source_origin.IsOpaque())
-    origin = source_origin.ToString();
-  ServiceWorkerClient* source = nullptr;
-  if (client.client_type == mojom::ServiceWorkerClientType::kWindow)
-    source = ServiceWorkerWindowClient::Create(client);
-  else
-    source = ServiceWorkerClient::Create(client);
-  WaitUntilObserver* observer = WaitUntilObserver::Create(
-      WorkerGlobalScope(), WaitUntilObserver::kMessage, event_id);
-
-  Event* event = ExtendableMessageEvent::Create(std::move(msg.message), origin,
-                                                ports, source, observer);
-  WorkerGlobalScope()->DispatchExtendableEvent(event, observer);
-}
-
-void ServiceWorkerGlobalScopeProxy::DispatchExtendableMessageEvent(
-    int event_id,
-    TransferableMessage message,
-    const WebSecurityOrigin& source_origin,
-    WebServiceWorkerObjectInfo info) {
-  DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
-  auto msg = ToBlinkTransferableMessage(std::move(message));
-  MessagePortArray* ports =
-      MessagePort::EntanglePorts(*worker_global_scope_, std::move(msg.ports));
-  String origin;
-  if (!source_origin.IsOpaque())
-    origin = source_origin.ToString();
-  ServiceWorker* source = ServiceWorker::From(
-      worker_global_scope_->GetExecutionContext(), std::move(info));
-  WaitUntilObserver* observer = WaitUntilObserver::Create(
-      WorkerGlobalScope(), WaitUntilObserver::kMessage, event_id);
-
-  Event* event = ExtendableMessageEvent::Create(std::move(msg.message), origin,
-                                                ports, source, observer);
-  WorkerGlobalScope()->DispatchExtendableEvent(event, observer);
-}
-
-void ServiceWorkerGlobalScopeProxy::DispatchFetchEvent(
-    int fetch_event_id,
-    const WebServiceWorkerRequest& web_request,
-    bool navigation_preload_sent) {
-  DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
-  ScriptState::Scope scope(
-      WorkerGlobalScope()->ScriptController()->GetScriptState());
-  WaitUntilObserver* wait_until_observer = WaitUntilObserver::Create(
-      WorkerGlobalScope(), WaitUntilObserver::kFetch, fetch_event_id);
-  FetchRespondWithObserver* respond_with_observer =
-      FetchRespondWithObserver::Create(
-          WorkerGlobalScope(), fetch_event_id, web_request.Url(),
-          web_request.Mode(), web_request.RedirectMode(),
-          web_request.GetFrameType(), web_request.GetRequestContext(),
-          wait_until_observer);
-  Request* request = Request::Create(
-      WorkerGlobalScope()->ScriptController()->GetScriptState(), web_request);
-  request->getHeaders()->SetGuard(Headers::kImmutableGuard);
-  FetchEventInit* event_init = FetchEventInit::Create();
-  event_init->setCancelable(true);
-  event_init->setRequest(request);
-  event_init->setClientId(
-      web_request.IsMainResourceLoad() ? WebString() : web_request.ClientId());
-  event_init->setResultingClientId(
-      !web_request.IsMainResourceLoad() ? WebString() : web_request.ClientId());
-  event_init->setIsReload(web_request.IsReload());
-  ScriptState* script_state =
-      WorkerGlobalScope()->ScriptController()->GetScriptState();
-  FetchEvent* fetch_event = FetchEvent::Create(
-      script_state, event_type_names::kFetch, event_init, respond_with_observer,
-      wait_until_observer, navigation_preload_sent);
-  if (navigation_preload_sent) {
-    // Keep |fetchEvent| until OnNavigationPreloadComplete() or
-    // onNavigationPreloadError() will be called.
-    pending_preload_fetch_events_.insert(fetch_event_id, fetch_event);
-  }
-
-  WorkerGlobalScope()->DispatchExtendableEventWithRespondWith(
-      fetch_event, wait_until_observer, respond_with_observer);
+  WorkerGlobalScope()->BindControllerServiceWorker(
+      mojom::blink::ControllerServiceWorkerRequest(std::move(request)));
 }
 
 void ServiceWorkerGlobalScopeProxy::OnNavigationPreloadResponse(
@@ -420,35 +97,16 @@
     std::unique_ptr<WebURLResponse> response,
     mojo::ScopedDataPipeConsumerHandle data_pipe) {
   DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
-  auto it = pending_preload_fetch_events_.find(fetch_event_id);
-  DCHECK(it != pending_preload_fetch_events_.end());
-  FetchEvent* fetch_event = it->value.Get();
-  DCHECK(fetch_event);
-  fetch_event->OnNavigationPreloadResponse(
-      WorkerGlobalScope()->ScriptController()->GetScriptState(),
-      std::move(response), std::move(data_pipe));
+  WorkerGlobalScope()->OnNavigationPreloadResponse(
+      fetch_event_id, std::move(response), std::move(data_pipe));
 }
 
 void ServiceWorkerGlobalScopeProxy::OnNavigationPreloadError(
     int fetch_event_id,
     std::unique_ptr<WebServiceWorkerError> error) {
   DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
-  FetchEvent* fetch_event = pending_preload_fetch_events_.Take(fetch_event_id);
-  DCHECK(fetch_event);
-  // Display an error message to the console, preferring the unsanitized one if
-  // available.
-  const WebString& error_message = error->unsanitized_message.IsEmpty()
-                                       ? error->message
-                                       : error->unsanitized_message;
-  if (!error_message.IsEmpty()) {
-    WorkerGlobalScope()->AddConsoleMessage(ConsoleMessage::Create(
-        mojom::ConsoleMessageSource::kWorker,
-        mojom::ConsoleMessageLevel::kError, error_message));
-  }
-  // Reject the preloadResponse promise.
-  fetch_event->OnNavigationPreloadError(
-      WorkerGlobalScope()->ScriptController()->GetScriptState(),
-      std::move(error));
+  WorkerGlobalScope()->OnNavigationPreloadError(fetch_event_id,
+                                                std::move(error));
 }
 
 void ServiceWorkerGlobalScopeProxy::OnNavigationPreloadComplete(
@@ -458,159 +116,9 @@
     int64_t encoded_body_length,
     int64_t decoded_body_length) {
   DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
-  FetchEvent* fetch_event = pending_preload_fetch_events_.Take(fetch_event_id);
-  DCHECK(fetch_event);
-  fetch_event->OnNavigationPreloadComplete(
-      WorkerGlobalScope(), completion_time, encoded_data_length,
-      encoded_body_length, decoded_body_length);
-}
-
-void ServiceWorkerGlobalScopeProxy::DispatchInstallEvent(int event_id) {
-  DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
-  WaitUntilObserver* observer = WaitUntilObserver::Create(
-      WorkerGlobalScope(), WaitUntilObserver::kInstall, event_id);
-  Event* event =
-      InstallEvent::Create(event_type_names::kInstall,
-                           ExtendableEventInit::Create(), event_id, observer);
-  WorkerGlobalScope()->SetIsInstalling(true);
-  WorkerGlobalScope()->DispatchExtendableEvent(event, observer);
-}
-
-void ServiceWorkerGlobalScopeProxy::DispatchNotificationClickEvent(
-    int event_id,
-    const WebString& notification_id,
-    const WebNotificationData& data,
-    int action_index,
-    const WebString& reply) {
-  DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
-  WaitUntilObserver* observer = WaitUntilObserver::Create(
-      WorkerGlobalScope(), WaitUntilObserver::kNotificationClick, event_id);
-  NotificationEventInit* event_init = NotificationEventInit::Create();
-  event_init->setNotification(Notification::Create(
-      WorkerGlobalScope(), notification_id,
-      mojom::blink::NotificationData::From(data), true /* showing */));
-  if (0 <= action_index && action_index < static_cast<int>(data.actions.size()))
-    event_init->setAction(data.actions[action_index].action);
-  event_init->setReply(reply);
-  Event* event = NotificationEvent::Create(event_type_names::kNotificationclick,
-                                           event_init, observer);
-  WorkerGlobalScope()->DispatchExtendableEvent(event, observer);
-}
-
-void ServiceWorkerGlobalScopeProxy::DispatchNotificationCloseEvent(
-    int event_id,
-    const WebString& notification_id,
-    const WebNotificationData& data) {
-  DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
-  WaitUntilObserver* observer = WaitUntilObserver::Create(
-      WorkerGlobalScope(), WaitUntilObserver::kNotificationClose, event_id);
-  NotificationEventInit* event_init = NotificationEventInit::Create();
-  event_init->setAction(WTF::String());  // initialize as null.
-  event_init->setNotification(Notification::Create(
-      WorkerGlobalScope(), notification_id,
-      mojom::blink::NotificationData::From(data), false /* showing */));
-  Event* event = NotificationEvent::Create(event_type_names::kNotificationclose,
-                                           event_init, observer);
-  WorkerGlobalScope()->DispatchExtendableEvent(event, observer);
-}
-
-void ServiceWorkerGlobalScopeProxy::DispatchPushEvent(int event_id,
-                                                      const WebString& data) {
-  DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
-  WaitUntilObserver* observer = WaitUntilObserver::Create(
-      WorkerGlobalScope(), WaitUntilObserver::kPush, event_id);
-  Event* event = PushEvent::Create(event_type_names::kPush,
-                                   PushMessageData::Create(data), observer);
-  WorkerGlobalScope()->DispatchExtendableEvent(event, observer);
-}
-
-void ServiceWorkerGlobalScopeProxy::DispatchSyncEvent(int event_id,
-                                                      const WebString& id,
-                                                      bool last_chance) {
-  DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
-  WaitUntilObserver* observer = WaitUntilObserver::Create(
-      WorkerGlobalScope(), WaitUntilObserver::kSync, event_id);
-  Event* event =
-      SyncEvent::Create(event_type_names::kSync, id, last_chance, observer);
-
-  WorkerGlobalScope()->DispatchExtendableEvent(event, observer);
-}
-
-void ServiceWorkerGlobalScopeProxy::DispatchPeriodicSyncEvent(
-    int event_id,
-    const WebString& id) {
-  DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
-  WaitUntilObserver* observer = WaitUntilObserver::Create(
-      WorkerGlobalScope(), WaitUntilObserver::kPeriodicSync, event_id);
-  Event* event =
-      PeriodicSyncEvent::Create(event_type_names::kPeriodicsync, id, observer);
-
-  WorkerGlobalScope()->DispatchExtendableEvent(event, observer);
-}
-
-void ServiceWorkerGlobalScopeProxy::DispatchAbortPaymentEvent(int event_id) {
-  DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
-  WaitUntilObserver* wait_until_observer = WaitUntilObserver::Create(
-      WorkerGlobalScope(), WaitUntilObserver::kAbortPayment, event_id);
-  AbortPaymentRespondWithObserver* respond_with_observer =
-      MakeGarbageCollected<AbortPaymentRespondWithObserver>(
-          WorkerGlobalScope(), event_id, wait_until_observer);
-
-  Event* event = AbortPaymentEvent::Create(
-      event_type_names::kAbortpayment, ExtendableEventInit::Create(),
-      respond_with_observer, wait_until_observer);
-
-  WorkerGlobalScope()->DispatchExtendableEventWithRespondWith(
-      event, wait_until_observer, respond_with_observer);
-}
-
-void ServiceWorkerGlobalScopeProxy::DispatchCanMakePaymentEvent(
-    int event_id,
-    const WebCanMakePaymentEventData& web_event_data) {
-  DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
-  WaitUntilObserver* wait_until_observer = WaitUntilObserver::Create(
-      WorkerGlobalScope(), WaitUntilObserver::kCanMakePayment, event_id);
-  CanMakePaymentRespondWithObserver* respond_with_observer =
-      MakeGarbageCollected<CanMakePaymentRespondWithObserver>(
-          WorkerGlobalScope(), event_id, wait_until_observer);
-
-  Event* event = CanMakePaymentEvent::Create(
-      event_type_names::kCanmakepayment,
-      PaymentEventDataConversion::ToCanMakePaymentEventInit(
-          WorkerGlobalScope()->ScriptController()->GetScriptState(),
-          web_event_data),
-      respond_with_observer, wait_until_observer);
-
-  WorkerGlobalScope()->DispatchExtendableEventWithRespondWith(
-      event, wait_until_observer, respond_with_observer);
-}
-
-void ServiceWorkerGlobalScopeProxy::DispatchPaymentRequestEvent(
-    int event_id,
-    std::unique_ptr<WebPaymentRequestEventData> web_app_request) {
-  DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
-  WaitUntilObserver* wait_until_observer = WaitUntilObserver::Create(
-      WorkerGlobalScope(), WaitUntilObserver::kPaymentRequest, event_id);
-  PaymentRequestRespondWithObserver* respond_with_observer =
-      PaymentRequestRespondWithObserver::Create(WorkerGlobalScope(), event_id,
-                                                wait_until_observer);
-  Event* event = PaymentRequestEvent::Create(
-      event_type_names::kPaymentrequest,
-      PaymentEventDataConversion::ToPaymentRequestEventInit(
-          WorkerGlobalScope()->ScriptController()->GetScriptState(),
-          *web_app_request),
-      payments::mojom::blink::PaymentHandlerHostPtrInfo(
-          std::move(web_app_request->payment_handler_host_handle),
-          payments::mojom::blink::PaymentHandlerHost::Version_),
-      respond_with_observer, wait_until_observer);
-
-  WorkerGlobalScope()->DispatchExtendableEventWithRespondWith(
-      event, wait_until_observer, respond_with_observer);
-}
-
-bool ServiceWorkerGlobalScopeProxy::HasFetchEventHandler() {
-  DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
-  return WorkerGlobalScope()->HasEventListeners(event_type_names::kFetch);
+  WorkerGlobalScope()->OnNavigationPreloadComplete(
+      fetch_event_id, completion_time, encoded_data_length, encoded_body_length,
+      decoded_body_length);
 }
 
 void ServiceWorkerGlobalScopeProxy::CountFeature(WebFeature feature) {
@@ -657,13 +165,9 @@
   DCHECK(!worker_global_scope_);
   worker_global_scope_ =
       static_cast<ServiceWorkerGlobalScope*>(worker_global_scope);
-  // ServiceWorkerContextClient uses this task runner to bind its Mojo
-  // interface, so use kInternalIPC type.
-  // TODO(falken): Consider adding task types for "the handle fetch task source"
-  // and "handle functional event task source" defined in the service worker
-  // spec and use them when dispatching events.
   scoped_refptr<base::SequencedTaskRunner> worker_task_runner =
-      worker_global_scope->GetThread()->GetTaskRunner(TaskType::kInternalIPC);
+      worker_global_scope->GetThread()->GetTaskRunner(
+          TaskType::kInternalDefault);
   Client().WorkerContextStarted(this, std::move(worker_task_runner));
 }
 
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h
index 0acb97b3..a7b30cc 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h
@@ -46,14 +46,10 @@
 
 namespace blink {
 
-class FetchEvent;
 class ParentExecutionContextTaskRunners;
 class ServiceWorkerGlobalScope;
 class WebEmbeddedWorkerImpl;
 class WebServiceWorkerContextClient;
-struct WebServiceWorkerError;
-class WebServiceWorkerRequest;
-class WebURLResponse;
 
 // This class is created and destructed on the main thread, but live most
 // of its time as a resident of the worker thread. All methods other than its
@@ -80,65 +76,9 @@
   ~ServiceWorkerGlobalScopeProxy() override;
 
   // WebServiceWorkerContextProxy overrides:
-  void BindServiceWorkerHost(
-      mojo::ScopedInterfaceEndpointHandle service_worker_host) override;
-  void SetRegistration(WebServiceWorkerRegistrationObjectInfo info) override;
-  void SetFetchHandlerExistence(
-      FetchHandlerExistence fetch_handler_existence) override;
-  // Must be called after the above BindServiceWorkerHost() and
-  // SetRegistration() got called.
-  void ReadyToEvaluateScript() override;
-  void DispatchActivateEvent(int) override;
-  void DispatchBackgroundFetchAbortEvent(
-      int event_id,
-      WebBackgroundFetchRegistration registration) override;
-  void DispatchBackgroundFetchClickEvent(
-      int event_id,
-      WebBackgroundFetchRegistration registration) override;
-  void DispatchBackgroundFetchFailEvent(
-      int event_id,
-      WebBackgroundFetchRegistration registration) override;
-  void DispatchBackgroundFetchSuccessEvent(
-      int event_id,
-      WebBackgroundFetchRegistration registration) override;
-  void DispatchCookieChangeEvent(
-      int event_id,
-      const WebCanonicalCookie& cookie,
-      network::mojom::CookieChangeCause change_cause) override;
-  void DispatchExtendableMessageEvent(
-      int event_id,
-      TransferableMessage,
-      const WebSecurityOrigin& source_origin,
-      const WebServiceWorkerClientInfo&) override;
-  void DispatchExtendableMessageEvent(int event_id,
-                                      TransferableMessage,
-                                      const WebSecurityOrigin& source_origin,
-                                      WebServiceWorkerObjectInfo) override;
-  void DispatchFetchEvent(int fetch_event_id,
-                          const WebServiceWorkerRequest&,
-                          bool navigation_preload_sent) override;
-  void DispatchInstallEvent(int) override;
-  void DispatchNotificationClickEvent(int,
-                                      const WebString& notification_id,
-                                      const WebNotificationData&,
-                                      int action_index,
-                                      const WebString& reply) override;
-  void DispatchNotificationCloseEvent(int,
-                                      const WebString& notification_id,
-                                      const WebNotificationData&) override;
-  void DispatchPushEvent(int, const WebString& data) override;
-  void DispatchSyncEvent(int sync_event_id,
-                         const WebString& tag,
-                         bool last_chance) override;
-  void DispatchPeriodicSyncEvent(int periodic_sync_event_id,
-                                 const WebString& tag) override;
-  void DispatchAbortPaymentEvent(int) override;
-  void DispatchCanMakePaymentEvent(int,
-                                   const WebCanMakePaymentEventData&) override;
-  void DispatchPaymentRequestEvent(
-      int,
-      std::unique_ptr<WebPaymentRequestEventData>) override;
-  bool HasFetchEventHandler() override;
+  void BindServiceWorker(mojo::ScopedMessagePipeHandle request) override;
+  void BindControllerServiceWorker(
+      mojo::ScopedMessagePipeHandle request) override;
   void OnNavigationPreloadResponse(
       int fetch_event_id,
       std::unique_ptr<WebURLResponse>,
@@ -203,16 +143,6 @@
   Member<ParentExecutionContextTaskRunners>
       parent_execution_context_task_runners_;
 
-  // The worker thread uses this map to track |FetchEvent|s created
-  // on the worker thread (heap.) But as the proxy object is created
-  // on the main thread & its heap, we must use a cross-heap reference
-  // to each |FetchEvent| so as to obey the "per-thread heap rule" that
-  // a heap should only have per-thread heap references. Keeping a
-  // cross-heap reference requires the use of a CrossThreadPersistent<>
-  // to remain safe and sound.
-  //
-  HashMap<int, CrossThreadPersistent<FetchEvent>> pending_preload_fetch_events_;
-
   WebServiceWorkerContextClient* client_;
 
   CrossThreadPersistent<ServiceWorkerGlobalScope> worker_global_scope_;
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_registration.cc b/third_party/blink/renderer/modules/service_worker/service_worker_registration.cc
index 87b1e59..5800104 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_registration.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_registration.cc
@@ -138,6 +138,33 @@
   Attach(std::move(info));
 }
 
+ServiceWorkerRegistration::ServiceWorkerRegistration(
+    ExecutionContext* execution_context,
+    mojom::blink::ServiceWorkerRegistrationObjectInfoPtr info)
+    : ContextLifecycleObserver(execution_context),
+      registration_id_(info->registration_id),
+      scope_(std::move(info->scope)),
+      binding_(this),
+      stopped_(false) {
+  DCHECK_NE(mojom::blink::kInvalidServiceWorkerRegistrationId,
+            registration_id_);
+
+  host_.Bind(
+      std::move(info->host_ptr_info),
+      GetExecutionContext()->GetTaskRunner(blink::TaskType::kInternalDefault));
+  // The host expects us to use |info.request| so bind to it.
+  binding_.Bind(
+      std::move(info->request),
+      GetExecutionContext()->GetTaskRunner(blink::TaskType::kInternalDefault));
+
+  update_via_cache_ = info->update_via_cache;
+  installing_ =
+      ServiceWorker::From(GetExecutionContext(), std::move(info->installing));
+  waiting_ =
+      ServiceWorker::From(GetExecutionContext(), std::move(info->waiting));
+  active_ = ServiceWorker::From(GetExecutionContext(), std::move(info->active));
+}
+
 void ServiceWorkerRegistration::Attach(
     WebServiceWorkerRegistrationObjectInfo info) {
   DCHECK_EQ(registration_id_, info.registration_id);
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_registration.h b/third_party/blink/renderer/modules/service_worker/service_worker_registration.h
index 6c73d948..9325e98 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_registration.h
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_registration.h
@@ -44,6 +44,10 @@
   ServiceWorkerRegistration(ExecutionContext*,
                             WebServiceWorkerRegistrationObjectInfo);
 
+  ServiceWorkerRegistration(
+      ExecutionContext*,
+      mojom::blink::ServiceWorkerRegistrationObjectInfoPtr);
+
   // Eager finalization needed to promptly invalidate the corresponding entry of
   // the (registration id, WeakMember<ServiceWorkerRegistration>) map inside
   // ServiceWorkerContainer.
diff --git a/content/renderer/service_worker/service_worker_timeout_timer.cc b/third_party/blink/renderer/modules/service_worker/service_worker_timeout_timer.cc
similarity index 89%
rename from content/renderer/service_worker/service_worker_timeout_timer.cc
rename to third_party/blink/renderer/modules/service_worker/service_worker_timeout_timer.cc
index 76293d25..ca7c482 100644
--- a/content/renderer/service_worker/service_worker_timeout_timer.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_timeout_timer.cc
@@ -2,15 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/renderer/service_worker/service_worker_timeout_timer.h"
+#include "third_party/blink/renderer/modules/service_worker/service_worker_timeout_timer.h"
 
 #include "base/atomic_sequence_num.h"
 #include "base/bind.h"
 #include "base/stl_util.h"
 #include "base/time/default_tick_clock.h"
 #include "base/time/time.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
 
-namespace content {
+namespace blink {
 
 namespace {
 
@@ -59,15 +60,15 @@
     const base::TickClock* tick_clock)
     : idle_callback_(std::move(idle_callback)),
       tick_clock_(tick_clock),
-      weak_factory_(this) {
-}
+      weak_factory_(this) {}
 
 ServiceWorkerTimeoutTimer::~ServiceWorkerTimeoutTimer() {
   in_dtor_ = true;
   // Abort all callbacks.
-  for (auto& event : inflight_events_)
+  for (auto& event : inflight_events_) {
     std::move(event.abort_callback)
         .Run(blink::mojom::ServiceWorkerEventStatus::ABORTED);
+  }
 }
 
 void ServiceWorkerTimeoutTimer::Start() {
@@ -76,8 +77,8 @@
   if (!HasInflightEvent() && idle_time_.is_null())
     idle_time_ = tick_clock_->NowTicks() + kIdleDelay;
   timer_.Start(FROM_HERE, kUpdateInterval,
-               base::BindRepeating(&ServiceWorkerTimeoutTimer::UpdateStatus,
-                                   base::Unretained(this)));
+               WTF::BindRepeating(&ServiceWorkerTimeoutTimer::UpdateStatus,
+                                  WTF::Unretained(this)));
 }
 
 int ServiceWorkerTimeoutTimer::StartEvent(AbortCallback abort_callback) {
@@ -93,9 +94,8 @@
     did_idle_timeout_ = false;
 
     running_pending_tasks_ = true;
-    while (!pending_tasks_.empty()) {
-      std::move(pending_tasks_.front()).Run();
-      pending_tasks_.pop();
+    while (!pending_tasks_.IsEmpty()) {
+      pending_tasks_.TakeFirst().Run();
     }
     running_pending_tasks_ = false;
   }
@@ -104,9 +104,9 @@
   const int event_id = NextEventId();
   std::set<EventInfo>::iterator iter;
   bool is_inserted;
-  std::tie(iter, is_inserted) = inflight_events_.emplace(
-      event_id, tick_clock_->NowTicks() + timeout,
-      base::BindOnce(std::move(abort_callback), event_id));
+  std::tie(iter, is_inserted) =
+      inflight_events_.emplace(event_id, tick_clock_->NowTicks() + timeout,
+                               WTF::Bind(std::move(abort_callback), event_id));
   DCHECK(is_inserted);
   id_event_map_.emplace(event_id, iter);
   return event_id;
@@ -136,7 +136,7 @@
 void ServiceWorkerTimeoutTimer::PushPendingTask(
     base::OnceClosure pending_task) {
   DCHECK(did_idle_timeout());
-  pending_tasks_.emplace(std::move(pending_task));
+  pending_tasks_.emplace_back(std::move(pending_task));
 }
 
 void ServiceWorkerTimeoutTimer::SetIdleTimerDelayToZero() {
@@ -214,4 +214,4 @@
   return expiration_time < other.expiration_time;
 }
 
-}  // namespace content
+}  // namespace blink
diff --git a/content/renderer/service_worker/service_worker_timeout_timer.h b/third_party/blink/renderer/modules/service_worker/service_worker_timeout_timer.h
similarity index 89%
rename from content/renderer/service_worker/service_worker_timeout_timer.h
rename to third_party/blink/renderer/modules/service_worker/service_worker_timeout_timer.h
index f16f2399..cd442c9 100644
--- a/content/renderer/service_worker/service_worker_timeout_timer.h
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_timeout_timer.h
@@ -2,19 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_TIMEOUT_TIMER_H_
-#define CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_TIMEOUT_TIMER_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_SERVICE_WORKER_TIMEOUT_TIMER_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_SERVICE_WORKER_TIMEOUT_TIMER_H_
 
 #include <map>
 #include <set>
 
 #include "base/callback.h"
-#include "base/containers/queue.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
-#include "content/common/content_export.h"
-#include "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom.h"
+#include "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom-blink.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/platform/wtf/deque.h"
 
 namespace base {
 
@@ -22,7 +22,7 @@
 
 }  // namespace base
 
-namespace content {
+namespace blink {
 
 // ServiceWorkerTimeoutTimer manages two types of timeouts: the long standing
 // event timeout and the idle timeout.
@@ -40,11 +40,11 @@
 // The lifetime of ServiceWorkerTimeoutTimer is the same with the worker
 // thread. If ServiceWorkerTimeoutTimer is destructed while there are inflight
 // events, all |abort_callback|s will be immediately called with status ABORTED.
-class CONTENT_EXPORT ServiceWorkerTimeoutTimer {
+class MODULES_EXPORT ServiceWorkerTimeoutTimer {
  public:
   // A token to keep the timeout timer from going into the idle state if any of
   // them are alive.
-  class CONTENT_EXPORT StayAwakeToken {
+  class MODULES_EXPORT StayAwakeToken {
    public:
     explicit StayAwakeToken(base::WeakPtr<ServiceWorkerTimeoutTimer> timer);
     ~StayAwakeToken();
@@ -55,7 +55,7 @@
 
   using AbortCallback =
       base::OnceCallback<void(int /* event_id */,
-                              blink::mojom::ServiceWorkerEventStatus)>;
+                              mojom::blink::ServiceWorkerEventStatus)>;
 
   explicit ServiceWorkerTimeoutTimer(base::RepeatingClosure idle_callback);
   // For testing.
@@ -135,7 +135,7 @@
   struct EventInfo {
     EventInfo(int id,
               base::TimeTicks expiration_time,
-              base::OnceCallback<void(blink::mojom::ServiceWorkerEventStatus)>
+              base::OnceCallback<void(mojom::blink::ServiceWorkerEventStatus)>
                   abort_callback);
     ~EventInfo();
     // Compares |expiration_time|, or |id| if |expiration_time| is the same.
@@ -143,7 +143,7 @@
 
     const int id;
     const base::TimeTicks expiration_time;
-    mutable base::OnceCallback<void(blink::mojom::ServiceWorkerEventStatus)>
+    mutable base::OnceCallback<void(mojom::blink::ServiceWorkerEventStatus)>
         abort_callback;
   };
 
@@ -175,7 +175,7 @@
   // terminate it due to idleness. These tasks run once StartEvent() is called
   // due to a new event from the browser, signalling that the browser decided
   // not to terminate the worker.
-  base::queue<base::OnceClosure> pending_tasks_;
+  Deque<base::OnceClosure> pending_tasks_;
 
   // Set to true during running |pending_tasks_|. This is used for avoiding to
   // invoke |idle_callback_| when running |pending_tasks_|.
@@ -195,6 +195,6 @@
   base::WeakPtrFactory<ServiceWorkerTimeoutTimer> weak_factory_;
 };
 
-}  // namespace content
+}  // namespace blink
 
-#endif  // CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_TIMEOUT_TIMER_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_SERVICE_WORKER_TIMEOUT_TIMER_H_
diff --git a/content/renderer/service_worker/service_worker_timeout_timer_unittest.cc b/third_party/blink/renderer/modules/service_worker/service_worker_timeout_timer_test.cc
similarity index 90%
rename from content/renderer/service_worker/service_worker_timeout_timer_unittest.cc
rename to third_party/blink/renderer/modules/service_worker/service_worker_timeout_timer_test.cc
index 68f602a..93b7edb 100644
--- a/content/renderer/service_worker/service_worker_timeout_timer_unittest.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_timeout_timer_test.cc
@@ -2,21 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/renderer/service_worker/service_worker_timeout_timer.h"
+#include "third_party/blink/renderer/modules/service_worker/service_worker_timeout_timer.h"
 
-#include "base/bind.h"
 #include "base/bind_helpers.h"
-#include "base/location.h"
-#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/optional.h"
 #include "base/test/test_mock_time_task_runner.h"
-#include "base/time/tick_clock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom.h"
+#include "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom-blink.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
 
-namespace content {
+namespace blink {
 
 namespace {
 
@@ -25,37 +22,37 @@
   MockEvent() : weak_factory_(this) {}
 
   ServiceWorkerTimeoutTimer::AbortCallback CreateAbortCallback() {
-    return base::BindOnce(&MockEvent::Abort, weak_factory_.GetWeakPtr());
+    return WTF::Bind(&MockEvent::Abort, weak_factory_.GetWeakPtr());
   }
 
   int event_id() const { return event_id_; }
   void set_event_id(int event_id) { event_id_ = event_id; }
-  const base::Optional<blink::mojom::ServiceWorkerEventStatus>& status() const {
+  const base::Optional<mojom::blink::ServiceWorkerEventStatus>& status() const {
     return status_;
   }
 
  private:
-  void Abort(int event_id, blink::mojom::ServiceWorkerEventStatus status) {
+  void Abort(int event_id, mojom::blink::ServiceWorkerEventStatus status) {
     EXPECT_EQ(event_id_, event_id);
     EXPECT_FALSE(status_.has_value());
     status_ = status;
   }
 
   int event_id_ = 0;
-  base::Optional<blink::mojom::ServiceWorkerEventStatus> status_;
+  base::Optional<mojom::blink::ServiceWorkerEventStatus> status_;
   base::WeakPtrFactory<MockEvent> weak_factory_;
 };
 
 base::RepeatingClosure CreateReceiverWithCalledFlag(bool* out_is_called) {
-  return base::BindRepeating([](bool* out_is_called) { *out_is_called = true; },
-                             out_is_called);
+  return WTF::BindRepeating([](bool* out_is_called) { *out_is_called = true; },
+                            WTF::Unretained(out_is_called));
 }
 
 base::OnceClosure CreateDispatchingEventTask(
     ServiceWorkerTimeoutTimer* timer,
     std::string tag,
     std::vector<std::string>* out_tags) {
-  return base::BindOnce(
+  return WTF::Bind(
       [](ServiceWorkerTimeoutTimer* timer, std::string tag,
          std::vector<std::string>* out_tags) {
         // Event dispatched inside of pending task should run successfully.
@@ -70,7 +67,7 @@
         timer->EndEvent(event_id);
         EXPECT_FALSE(event.status().has_value());
       },
-      timer, std::move(tag), out_tags);
+      WTF::Unretained(timer), std::move(tag), WTF::Unretained(out_tags));
 }
 
 }  // namespace
@@ -82,14 +79,19 @@
   void SetUp() override {
     task_runner_ = base::MakeRefCounted<base::TestMockTimeTaskRunner>(
         base::Time::Now(), base::TimeTicks::Now());
-    message_loop_.SetTaskRunner(task_runner_);
+    // Ensure all things run on |task_runner_| instead of the default task
+    // runner initialized by blink_unittests.
+    task_runner_context_ =
+        std::make_unique<base::TestMockTimeTaskRunner::ScopedContext>(
+            task_runner_);
   }
 
   base::TestMockTimeTaskRunner* task_runner() { return task_runner_.get(); }
 
  private:
-  base::MessageLoop message_loop_;
   scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
+  std::unique_ptr<base::TestMockTimeTaskRunner::ScopedContext>
+      task_runner_context_;
 };
 
 TEST_F(ServiceWorkerTimeoutTimerTest, IdleTimer) {
@@ -222,7 +224,7 @@
 
   EXPECT_FALSE(event1.status().has_value());
   EXPECT_TRUE(event2.status().has_value());
-  EXPECT_EQ(blink::mojom::ServiceWorkerEventStatus::TIMEOUT,
+  EXPECT_EQ(mojom::blink::ServiceWorkerEventStatus::TIMEOUT,
             event2.status().value());
 }
 
@@ -245,14 +247,14 @@
 
   EXPECT_TRUE(event1.status().has_value());
   EXPECT_FALSE(event2.status().has_value());
-  EXPECT_EQ(blink::mojom::ServiceWorkerEventStatus::TIMEOUT,
+  EXPECT_EQ(mojom::blink::ServiceWorkerEventStatus::TIMEOUT,
             event1.status().value());
   task_runner()->FastForwardBy(ServiceWorkerTimeoutTimer::kUpdateInterval +
                                base::TimeDelta::FromSeconds(1));
 
   EXPECT_TRUE(event1.status().has_value());
   EXPECT_TRUE(event2.status().has_value());
-  EXPECT_EQ(blink::mojom::ServiceWorkerEventStatus::TIMEOUT,
+  EXPECT_EQ(mojom::blink::ServiceWorkerEventStatus::TIMEOUT,
             event2.status().value());
 }
 
@@ -294,10 +296,10 @@
   }
 
   EXPECT_TRUE(event1.status().has_value());
-  EXPECT_EQ(blink::mojom::ServiceWorkerEventStatus::ABORTED,
+  EXPECT_EQ(mojom::blink::ServiceWorkerEventStatus::ABORTED,
             event1.status().value());
   EXPECT_TRUE(event2.status().has_value());
-  EXPECT_EQ(blink::mojom::ServiceWorkerEventStatus::ABORTED,
+  EXPECT_EQ(mojom::blink::ServiceWorkerEventStatus::ABORTED,
             event2.status().value());
 }
 
@@ -416,4 +418,4 @@
   }
 }
 
-}  // namespace content
+}  // namespace blink
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_window_client.cc b/third_party/blink/renderer/modules/service_worker/service_worker_window_client.cc
index 031ec98..a79d6d5 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_window_client.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_window_client.cc
@@ -41,24 +41,12 @@
 }  // namespace
 
 ServiceWorkerWindowClient* ServiceWorkerWindowClient::Create(
-    const WebServiceWorkerClientInfo& info) {
-  DCHECK_EQ(mojom::blink::ServiceWorkerClientType::kWindow, info.client_type);
-  return MakeGarbageCollected<ServiceWorkerWindowClient>(info);
-}
-
-ServiceWorkerWindowClient* ServiceWorkerWindowClient::Create(
     const mojom::blink::ServiceWorkerClientInfo& info) {
   DCHECK_EQ(mojom::blink::ServiceWorkerClientType::kWindow, info.client_type);
   return MakeGarbageCollected<ServiceWorkerWindowClient>(info);
 }
 
 ServiceWorkerWindowClient::ServiceWorkerWindowClient(
-    const WebServiceWorkerClientInfo& info)
-    : ServiceWorkerClient(info),
-      page_hidden_(info.page_hidden),
-      is_focused_(info.is_focused) {}
-
-ServiceWorkerWindowClient::ServiceWorkerWindowClient(
     const mojom::blink::ServiceWorkerClientInfo& info)
     : ServiceWorkerClient(info),
       page_hidden_(info.page_hidden),
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_window_client.h b/third_party/blink/renderer/modules/service_worker/service_worker_window_client.h
index 1e1f553..1cb25b9 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_window_client.h
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_window_client.h
@@ -21,11 +21,9 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static ServiceWorkerWindowClient* Create(const WebServiceWorkerClientInfo&);
   static ServiceWorkerWindowClient* Create(
       const mojom::blink::ServiceWorkerClientInfo&);
 
-  explicit ServiceWorkerWindowClient(const WebServiceWorkerClientInfo&);
   explicit ServiceWorkerWindowClient(
       const mojom::blink::ServiceWorkerClientInfo&);
   ~ServiceWorkerWindowClient() override;
diff --git a/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc b/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc
index eab8cda..eb338c04 100644
--- a/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc
+++ b/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc
@@ -246,8 +246,8 @@
       break;
   }
 
-  ServiceWorkerGlobalScopeClient* client =
-      ServiceWorkerGlobalScopeClient::From(GetExecutionContext());
+  ServiceWorkerGlobalScope* service_worker_global_scope =
+      To<ServiceWorkerGlobalScope>(GetExecutionContext());
   mojom::ServiceWorkerEventStatus status =
       (event_dispatch_state_ == EventDispatchState::kFailed ||
        has_rejected_promise_)
@@ -255,59 +255,71 @@
           : mojom::ServiceWorkerEventStatus::COMPLETED;
   switch (type_) {
     case kAbortPayment:
-      client->DidHandleAbortPaymentEvent(event_id_, status);
+      service_worker_global_scope->DidHandleAbortPaymentEvent(event_id_,
+                                                              status);
       break;
     case kActivate:
-      client->DidHandleActivateEvent(event_id_, status);
+      service_worker_global_scope->DidHandleActivateEvent(event_id_, status);
       break;
     case kCanMakePayment:
-      client->DidHandleCanMakePaymentEvent(event_id_, status);
+      service_worker_global_scope->DidHandleCanMakePaymentEvent(event_id_,
+                                                                status);
       break;
     case kCookieChange:
-      client->DidHandleCookieChangeEvent(event_id_, status);
+      service_worker_global_scope->DidHandleCookieChangeEvent(event_id_,
+                                                              status);
       break;
     case kFetch:
-      client->DidHandleFetchEvent(event_id_, status);
+      service_worker_global_scope->DidHandleFetchEvent(event_id_, status);
       break;
     case kInstall:
       To<ServiceWorkerGlobalScope>(*GetExecutionContext())
           .SetIsInstalling(false);
-      client->DidHandleInstallEvent(event_id_, status);
+      service_worker_global_scope->DidHandleInstallEvent(event_id_, status);
       break;
     case kMessage:
-      client->DidHandleExtendableMessageEvent(event_id_, status);
+      service_worker_global_scope->DidHandleExtendableMessageEvent(event_id_,
+                                                                   status);
       break;
     case kNotificationClick:
-      client->DidHandleNotificationClickEvent(event_id_, status);
+      service_worker_global_scope->DidHandleNotificationClickEvent(event_id_,
+                                                                   status);
       consume_window_interaction_timer_.Stop();
       ConsumeWindowInteraction(nullptr);
       break;
     case kNotificationClose:
-      client->DidHandleNotificationCloseEvent(event_id_, status);
+      service_worker_global_scope->DidHandleNotificationCloseEvent(event_id_,
+                                                                   status);
       break;
     case kPush:
-      client->DidHandlePushEvent(event_id_, status);
+      service_worker_global_scope->DidHandlePushEvent(event_id_, status);
       break;
     case kSync:
-      client->DidHandleSyncEvent(event_id_, status);
+      service_worker_global_scope->DidHandleSyncEvent(event_id_, status);
       break;
     case kPeriodicSync:
-      client->DidHandlePeriodicSyncEvent(event_id_, status);
+      service_worker_global_scope->DidHandlePeriodicSyncEvent(event_id_,
+                                                              status);
       break;
     case kPaymentRequest:
-      client->DidHandlePaymentRequestEvent(event_id_, status);
+      service_worker_global_scope->DidHandlePaymentRequestEvent(event_id_,
+                                                                status);
       break;
     case kBackgroundFetchAbort:
-      client->DidHandleBackgroundFetchAbortEvent(event_id_, status);
+      service_worker_global_scope->DidHandleBackgroundFetchAbortEvent(event_id_,
+                                                                      status);
       break;
     case kBackgroundFetchClick:
-      client->DidHandleBackgroundFetchClickEvent(event_id_, status);
+      service_worker_global_scope->DidHandleBackgroundFetchClickEvent(event_id_,
+                                                                      status);
       break;
     case kBackgroundFetchFail:
-      client->DidHandleBackgroundFetchFailEvent(event_id_, status);
+      service_worker_global_scope->DidHandleBackgroundFetchFailEvent(event_id_,
+                                                                     status);
       break;
     case kBackgroundFetchSuccess:
-      client->DidHandleBackgroundFetchSuccessEvent(event_id_, status);
+      service_worker_global_scope->DidHandleBackgroundFetchSuccessEvent(
+          event_id_, status);
       break;
   }
 }
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 514db76..c041ccef 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
@@ -14,6 +14,7 @@
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/common/messaging/message_port_channel.h"
 #include "third_party/blink/public/mojom/service_worker/controller_service_worker_mode.mojom-blink.h"
+#include "third_party/blink/public/mojom/service_worker/service_worker.mojom-blink.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_installed_scripts_manager.mojom-blink.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom-blink.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_network_provider.h"
@@ -158,10 +159,35 @@
 
   void WorkerContextStarted(WebServiceWorkerContextProxy* proxy,
                             scoped_refptr<base::SequencedTaskRunner>) override {
-    // In production code, ReadyToEvaluateScript() is called when
-    // ServiceWorkerContextClient receives the InitializeGlobalScope() IPC
-    // message.
-    proxy->ReadyToEvaluateScript();
+    mojom::blink::ServiceWorkerHostAssociatedPtrInfo host_ptr_info;
+    auto host_request = mojo::MakeRequest(&host_ptr_info);
+
+    mojom::blink::ServiceWorkerRegistrationObjectHostAssociatedPtrInfo
+        registration_object_host_ptr_info;
+    auto registration_object_host_request =
+        mojo::MakeRequest(&registration_object_host_ptr_info);
+    mojom::blink::ServiceWorkerRegistrationObjectAssociatedPtrInfo
+        registration_object_ptr_info;
+
+    // Simulates calling blink.mojom.ServiceWorker.InitializeGlobalScope() to
+    // unblock the service worker script evaluation.
+    mojom::blink::ServiceWorkerPtr service_worker;
+    proxy->BindServiceWorker(
+        mojo::MakeRequest(&service_worker).PassMessagePipe());
+    service_worker->InitializeGlobalScope(
+        std::move(host_ptr_info),
+        mojom::blink::ServiceWorkerRegistrationObjectInfo::New(
+            2 /* registration_id */, KURL("https://example.com"),
+            mojom::blink::ServiceWorkerUpdateViaCache::kImports,
+            std::move(registration_object_host_ptr_info),
+            mojo::MakeRequest(&registration_object_ptr_info), nullptr, nullptr,
+            nullptr),
+        mojom::blink::FetchHandlerExistence::EXISTS);
+
+    // To make the other side callable.
+    mojo::AssociateWithDisconnectedPipe(host_request.PassHandle());
+    mojo::AssociateWithDisconnectedPipe(
+        registration_object_host_request.PassHandle());
   }
 
   void FailedToLoadClassicScript() override {
diff --git a/third_party/blink/renderer/modules/speech/speech_synthesis.cc b/third_party/blink/renderer/modules/speech/speech_synthesis.cc
index a236d8e..d6606fd 100644
--- a/third_party/blink/renderer/modules/speech/speech_synthesis.cc
+++ b/third_party/blink/renderer/modules/speech/speech_synthesis.cc
@@ -115,8 +115,8 @@
   // Note: Non-UseCounter based TTS metrics are of the form TextToSpeech.* and
   // are generally global, whereas these are scoped to a single page load.
   UseCounter::Count(document, WebFeature::kTextToSpeech_Speak);
-  UseCounter::CountCrossOriginIframe(
-      *document, WebFeature::kTextToSpeech_SpeakCrossOrigin);
+  document->CountUseOnlyInCrossOriginIframe(
+      WebFeature::kTextToSpeech_SpeakCrossOrigin);
   if (!IsAllowedToStartByAutoplay()) {
     Deprecation::CountDeprecation(
         document, WebFeature::kTextToSpeech_SpeakDisallowedByAutoplay);
diff --git a/third_party/blink/renderer/modules/vr/vr_display.cc b/third_party/blink/renderer/modules/vr/vr_display.cc
index 7cd0579..39424e8 100644
--- a/third_party/blink/renderer/modules/vr/vr_display.cc
+++ b/third_party/blink/renderer/modules/vr/vr_display.cc
@@ -150,12 +150,8 @@
   device::mojom::blink::XRSessionOptionsPtr options =
       device::mojom::blink::XRSessionOptions::New();
   options->immersive = false;
-  // Set in_on_display_activate to true, this will prevent the request present
-  // from being logged.
-  // TODO(http://crbug.com/842025): clean up the logging when refactors are
-  // complete.
   device_ptr_->RequestSession(
-      std::move(options), true,
+      std::move(options),
       WTF::Bind(&VRDisplay::OnNonImmersiveSessionRequestReturned,
                 WrapPersistent(this)));
 }
@@ -549,7 +545,7 @@
     options->use_legacy_webvr_render_path = true;
 
     device_ptr_->RequestSession(
-        std::move(options), in_display_activate_,
+        std::move(options),
         WTF::Bind(&VRDisplay::OnRequestImmersiveSessionReturned,
                   WrapPersistent(this)));
     pending_present_request_ = true;
@@ -979,8 +975,6 @@
   if (reason == device::mojom::blink::VRDisplayEventReason::MOUNTED)
     gesture_indicator = LocalFrame::NotifyUserActivation(doc->GetFrame());
 
-  base::AutoReset<bool> in_activate(&in_display_activate_, true);
-
   navigator_vr_->DispatchVREvent(VRDisplayEvent::Create(
       event_type_names::kVrdisplayactivate, this, reason));
   std::move(on_handled).Run(!pending_present_request_ && !is_presenting_);
diff --git a/third_party/blink/renderer/modules/webaudio/audio_context.cc b/third_party/blink/renderer/modules/webaudio/audio_context.cc
index 7cc0605..cb6c147 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_context.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_context.cc
@@ -55,8 +55,8 @@
                                    ExceptionState& exception_state) {
   DCHECK(IsMainThread());
 
-  UseCounter::CountCrossOriginIframe(
-      document, WebFeature::kAudioContextCrossOriginIframe);
+  document.CountUseOnlyInCrossOriginIframe(
+      WebFeature::kAudioContextCrossOriginIframe);
 
   WebAudioLatencyHint latency_hint(WebAudioLatencyHint::kCategoryInteractive);
   if (context_options->latencyHint().IsAudioContextLatencyCategory()) {
diff --git a/third_party/blink/renderer/modules/webmidi/navigator_web_midi.cc b/third_party/blink/renderer/modules/webmidi/navigator_web_midi.cc
index 6250d41..c29fdd7 100644
--- a/third_party/blink/renderer/modules/webmidi/navigator_web_midi.cc
+++ b/third_party/blink/renderer/modules/webmidi/navigator_web_midi.cc
@@ -96,8 +96,7 @@
     UseCounter::Count(
         document,
         WebFeature::kRequestMIDIAccessWithSysExOption_ObscuredByFootprinting);
-    UseCounter::CountCrossOriginIframe(
-        document,
+    document.CountUseOnlyInCrossOriginIframe(
         WebFeature::
             kRequestMIDIAccessIframeWithSysExOption_ObscuredByFootprinting);
   } else {
@@ -110,8 +109,8 @@
                       ? WebFeature::kNoSysexWebMIDIWithoutPermission
                       : WebFeature::kNoSysexWebMIDIOnInsecureOrigin);
   }
-  UseCounter::CountCrossOriginIframe(
-      document, WebFeature::kRequestMIDIAccessIframe_ObscuredByFootprinting);
+  document.CountUseOnlyInCrossOriginIframe(
+      WebFeature::kRequestMIDIAccessIframe_ObscuredByFootprinting);
 
   if (!document.IsFeatureEnabled(mojom::FeaturePolicyFeature::kMidiFeature,
                                  ReportOptions::kReportOnFailure,
diff --git a/third_party/blink/renderer/modules/webshare/navigator_share_test.cc b/third_party/blink/renderer/modules/webshare/navigator_share_test.cc
index e4c628a..5568861 100644
--- a/third_party/blink/renderer/modules/webshare/navigator_share_test.cc
+++ b/third_party/blink/renderer/modules/webshare/navigator_share_test.cc
@@ -140,8 +140,8 @@
   EXPECT_EQ(mock_share_service().text(), message);
   EXPECT_EQ(mock_share_service().url(), KURL(url));
   EXPECT_EQ(mock_share_service().files().size(), 0U);
-  EXPECT_TRUE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kWebShareSuccessfulWithoutFiles));
+  EXPECT_TRUE(
+      GetDocument().IsUseCounted(WebFeature::kWebShareSuccessfulWithoutFiles));
 }
 
 File* CreateSampleFile(ExecutionContext* context,
@@ -175,8 +175,8 @@
   EXPECT_EQ(mock_share_service().files()[0]->blob->GetType(), content_type);
   EXPECT_EQ(mock_share_service().files()[0]->blob->size(),
             file_contents.length());
-  EXPECT_TRUE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kWebShareSuccessfulContainingFiles));
+  EXPECT_TRUE(GetDocument().IsUseCounted(
+      WebFeature::kWebShareSuccessfulContainingFiles));
 }
 
 TEST_F(NavigatorShareTest, CancelShare) {
@@ -186,8 +186,8 @@
 
   mock_share_service().set_error(mojom::blink::ShareError::CANCELED);
   Share(share_data);
-  EXPECT_TRUE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kWebShareUnsuccessfulWithoutFiles));
+  EXPECT_TRUE(GetDocument().IsUseCounted(
+      WebFeature::kWebShareUnsuccessfulWithoutFiles));
 }
 
 TEST_F(NavigatorShareTest, CancelShareWithFile) {
@@ -204,8 +204,8 @@
 
   mock_share_service().set_error(mojom::blink::ShareError::CANCELED);
   Share(share_data);
-  EXPECT_TRUE(UseCounter::IsCounted(
-      GetDocument(), WebFeature::kWebShareUnsuccessfulContainingFiles));
+  EXPECT_TRUE(GetDocument().IsUseCounted(
+      WebFeature::kWebShareUnsuccessfulContainingFiles));
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/xr/xr.cc b/third_party/blink/renderer/modules/xr/xr.cc
index a62f61a..81d56ba 100644
--- a/third_party/blink/renderer/modules/xr/xr.cc
+++ b/third_party/blink/renderer/modules/xr/xr.cc
@@ -354,7 +354,7 @@
   // legacy API has been removed.
   outstanding_request_queries_.insert(query);
   device_->RequestSession(
-      std::move(session_options), false /* triggered by display activate */,
+      std::move(session_options),
       WTF::Bind(&XR::OnRequestSessionReturned, WrapWeakPersistent(this),
                 WrapPersistent(query)));
 }
@@ -510,6 +510,8 @@
         &XR::OnMagicWindowProviderDisconnect, WrapWeakPersistent(this)));
   }
 
+  UseCounter::Count(ExecutionContext::From(query->resolver->GetScriptState()),
+                    WebFeature::kWebXrSessionCreated);
   query->resolver->Resolve(session);
 }
 
diff --git a/third_party/blink/renderer/modules/xr/xr_input_source.idl b/third_party/blink/renderer/modules/xr/xr_input_source.idl
index 9b347a8..a3b5000 100644
--- a/third_party/blink/renderer/modules/xr/xr_input_source.idl
+++ b/third_party/blink/renderer/modules/xr/xr_input_source.idl
@@ -23,5 +23,5 @@
   readonly attribute XRTargetRayMode targetRayMode;
   [SameObject] readonly attribute XRSpace targetRaySpace;
   [SameObject] readonly attribute XRSpace? gripSpace;
-  [SameObject] readonly attribute Gamepad? gamepad;
+  [SameObject, Measure] readonly attribute Gamepad? gamepad;
 };
diff --git a/third_party/blink/renderer/modules/xr/xr_reference_space.cc b/third_party/blink/renderer/modules/xr/xr_reference_space.cc
index cc683be..16256419 100644
--- a/third_party/blink/renderer/modules/xr/xr_reference_space.cc
+++ b/third_party/blink/renderer/modules/xr/xr_reference_space.cc
@@ -13,7 +13,24 @@
 namespace blink {
 
 // Rough estimate of avg human eye height in meters.
-const double kDefaultEmulationHeight = 1.6;
+const double kDefaultEmulationHeightMeters = 1.6;
+
+XRReferenceSpace::Type XRReferenceSpace::StringToReferenceSpaceType(
+    const String& reference_space_type) {
+  if (reference_space_type == "viewer") {
+    return XRReferenceSpace::Type::kTypeViewer;
+  } else if (reference_space_type == "local") {
+    return XRReferenceSpace::Type::kTypeLocal;
+  } else if (reference_space_type == "local-floor") {
+    return XRReferenceSpace::Type::kTypeLocalFloor;
+  } else if (reference_space_type == "bounded-floor") {
+    return XRReferenceSpace::Type::kTypeBoundedFloor;
+  } else if (reference_space_type == "unbounded") {
+    return XRReferenceSpace::Type::kTypeUnbounded;
+  }
+  NOTREACHED();
+  return Type::kTypeViewer;
+}
 
 // origin offset starts as identity transform
 XRReferenceSpace::XRReferenceSpace(XRSession* session, Type type)
@@ -31,7 +48,7 @@
 XRPose* XRReferenceSpace::getPose(
     XRSpace* other_space,
     std::unique_ptr<TransformationMatrix> base_pose_matrix) {
-  if (type_ == kTypeViewer) {
+  if (type_ == Type::kTypeViewer) {
     std::unique_ptr<TransformationMatrix> viewer_pose_matrix =
         other_space->GetViewerPoseMatrix(std::move(base_pose_matrix));
     if (!viewer_pose_matrix) {
@@ -58,7 +75,7 @@
   } else {
     // Otherwise, create a transform based on the default emulated height.
     floor_level_transform_ = std::make_unique<TransformationMatrix>();
-    floor_level_transform_->Translate3d(0, kDefaultEmulationHeight, 0);
+    floor_level_transform_->Translate3d(0, kDefaultEmulationHeightMeters, 0);
   }
 
   display_info_id_ = session()->DisplayInfoPtrId();
@@ -68,8 +85,8 @@
 // viewer reference spaces.
 std::unique_ptr<TransformationMatrix> XRReferenceSpace::DefaultPose() {
   // A viewer reference space always returns an identity matrix.
-  return type_ == kTypeViewer ? std::make_unique<TransformationMatrix>()
-                              : nullptr;
+  return type_ == Type::kTypeViewer ? std::make_unique<TransformationMatrix>()
+                                    : nullptr;
 }
 
 // Transforms a given pose from a "base" reference space used by the XR
@@ -77,11 +94,11 @@
 std::unique_ptr<TransformationMatrix> XRReferenceSpace::TransformBasePose(
     const TransformationMatrix& base_pose) {
   switch (type_) {
-    case kTypeLocal:
+    case Type::kTypeLocal:
       // Currently all base poses are 'local' poses, so return directly.
       return std::make_unique<TransformationMatrix>(base_pose);
       break;
-    case kTypeLocalFloor:
+    case Type::kTypeLocalFloor:
       // Currently all base poses are 'local' space, so use of 'local-floor'
       // reference spaces requires adjustment. Ideally the service will
       // eventually provide poses in the requested space directly, avoiding the
@@ -100,15 +117,15 @@
         return pose;
       }
       break;
-    case kTypeViewer:
+    case Type::kTypeViewer:
       // Always return the default pose because we will only get here for an
       // "viewer" reference space.
       return DefaultPose();
-    case kTypeUnbounded:
+    case Type::kTypeUnbounded:
       // For now we assume that poses returned by systems that support unbounded
       // reference spaces are already in the correct space.
       return std::make_unique<TransformationMatrix>(base_pose);
-    case kTypeBoundedFloor:
+    case Type::kTypeBoundedFloor:
       break;
   }
 
@@ -122,12 +139,12 @@
     const TransformationMatrix& base_input_pose,
     const TransformationMatrix& base_pose) {
   switch (type_) {
-    case kTypeViewer:
-    case kTypeLocal:
-    case kTypeLocalFloor:
-    case kTypeUnbounded:
+    case Type::kTypeViewer:
+    case Type::kTypeLocal:
+    case Type::kTypeLocalFloor:
+    case Type::kTypeUnbounded:
       return TransformBasePose(base_input_pose);
-    case kTypeBoundedFloor:
+    case Type::kTypeBoundedFloor:
       break;
   }
   return nullptr;
@@ -181,7 +198,7 @@
 }
 
 void XRReferenceSpace::OnReset() {
-  if (type_ != kTypeViewer) {
+  if (type_ != Type::kTypeViewer) {
     DispatchEvent(
         *XRReferenceSpaceEvent::Create(event_type_names::kReset, this));
   }
diff --git a/third_party/blink/renderer/modules/xr/xr_reference_space.h b/third_party/blink/renderer/modules/xr/xr_reference_space.h
index ecea6f0..06770080 100644
--- a/third_party/blink/renderer/modules/xr/xr_reference_space.h
+++ b/third_party/blink/renderer/modules/xr/xr_reference_space.h
@@ -18,14 +18,18 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  enum Type {
-    kTypeViewer,
-    kTypeLocal,
-    kTypeLocalFloor,
-    kTypeBoundedFloor,
-    kTypeUnbounded,
+  // Used for metrics, don't remove or change values.
+  enum class Type : int {
+    kTypeViewer = 0,
+    kTypeLocal = 1,
+    kTypeLocalFloor = 2,
+    kTypeBoundedFloor = 3,
+    kTypeUnbounded = 4,
+    kMaxValue = kTypeUnbounded,
   };
 
+  static Type StringToReferenceSpaceType(const String& reference_space_type);
+
   XRReferenceSpace(XRSession*, Type);
   XRReferenceSpace(XRSession*, XRRigidTransform*, Type);
   ~XRReferenceSpace() override;
diff --git a/third_party/blink/renderer/modules/xr/xr_reference_space.idl b/third_party/blink/renderer/modules/xr/xr_reference_space.idl
index 691a542..cb95b2c 100644
--- a/third_party/blink/renderer/modules/xr/xr_reference_space.idl
+++ b/third_party/blink/renderer/modules/xr/xr_reference_space.idl
@@ -18,5 +18,5 @@
     RuntimeEnabled=WebXR
 ] interface XRReferenceSpace : XRSpace {
   attribute EventHandler onreset;
-  XRReferenceSpace getOffsetReferenceSpace(XRRigidTransform originOffset);
+  [Measure] XRReferenceSpace getOffsetReferenceSpace(XRRigidTransform originOffset);
 };
diff --git a/third_party/blink/renderer/modules/xr/xr_session.cc b/third_party/blink/renderer/modules/xr/xr_session.cc
index 1aef084..6d1981b 100644
--- a/third_party/blink/renderer/modules/xr/xr_session.cc
+++ b/third_party/blink/renderer/modules/xr/xr_session.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "base/auto_reset.h"
+#include "base/metrics/histogram_macros.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_xr_frame_request_callback.h"
@@ -49,8 +50,6 @@
 
 const char kSessionEnded[] = "XRSession has already ended.";
 
-const char kUnknownReferenceSpace[] = "Unknown reference space type.";
-
 const char kReferenceSpaceNotSupported[] =
     "This device does not support the requested reference space type.";
 
@@ -247,7 +246,14 @@
                           DOMExceptionCode::kInvalidStateError, kSessionEnded));
   }
 
-  if (sensorless_session_ && type != "viewer") {
+  XRReferenceSpace::Type requested_type =
+      XRReferenceSpace::StringToReferenceSpaceType(type);
+
+  UMA_HISTOGRAM_ENUMERATION("XR.WebXR.ReferenceSpace.Requested",
+                            requested_type);
+
+  if (sensorless_session_ &&
+      requested_type != XRReferenceSpace::Type::kTypeViewer) {
     return ScriptPromise::RejectWithDOMException(
         script_state,
         MakeGarbageCollected<DOMException>(DOMExceptionCode::kNotSupportedError,
@@ -255,59 +261,57 @@
   }
 
   XRReferenceSpace* reference_space = nullptr;
-  if (type == "viewer") {
-    reference_space = MakeGarbageCollected<XRReferenceSpace>(
-        this, XRReferenceSpace::Type::kTypeViewer);
-  } else if (type == "local") {
-    reference_space = MakeGarbageCollected<XRReferenceSpace>(
-        this, XRReferenceSpace::Type::kTypeLocal);
-  } else if (type == "local-floor") {
-    reference_space = MakeGarbageCollected<XRReferenceSpace>(
-        this, XRReferenceSpace::Type::kTypeLocalFloor);
-  } else if (type == "bounded-floor") {
-    bool supports_bounded = false;
-    if (immersive() && display_info_->stageParameters) {
-      if (display_info_->stageParameters->bounds) {
-        supports_bounded = true;
-      } else if (display_info_->stageParameters->sizeX > 0 &&
-                 display_info_->stageParameters->sizeZ > 0) {
-        supports_bounded = true;
+  switch (requested_type) {
+    case XRReferenceSpace::Type::kTypeViewer:
+    case XRReferenceSpace::Type::kTypeLocal:
+    case XRReferenceSpace::Type::kTypeLocalFloor:
+      reference_space =
+          MakeGarbageCollected<XRReferenceSpace>(this, requested_type);
+      break;
+    case XRReferenceSpace::Type::kTypeBoundedFloor: {
+      bool supports_bounded = false;
+      if (immersive() && display_info_->stageParameters) {
+        if (display_info_->stageParameters->bounds) {
+          supports_bounded = true;
+        } else if (display_info_->stageParameters->sizeX > 0 &&
+                   display_info_->stageParameters->sizeZ > 0) {
+          supports_bounded = true;
+        }
       }
-    }
 
-    if (supports_bounded) {
-      reference_space = MakeGarbageCollected<XRBoundedReferenceSpace>(this);
-    } else {
-      return ScriptPromise::RejectWithDOMException(
-          script_state, MakeGarbageCollected<DOMException>(
-                            DOMExceptionCode::kNotSupportedError,
-                            kReferenceSpaceNotSupported));
+      if (supports_bounded) {
+        reference_space = MakeGarbageCollected<XRBoundedReferenceSpace>(this);
+      } else {
+        return ScriptPromise::RejectWithDOMException(
+            script_state, MakeGarbageCollected<DOMException>(
+                              DOMExceptionCode::kNotSupportedError,
+                              kReferenceSpaceNotSupported));
+      }
+      break;
     }
-  } else if (type == "unbounded") {
-    if (immersive() && environment_integration_) {
-      reference_space = MakeGarbageCollected<XRReferenceSpace>(
-          this, XRReferenceSpace::Type::kTypeUnbounded);
-    } else {
-      return ScriptPromise::RejectWithDOMException(
-          script_state, MakeGarbageCollected<DOMException>(
-                            DOMExceptionCode::kNotSupportedError,
-                            kReferenceSpaceNotSupported));
-    }
+    case XRReferenceSpace::Type::kTypeUnbounded:
+      if (immersive() && environment_integration_) {
+        reference_space = MakeGarbageCollected<XRReferenceSpace>(
+            this, XRReferenceSpace::Type::kTypeUnbounded);
+      } else {
+        return ScriptPromise::RejectWithDOMException(
+            script_state, MakeGarbageCollected<DOMException>(
+                              DOMExceptionCode::kNotSupportedError,
+                              kReferenceSpaceNotSupported));
+      }
+      break;
   }
 
-  if (!reference_space) {
-    return ScriptPromise::RejectWithDOMException(
-        script_state,
-        MakeGarbageCollected<DOMException>(DOMExceptionCode::kNotSupportedError,
-                                           kUnknownReferenceSpace));
-  } else {
-    reference_spaces_.push_back(reference_space);
-  }
+  DCHECK(reference_space);
+  reference_spaces_.push_back(reference_space);
 
   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
   ScriptPromise promise = resolver->Promise();
   resolver->Resolve(reference_space);
 
+  UMA_HISTOGRAM_ENUMERATION("XR.WebXR.ReferenceSpace.Succeeded",
+                            requested_type);
+
   return promise;
 }
 
diff --git a/third_party/blink/renderer/modules/xr/xr_session.idl b/third_party/blink/renderer/modules/xr/xr_session.idl
index 42ebc42..46b0728d 100644
--- a/third_party/blink/renderer/modules/xr/xr_session.idl
+++ b/third_party/blink/renderer/modules/xr/xr_session.idl
@@ -48,5 +48,5 @@
   [RuntimeEnabled=WebXRPlaneDetection] readonly attribute XRWorldTrackingState worldTrackingState;
   [RuntimeEnabled=WebXRPlaneDetection, RaisesException] void updateWorldTrackingState(optional XRWorldTrackingStateInit state);
 
-  [CallWith=ScriptState] Promise<void> end();
+  [CallWith=ScriptState, Measure] Promise<void> end();
 };
diff --git a/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc b/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc
index deecb6d..b26d684c 100644
--- a/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc
+++ b/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc
@@ -71,9 +71,17 @@
   bool want_alpha_channel = initializer->alpha();
   bool want_ignore_depth_values = initializer->ignoreDepthValues();
 
+  if (want_ignore_depth_values) {
+    UseCounter::Count(session->GetExecutionContext(),
+                      WebFeature::kWebXrIgnoreDepthValues);
+  }
+
   double framebuffer_scale = 1.0;
 
   if (initializer->hasFramebufferScaleFactor()) {
+    UseCounter::Count(session->GetExecutionContext(),
+                      WebFeature::kWebXrFramebufferScale);
+
     // The max size will be either the native resolution or the default
     // if that happens to be larger than the native res. (That can happen on
     // desktop systems.)
diff --git a/third_party/blink/renderer/modules/xr/xr_webgl_layer.idl b/third_party/blink/renderer/modules/xr/xr_webgl_layer.idl
index 3466ba52..e9cd552 100644
--- a/third_party/blink/renderer/modules/xr/xr_webgl_layer.idl
+++ b/third_party/blink/renderer/modules/xr/xr_webgl_layer.idl
@@ -10,7 +10,8 @@
     Exposed=Window,
     RuntimeEnabled=WebXR,
     Constructor(XRSession session, XRWebGLRenderingContext context, optional XRWebGLLayerInit layerInit),
-    RaisesException=Constructor
+    RaisesException=Constructor,
+    Measure
 ] interface XRWebGLLayer : XRLayer {
   [SameObject, SaveSameObject, ImplementedAs=getXRWebGLRenderingContext] readonly attribute XRWebGLRenderingContext context;
   readonly attribute boolean antialias;
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index 99269e8..63a8fb7d 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -512,7 +512,6 @@
     "exported/mediastream/web_platform_media_stream_source.cc",
     "exported/mediastream/web_platform_media_stream_track.cc",
     "exported/mediastream/webrtc_uma_histograms.cc",
-    "exported/notification_data_conversions.cc",
     "exported/platform.cc",
     "exported/service_registry.cc",
     "exported/url_conversion.cc",
@@ -575,8 +574,6 @@
     "exported/web_rtc_void_request.cc",
     "exported/web_runtime_features.cc",
     "exported/web_security_origin.cc",
-    "exported/web_service_worker_request.cc",
-    "exported/web_service_worker_response.cc",
     "exported/web_service_worker_stream_handle.cc",
     "exported/web_speech_synthesis_utterance.cc",
     "exported/web_speech_synthesis_voice.cc",
@@ -1674,7 +1671,6 @@
     "exported/file_path_conversion_test.cc",
     "exported/mediastream/media_stream_audio_processor_options_test.cc",
     "exported/mediastream/webrtc_uma_histograms_test.cc",
-    "exported/notification_data_conversions_test.cc",
     "exported/web_canonical_cookie_test.cc",
     "exported/web_string_test.cc",
     "fonts/android/font_cache_android_test.cc",
diff --git a/third_party/blink/renderer/platform/exported/notification_data_conversions.cc b/third_party/blink/renderer/platform/exported/notification_data_conversions.cc
deleted file mode 100644
index 7e62329..0000000
--- a/third_party/blink/renderer/platform/exported/notification_data_conversions.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/public/platform/notification_data_conversions.h"
-
-#include "third_party/blink/public/mojom/notifications/notification.mojom-shared.h"
-#include "third_party/blink/public/platform/modules/notifications/web_notification_action.h"
-#include "third_party/blink/public/platform/url_conversion.h"
-#include "third_party/blink/public/platform/web_string.h"
-#include "third_party/blink/public/platform/web_url.h"
-#include "third_party/blink/public/platform/web_vector.h"
-#include "third_party/blink/renderer/platform/weborigin/kurl.h"
-
-namespace blink {
-
-WebNotificationData ToWebNotificationData(
-    const PlatformNotificationData& platform_data) {
-  WebNotificationData web_data;
-  web_data.title = WebString::FromUTF16(platform_data.title);
-  web_data.direction = platform_data.direction;
-  web_data.lang = WebString::FromUTF8(platform_data.lang);
-  web_data.body = WebString::FromUTF16(platform_data.body);
-  web_data.tag = WebString::FromUTF8(platform_data.tag);
-  web_data.image = WebURL(KURL(platform_data.image));
-  web_data.icon = WebURL(KURL(platform_data.icon));
-  web_data.badge = WebURL(KURL(platform_data.badge));
-  web_data.vibrate = platform_data.vibration_pattern;
-  web_data.timestamp = platform_data.timestamp.ToJsTime();
-  web_data.renotify = platform_data.renotify;
-  web_data.silent = platform_data.silent;
-  web_data.require_interaction = platform_data.require_interaction;
-  web_data.data = platform_data.data;
-  WebVector<WebNotificationAction> resized(platform_data.actions.size());
-  web_data.actions.Swap(resized);
-  for (size_t i = 0; i < platform_data.actions.size(); ++i) {
-    switch (platform_data.actions[i].type) {
-      case PLATFORM_NOTIFICATION_ACTION_TYPE_BUTTON:
-        web_data.actions[i].type = WebNotificationAction::kButton;
-        break;
-      case PLATFORM_NOTIFICATION_ACTION_TYPE_TEXT:
-        web_data.actions[i].type = WebNotificationAction::kText;
-        break;
-      default:
-        NOTREACHED() << "Unknown platform data type: "
-                     << platform_data.actions[i].type;
-    }
-    web_data.actions[i].action =
-        WebString::FromUTF8(platform_data.actions[i].action);
-    web_data.actions[i].title =
-        WebString::FromUTF16(platform_data.actions[i].title);
-    web_data.actions[i].icon = WebURL(KURL(platform_data.actions[i].icon));
-    web_data.actions[i].placeholder =
-        WebString::FromUTF16(platform_data.actions[i].placeholder);
-  }
-  web_data.show_trigger_timestamp = platform_data.show_trigger_timestamp;
-
-  return web_data;
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/platform/exported/notification_data_conversions_test.cc b/third_party/blink/renderer/platform/exported/notification_data_conversions_test.cc
deleted file mode 100644
index ee6ae9f..0000000
--- a/third_party/blink/renderer/platform/exported/notification_data_conversions_test.cc
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/public/platform/notification_data_conversions.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "base/stl_util.h"
-#include "base/strings/nullable_string16.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/time/time.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/common/notifications/platform_notification_data.h"
-#include "third_party/blink/public/platform/modules/notifications/web_notification_data.h"
-#include "third_party/blink/public/platform/web_string.h"
-#include "third_party/blink/public/platform/web_url.h"
-
-namespace blink {
-
-const char kNotificationTitle[] = "My Notification";
-const char kNotificationLang[] = "nl";
-const char kNotificationBody[] = "Hello, world!";
-const char kNotificationTag[] = "my_tag";
-const char kNotificationImageUrl[] = "https://example.com/image.jpg";
-const char kNotificationIconUrl[] = "https://example.com/icon.png";
-const char kNotificationBadgeUrl[] = "https://example.com/badge.png";
-const int kNotificationVibrationPattern[] = {100, 200, 300};
-const double kNotificationTimestamp = 621046800.;
-const unsigned char kNotificationData[] = {0xdf, 0xff, 0x0, 0x0, 0xff, 0xdf};
-const char kAction1Name[] = "btn1";
-const char kAction1Title[] = "Button 1";
-const char kAction1IconUrl[] = "https://example.com/action_icon_1.png";
-const char kAction1Placeholder[] = "Run into the... friendliness pellets.";
-const char kAction2Name[] = "btn2";
-const char kAction2Title[] = "Button 2";
-const char kAction2IconUrl[] = "https://example.com/action_icon_2.png";
-const base::Time kShowTriggerTimestamp = base::Time::FromJsTime(621086800.);
-
-TEST(NotificationDataConversionsTest, ToWebNotificationData) {
-  std::vector<int> vibration_pattern(
-      kNotificationVibrationPattern,
-      kNotificationVibrationPattern +
-          base::size(kNotificationVibrationPattern));
-
-  std::vector<char> developer_data(
-      kNotificationData, kNotificationData + base::size(kNotificationData));
-
-  PlatformNotificationData platform_data;
-  platform_data.title = base::ASCIIToUTF16(kNotificationTitle);
-  platform_data.direction = mojom::NotificationDirection::LEFT_TO_RIGHT;
-  platform_data.lang = kNotificationLang;
-  platform_data.body = base::ASCIIToUTF16(kNotificationBody);
-  platform_data.tag = kNotificationTag;
-  platform_data.image = GURL(kNotificationImageUrl);
-  platform_data.icon = GURL(kNotificationIconUrl);
-  platform_data.badge = GURL(kNotificationBadgeUrl);
-  platform_data.vibration_pattern = vibration_pattern;
-  platform_data.timestamp = base::Time::FromJsTime(kNotificationTimestamp);
-  platform_data.renotify = true;
-  platform_data.silent = true;
-  platform_data.require_interaction = true;
-  platform_data.data = developer_data;
-  platform_data.actions.resize(2);
-  platform_data.actions[0].type = PLATFORM_NOTIFICATION_ACTION_TYPE_BUTTON;
-  platform_data.actions[0].action = kAction1Name;
-  platform_data.actions[0].title = base::ASCIIToUTF16(kAction1Title);
-  platform_data.actions[0].icon = GURL(kAction1IconUrl);
-  platform_data.actions[0].placeholder =
-      base::NullableString16(base::ASCIIToUTF16(kAction1Placeholder), false);
-  platform_data.actions[1].type = PLATFORM_NOTIFICATION_ACTION_TYPE_TEXT;
-  platform_data.actions[1].action = kAction2Name;
-  platform_data.actions[1].title = base::ASCIIToUTF16(kAction2Title);
-  platform_data.actions[1].icon = GURL(kAction2IconUrl);
-  platform_data.actions[1].placeholder = base::NullableString16();
-  platform_data.show_trigger_timestamp = kShowTriggerTimestamp;
-
-  WebNotificationData web_data = ToWebNotificationData(platform_data);
-  EXPECT_EQ(kNotificationTitle, web_data.title);
-  EXPECT_EQ(blink::mojom::NotificationDirection::LEFT_TO_RIGHT,
-            web_data.direction);
-  EXPECT_EQ(kNotificationLang, web_data.lang);
-  EXPECT_EQ(kNotificationBody, web_data.body);
-  EXPECT_EQ(kNotificationTag, web_data.tag);
-  EXPECT_EQ(kNotificationImageUrl, web_data.image.GetString());
-  EXPECT_EQ(kNotificationIconUrl, web_data.icon.GetString());
-  EXPECT_EQ(kNotificationBadgeUrl, web_data.badge.GetString());
-
-  ASSERT_EQ(vibration_pattern.size(), web_data.vibrate.size());
-  for (size_t i = 0; i < vibration_pattern.size(); ++i)
-    EXPECT_EQ(vibration_pattern[i], web_data.vibrate[i]);
-
-  EXPECT_DOUBLE_EQ(kNotificationTimestamp, web_data.timestamp);
-  EXPECT_TRUE(web_data.renotify);
-  EXPECT_TRUE(web_data.silent);
-  EXPECT_TRUE(web_data.require_interaction);
-
-  ASSERT_EQ(developer_data.size(), web_data.data.size());
-  for (size_t i = 0; i < developer_data.size(); ++i)
-    EXPECT_EQ(developer_data[i], web_data.data[i]);
-
-  ASSERT_EQ(platform_data.actions.size(), web_data.actions.size());
-  EXPECT_EQ(WebNotificationAction::kButton, web_data.actions[0].type);
-  EXPECT_EQ(kAction1Name, web_data.actions[0].action);
-  EXPECT_EQ(kAction1Title, web_data.actions[0].title);
-  EXPECT_EQ(kAction1IconUrl, web_data.actions[0].icon.GetString());
-  EXPECT_EQ(kAction1Placeholder, web_data.actions[0].placeholder);
-  EXPECT_EQ(WebNotificationAction::kText, web_data.actions[1].type);
-  EXPECT_EQ(kAction2Name, web_data.actions[1].action);
-  EXPECT_EQ(kAction2Title, web_data.actions[1].title);
-  EXPECT_EQ(kAction2IconUrl, web_data.actions[1].icon.GetString());
-  EXPECT_TRUE(web_data.actions[1].placeholder.IsNull());
-  EXPECT_EQ(kShowTriggerTimestamp, web_data.show_trigger_timestamp);
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/platform/exported/web_runtime_features.cc b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
index cee4e00..27bb2f24 100644
--- a/third_party/blink/renderer/platform/exported/web_runtime_features.cc
+++ b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
@@ -516,12 +516,6 @@
   RuntimeEnabledFeatures::SetResourceLoadSchedulerEnabled(enable);
 }
 
-void WebRuntimeFeatures::EnableRestrictDeviceSensorEventsToSecureContexts(
-    bool enable) {
-  RuntimeEnabledFeatures::SetRestrictDeviceSensorEventsToSecureContextsEnabled(
-      enable);
-}
-
 void WebRuntimeFeatures::EnableRestrictLazyFrameLoadingToDataSaver(
     bool enable) {
   RuntimeEnabledFeatures::SetRestrictLazyFrameLoadingToDataSaverEnabled(enable);
diff --git a/third_party/blink/renderer/platform/exported/web_service_worker_request.cc b/third_party/blink/renderer/platform/exported/web_service_worker_request.cc
deleted file mode 100644
index a4d985a..0000000
--- a/third_party/blink/renderer/platform/exported/web_service_worker_request.cc
+++ /dev/null
@@ -1,258 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_request.h"
-
-#include "base/unguessable_token.h"
-#include "third_party/blink/public/platform/web_http_body.h"
-#include "third_party/blink/public/platform/web_http_header_visitor.h"
-#include "third_party/blink/public/platform/web_string.h"
-#include "third_party/blink/public/platform/web_url_request.h"
-#include "third_party/blink/renderer/platform/network/encoded_form_data.h"
-#include "third_party/blink/renderer/platform/weborigin/kurl.h"
-#include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/ref_counted.h"
-
-namespace blink {
-
-class WebServiceWorkerRequestPrivate
-    : public RefCounted<WebServiceWorkerRequestPrivate> {
-  USING_FAST_MALLOC(WebServiceWorkerRequestPrivate);
-
- public:
-  WebURL url_;
-  WebString method_;
-  HTTPHeaderMap headers_;
-  scoped_refptr<EncodedFormData> http_body;
-  Referrer referrer_;
-  network::mojom::FetchRequestMode mode_ =
-      network::mojom::FetchRequestMode::kNoCors;
-  bool is_main_resource_load_ = false;
-  network::mojom::FetchCredentialsMode credentials_mode_ =
-      network::mojom::FetchCredentialsMode::kOmit;
-  mojom::FetchCacheMode cache_mode_ = mojom::FetchCacheMode::kDefault;
-  network::mojom::FetchRedirectMode redirect_mode_ =
-      network::mojom::FetchRedirectMode::kFollow;
-  mojom::RequestContextType request_context_ =
-      mojom::RequestContextType::UNSPECIFIED;
-  network::mojom::RequestContextFrameType frame_type_ =
-      network::mojom::RequestContextFrameType::kNone;
-  WebString integrity_;
-  WebURLRequest::Priority priority_ = WebURLRequest::Priority::kUnresolved;
-  bool keepalive_ = false;
-  WebString client_id_;
-  bool is_reload_ = false;
-  bool is_history_navigation_ = false;
-  base::UnguessableToken window_id_;
-};
-
-WebServiceWorkerRequest::WebServiceWorkerRequest()
-    : private_(base::AdoptRef(new WebServiceWorkerRequestPrivate)) {}
-
-void WebServiceWorkerRequest::Reset() {
-  private_.Reset();
-}
-
-void WebServiceWorkerRequest::Assign(const WebServiceWorkerRequest& other) {
-  private_ = other.private_;
-}
-
-void WebServiceWorkerRequest::SetURL(const WebURL& url) {
-  private_->url_ = url;
-}
-
-const WebString& WebServiceWorkerRequest::Integrity() const {
-  return private_->integrity_;
-}
-
-WebURLRequest::Priority WebServiceWorkerRequest::Priority() const {
-  return private_->priority_;
-}
-
-bool WebServiceWorkerRequest::Keepalive() const {
-  return private_->keepalive_;
-}
-
-const WebURL& WebServiceWorkerRequest::Url() const {
-  return private_->url_;
-}
-
-void WebServiceWorkerRequest::SetMethod(const WebString& method) {
-  private_->method_ = method;
-}
-
-const WebString& WebServiceWorkerRequest::Method() const {
-  return private_->method_;
-}
-
-void WebServiceWorkerRequest::SetHeader(const WebString& key,
-                                        const WebString& value) {
-  if (DeprecatedEqualIgnoringCase(key, "referer"))
-    return;
-  private_->headers_.Set(key, value);
-}
-
-void WebServiceWorkerRequest::AppendHeader(const WebString& key,
-                                           const WebString& value) {
-  if (DeprecatedEqualIgnoringCase(key, "referer"))
-    return;
-  HTTPHeaderMap::AddResult result = private_->headers_.Add(key, value);
-  if (!result.is_new_entry)
-    result.stored_value->value =
-        result.stored_value->value + ", " + String(value);
-}
-
-void WebServiceWorkerRequest::VisitHttpHeaderFields(
-    WebHTTPHeaderVisitor* header_visitor) const {
-  for (HTTPHeaderMap::const_iterator i = private_->headers_.begin(),
-                                     end = private_->headers_.end();
-       i != end; ++i)
-    header_visitor->VisitHeader(i->key, i->value);
-}
-
-const HTTPHeaderMap& WebServiceWorkerRequest::Headers() const {
-  return private_->headers_;
-}
-
-void WebServiceWorkerRequest::SetBody(const WebHTTPBody& body) {
-  private_->http_body = body;
-}
-
-WebHTTPBody WebServiceWorkerRequest::Body() const {
-  return private_->http_body;
-}
-
-void WebServiceWorkerRequest::SetReferrer(
-    const WebString& web_referrer,
-    network::mojom::ReferrerPolicy referrer_policy) {
-  // WebString doesn't have the distinction between empty and null. We use
-  // the null WTFString for referrer.
-  DCHECK_EQ(Referrer::NoReferrer(), String());
-  String referrer =
-      web_referrer.IsEmpty() ? Referrer::NoReferrer() : String(web_referrer);
-  private_->referrer_ = Referrer(referrer, referrer_policy);
-}
-
-WebURL WebServiceWorkerRequest::ReferrerUrl() const {
-  return KURL(private_->referrer_.referrer);
-}
-
-network::mojom::ReferrerPolicy WebServiceWorkerRequest::GetReferrerPolicy()
-    const {
-  return private_->referrer_.referrer_policy;
-}
-
-const Referrer& WebServiceWorkerRequest::GetReferrer() const {
-  return private_->referrer_;
-}
-
-void WebServiceWorkerRequest::SetMode(network::mojom::FetchRequestMode mode) {
-  private_->mode_ = mode;
-}
-
-network::mojom::FetchRequestMode WebServiceWorkerRequest::Mode() const {
-  return private_->mode_;
-}
-
-void WebServiceWorkerRequest::SetIsMainResourceLoad(
-    bool is_main_resource_load) {
-  private_->is_main_resource_load_ = is_main_resource_load;
-}
-
-bool WebServiceWorkerRequest::IsMainResourceLoad() const {
-  return private_->is_main_resource_load_;
-}
-
-void WebServiceWorkerRequest::SetCredentialsMode(
-    network::mojom::FetchCredentialsMode credentials_mode) {
-  private_->credentials_mode_ = credentials_mode;
-}
-
-void WebServiceWorkerRequest::SetIntegrity(const WebString& integrity) {
-  private_->integrity_ = integrity;
-}
-
-void WebServiceWorkerRequest::SetPriority(WebURLRequest::Priority priority) {
-  private_->priority_ = priority;
-}
-
-void WebServiceWorkerRequest::SetKeepalive(bool keepalive) {
-  private_->keepalive_ = keepalive;
-}
-
-network::mojom::FetchCredentialsMode WebServiceWorkerRequest::CredentialsMode()
-    const {
-  return private_->credentials_mode_;
-}
-
-void WebServiceWorkerRequest::SetCacheMode(mojom::FetchCacheMode cache_mode) {
-  private_->cache_mode_ = cache_mode;
-}
-
-mojom::FetchCacheMode WebServiceWorkerRequest::CacheMode() const {
-  return private_->cache_mode_;
-}
-
-void WebServiceWorkerRequest::SetRedirectMode(
-    network::mojom::FetchRedirectMode redirect_mode) {
-  private_->redirect_mode_ = redirect_mode;
-}
-
-network::mojom::FetchRedirectMode WebServiceWorkerRequest::RedirectMode()
-    const {
-  return private_->redirect_mode_;
-}
-
-void WebServiceWorkerRequest::SetRequestContext(
-    mojom::RequestContextType request_context) {
-  private_->request_context_ = request_context;
-}
-
-mojom::RequestContextType WebServiceWorkerRequest::GetRequestContext() const {
-  return private_->request_context_;
-}
-
-void WebServiceWorkerRequest::SetFrameType(
-    network::mojom::RequestContextFrameType frame_type) {
-  private_->frame_type_ = frame_type;
-}
-
-network::mojom::RequestContextFrameType WebServiceWorkerRequest::GetFrameType()
-    const {
-  return private_->frame_type_;
-}
-
-void WebServiceWorkerRequest::SetClientId(const WebString& client_id) {
-  private_->client_id_ = client_id;
-}
-
-const WebString& WebServiceWorkerRequest::ClientId() const {
-  return private_->client_id_;
-}
-
-void WebServiceWorkerRequest::SetIsReload(bool is_reload) {
-  private_->is_reload_ = is_reload;
-}
-
-bool WebServiceWorkerRequest::IsReload() const {
-  return private_->is_reload_;
-}
-
-void WebServiceWorkerRequest::SetIsHistoryNavigation(bool b) {
-  private_->is_history_navigation_ = b;
-}
-
-bool WebServiceWorkerRequest::IsHistoryNavigation() const {
-  return private_->is_history_navigation_;
-}
-
-void WebServiceWorkerRequest::SetWindowId(const base::UnguessableToken& id) {
-  private_->window_id_ = id;
-}
-
-const base::UnguessableToken& WebServiceWorkerRequest::GetWindowId() const {
-  return private_->window_id_;
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/platform/exported/web_service_worker_response.cc b/third_party/blink/renderer/platform/exported/web_service_worker_response.cc
deleted file mode 100644
index 317e4d1..0000000
--- a/third_party/blink/renderer/platform/exported/web_service_worker_response.cc
+++ /dev/null
@@ -1,238 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_response.h"
-
-#include "third_party/blink/public/mojom/blob/blob.mojom-blink.h"
-#include "third_party/blink/public/platform/web_http_header_visitor.h"
-#include "third_party/blink/renderer/platform/blob/blob_data.h"
-#include "third_party/blink/renderer/platform/network/http_header_map.h"
-#include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/hash_map.h"
-#include "third_party/blink/renderer/platform/wtf/ref_counted.h"
-#include "third_party/blink/renderer/platform/wtf/time.h"
-
-namespace blink {
-
-class WebServiceWorkerResponsePrivate
-    : public RefCounted<WebServiceWorkerResponsePrivate> {
-  USING_FAST_MALLOC(WebServiceWorkerResponsePrivate);
-
- public:
-  WebServiceWorkerResponsePrivate()
-      : status(0),
-        response_type(network::mojom::FetchResponseType::kDefault),
-        response_source(network::mojom::FetchResponseSource::kUnspecified),
-        error(mojom::ServiceWorkerResponseError::kUnknown) {}
-  WebVector<WebURL> url_list;
-  uint16_t status;
-  WebString status_text;
-  network::mojom::FetchResponseType response_type;
-  network::mojom::FetchResponseSource response_source;
-  HTTPHeaderMap headers;
-  scoped_refptr<BlobDataHandle> blob_data_handle;
-  mojom::ServiceWorkerResponseError error;
-  Time response_time;
-  WebString cache_storage_cache_name;
-  WebVector<WebString> cors_exposed_header_names;
-  scoped_refptr<BlobDataHandle> side_data_blob_data_handle;
-};
-
-WebServiceWorkerResponse::WebServiceWorkerResponse()
-    : private_(base::AdoptRef(new WebServiceWorkerResponsePrivate)) {}
-
-void WebServiceWorkerResponse::Reset() {
-  private_.Reset();
-}
-
-void WebServiceWorkerResponse::Assign(const WebServiceWorkerResponse& other) {
-  private_ = other.private_;
-}
-
-void WebServiceWorkerResponse::SetURLList(const WebVector<WebURL>& url_list) {
-  private_->url_list = url_list;
-}
-
-const WebVector<WebURL>& WebServiceWorkerResponse::UrlList() const {
-  return private_->url_list;
-}
-
-void WebServiceWorkerResponse::SetStatus(uint16_t status) {
-  private_->status = status;
-}
-
-uint16_t WebServiceWorkerResponse::Status() const {
-  return private_->status;
-}
-
-void WebServiceWorkerResponse::SetStatusText(const WebString& status_text) {
-  private_->status_text = status_text;
-}
-
-const WebString& WebServiceWorkerResponse::StatusText() const {
-  return private_->status_text;
-}
-
-void WebServiceWorkerResponse::SetResponseType(
-    network::mojom::FetchResponseType response_type) {
-  private_->response_type = response_type;
-}
-
-network::mojom::FetchResponseType WebServiceWorkerResponse::ResponseType()
-    const {
-  return private_->response_type;
-}
-
-void WebServiceWorkerResponse::SetResponseSource(
-    network::mojom::FetchResponseSource response_source) {
-  private_->response_source = response_source;
-}
-
-network::mojom::FetchResponseSource WebServiceWorkerResponse::ResponseSource()
-    const {
-  return private_->response_source;
-}
-
-void WebServiceWorkerResponse::SetHeader(const WebString& key,
-                                         const WebString& value) {
-  private_->headers.Set(key, value);
-}
-
-void WebServiceWorkerResponse::AppendHeader(const WebString& key,
-                                            const WebString& value) {
-  HTTPHeaderMap::AddResult add_result = private_->headers.Add(key, value);
-  if (!add_result.is_new_entry)
-    add_result.stored_value->value =
-        add_result.stored_value->value + ", " + String(value);
-}
-
-WebVector<WebString> WebServiceWorkerResponse::GetHeaderKeys() const {
-  Vector<String> keys;
-  for (HTTPHeaderMap::const_iterator it = private_->headers.begin(),
-                                     end = private_->headers.end();
-       it != end; ++it)
-    keys.push_back(it->key);
-
-  return keys;
-}
-
-WebString WebServiceWorkerResponse::GetHeader(const WebString& key) const {
-  return private_->headers.Get(key);
-}
-
-void WebServiceWorkerResponse::VisitHttpHeaderFields(
-    WebHTTPHeaderVisitor* header_visitor) const {
-  for (HTTPHeaderMap::const_iterator i = private_->headers.begin(),
-                                     end = private_->headers.end();
-       i != end; ++i)
-    header_visitor->VisitHeader(i->key, i->value);
-}
-
-void WebServiceWorkerResponse::SetBlob(
-    const WebString& uuid,
-    uint64_t size,
-    mojo::ScopedMessagePipeHandle blob_pipe) {
-  private_->blob_data_handle = BlobDataHandle::Create(
-      uuid, String(), size,
-      mojom::blink::BlobPtrInfo(std::move(blob_pipe),
-                                mojom::blink::Blob::Version_));
-}
-
-WebString WebServiceWorkerResponse::BlobUUID() const {
-  if (!private_->blob_data_handle)
-    return WebString();
-  return private_->blob_data_handle->Uuid();
-}
-
-uint64_t WebServiceWorkerResponse::BlobSize() const {
-  if (!private_->blob_data_handle)
-    return 0;
-  return private_->blob_data_handle->size();
-}
-
-mojo::ScopedMessagePipeHandle WebServiceWorkerResponse::CloneBlobPtr() const {
-  if (!private_->blob_data_handle)
-    return mojo::ScopedMessagePipeHandle();
-  return private_->blob_data_handle->CloneBlobPtr()
-      .PassInterface()
-      .PassHandle();
-}
-
-void WebServiceWorkerResponse::SetError(
-    mojom::ServiceWorkerResponseError error) {
-  private_->error = error;
-}
-
-mojom::ServiceWorkerResponseError WebServiceWorkerResponse::GetError() const {
-  return private_->error;
-}
-
-void WebServiceWorkerResponse::SetResponseTime(base::Time time) {
-  private_->response_time = time;
-}
-
-base::Time WebServiceWorkerResponse::ResponseTime() const {
-  return private_->response_time;
-}
-
-void WebServiceWorkerResponse::SetCacheStorageCacheName(
-    const WebString& cache_storage_cache_name) {
-  private_->cache_storage_cache_name = cache_storage_cache_name;
-}
-
-const WebString& WebServiceWorkerResponse::CacheStorageCacheName() const {
-  return private_->cache_storage_cache_name;
-}
-
-void WebServiceWorkerResponse::SetCorsExposedHeaderNames(
-    const WebVector<WebString>& header_names) {
-  private_->cors_exposed_header_names = header_names;
-}
-
-const WebVector<WebString>& WebServiceWorkerResponse::CorsExposedHeaderNames()
-    const {
-  return private_->cors_exposed_header_names;
-}
-
-const HTTPHeaderMap& WebServiceWorkerResponse::Headers() const {
-  return private_->headers;
-}
-
-void WebServiceWorkerResponse::SetBlobDataHandle(
-    scoped_refptr<BlobDataHandle> blob_data_handle) {
-  private_->blob_data_handle = std::move(blob_data_handle);
-}
-
-scoped_refptr<BlobDataHandle> WebServiceWorkerResponse::GetBlobDataHandle()
-    const {
-  return private_->blob_data_handle;
-}
-
-void WebServiceWorkerResponse::SetSideDataBlobDataHandle(
-    scoped_refptr<BlobDataHandle> blob_data_handle) {
-  private_->side_data_blob_data_handle = std::move(blob_data_handle);
-}
-
-WebString WebServiceWorkerResponse::SideDataBlobUUID() const {
-  if (!private_->side_data_blob_data_handle)
-    return WebString();
-  return private_->side_data_blob_data_handle->Uuid();
-}
-
-uint64_t WebServiceWorkerResponse::SideDataBlobSize() const {
-  if (!private_->side_data_blob_data_handle)
-    return 0;
-  return private_->side_data_blob_data_handle->size();
-}
-
-mojo::ScopedMessagePipeHandle WebServiceWorkerResponse::CloneSideDataBlobPtr()
-    const {
-  if (!private_->side_data_blob_data_handle)
-    return mojo::ScopedMessagePipeHandle();
-  return private_->side_data_blob_data_handle->CloneBlobPtr()
-      .PassInterface()
-      .PassHandle();
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc
index 6dc0061..fb73b18 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc
@@ -948,7 +948,7 @@
 
   unsigned length = end - start;
   scoped_refptr<ShapeResult> result =
-      ShapeResult::Create(font, length, direction);
+      ShapeResult::Create(font, start, length, direction);
 
   HarfBuzzScopedPtr<hb_buffer_t> buffer(hb_buffer_create(), hb_buffer_destroy);
   RangeData range_data = CreateRangeData(font, direction, buffer.Get());
@@ -983,10 +983,6 @@
     }
   }
 
-  // Ensure |start_index_| is updated even when no runs were inserted.
-  if (UNLIKELY(result->runs_.IsEmpty()))
-    result->start_index_ = start;
-
 #if DCHECK_IS_ON()
   if (result)
     CheckShapeResultRange(result.get(), start, end, text_, font);
@@ -1009,7 +1005,7 @@
 
   unsigned length = end - start;
   scoped_refptr<ShapeResult> result =
-      ShapeResult::Create(font, length, direction);
+      ShapeResult::Create(font, start, length, direction);
 
   HarfBuzzScopedPtr<hb_buffer_t> buffer(hb_buffer_create(), hb_buffer_destroy);
   RangeData range_data = CreateRangeData(font, direction, buffer.Get());
@@ -1024,10 +1020,6 @@
     ShapeSegment(&range_data, segmented_range, result.get());
   }
 
-  // Ensure |start_index_| is updated even when no runs were inserted.
-  if (UNLIKELY(result->runs_.IsEmpty()))
-    result->start_index_ = start;
-
 #if DCHECK_IS_ON()
   if (result)
     CheckShapeResultRange(result.get(), start, end, text_, font);
@@ -1049,7 +1041,7 @@
 
   unsigned length = end - start;
   scoped_refptr<ShapeResult> result =
-      ShapeResult::Create(font, length, direction);
+      ShapeResult::Create(font, start, length, direction);
 
   HarfBuzzScopedPtr<hb_buffer_t> buffer(hb_buffer_create(), hb_buffer_destroy);
   RangeData range_data = CreateRangeData(font, direction, buffer.Get());
@@ -1058,10 +1050,6 @@
 
   ShapeSegment(&range_data, pre_segmented, result.get());
 
-  // Ensure |start_index_| is updated even when no runs were inserted.
-  if (UNLIKELY(result->runs_.IsEmpty()))
-    result->start_index_ = start;
-
 #if DCHECK_IS_ON()
   if (result)
     CheckShapeResultRange(result.get(), start, end, text_, font);
diff --git a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_test.cc b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_test.cc
index db3c0098..b4794c7a 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_test.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_test.cc
@@ -16,6 +16,7 @@
 #include "third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h"
 #include "third_party/blink/renderer/platform/fonts/shaping/shape_result_spacing.h"
 #include "third_party/blink/renderer/platform/fonts/shaping/shape_result_test_info.h"
+#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h"
 #include "third_party/blink/renderer/platform/testing/font_test_helpers.h"
 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
 #include "third_party/blink/renderer/platform/text/text_break_iterator.h"
@@ -102,6 +103,16 @@
     return shape_result;
   }
 
+  scoped_refptr<ShapeResult> CreateMissingRunResult(TextDirection direction) {
+    scoped_refptr<ShapeResult> result =
+        ShapeResult::Create(&font, 2, 8, direction);
+    result->InsertRunForTesting(2, 1, direction, {0});
+    result->InsertRunForTesting(3, 3, direction, {0, 1});
+    // The character index 6 and 7 is missing.
+    result->InsertRunForTesting(8, 2, direction, {0});
+    return result;
+  }
+
   FontCachePurgePreventer font_cache_purge_preventer;
   FontDescription font_description;
   Font font;
@@ -178,7 +189,7 @@
 
 TEST_F(HarfBuzzShaperTest, MutableUnique) {
   scoped_refptr<ShapeResult> result =
-      ShapeResult::Create(&font, 0, TextDirection::kLtr);
+      ShapeResult::Create(&font, 0, 0, TextDirection::kLtr);
   EXPECT_TRUE(result->HasOneRef());
 
   // At this point, |result| has only one ref count.
@@ -462,7 +473,7 @@
       shaper.Shape(&font, direction, 3, string.length());
 
   scoped_refptr<ShapeResult> composite_result =
-      ShapeResult::Create(&font, 0, direction);
+      ShapeResult::Create(&font, 0, 0, direction);
   result1->CopyRange(0, 3, composite_result.get());
   result2->CopyRange(3, string.length(), composite_result.get());
 
@@ -486,7 +497,7 @@
       shaper.Shape(&font, direction, 3, string.length());
 
   scoped_refptr<ShapeResult> composite_result =
-      ShapeResult::Create(&font, 0, direction);
+      ShapeResult::Create(&font, 0, 0, direction);
   result1->CopyRange(0, 3, composite_result.get());
   result2->CopyRange(3, string.length(), composite_result.get());
 
@@ -554,7 +565,7 @@
       shaper.Shape(&font, direction, 3, string.length());
 
   scoped_refptr<ShapeResult> composite_result =
-      ShapeResult::Create(&font, 0, direction);
+      ShapeResult::Create(&font, 0, 0, direction);
   result1->CopyRange(0, 3, composite_result.get());
   result2->CopyRange(3, string.length(), composite_result.get());
 
@@ -1129,13 +1140,15 @@
   scoped_refptr<ShapeResult> result = shaper.Shape(&font, direction);
 
   // Split the result.
-  scoped_refptr<ShapeResult> result1 = ShapeResult::Create(&font, 0, direction);
+  scoped_refptr<ShapeResult> result1 =
+      ShapeResult::Create(&font, 0, 0, direction);
   result->CopyRange(0, test_data.break_point, result1.get());
   EXPECT_EQ(test_data.break_point, result1->NumCharacters());
   EXPECT_EQ(0u, result1->StartIndex());
   EXPECT_EQ(test_data.break_point, result1->EndIndex());
 
-  scoped_refptr<ShapeResult> result2 = ShapeResult::Create(&font, 0, direction);
+  scoped_refptr<ShapeResult> result2 =
+      ShapeResult::Create(&font, 0, 0, direction);
   result->CopyRange(test_data.break_point, string.length(), result2.get());
   EXPECT_EQ(string.length() - test_data.break_point, result2->NumCharacters());
   EXPECT_EQ(test_data.break_point, result2->StartIndex());
@@ -1143,7 +1156,7 @@
 
   // Combine them.
   scoped_refptr<ShapeResult> composite_result =
-      ShapeResult::Create(&font, 0, direction);
+      ShapeResult::Create(&font, 0, 0, direction);
   result1->CopyRange(0, test_data.break_point, composite_result.get());
   result2->CopyRange(0, string.length(), composite_result.get());
   EXPECT_EQ(string.length(), composite_result->NumCharacters());
@@ -1176,7 +1189,7 @@
 
   // Combine them.
   scoped_refptr<ShapeResult> composite_result =
-      ShapeResult::Create(&font, 0, direction);
+      ShapeResult::Create(&font, 0, 0, direction);
   result1->CopyRange(0, test_data.break_point, composite_result.get());
   result2->CopyRange(0, string.length(), composite_result.get());
   EXPECT_EQ(string.length(), composite_result->NumCharacters());
@@ -1197,7 +1210,7 @@
   scoped_refptr<ShapeResult> result = shaper.Shape(&font, direction);
 
   scoped_refptr<ShapeResult> composite_result =
-      ShapeResult::Create(&font, 0, direction);
+      ShapeResult::Create(&font, 0, 0, direction);
   result->CopyRange(0, 10, composite_result.get());
   result->CopyRange(10, 20, composite_result.get());
   result->CopyRange(20, 30, composite_result.get());
@@ -1228,7 +1241,7 @@
   scoped_refptr<ShapeResult> result = shaper.Shape(&font, direction);
 
   scoped_refptr<ShapeResult> composite_result =
-      ShapeResult::Create(&font, 0, direction);
+      ShapeResult::Create(&font, 0, 0, direction);
   result->CopyRange(0, 4, composite_result.get());
   result->CopyRange(4, 6, composite_result.get());
   result->CopyRange(6, 8, composite_result.get());
@@ -1266,7 +1279,8 @@
   scoped_refptr<ShapeResult> result = shaper.Shape(&font, direction);
 
   // CopyRange(5, 7) should copy 1 character from [1] and 1 from [2].
-  scoped_refptr<ShapeResult> target = ShapeResult::Create(&font, 0, direction);
+  scoped_refptr<ShapeResult> target =
+      ShapeResult::Create(&font, 0, 0, direction);
   result->CopyRange(5, 7, target.get());
   EXPECT_EQ(2u, target->NumCharacters());
 }
@@ -1296,7 +1310,7 @@
       shaper.Shape(&font, direction, 6, string.length());
 
   scoped_refptr<ShapeResult> composite_result =
-      ShapeResult::Create(&font, 0, direction);
+      ShapeResult::Create(&font, 0, 0, direction);
   result1->CopyRange(0, 6, composite_result.get());
   result2->CopyRange(6, string.length(), composite_result.get());
 
@@ -1344,7 +1358,7 @@
   // Verify safe to break information in copied results to ensure that both
   // copying and multi-run break information works.
   scoped_refptr<ShapeResult> copied_result =
-      ShapeResult::Create(&testFont, 0, TextDirection::kLtr);
+      ShapeResult::Create(&testFont, 0, 0, TextDirection::kLtr);
   result->CopyRange(0, 3, copied_result.get());
   result->CopyRange(3, string.length(), copied_result.get());
 
@@ -1384,7 +1398,7 @@
   // Verify safe to break information in copied results to ensure that both
   // copying and multi-run break information works.
   scoped_refptr<ShapeResult> copied_result =
-      ShapeResult::Create(&testFont, 0, TextDirection::kLtr);
+      ShapeResult::Create(&testFont, 0, 0, TextDirection::kLtr);
   result->CopyRange(0, 3, copied_result.get());
   result->CopyRange(3, string.length(), copied_result.get());
 
@@ -1493,11 +1507,7 @@
 // Test when some characters are missing in |runs_|.
 TEST_P(ShapeParameterTest, SafeToBreakMissingRun) {
   TextDirection direction = GetParam();
-  scoped_refptr<ShapeResult> result = ShapeResult::Create(&font, 8, direction);
-  result->InsertRunForTesting(2, 1, direction, {0});
-  result->InsertRunForTesting(3, 3, direction, {0, 1});
-  // The character index 6 and 7 is missing.
-  result->InsertRunForTesting(8, 2, direction, {0});
+  scoped_refptr<ShapeResult> result = CreateMissingRunResult(direction);
 #if DCHECK_IS_ON()
   result->CheckConsistency();
 #endif
@@ -1524,6 +1534,53 @@
   EXPECT_EQ(8u, result->PreviousSafeToBreakOffset(9));
 }
 
+TEST_P(ShapeParameterTest, CopyRangeMissingRun) {
+  TextDirection direction = GetParam();
+  scoped_refptr<ShapeResult> result = CreateMissingRunResult(direction);
+
+  // 6 and 7 are missing but NumCharacters() should be 4.
+  scoped_refptr<ShapeResult> sub = result->SubRange(5, 9);
+  EXPECT_EQ(sub->StartIndex(), 5u);
+  EXPECT_EQ(sub->EndIndex(), 9u);
+  EXPECT_EQ(sub->NumCharacters(), 4u);
+
+  // The end is missing.
+  sub = result->SubRange(5, 7);
+  EXPECT_EQ(sub->StartIndex(), 5u);
+  EXPECT_EQ(sub->EndIndex(), 7u);
+  EXPECT_EQ(sub->NumCharacters(), 2u);
+
+  // The start is missing.
+  sub = result->SubRange(7, 9);
+  EXPECT_EQ(sub->StartIndex(), 7u);
+  EXPECT_EQ(sub->EndIndex(), 9u);
+  EXPECT_EQ(sub->NumCharacters(), 2u);
+}
+
+TEST_P(ShapeParameterTest, ShapeResultViewMissingRun) {
+  TextDirection direction = GetParam();
+  scoped_refptr<ShapeResult> result = CreateMissingRunResult(direction);
+
+  // 6 and 7 are missing but NumCharacters() should be 4.
+  scoped_refptr<ShapeResultView> view =
+      ShapeResultView::Create(result.get(), 5, 9);
+  EXPECT_EQ(view->StartIndex(), 5u);
+  EXPECT_EQ(view->EndIndex(), 9u);
+  EXPECT_EQ(view->NumCharacters(), 4u);
+
+  // The end is missing.
+  view = ShapeResultView::Create(result.get(), 5, 7);
+  EXPECT_EQ(view->StartIndex(), 5u);
+  EXPECT_EQ(view->EndIndex(), 7u);
+  EXPECT_EQ(view->NumCharacters(), 2u);
+
+  // The start is missing.
+  view = ShapeResultView::Create(result.get(), 7, 9);
+  EXPECT_EQ(view->StartIndex(), 7u);
+  EXPECT_EQ(view->EndIndex(), 9u);
+  EXPECT_EQ(view->NumCharacters(), 2u);
+}
+
 // Call this to ensure your test string has some kerning going on.
 static bool KerningIsHappening(const FontDescription& font_description,
                                TextDirection direction,
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc b/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
index 5cf513a4..7a187aed 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
@@ -363,19 +363,23 @@
 }
 
 ShapeResult::ShapeResult(scoped_refptr<const SimpleFontData> font_data,
+                         unsigned start_index,
                          unsigned num_characters,
                          TextDirection direction)
     : width_(0),
       primary_font_(font_data),
+      start_index_(start_index),
       num_characters_(num_characters),
       num_glyphs_(0),
       direction_(static_cast<unsigned>(direction)),
       has_vertical_offsets_(0) {}
 
 ShapeResult::ShapeResult(const Font* font,
+                         unsigned start_index,
                          unsigned num_characters,
                          TextDirection direction)
-    : ShapeResult(font->PrimaryFont(), num_characters, direction) {}
+    : ShapeResult(font->PrimaryFont(), start_index, num_characters, direction) {
+}
 
 ShapeResult::ShapeResult(const ShapeResult& other)
     : width_(other.width_),
@@ -1096,10 +1100,6 @@
   // If we didn't find an existing slot to place it, append.
   if (run)
     runs_.push_back(std::move(run));
-
-  // TODO(layout-dev): We could skip this unless the inserted run is the first
-  // one but determiening that is likely as expensive as the computation.
-  UpdateStartIndex();
 }
 
 ShapeResult::RunInfo* ShapeResult::InsertRunForTesting(
@@ -1154,21 +1154,6 @@
   runs_.swap(new_runs);
 }
 
-unsigned ShapeResult::ComputeStartIndex() const {
-  if (UNLIKELY(runs_.IsEmpty()))
-    return 0;
-  const RunInfo& first_run = *runs_.front();
-  if (!Rtl())  // Left-to-right.
-    return first_run.start_index_;
-  // Right-to-left.
-  unsigned end_index = first_run.start_index_ + first_run.num_characters_;
-  return end_index - num_characters_;
-}
-
-void ShapeResult::UpdateStartIndex() {
-  start_index_ = ComputeStartIndex();
-}
-
 void ShapeResult::CopyRange(unsigned start_offset,
                             unsigned end_offset,
                             ShapeResult* target) const {
@@ -1224,10 +1209,20 @@
 
   // When |target| is empty, its character indexes are the specified sub range
   // of |this|. Otherwise the character indexes are renumbered to be continuous.
-  int index_diff =
-      !target->num_characters_
-          ? 0
-          : target->EndIndex() - std::max(start_offset, StartIndex());
+  //
+  // Compute the diff of index and the number of characters from the source
+  // ShapeResult and given offsets, because computing them from runs/parts can
+  // be inaccurate when all characters in a run/part are missing.
+  int index_diff;
+  if (!target->num_characters_) {
+    index_diff = 0;
+    target->start_index_ = start_offset;
+  } else {
+    index_diff = target->EndIndex() - std::max(start_offset, StartIndex());
+  }
+  target->num_characters_ +=
+      std::min(end_offset, EndIndex()) - std::max(start_offset, StartIndex());
+
   unsigned target_run_size_before = target->runs_.size();
   for (; run_index < runs_.size(); run_index++) {
     const auto& run = runs_[run_index];
@@ -1242,7 +1237,6 @@
       auto sub_run = run->CreateSubRun(start, end);
       sub_run->start_index_ += index_diff;
       target->width_ += sub_run->width_;
-      target->num_characters_ += sub_run->num_characters_;
       target->num_glyphs_ += sub_run->glyph_data_.size();
       target->runs_.push_back(std::move(sub_run));
 
@@ -1255,7 +1249,6 @@
   }
 
   if (!target->num_glyphs_) {
-    target->UpdateStartIndex();
     return run_index;
   }
 
@@ -1266,7 +1259,6 @@
     target->ReorderRtlRuns(target_run_size_before);
 
   target->has_vertical_offsets_ |= has_vertical_offsets_;
-  target->UpdateStartIndex();
 
 #if DCHECK_IS_ON()
   DCHECK_EQ(
@@ -1281,7 +1273,7 @@
 scoped_refptr<ShapeResult> ShapeResult::SubRange(unsigned start_offset,
                                                  unsigned end_offset) const {
   scoped_refptr<ShapeResult> sub_range =
-      Create(primary_font_.get(), 0, Direction());
+      Create(primary_font_.get(), 0, 0, Direction());
   CopyRange(start_offset, end_offset, sub_range.get());
   return sub_range;
 }
@@ -1302,7 +1294,7 @@
     }
   }
 
-  result->UpdateStartIndex();
+  result->start_index_ = start_index;
   return result;
 }
 
@@ -1314,7 +1306,6 @@
     return;
   }
 
-  DCHECK_EQ(start_index_, ComputeStartIndex());
   const unsigned start_index = StartIndex();
   unsigned index = start_index;
   unsigned num_glyphs = 0;
@@ -1361,7 +1352,7 @@
   DCHECK_GT(length, 0u);
   const SimpleFontData* font_data = font->PrimaryFont();
   scoped_refptr<ShapeResult> result =
-      ShapeResult::Create(font, length, direction);
+      ShapeResult::Create(font, start_index, length, direction);
   result->num_glyphs_ = length;
   DCHECK_EQ(result->num_glyphs_, length);  // no overflow
   result->has_vertical_offsets_ =
@@ -1394,7 +1385,6 @@
     length -= run_length;
     start_index += run_length;
   } while (length);
-  result->UpdateStartIndex();
   return result;
 }
 
@@ -1406,7 +1396,7 @@
   DCHECK_GT(length, 0u);
   const SimpleFontData* font_data = font->PrimaryFont();
   scoped_refptr<ShapeResult> result =
-      ShapeResult::Create(font, length, direction);
+      ShapeResult::Create(font, start_index, length, direction);
   result->num_glyphs_ = length;
   DCHECK_EQ(result->num_glyphs_, length);  // no overflow
   result->has_vertical_offsets_ =
@@ -1423,7 +1413,6 @@
     width = 0;
   }
   result->runs_.push_back(std::move(run));
-  result->UpdateStartIndex();
   return result;
 }
 
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result.h b/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
index 7c12c6d..2051331 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
@@ -112,13 +112,15 @@
 
  public:
   static scoped_refptr<ShapeResult> Create(const Font* font,
-                                    unsigned num_characters,
-                                    TextDirection direction) {
-    return base::AdoptRef(new ShapeResult(font, num_characters, direction));
+                                           unsigned start_index,
+                                           unsigned num_characters,
+                                           TextDirection direction) {
+    return base::AdoptRef(
+        new ShapeResult(font, start_index, num_characters, direction));
   }
   static scoped_refptr<ShapeResult> CreateEmpty(const ShapeResult& other) {
     return base::AdoptRef(
-        new ShapeResult(other.primary_font_, 0, other.Direction()));
+        new ShapeResult(other.primary_font_, 0, 0, other.Direction()));
   }
   static scoped_refptr<ShapeResult> Create(const ShapeResult& other) {
     return base::AdoptRef(new ShapeResult(other));
@@ -342,16 +344,21 @@
 
  protected:
   ShapeResult(scoped_refptr<const SimpleFontData>,
+              unsigned start_index,
               unsigned num_characters,
               TextDirection);
-  ShapeResult(const Font*, unsigned num_characters, TextDirection);
+  ShapeResult(const Font*,
+              unsigned start_index,
+              unsigned num_characters,
+              TextDirection);
   ShapeResult(const ShapeResult&);
 
   static scoped_refptr<ShapeResult> Create(const SimpleFontData* font_data,
+                                           unsigned start_index,
                                            unsigned num_characters,
                                            TextDirection direction) {
     return base::AdoptRef(
-        new ShapeResult(font_data, num_characters, direction));
+        new ShapeResult(font_data, start_index, num_characters, direction));
   }
 
   // Ensure |grapheme_| is computed. |BreakGlyphs| is valid only when
@@ -447,8 +454,6 @@
                  hb_buffer_t*);
   void InsertRun(scoped_refptr<ShapeResult::RunInfo>);
   void ReorderRtlRuns(unsigned run_size_before);
-  unsigned ComputeStartIndex() const;
-  void UpdateStartIndex();
 
   template <bool is_horizontal_run>
   void ComputeRunInkBounds(const ShapeResult::RunInfo&,
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_test.cc b/third_party/blink/renderer/platform/fonts/shaping/shape_result_test.cc
index e2eb7e3f..af553e3 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_test.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_test.cc
@@ -45,7 +45,8 @@
 
   ShapeResult* CreateShapeResult(TextDirection direction) const {
     return new ShapeResult(
-        direction == TextDirection::kLtr ? &font : &arabic_font, 0, direction);
+        direction == TextDirection::kLtr ? &font : &arabic_font, 0, 0,
+        direction);
   }
 
   FontCachePurgePreventer font_cache_purge_preventer;
@@ -150,7 +151,8 @@
 
   // Combine four separate results into a single one to ensure we have a result
   // with multiple runs.
-  scoped_refptr<ShapeResult> result = ShapeResult::Create(&font, 0, direction);
+  scoped_refptr<ShapeResult> result =
+      ShapeResult::Create(&font, 0, 0, direction);
   shaper_a.Shape(&font, direction)->CopyRange(0u, 5u, result.get());
   shaper_b.Shape(&font, direction)->CopyRange(0u, 2u, result.get());
   shaper_c.Shape(&font, direction)->CopyRange(0u, 25u, result.get());
@@ -166,7 +168,8 @@
   HarfBuzzShaper shaper_c(string.Substring(7, 32));
   HarfBuzzShaper shaper_d(string.Substring(32, 34));
 
-  scoped_refptr<ShapeResult> result = ShapeResult::Create(&font, 0, direction);
+  scoped_refptr<ShapeResult> result =
+      ShapeResult::Create(&font, 0, 0, direction);
   shaper_a.Shape(&font, direction)->CopyRange(0u, 5u, result.get());
   shaper_b.Shape(&font, direction)->CopyRange(0u, 2u, result.get());
   shaper_c.Shape(&font, direction)->CopyRange(0u, 25u, result.get());
@@ -232,7 +235,7 @@
   // Combine three separate results into a single one to ensure we have a result
   // with multiple runs.
   scoped_refptr<ShapeResult> result =
-      ShapeResult::Create(&arabic_font, 0, direction);
+      ShapeResult::Create(&arabic_font, 0, 0, direction);
   shaper_a.Shape(&arabic_font, direction)->CopyRange(0u, 2u, result.get());
   shaper_b.Shape(&arabic_font, direction)->CopyRange(0u, 7u, result.get());
   shaper_c.Shape(&arabic_font, direction)->CopyRange(0u, 8u, result.get());
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.cc b/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.cc
index 490b73f..42e7c42 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.cc
@@ -126,7 +126,8 @@
 
 scoped_refptr<ShapeResult> ShapeResultView::CreateShapeResult() const {
   ShapeResult* new_result =
-      new ShapeResult(primary_font_, num_characters_, Direction());
+      new ShapeResult(primary_font_, start_index_ + char_index_offset_,
+                      num_characters_, Direction());
   new_result->runs_.ReserveCapacity(parts_.size());
   for (const auto& part : parts_) {
     auto new_run = ShapeResult::RunInfo::Create(
@@ -145,7 +146,6 @@
     new_result->runs_.push_back(std::move(new_run));
   }
 
-  new_result->start_index_ = start_index_ + char_index_offset_;
   new_result->num_glyphs_ = num_glyphs_;
   new_result->has_vertical_offsets_ = has_vertical_offsets_;
   new_result->width_ = width_;
@@ -157,7 +157,14 @@
 void ShapeResultView::CreateViewsForResult(const ShapeResultType* other,
                                            unsigned start_index,
                                            unsigned end_index) {
-  bool first_result = num_characters_ == 0;
+  // Compute the diff of index and the number of characters from the source
+  // ShapeResult and given offsets, because computing them from runs/parts can
+  // be inaccurate when all characters in a run/part are missing.
+  int index_diff = start_index_ + num_characters_ -
+                   std::max(start_index, other->StartIndex());
+  num_characters_ += std::min(end_index, other->EndIndex()) -
+                     std::max(start_index, other->StartIndex());
+
   for (const auto& run : other->RunsOrParts()) {
     if (!run->GetRunInfo())
       continue;
@@ -190,28 +197,16 @@
       }
 
       // Adjust start_index for runs to be continuous.
-      unsigned part_start_index;
-      unsigned part_offset;
-      if (!run->Rtl()) {  // Left-to-right
-        part_start_index = start_index_ + num_characters_;
-        part_offset = adjusted_start;
-      } else {  // Right-to-left
-        part_start_index = run->start_index_ + adjusted_start;
-        part_offset = adjusted_start;
-      }
-
+      unsigned part_start_index = run_start + adjusted_start + index_diff;
+      unsigned part_offset = adjusted_start;
       parts_.push_back(std::make_unique<RunInfoPart>(
           run->GetRunInfo(), range, part_start_index, part_offset,
           part_characters, part_width));
 
-      num_characters_ += part_characters;
       num_glyphs_ += range.end - range.begin;
       width_ += part_width;
     }
   }
-
-  if (first_result || Rtl())
-    start_index_ = ComputeStartIndex();
 }
 
 scoped_refptr<ShapeResultView> ShapeResultView::Create(const Segment* segments,
@@ -251,7 +246,13 @@
   // This specialization is an optimization to allow the bounding box to be
   // re-used.
   ShapeResultView* out = new ShapeResultView(result);
-  out->char_index_offset_ = out->Rtl() ? 0 : result->StartIndex();
+  out->char_index_offset_ = result->StartIndex();
+  if (!out->Rtl()) {
+    out->start_index_ = 0;
+  } else {
+    out->start_index_ = out->char_index_offset_;
+    out->char_index_offset_ = 0;
+  }
   out->CreateViewsForResult(result, 0, std::numeric_limits<unsigned>::max());
   out->has_vertical_offsets_ = result->has_vertical_offsets_;
   return base::AdoptRef(out);
@@ -269,11 +270,13 @@
 
   // Compute start index offset for the overall run. This is added to the start
   // index of each glyph to ensure consistency with ShapeResult::SubRange
+  char_index_offset_ = segments[0].result ? segments[0].result->StartIndex()
+                                          : segments[0].view->StartIndex();
+  char_index_offset_ = std::max(char_index_offset_, segments[0].start_index);
   if (!Rtl()) {  // Left-to-right
-    char_index_offset_ = segments[0].result ? segments[0].result->StartIndex()
-                                            : segments[0].view->StartIndex();
-    char_index_offset_ = std::max(char_index_offset_, segments[0].start_index);
+    start_index_ = 0;
   } else {  // Right to left
+    start_index_ = char_index_offset_;
     char_index_offset_ = 0;
   }
 
@@ -295,17 +298,6 @@
   }
 }
 
-unsigned ShapeResultView::ComputeStartIndex() const {
-  if (UNLIKELY(parts_.IsEmpty()))
-    return 0;
-  const RunInfoPart& first_part = *parts_.front();
-  if (!Rtl())  // Left-to-right.
-    return first_part.start_index_;
-  // Right-to-left.
-  unsigned end_index = first_part.start_index_ + first_part.num_characters_;
-  return end_index - num_characters_;
-}
-
 unsigned ShapeResultView::PreviousSafeToBreakOffset(unsigned index) const {
   for (auto it = parts_.rbegin(); it != parts_.rend(); ++it) {
     const auto& part = *it;
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h b/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h
index dba8d9a2..3181b9d 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h
@@ -147,7 +147,6 @@
  private:
   template <class ShapeResultType>
   ShapeResultView(const ShapeResultType*);
-  unsigned ComputeStartIndex() const;
 
   struct RunInfoPart;
   template <class ShapeResultType>
@@ -171,7 +170,7 @@
 
   scoped_refptr<const SimpleFontData> primary_font_;
 
-  mutable unsigned start_index_;  // Cached and updated by ComputeStartIndex.
+  unsigned start_index_;
   unsigned num_characters_;
   unsigned num_glyphs_ : 30;
 
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_view_test.cc b/third_party/blink/renderer/platform/fonts/shaping/shape_result_view_test.cc
index 74a8b14..ce0f6cc 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_view_test.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_view_test.cc
@@ -135,7 +135,8 @@
 
   // Combine four separate results into a single one to ensure we have a result
   // with multiple runs: "hello world!"
-  scoped_refptr<ShapeResult> result = ShapeResult::Create(&font, 0, direction);
+  scoped_refptr<ShapeResult> result =
+      ShapeResult::Create(&font, 0, 0, direction);
   shaper_a.Shape(&font, direction)->CopyRange(0u, 5u, result.get());
   shaper_b.Shape(&font, direction)->CopyRange(0u, 2u, result.get());
   shaper_c.Shape(&font, direction)->CopyRange(0u, 4u, result.get());
@@ -177,7 +178,7 @@
                                  static_cast<void*>(&reference_glyphs));
 
   scoped_refptr<ShapeResult> composite_copy =
-      ShapeResult::Create(&font, 0, direction);
+      ShapeResult::Create(&font, 0, 0, direction);
   result->CopyRange(0, 8, composite_copy.get());
   result->CopyRange(7, 8, composite_copy.get());
   result->CopyRange(10, 11, composite_copy.get());
@@ -216,7 +217,7 @@
   // TODO(layout-dev): Arguably both should be updated to renumber the first
   // result as well but some callers depend on the existing behavior.
   scoped_refptr<ShapeResult> composite_copy =
-      ShapeResult::Create(&font, 0, direction);
+      ShapeResult::Create(&font, 0, 0, direction);
   result->CopyRange(14, 23, composite_copy.get());
   result->CopyRange(33, 55, composite_copy.get());
   result->CopyRange(4, 5, composite_copy.get());
@@ -267,7 +268,7 @@
   // reference_result data might use different fonts, resulting in different
   // glyph ids and metrics.
   scoped_refptr<ShapeResult> composite_copy =
-      ShapeResult::Create(&font, 0, direction);
+      ShapeResult::Create(&font, 0, 0, direction);
   result_a->CopyRange(0, 22, composite_copy.get());
   result_b->CopyRange(0, 7, composite_copy.get());
   EXPECT_EQ(composite_copy->NumCharacters(), reference_result->NumCharacters());
diff --git a/third_party/blink/renderer/platform/instrumentation/BUILD.gn b/third_party/blink/renderer/platform/instrumentation/BUILD.gn
index 8cf23636..9beaee5d 100644
--- a/third_party/blink/renderer/platform/instrumentation/BUILD.gn
+++ b/third_party/blink/renderer/platform/instrumentation/BUILD.gn
@@ -21,6 +21,7 @@
     "tracing/web_memory_allocator_dump.h",
     "tracing/web_process_memory_dump.cc",
     "tracing/web_process_memory_dump.h",
+    "use_counter.h",
   ]
 
   deps = [
diff --git a/third_party/blink/renderer/platform/instrumentation/use_counter.h b/third_party/blink/renderer/platform/instrumentation/use_counter.h
new file mode 100644
index 0000000..591ab8f
--- /dev/null
+++ b/third_party/blink/renderer/platform/instrumentation/use_counter.h
@@ -0,0 +1,59 @@
+// 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_PLATFORM_INSTRUMENTATION_USE_COUNTER_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_INSTRUMENTATION_USE_COUNTER_H_
+
+#include "third_party/blink/public/mojom/web_feature/web_feature.mojom-shared.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+
+namespace blink {
+
+// TODO(yhirano): Remove this.
+using WebFeature = mojom::WebFeature;
+
+// Definition for UseCounter features can be found in:
+// third_party/blink/public/mojom/web_feature/web_feature.mojom
+//
+// UseCounter is used for counting the number of times features of
+// Blink are used on real web pages and help us know commonly
+// features are used and thus when it's safe to remove or change them. It's
+// counting whether a feature is used in a context (e.g., a page), so calling
+// a counting function multiple times for the same UseCounter with the same
+// feature will be ignored.
+//
+// The Chromium Content layer controls what is done with this data.
+//
+// For instance, in Google Chrome, these counts are submitted anonymously
+// through the UMA histogram recording system in Chrome for users who have the
+// "Automatically send usage statistics and crash reports to Google" setting
+// enabled:
+// http://www.google.com/chrome/intl/en/privacy.html
+//
+// This is a pure virtual interface class with some utility static functions.
+class UseCounter : public GarbageCollectedMixin {
+ public:
+  static void Count(UseCounter* use_counter, mojom::WebFeature feature) {
+    if (use_counter) {
+      use_counter->CountUse(feature);
+    }
+  }
+  static void Count(UseCounter& use_counter, mojom::WebFeature feature) {
+    use_counter.CountUse(feature);
+  }
+
+ public:
+  UseCounter() = default;
+  virtual ~UseCounter() = default;
+
+  // Counts a use of the given feature. Repeated calls are ignored.
+  virtual void CountUse(mojom::WebFeature feature) = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(UseCounter);
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_INSTRUMENTATION_USE_COUNTER_H_
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
index fcb6e49..30093e9a 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -248,11 +248,11 @@
   return value;
 }
 
-// This function corresponds with step 2 substep 7 of
-// https://fetch.spec.whatwg.org/#main-fetch.
 void SetReferrer(
     ResourceRequest& request,
     const FetchClientSettingsObject& fetch_client_settings_object) {
+  // TODO(domfarolino): we can probably *just set* the HTTP `Referer` here
+  // no matter what now.
   if (!request.DidSetHttpReferrer()) {
     String referrer_to_use = request.ReferrerString();
     network::mojom::ReferrerPolicy referrer_policy_to_use =
@@ -261,24 +261,20 @@
     if (referrer_to_use == Referrer::ClientReferrerString())
       referrer_to_use = fetch_client_settings_object.GetOutgoingReferrer();
 
-    if (referrer_policy_to_use == network::mojom::ReferrerPolicy::kDefault)
+    if (referrer_policy_to_use == network::mojom::ReferrerPolicy::kDefault) {
       referrer_policy_to_use = fetch_client_settings_object.GetReferrerPolicy();
+    }
 
-    request.SetReferrerString(referrer_to_use);
-    request.SetReferrerPolicy(referrer_policy_to_use);
     // TODO(domfarolino): Stop storing ResourceRequest's referrer as a header
     // and store it elsewhere. See https://crbug.com/850813.
     request.SetHttpReferrer(SecurityPolicy::GenerateReferrer(
         referrer_policy_to_use, request.Url(), referrer_to_use));
   } else {
-    // In the case of stale requests that are being revalidated, these requests
-    // will already have their HttpReferrer set, and we will end up here. We
-    // won't regenerate the referrer, but instead check that it's still correct.
-    CHECK_EQ(SecurityPolicy::GenerateReferrer(request.GetReferrerPolicy(),
-                                              request.Url(),
-                                              request.ReferrerString())
-                 .referrer,
-             request.HttpReferrer());
+    CHECK_EQ(
+        SecurityPolicy::GenerateReferrer(request.GetReferrerPolicy(),
+                                         request.Url(), request.HttpReferrer())
+            .referrer,
+        request.HttpReferrer());
   }
 }
 
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_response.h b/third_party/blink/renderer/platform/loader/fetch/resource_response.h
index e38bb9b..1cdb0045 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_response.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_response.h
@@ -488,9 +488,7 @@
   // https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html
   bool is_signed_exchange_inner_response_ = false;
 
-  // True if this resource is served from the prefetch cache. Currently this
-  // flag is used only for prefetched signed exchanges.
-  // TODO(horo): Mark this also for general prefetch cases.
+  // True if this resource is served from the prefetch cache.
   bool was_in_prefetch_cache_ = false;
 
   // True if this resource was loaded from the network.
diff --git a/third_party/blink/renderer/platform/network/encoded_form_data_mojom_traits.cc b/third_party/blink/renderer/platform/network/encoded_form_data_mojom_traits.cc
index 6ee4dcf6..d82395f 100644
--- a/third_party/blink/renderer/platform/network/encoded_form_data_mojom_traits.cc
+++ b/third_party/blink/renderer/platform/network/encoded_form_data_mojom_traits.cc
@@ -6,11 +6,13 @@
 
 #include "third_party/blink/renderer/platform/network/encoded_form_data_mojom_traits.h"
 
+#include "base/feature_list.h"
 #include "mojo/public/cpp/base/file_mojom_traits.h"
 #include "mojo/public/cpp/base/file_path_mojom_traits.h"
 #include "mojo/public/cpp/base/time_mojom_traits.h"
 #include "mojo/public/cpp/bindings/array_traits_wtf_vector.h"
 #include "mojo/public/cpp/bindings/string_traits_wtf.h"
+#include "services/network/public/cpp/features.h"
 #include "services/network/public/mojom/data_pipe_getter.mojom-blink.h"
 #include "third_party/blink/public/mojom/blob/blob.mojom-blink.h"
 #include "third_party/blink/public/mojom/blob/blob_registry.mojom-blink.h"
@@ -138,10 +140,15 @@
       break;
     }
     case network::mojom::DataElementType::kBlob: {
+      // Blobs are actually passed around as kDataPipe elements when network
+      // service is enabled, which keeps the blobs alive.
+      DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
       out->type_ = blink::FormDataElement::kEncodedBlob;
       if (!data.ReadBlobUuid(&out->blob_uuid_)) {
         return false;
       }
+      out->optional_blob_data_handle_ = blink::BlobDataHandle::Create(
+          out->blob_uuid_, "" /* type is not necessary */, data.length());
       break;
     }
     case network::mojom::DataElementType::kDataPipe: {
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 445778a..6c36b1b 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1233,10 +1233,6 @@
       status: "stable",
     },
     {
-      // Controlled through the base::Feature with the same name.
-      name: "RestrictDeviceSensorEventsToSecureContexts",
-    },
-    {
       name: "RestrictLazyFrameLoadingToDataSaver",
     },
     {
diff --git a/third_party/blink/renderer/platform/weborigin/security_policy.cc b/third_party/blink/renderer/platform/weborigin/security_policy.cc
index 86b6128..4972b109 100644
--- a/third_party/blink/renderer/platform/weborigin/security_policy.cc
+++ b/third_party/blink/renderer/platform/weborigin/security_policy.cc
@@ -68,20 +68,6 @@
   return safelist;
 }
 
-network::mojom::ReferrerPolicy ReferrerPolicyResolveDefault(
-    network::mojom::ReferrerPolicy referrer_policy) {
-  if (referrer_policy == network::mojom::ReferrerPolicy::kDefault) {
-    if (RuntimeEnabledFeatures::ReducedReferrerGranularityEnabled()) {
-      return network::mojom::ReferrerPolicy::
-          kNoReferrerWhenDowngradeOriginWhenCrossOrigin;
-    } else {
-      return network::mojom::ReferrerPolicy::kNoReferrerWhenDowngrade;
-    }
-  }
-
-  return referrer_policy;
-}
-
 void SecurityPolicy::Init() {
   TrustworthyOriginSafelist();
 }
@@ -107,8 +93,16 @@
     network::mojom::ReferrerPolicy referrer_policy,
     const KURL& url,
     const String& referrer) {
-  network::mojom::ReferrerPolicy referrer_policy_no_default =
-      ReferrerPolicyResolveDefault(referrer_policy);
+  network::mojom::ReferrerPolicy referrer_policy_no_default = referrer_policy;
+  if (referrer_policy_no_default == network::mojom::ReferrerPolicy::kDefault) {
+    if (RuntimeEnabledFeatures::ReducedReferrerGranularityEnabled()) {
+      referrer_policy_no_default = network::mojom::ReferrerPolicy::
+          kNoReferrerWhenDowngradeOriginWhenCrossOrigin;
+    } else {
+      referrer_policy_no_default =
+          network::mojom::ReferrerPolicy::kNoReferrerWhenDowngrade;
+    }
+  }
   if (referrer == Referrer::NoReferrer())
     return Referrer(Referrer::NoReferrer(), referrer_policy_no_default);
   DCHECK(!referrer.IsEmpty());
diff --git a/third_party/blink/renderer/platform/weborigin/security_policy.h b/third_party/blink/renderer/platform/weborigin/security_policy.h
index 32e9d45..56bbb4b 100644
--- a/third_party/blink/renderer/platform/weborigin/security_policy.h
+++ b/third_party/blink/renderer/platform/weborigin/security_policy.h
@@ -46,14 +46,6 @@
   kDoNotSupportReferrerPolicyLegacyKeywords,
 };
 
-// The ReferrerPolicy enum contains a member kDefault, which not a real referrer
-// policy, but instead a value Blink uses to fallback to
-// kNoReferrerWhenDowngrade at certain times. The function below is provided so
-// that a referrer policy which may be kDefault can be resolved to a valid
-// value.
-PLATFORM_EXPORT network::mojom::ReferrerPolicy ReferrerPolicyResolveDefault(
-    network::mojom::ReferrerPolicy);
-
 class PLATFORM_EXPORT SecurityPolicy {
   STATIC_ONLY(SecurityPolicy);
 
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
index 1a7ad97..e996a11 100755
--- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
+++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -33,6 +33,7 @@
             'base::AdoptRef',
             'base::AutoReset',
             'base::CreateSequencedTaskRunnerWithTraits',
+            'base::DefaultTickClock',
             'base::ElapsedTimer',
             'base::File',
             'base::FilePath',
@@ -47,12 +48,14 @@
             'base::RunLoop',
             'base::ReadOnlySharedMemoryMapping',
             'base::ReadOnlySharedMemoryRegion',
+            'base::RepeatingTimer',
             'base::SequencedTaskRunner',
             'base::SingleThreadTaskRunner',
             'base::ScopedFD',
             'base::SupportsWeakPtr',
             'base::SysInfo',
             'base::ThreadChecker',
+            'base::TickClock',
             'base::Time',
             'base::TimeDelta',
             'base::TimeTicks',
diff --git a/third_party/blink/web_tests/NeverFixTests b/third_party/blink/web_tests/NeverFixTests
index b2d9280..a7cee3c 100644
--- a/third_party/blink/web_tests/NeverFixTests
+++ b/third_party/blink/web_tests/NeverFixTests
@@ -2069,7 +2069,7 @@
 external/wpt/payment-request/payment-response/retry-method-manual.https.html [ WontFix ]
 external/wpt/payment-request/payment-response/shippingAddress-attribute-manual.https.html [ WontFix ]
 external/wpt/payment-request/payment-response/shippingOption-attribute-manual.https.html [ WontFix ]
-external/wpt/payment-request/rejects_if_not_active_manual.https.html [ WontFix ]
+external/wpt/payment-request/rejects_if_not_active-manual.https.html [ WontFix ]
 external/wpt/payment-request/shipping-address-changed-manual.https.html [ WontFix ]
 external/wpt/payment-request/show-method-optional-promise-rejects-manual.https.html [ WontFix ]
 external/wpt/payment-request/show-method-optional-promise-resolves-manual.https.html [ WontFix ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 47f62ea..3bfa1b0 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -549,6 +549,7 @@
 crbug.com/880802 external/wpt/css/css-contain/contain-layout-017.html [ Failure ]
 crbug.com/671132 external/wpt/css/css-contain/contain-layout-baseline-005.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-contain/contain-layout-breaks-002.html [ Failure ]
+crbug.com/965740 external/wpt/css/css-contain/contain-layout-button-001.html [ Failure ]
 crbug.com/847274 external/wpt/css/css-contain/contain-paint-005.html [ Failure ]
 crbug.com/847274 external/wpt/css/css-contain/contain-paint-006.html [ Failure ]
 crbug.com/880802 external/wpt/css/css-contain/contain-paint-021.html [ Failure ]
@@ -574,6 +575,7 @@
 crbug.com/880802 virtual/layout_ng_experimental/external/wpt/css/css-contain/contain-layout-017.html [ Failure ]
 crbug.com/671132 virtual/layout_ng_experimental/external/wpt/css/css-contain/contain-layout-baseline-005.html [ Failure ]
 crbug.com/626703 virtual/layout_ng_experimental/external/wpt/css/css-contain/contain-layout-breaks-002.html [ Failure ]
+crbug.com/965740 virtual/layout_ng_experimental/external/wpt/css/css-contain/contain-layout-button-001.html [ Failure ]
 crbug.com/847274 virtual/layout_ng_experimental/external/wpt/css/css-contain/contain-paint-005.html [ Failure ]
 crbug.com/847274 virtual/layout_ng_experimental/external/wpt/css/css-contain/contain-paint-006.html [ Failure ]
 crbug.com/880802 virtual/layout_ng_experimental/external/wpt/css/css-contain/contain-paint-021.html [ Failure ]
@@ -1866,6 +1868,19 @@
 crbug.com/652964 [ Linux ] fast/text/hyphens/midword-break-priority.html [ Skip ]
 crbug.com/652964 [ Win ] fast/text/hyphens/midword-break-priority.html [ Skip ]
 
+crbug.com/305376 external/wpt/css/css-overflow/webkit-line-clamp-009.html [ Failure ]
+crbug.com/305376 external/wpt/css/css-overflow/webkit-line-clamp-010.html [ Failure ]
+crbug.com/305376 external/wpt/css/css-overflow/webkit-line-clamp-011.html [ Failure ]
+crbug.com/305376 external/wpt/css/css-overflow/webkit-line-clamp-012.html [ Failure ]
+crbug.com/305376 external/wpt/css/css-overflow/webkit-line-clamp-013.html [ Failure ]
+crbug.com/305376 external/wpt/css/css-overflow/webkit-line-clamp-014.html [ Failure ]
+crbug.com/305376 external/wpt/css/css-overflow/webkit-line-clamp-018.html [ Failure ]
+crbug.com/305376 external/wpt/css/css-overflow/webkit-line-clamp-024.html [ Failure ]
+crbug.com/305376 external/wpt/css/css-overflow/webkit-line-clamp-025.html [ Failure ]
+crbug.com/965137 external/wpt/css/css-overflow/webkit-line-clamp-026.html [ Failure ]
+crbug.com/305376 external/wpt/css/css-overflow/webkit-line-clamp-027.html [ Failure ]
+crbug.com/305376 external/wpt/css/css-overflow/webkit-line-clamp-033.html [ Failure ]
+
 crbug.com/405389 external/wpt/css/css-shapes/shape-outside/supported-shapes/polygon/shape-outside-polygon-017.html [ Failure ]
 crbug.com/424365 external/wpt/css/css-shapes/shape-outside/shape-image/shape-image-024.html [ Failure ]
 crbug.com/441840 [ Win ] external/wpt/css/css-shapes/shape-outside/values/shape-margin-001.html [ Failure ]
@@ -2118,6 +2133,8 @@
 crbug.com/658305 css3/filters/effect-reference-zoom-hw.html [ Failure Pass ]
 crbug.com/658305 css3/filters/filter-effect-removed.html [ Failure Pass ]
 
+crbug.com/968033 [ Mac ] fast/writing-mode/text-combine-line-break.html [ Failure ]
+
 crbug.com/524160 [ Debug ] http/tests/media/media-source/stream_memory_tests/mediasource-appendbuffer-quota-exceeded-default-buffers.html [ Timeout ]
 
 # Run the tests with the default MSE buffer sizes in the main test suite and the tests for 1MB buffers set via command line in a virtual test suite
@@ -2791,8 +2808,6 @@
 crbug.com/626703 [ Mac10.13 ] external/wpt/preload/onerror-event.html [ Failure Timeout ]
 crbug.com/626703 [ Retina ] external/wpt/preload/onerror-event.html [ Timeout ]
 crbug.com/626703 [ Win7 ] external/wpt/service-workers/service-worker/fetch-event-async-respond-with.https.html [ Timeout ]
-crbug.com/626703 virtual/layout_ng_experimental/external/wpt/css/css-contain/contain-layout-button-001.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-contain/contain-layout-button-001.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-writing-modes/text-combine-upright-digits-001-manual.html [ Skip ]
 crbug.com/626703 external/wpt/web-animations/timing-model/timelines/update-and-send-events-replacement.html [ Timeout ]
 crbug.com/626703 external/wpt/css/css-ui/webkit-appearance-menulist-001.html [ Failure ]
@@ -2818,18 +2833,6 @@
 crbug.com/626703 external/wpt/css/css-writing-modes/text-combine-upright-digits-004-manual.html [ Skip ]
 crbug.com/626703 external/wpt/html/semantics/scripting-1/the-script-element/json-module/parse-error.html [ Timeout ]
 crbug.com/626703 external/wpt/css/css-ui/webkit-appearance-slider-horizontal-001.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-overflow/webkit-line-clamp-018.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-overflow/webkit-line-clamp-009.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-overflow/webkit-line-clamp-024.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-overflow/webkit-line-clamp-010.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-overflow/webkit-line-clamp-012.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-overflow/webkit-line-clamp-033.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-overflow/webkit-line-clamp-027.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-overflow/webkit-line-clamp-011.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-overflow/webkit-line-clamp-013.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-overflow/webkit-line-clamp-014.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-overflow/webkit-line-clamp-025.html [ Failure ]
-crbug.com/965137 external/wpt/css/css-overflow/webkit-line-clamp-026.html [ Failure ]
 crbug.com/626703 [ Mac10.13 ] external/wpt/preload/preload-with-type.html [ Failure Timeout ]
 crbug.com/626703 [ Retina ] external/wpt/preload/preload-with-type.html [ Timeout ]
 crbug.com/626703 [ Mac10.13 ] external/wpt/preload/onload-event.html [ Failure Timeout ]
@@ -3176,6 +3179,10 @@
 crbug.com/626703 virtual/omt-worker-fetch/external/wpt/referrer-policy/css-integration/svg/presentation-attribute.html [ Timeout Failure ]
 crbug.com/626703 virtual/omt-worker-fetch/external/wpt/referrer-policy/css-integration/svg/processing-instruction.html [ Timeout Failure ]
 
+crbug.com/906959 external/wpt/referrer-policy/no-referrer/http-rp/same-origin/http-http/shared-worker/keep-origin-redirect/generic.http.html [ Failure ]
+crbug.com/906959 external/wpt/referrer-policy/no-referrer/http-rp/same-origin/http-http/shared-worker/no-redirect/generic.http.html [ Failure ]
+crbug.com/906959 external/wpt/referrer-policy/no-referrer/meta-referrer/same-origin/http-http/shared-worker/keep-origin-redirect/generic.http.html [ Failure ]
+crbug.com/906959 external/wpt/referrer-policy/no-referrer/meta-referrer/same-origin/http-http/shared-worker/no-redirect/generic.http.html [ Failure ]
 crbug.com/906959 external/wpt/referrer-policy/no-referrer-when-downgrade/http-rp/same-origin/http-http/shared-worker/keep-origin-redirect/insecure-protocol.http.html [ Failure ]
 crbug.com/906959 external/wpt/referrer-policy/no-referrer-when-downgrade/http-rp/same-origin/http-http/shared-worker/no-redirect/insecure-protocol.http.html [ Failure ]
 crbug.com/906959 external/wpt/referrer-policy/no-referrer-when-downgrade/meta-referrer/same-origin/http-http/shared-worker/keep-origin-redirect/insecure-protocol.http.html [ Failure ]
@@ -5488,10 +5495,6 @@
 crbug.com/936279 external/wpt/import-maps/fallback-disallowed.sub.tentative.html [ Failure Pass Timeout ]
 crbug.com/936615 [ Win7 ] external/wpt/kv-storage/values.https.html [ Timeout Pass ]
 
-# Device Sensor Events were restricted to secure browsing contexts in M74, with a flag available until M76 to undo the change in case of an emergency.
-crbug.com/932078 http/tests/security/powerfulFeatureRestrictions/device-orientation-on-insecure-origin.html [ Skip ]
-crbug.com/932078 virtual/insecure-device-sensor-events/http/tests/security/powerfulFeatureRestrictions/device-orientation-handler-not-fired-on-insecure-origin.html [ Skip ]
-
 crbug.com/935064 external/wpt/content-security-policy/inheritance/iframe-all-local-schemes.sub.html [ Failure ]
 
 # Sheriff 2019-02-28
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index 6e6c6573..8231526 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -963,11 +963,6 @@
     "args": ["--enable-features=FreezeUserAgent"]
   },
   {
-    "prefix": "insecure-device-sensor-events",
-    "base": "http/tests/security/powerfulFeatureRestrictions/",
-    "args": ["--disable-features=RestrictDeviceSensorEventsToSecureContexts"]
-  },
-  {
     "prefix": "native-file-system",
     "base": "external/wpt/native-file-system",
     "args": ["--enable-features=NativeFileSystemAPI"]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
index 00f086fb..af672bb 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
@@ -6367,6 +6367,12 @@
      {}
     ]
    ],
+   "payment-request/rejects_if_not_active-manual.https.html": [
+    [
+     "payment-request/rejects_if_not_active-manual.https.html",
+     {}
+    ]
+   ],
    "payment-request/shipping-address-changed-manual.https.html": [
     [
      "payment-request/shipping-address-changed-manual.https.html",
@@ -275033,6 +275039,12 @@
      {}
     ]
    ],
+   "html/semantics/text-level-semantics/the-ruby-element/rt-without-ruby-crash.html": [
+    [
+     "html/semantics/text-level-semantics/the-ruby-element/rt-without-ruby-crash.html",
+     {}
+    ]
+   ],
    "html/semantics/text-level-semantics/the-time-element/001.html": [
     [
      "html/semantics/text-level-semantics/the-time-element/001.html",
@@ -294384,12 +294396,6 @@
      }
     ]
    ],
-   "payment-request/rejects_if_not_active_manual.https.html": [
-    [
-     "payment-request/rejects_if_not_active_manual.https.html",
-     {}
-    ]
-   ],
    "performance-timeline/case-sensitivity.any.js": [
     [
      "performance-timeline/case-sensitivity.any.html",
@@ -464324,6 +464330,10 @@
    "1dfa6836f398cc0d7e15a694655a68771d51c804",
    "reftest"
   ],
+  "html/semantics/text-level-semantics/the-ruby-element/rt-without-ruby-crash.html": [
+   "3caed3a02e87ccb9797ba6728bebc5294be2658e",
+   "testharness"
+  ],
   "html/semantics/text-level-semantics/the-ruby-element/ruby-usage-notref.html": [
    "f5747811ae40ec6114976d05955e4a85a7c4cf44",
    "support"
@@ -481168,6 +481178,10 @@
    "687d3a52de9f6bfdb10456147586008b18683eb2",
    "manual"
   ],
+  "payment-request/rejects_if_not_active-manual.https.html": [
+   "f1d2fb83e0e0b17e0030bc991b0135bd21200aa0",
+   "manual"
+  ],
   "payment-request/rejects_if_not_active.https-expected.txt": [
    "0d8fb1a5d178a8848d827d781c90d92fe18ddeaa",
    "support"
@@ -481176,10 +481190,6 @@
    "3c7e85ba970f8c6f2d608f02dd2f60f911124da2",
    "testharness"
   ],
-  "payment-request/rejects_if_not_active_manual.https.html": [
-   "f1d2fb83e0e0b17e0030bc991b0135bd21200aa0",
-   "testharness"
-  ],
   "payment-request/resources/page1.html": [
    "7fc080d380c4bd46dfb011910e570ee412561b92",
    "support"
@@ -481669,7 +481679,7 @@
    "testharness"
   ],
   "pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch.html": [
-   "bdd2809354c7a39a7b9acd75c5208cba324fecf1",
+   "f05aadf39e8435dea374386a796c15fc747f15b0",
    "testharness"
   ],
   "pointerevents/pointerevent_touch-action-inherit_child-none_touch.html": [
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html b/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html
index fff4f34..453184a 100644
--- a/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html
+++ b/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html
@@ -27,7 +27,6 @@
     "frameRate",
     "facingMode",
     "resizeMode",
-    "volume",
     "sampleRate",
     "sampleSize",
     "echoCancellation",
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStreamTrack-getCapabilities.https-expected.txt b/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStreamTrack-getCapabilities.https-expected.txt
deleted file mode 100644
index e7f474c..0000000
--- a/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStreamTrack-getCapabilities.https-expected.txt
+++ /dev/null
@@ -1,116 +0,0 @@
-This is a testharness.js-based test.
-Found 112 tests; 108 PASS, 4 FAIL, 0 TIMEOUT, 0 NOTRUN.
-PASS Setup audio MediaStreamTrack getCapabilities() test for volume
-PASS Setup audio MediaStreamTrack getCapabilities() test for sampleRate
-PASS Setup audio MediaStreamTrack getCapabilities() test for sampleSize
-PASS Setup audio MediaStreamTrack getCapabilities() test for echoCancellation
-PASS Setup audio MediaStreamTrack getCapabilities() test for autoGainControl
-PASS Setup audio MediaStreamTrack getCapabilities() test for noiseSuppression
-PASS Setup audio MediaStreamTrack getCapabilities() test for latency
-PASS Setup audio MediaStreamTrack getCapabilities() test for channelCount
-PASS Setup audio MediaStreamTrack getCapabilities() test for deviceId
-PASS Setup audio MediaStreamTrack getCapabilities() test for groupId
-PASS Setup video MediaStreamTrack getCapabilities() test for width
-PASS Setup video MediaStreamTrack getCapabilities() test for height
-PASS Setup video MediaStreamTrack getCapabilities() test for aspectRatio
-PASS Setup video MediaStreamTrack getCapabilities() test for frameRate
-PASS Setup video MediaStreamTrack getCapabilities() test for facingMode
-PASS Setup video MediaStreamTrack getCapabilities() test for resizeMode
-PASS Setup video MediaStreamTrack getCapabilities() test for deviceId
-PASS Setup video MediaStreamTrack getCapabilities() test for groupId
-PASS Setup audio InputDeviceInfo getCapabilities() test for volume
-PASS Setup audio InputDeviceInfo getCapabilities() test for sampleRate
-PASS Setup audio InputDeviceInfo getCapabilities() test for sampleSize
-PASS Setup audio InputDeviceInfo getCapabilities() test for echoCancellation
-PASS Setup audio InputDeviceInfo getCapabilities() test for autoGainControl
-PASS Setup audio InputDeviceInfo getCapabilities() test for noiseSuppression
-PASS Setup audio InputDeviceInfo getCapabilities() test for latency
-PASS Setup audio InputDeviceInfo getCapabilities() test for channelCount
-PASS Setup audio InputDeviceInfo getCapabilities() test for deviceId
-PASS Setup audio InputDeviceInfo getCapabilities() test for groupId
-PASS Setup video InputDeviceInfo getCapabilities() test for width
-PASS Setup video InputDeviceInfo getCapabilities() test for height
-PASS Setup video InputDeviceInfo getCapabilities() test for aspectRatio
-PASS Setup video InputDeviceInfo getCapabilities() test for frameRate
-PASS Setup video InputDeviceInfo getCapabilities() test for facingMode
-PASS Setup video InputDeviceInfo getCapabilities() test for resizeMode
-PASS Setup video InputDeviceInfo getCapabilities() test for deviceId
-PASS Setup video InputDeviceInfo getCapabilities() test for groupId
-FAIL Audio track getCapabilities() volume property present. assert_true: expected true got false
-FAIL Audio track getCapabilities() volume properly supported. assert_equals: expected "object" but got "undefined"
-PASS Audio track getCapabilities() sampleRate property present.
-PASS Audio track getCapabilities() sampleRate properly supported.
-PASS Audio track getCapabilities() sampleSize property present.
-PASS Audio track getCapabilities() sampleSize properly supported.
-PASS Audio track getCapabilities() echoCancellation property present.
-PASS Audio track getCapabilities() echoCancellation properly supported.
-PASS Audio track getCapabilities() autoGainControl property present.
-PASS Audio track getCapabilities() autoGainControl properly supported.
-PASS Audio track getCapabilities() noiseSuppression property present.
-PASS Audio track getCapabilities() noiseSuppression properly supported.
-PASS Audio track getCapabilities() latency property present.
-PASS Audio track getCapabilities() latency properly supported.
-PASS Audio track getCapabilities() channelCount property present.
-PASS Audio track getCapabilities() channelCount properly supported.
-PASS Audio track getCapabilities() deviceId property present.
-PASS Audio track getCapabilities() deviceId properly supported.
-PASS Audio track getCapabilities() groupId property present.
-PASS Audio track getCapabilities() groupId properly supported.
-PASS Video track getCapabilities() width property present.
-PASS Video track getCapabilities() width properly supported.
-PASS Video track getCapabilities() height property present.
-PASS Video track getCapabilities() height properly supported.
-PASS Video track getCapabilities() aspectRatio property present.
-PASS Video track getCapabilities() aspectRatio properly supported.
-PASS Video track getCapabilities() frameRate property present.
-PASS Video track getCapabilities() frameRate properly supported.
-PASS Video track getCapabilities() facingMode property present.
-PASS Video track getCapabilities() facingMode properly supported.
-PASS Video track getCapabilities() resizeMode property present.
-PASS Video track getCapabilities() resizeMode properly supported.
-PASS Video track getCapabilities() resizeMode properly supported. Value: none
-PASS Video track getCapabilities() resizeMode properly supported. Value: crop-and-scale
-PASS Video track getCapabilities() deviceId property present.
-PASS Video track getCapabilities() deviceId properly supported.
-PASS Video track getCapabilities() groupId property present.
-PASS Video track getCapabilities() groupId properly supported.
-FAIL Audio device getCapabilities() volume property present. assert_true: expected true got false
-FAIL Audio device getCapabilities() volume properly supported. assert_equals: expected "object" but got "undefined"
-PASS Audio device getCapabilities() sampleRate property present.
-PASS Audio device getCapabilities() sampleRate properly supported.
-PASS Audio device getCapabilities() sampleSize property present.
-PASS Audio device getCapabilities() sampleSize properly supported.
-PASS Audio device getCapabilities() echoCancellation property present.
-PASS Audio device getCapabilities() echoCancellation properly supported.
-PASS Audio device getCapabilities() autoGainControl property present.
-PASS Audio device getCapabilities() autoGainControl properly supported.
-PASS Audio device getCapabilities() noiseSuppression property present.
-PASS Audio device getCapabilities() noiseSuppression properly supported.
-PASS Audio device getCapabilities() latency property present.
-PASS Audio device getCapabilities() latency properly supported.
-PASS Audio device getCapabilities() channelCount property present.
-PASS Audio device getCapabilities() channelCount properly supported.
-PASS Audio device getCapabilities() deviceId property present.
-PASS Audio device getCapabilities() deviceId properly supported.
-PASS Audio device getCapabilities() groupId property present.
-PASS Audio device getCapabilities() groupId properly supported.
-PASS Video device getCapabilities() width property present.
-PASS Video device getCapabilities() width properly supported.
-PASS Video device getCapabilities() height property present.
-PASS Video device getCapabilities() height properly supported.
-PASS Video device getCapabilities() aspectRatio property present.
-PASS Video device getCapabilities() aspectRatio properly supported.
-PASS Video device getCapabilities() frameRate property present.
-PASS Video device getCapabilities() frameRate properly supported.
-PASS Video device getCapabilities() facingMode property present.
-PASS Video device getCapabilities() facingMode properly supported.
-PASS Video device getCapabilities() resizeMode property present.
-PASS Video device getCapabilities() resizeMode properly supported.
-PASS Video device getCapabilities() resizeMode properly supported. Value: none
-PASS Video device getCapabilities() resizeMode properly supported. Value: crop-and-scale
-PASS Video device getCapabilities() deviceId property present.
-PASS Video device getCapabilities() deviceId properly supported.
-PASS Video device getCapabilities() groupId property present.
-PASS Video device getCapabilities() groupId properly supported.
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html b/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html
index aeb79b5..2334514 100644
--- a/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html
+++ b/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html
@@ -5,7 +5,6 @@
 <script>
 
 const audioProperties = [
-  {name: "volume", type: "number"},
   {name: "sampleRate", type: "number"},
   {name: "sampleSize", type: "number"},
   {name: "echoCancellation", type: "boolean"},
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStreamTrack-getSettings.https.html b/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStreamTrack-getSettings.https.html
index c062205f..4d51f9d 100644
--- a/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStreamTrack-getSettings.https.html
+++ b/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaStreamTrack-getSettings.https.html
@@ -97,13 +97,6 @@
 
   promise_test(async t => {
     const settings = await createAudioStreamAndGetSettings(t);
-    assert_equals(typeof(settings.volume), "number",
-                  "volume should exist and it should be a number.");
-    assert_between_inclusive(settings.volume, 0.0, 1.0);
-  }, 'volume is reported by getSettings() for getUserMedia() audio tracks');
-
-  promise_test(async t => {
-    const settings = await createAudioStreamAndGetSettings(t);
     assert_equals(typeof(settings.sampleRate), "number",
                   "sampleRate should exist and it should be a number.");
     assert_greater_than(settings.sampleRate, 0);
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/rejects_if_not_active_manual.https.html b/third_party/blink/web_tests/external/wpt/payment-request/rejects_if_not_active-manual.https.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/payment-request/rejects_if_not_active_manual.https.html
rename to third_party/blink/web_tests/external/wpt/payment-request/rejects_if_not_active-manual.https.html
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/fetch-request-xhr.https-expected.txt b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/fetch-request-xhr.https-expected.txt
index 44c6a05..a354755 100644
--- a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/fetch-request-xhr.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/fetch-request-xhr.https-expected.txt
@@ -1,9 +1,9 @@
 This is a testharness.js-based test.
 PASS initialize global state
 FAIL event.request has the expected headers for same-origin GET. promise_test: Unhandled rejection with value: object "Error: assert_array_equals: event.request has the expected headers for same-origin GET. lengths differ, expected 1 got 3"
-FAIL event.request has the expected headers for same-origin POST. promise_test: Unhandled rejection with value: object "Error: assert_array_equals: event.request has the expected headers for same-origin POST. lengths differ, expected 2 got 5"
+FAIL event.request has the expected headers for same-origin POST. promise_test: Unhandled rejection with value: object "Error: assert_array_equals: event.request has the expected headers for same-origin POST. lengths differ, expected 2 got 4"
 FAIL event.request has the expected headers for cross-origin GET. promise_test: Unhandled rejection with value: object "Error: assert_array_equals: event.request has the expected headers for cross-origin GET. lengths differ, expected 1 got 3"
-FAIL event.request has the expected headers for cross-origin POST. promise_test: Unhandled rejection with value: object "Error: assert_array_equals: event.request has the expected headers for cross-origin POST. lengths differ, expected 2 got 5"
+FAIL event.request has the expected headers for cross-origin POST. promise_test: Unhandled rejection with value: object "Error: assert_array_equals: event.request has the expected headers for cross-origin POST. lengths differ, expected 2 got 4"
 PASS FetchEvent#request.body contains XHR request data (string)
 PASS FetchEvent#request.body contains XHR request data (blob)
 PASS FetchEvent#request.method is set to XHR method
diff --git a/third_party/blink/web_tests/fast/mediastream/MediaDevices-getSupportedConstraints.html b/third_party/blink/web_tests/fast/mediastream/MediaDevices-getSupportedConstraints.html
index 4a4f8ed..5fff1ce 100644
--- a/third_party/blink/web_tests/fast/mediastream/MediaDevices-getSupportedConstraints.html
+++ b/third_party/blink/web_tests/fast/mediastream/MediaDevices-getSupportedConstraints.html
@@ -13,7 +13,6 @@
   assert_true(supported_constraints.frameRate);
   assert_true(supported_constraints.facingMode);
   assert_true(supported_constraints.resizeMode);
-  assert_true(supported_constraints.volume);
   assert_true(supported_constraints.sampleRate);
   assert_true(supported_constraints.sampleSize);
   assert_true(supported_constraints.echoCancellation);
diff --git a/third_party/blink/web_tests/fast/mediastream/MediaStreamTrack-applyConstraints.html b/third_party/blink/web_tests/fast/mediastream/MediaStreamTrack-applyConstraints.html
index ceb2833..32f68c1 100644
--- a/third_party/blink/web_tests/fast/mediastream/MediaStreamTrack-applyConstraints.html
+++ b/third_party/blink/web_tests/fast/mediastream/MediaStreamTrack-applyConstraints.html
@@ -96,7 +96,6 @@
     facingMode: { ideal: "user" },
     aspectRatio: { ideal: 1.3333333, exact: 1.4444 },
 
-    volume: 1.0,
     sampleRate: { ideal: 42, min: 31, max: 54 },
     sampleSize: 3,
     echoCancellation: { ideal: false, exact: true },
diff --git a/third_party/blink/web_tests/fast/mediastream/MediaStreamTrack-getConstraints.html b/third_party/blink/web_tests/fast/mediastream/MediaStreamTrack-getConstraints.html
index 9163cb1..2de0bde 100644
--- a/third_party/blink/web_tests/fast/mediastream/MediaStreamTrack-getConstraints.html
+++ b/third_party/blink/web_tests/fast/mediastream/MediaStreamTrack-getConstraints.html
@@ -68,7 +68,6 @@
   // These constraints are syntactically valid, but may cause rejection.
   // They are included in an "advanced" constraint.
   const ignorableConstraintSet = {
-    volume: { ideal: 1.0 },
     sampleRate: { ideal: 42 },
     sampleSize: { ideal: 3 },
     echoCancellation: { ideal: false },
diff --git a/third_party/blink/web_tests/http/tests/devtools/network/network-prefetch-expected.txt b/third_party/blink/web_tests/http/tests/devtools/network/network-prefetch-expected.txt
new file mode 100644
index 0000000..600c418a
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/devtools/network/network-prefetch-expected.txt
@@ -0,0 +1,5 @@
+fromPrefetchCache flag must be set for prefetched resousces.
+
+http://127.0.0.1:8000/devtools/network/resources/network-prefetch-target.html
+fromPrefetchCache: true
+
diff --git a/third_party/blink/web_tests/http/tests/devtools/network/network-prefetch.js b/third_party/blink/web_tests/http/tests/devtools/network/network-prefetch.js
new file mode 100644
index 0000000..0013286
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/devtools/network/network-prefetch.js
@@ -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.
+
+(async function() {
+  TestRunner.addResult(`fromPrefetchCache flag must be set for prefetched resousces.\n`);
+
+  await TestRunner.loadModule('network_test_runner');
+  await TestRunner.showPanel('network');
+  const ret = await TestRunner.evaluateInPageAsync(`
+    (function(){
+      return new Promise(resolve => {
+        const link = document.createElement('link');
+        link.rel = 'prefetch';
+        link.href = 'resources/network-prefetch-target.html';
+        link.addEventListener('load', resolve);
+        document.body.appendChild(link);
+      });
+    })();
+  `);
+  NetworkTestRunner.recordNetwork();
+  await TestRunner.addIframe('resources/network-prefetch-target.html');
+  var request1 = NetworkTestRunner.networkRequests().pop();
+  TestRunner.addResult(request1.url());
+  TestRunner.addResult('fromPrefetchCache: ' + request1.fromPrefetchCache());
+  TestRunner.completeTest();
+})();
diff --git a/third_party/blink/web_tests/http/tests/devtools/network/resources/network-prefetch-target.html b/third_party/blink/web_tests/http/tests/devtools/network/resources/network-prefetch-target.html
new file mode 100644
index 0000000..0b2e28f
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/devtools/network/resources/network-prefetch-target.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<title>Prefetch target</title>
diff --git a/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation-events-unavailable-on-insecure-origins.html b/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation-events-unavailable-on-insecure-origins.html
new file mode 100644
index 0000000..1cc1f6bf
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation-events-unavailable-on-insecure-origins.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<title>Device Sensor Events not exposed to insecure origins</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/get-host-info.js"></script>
+<script>
+
+if (window.location.origin != get_host_info().UNAUTHENTICATED_ORIGIN) {
+  window.location = get_host_info().UNAUTHENTICATED_ORIGIN + window.location.pathname;
+  promise_test(_ => new Promise(_ => {}), "Stall tests on the wrong host.");
+} else {
+
+  test(() => {
+    assert_false('DeviceMotionEvent' in window);
+    assert_false('DeviceOrientationEvent' in window);
+    assert_false('DeviceOrientationAbsoluteEvent' in window);
+    assert_false('DeviceMotionEventAcceleration' in window);
+    assert_false('DeviceMotionEventRotationRate' in window);
+    assert_false('ondevicemotion' in window);
+    assert_false('ondeviceorientation' in window);
+    assert_false('ondeviceorientationabsolute' in window);
+  }, 'Event interfaces and event handlers are not exposed on `window`.');
+}
+
+</script>
diff --git a/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation-handler-not-fired-on-insecure-origin.html b/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation-handler-not-fired-on-insecure-origin.html
deleted file mode 100644
index 55e4db6..0000000
--- a/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation-handler-not-fired-on-insecure-origin.html
+++ /dev/null
@@ -1,55 +0,0 @@
-<!DOCTYPE html>
-<title>Device Sensor Events on Insecure Origin. Codifies expected behavior once https://github.com/w3c/deviceorientation/issues/47 is resolved.</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/resources/get-host-info.js"></script>
-<script src="/resources/sensor-helpers.js"></script>
-<script src="/gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
-<script src="/gen/services/device/public/mojom/sensor_provider.mojom.js"></script>
-<script>
-
-// Cannot use `step_timeout()` because we need the `sensor_test` infrastructure below,
-// which, however, is using `promise_test` internally. Cannot use `promise_rejects`
-// either, as `sensor_test` does not expose the `test_object`.
-function waitForLackOfEvent(eventName) {
-  return new Promise((resolve, reject) => {
-    window.addEventListener(eventName, reject);
-    window.setTimeout(() => {
-      window.removeEventListener(eventName, reject);
-      resolve();
-    }, 1000);
-  });
-}
-
-if (window.location.origin != get_host_info().UNAUTHENTICATED_ORIGIN) {
-  window.location = get_host_info().UNAUTHENTICATED_ORIGIN + window.location.pathname;
-  promise_test(_ => new Promise(_ => {}), "Stall tests on the wrong host.");
-} else {
-
-  test(() => {
-    assert_false('DeviceMotionEvent' in window);
-    assert_false('DeviceOrientationEvent' in window);
-    assert_false('DeviceMotionEventAcceleration' in window);
-    assert_false('DeviceMotionEventRotationRate' in window);
-  }, 'Event interfaces are not exposed on `window`.');
-
-  sensor_test(sensorProvider => {
-    const FAKE_ACCELERATION_DATA = [1, 2, 3];
-    const FAKE_LINEAR_ACCELERATION_DATA = [4, 5, 6];
-    const FAKE_GYROSCOPE_DATA = [7, 8, 9];
-    setMockSensorDataForType(sensorProvider, device.mojom.SensorType.ACCELEROMETER, FAKE_ACCELERATION_DATA);
-    setMockSensorDataForType(sensorProvider, device.mojom.SensorType.LINEAR_ACCELERATION, FAKE_LINEAR_ACCELERATION_DATA);
-    setMockSensorDataForType(sensorProvider, device.mojom.SensorType.GYROSCOPE, FAKE_GYROSCOPE_DATA);
-
-    return waitForLackOfEvent('devicemotion');
-  }, 'DeviceMotionEvent never fires.');
-
-  sensor_test(sensorProvider => {
-    const FAKE_ORIENTATION_DATA = [1.1, 2.2, 3.3];
-    setMockSensorDataForType(sensorProvider, device.mojom.SensorType.RELATIVE_ORIENTATION_EULER_ANGLES, FAKE_ORIENTATION_DATA);
-
-    return waitForLackOfEvent('deviceorientation');
-  }, 'DeviceOrientationEvent never fires.');
-}
-
-</script>
diff --git a/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation-on-insecure-origin-expected.txt b/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation-on-insecure-origin-expected.txt
deleted file mode 100644
index d09230e..0000000
--- a/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation-on-insecure-origin-expected.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-CONSOLE WARNING: line 429: The `devicemotion` event is deprecated on insecure origins and will be removed. See https://www.chromestatus.com/feature/5688035094036480 for more details.
-CONSOLE WARNING: line 429: The `deviceorientation` event is deprecated on insecure origins and will be removed. See https://www.chromestatus.com/feature/5468407470227456 for more details.
-This is a testharness.js-based test.
-PASS Event handlers as well as interfaces are exposed on `window`.
-PASS DeviceMotionEvent fires.
-PASS DeviceOrientationEvent fires.
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation-on-insecure-origin.html b/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation-on-insecure-origin.html
deleted file mode 100644
index f969a3a..0000000
--- a/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation-on-insecure-origin.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE html>
-<title>Device Sensor Events on Insecure Origins</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/resources/get-host-info.js"></script>
-<script>
-window.location = get_host_info().UNAUTHENTICATED_ORIGIN +
-    "/security/powerfulFeatureRestrictions/device-orientation.html";
-promise_test(_ => new Promise(_ => {}), "Stall tests on the wrong host.");
-</script>
diff --git a/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation-on-secure-origin.https.html b/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation-on-secure-origin.https.html
index 31b6f107..7855472 100644
--- a/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation-on-secure-origin.https.html
+++ b/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation-on-secure-origin.https.html
@@ -1,5 +1,61 @@
 <!DOCTYPE html>
 <title>Device Sensor Events on Secure Origin</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/get-host-info.js"></script>
+<script src="/resources/sensor-helpers.js"></script>
+<script src="/gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
+<script src="/gen/services/device/public/mojom/sensor_provider.mojom.js"></script>
 <script>
-window.location = "device-orientation.html";
+
+test(() => {
+  assert_true('ondevicemotion' in window);
+  assert_true('ondeviceorientation' in window);
+  assert_true('DeviceMotionEvent' in window);
+  assert_true('DeviceOrientationEvent' in window);
+  assert_true('DeviceMotionEventAcceleration' in window);
+  assert_true('DeviceMotionEventRotationRate' in window);
+}, 'Event handlers as well as interfaces are exposed on `window`.');
+
+sensor_test(async sensorProvider => {
+  const FAKE_ACCELERATION_DATA = [1, 2, 3];
+  const FAKE_LINEAR_ACCELERATION_DATA = [4, 5, 6];
+  const FAKE_GYROSCOPE_DATA = [7, 8, 9];
+  setMockSensorDataForType(sensorProvider, device.mojom.SensorType.ACCELEROMETER, FAKE_ACCELERATION_DATA);
+  setMockSensorDataForType(sensorProvider, device.mojom.SensorType.LINEAR_ACCELERATION, FAKE_LINEAR_ACCELERATION_DATA);
+  setMockSensorDataForType(sensorProvider, device.mojom.SensorType.GYROSCOPE, FAKE_GYROSCOPE_DATA);
+
+  const radToDeg = 180 / Math.PI;
+  return waitForEvent(new DeviceMotionEvent('devicemotion', {
+      acceleration: {
+          x: FAKE_LINEAR_ACCELERATION_DATA[0],
+          y: FAKE_LINEAR_ACCELERATION_DATA[1],
+          z: FAKE_LINEAR_ACCELERATION_DATA[2],
+      },
+      accelerationIncludingGravity: {
+          x: FAKE_ACCELERATION_DATA[0],
+          y: FAKE_ACCELERATION_DATA[1],
+          z: FAKE_ACCELERATION_DATA[2],
+      },
+      rotationRate: {
+          alpha: FAKE_GYROSCOPE_DATA[0] * radToDeg,
+          beta: FAKE_GYROSCOPE_DATA[1] * radToDeg,
+          gamma: FAKE_GYROSCOPE_DATA[2] * radToDeg,
+      },
+      interval: 16,
+  }));
+}, 'DeviceMotionEvent fires.');
+
+sensor_test(async sensorProvider => {
+  const FAKE_ORIENTATION_DATA = [1.1, 2.2, 3.3];
+  setMockSensorDataForType(sensorProvider, device.mojom.SensorType.RELATIVE_ORIENTATION_EULER_ANGLES, FAKE_ORIENTATION_DATA);
+
+  return waitForEvent(new DeviceOrientationEvent('deviceorientation', {
+      alpha: FAKE_ORIENTATION_DATA[2],
+      beta: FAKE_ORIENTATION_DATA[0],
+      gamma: FAKE_ORIENTATION_DATA[1],
+      absolute: false,
+  }));
+}, 'DeviceOrientationEvent fires.');
+
 </script>
diff --git a/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation.html b/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation.html
deleted file mode 100644
index 12dd166..0000000
--- a/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/device-orientation.html
+++ /dev/null
@@ -1,61 +0,0 @@
-<!DOCTYPE html>
-<title>Device Sensor Events</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/resources/get-host-info.js"></script>
-<script src="/resources/sensor-helpers.js"></script>
-<script src="/gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
-<script src="/gen/services/device/public/mojom/sensor_provider.mojom.js"></script>
-<script>
-
-test(() => {
-  assert_true('ondevicemotion' in window);
-  assert_true('ondeviceorientation' in window);
-  assert_true('DeviceMotionEvent' in window);
-  assert_true('DeviceOrientationEvent' in window);
-  assert_true('DeviceMotionEventAcceleration' in window);
-  assert_true('DeviceMotionEventRotationRate' in window);
-}, 'Event handlers as well as interfaces are exposed on `window`.');
-
-sensor_test(async sensorProvider => {
-  const FAKE_ACCELERATION_DATA = [1, 2, 3];
-  const FAKE_LINEAR_ACCELERATION_DATA = [4, 5, 6];
-  const FAKE_GYROSCOPE_DATA = [7, 8, 9];
-  setMockSensorDataForType(sensorProvider, device.mojom.SensorType.ACCELEROMETER, FAKE_ACCELERATION_DATA);
-  setMockSensorDataForType(sensorProvider, device.mojom.SensorType.LINEAR_ACCELERATION, FAKE_LINEAR_ACCELERATION_DATA);
-  setMockSensorDataForType(sensorProvider, device.mojom.SensorType.GYROSCOPE, FAKE_GYROSCOPE_DATA);
-
-  const radToDeg = 180 / Math.PI;
-  return waitForEvent(new DeviceMotionEvent('devicemotion', {
-      acceleration: {
-          x: FAKE_LINEAR_ACCELERATION_DATA[0],
-          y: FAKE_LINEAR_ACCELERATION_DATA[1],
-          z: FAKE_LINEAR_ACCELERATION_DATA[2],
-      },
-      accelerationIncludingGravity: {
-          x: FAKE_ACCELERATION_DATA[0],
-          y: FAKE_ACCELERATION_DATA[1],
-          z: FAKE_ACCELERATION_DATA[2],
-      },
-      rotationRate: {
-          alpha: FAKE_GYROSCOPE_DATA[0] * radToDeg,
-          beta: FAKE_GYROSCOPE_DATA[1] * radToDeg,
-          gamma: FAKE_GYROSCOPE_DATA[2] * radToDeg,
-      },
-      interval: 16,
-  }));
-}, 'DeviceMotionEvent fires.');
-
-sensor_test(async sensorProvider => {
-  const FAKE_ORIENTATION_DATA = [1.1, 2.2, 3.3];
-  setMockSensorDataForType(sensorProvider, device.mojom.SensorType.RELATIVE_ORIENTATION_EULER_ANGLES, FAKE_ORIENTATION_DATA);
-
-  return waitForEvent(new DeviceOrientationEvent('deviceorientation', {
-      alpha: FAKE_ORIENTATION_DATA[2],
-      beta: FAKE_ORIENTATION_DATA[0],
-      gamma: FAKE_ORIENTATION_DATA[1],
-      absolute: false,
-  }));
-}, 'DeviceOrientationEvent fires.');
-
-</script>
diff --git a/third_party/blink/web_tests/http/tests/security/referrer-policy-conflicting-policies-font-face-expected.html b/third_party/blink/web_tests/http/tests/security/referrer-policy-conflicting-policies-font-face-expected.html
deleted file mode 100644
index 5c68ea1..0000000
--- a/third_party/blink/web_tests/http/tests/security/referrer-policy-conflicting-policies-font-face-expected.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!DOCTYPE html>
-<style>
-@font-face {
-  font-family: 'Test Font';
-  src: url(http://127.0.0.1:8000/security/resources/opensans.woff2) format('woff2');
-}
-
-body {
-  font-family: 'Test Font';
-}
-</style>
-<body>
-<p>
-Checks that a font face that was created before a referrer policy was set is
-loaded with the correct referrer, in this case, without a referrer.
-</p>
-<p>
-The test passes, a normal font will be loaded.
-</p>
-</body>
diff --git a/third_party/blink/web_tests/http/tests/security/referrer-policy-conflicting-policies-font-face.html b/third_party/blink/web_tests/http/tests/security/referrer-policy-conflicting-policies-font-face.html
deleted file mode 100644
index 47ef8b1..0000000
--- a/third_party/blink/web_tests/http/tests/security/referrer-policy-conflicting-policies-font-face.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<!DOCTYPE html>
-<script>
-if (window.testRunner)
-    testRunner.waitUntilDone();
-
-// For documentation on this test, see
-// referrer-policy-conflicting-policies.html.
-document.location = "https://127.0.0.1:8443/security/resources/referrer-policy-conflicting-policies-font-face.html";
-</script>
diff --git a/third_party/blink/web_tests/http/tests/security/referrer-policy-conflicting-policies-image-set-expected.html b/third_party/blink/web_tests/http/tests/security/referrer-policy-conflicting-policies-image-set-expected.html
deleted file mode 100644
index c42f349..0000000
--- a/third_party/blink/web_tests/http/tests/security/referrer-policy-conflicting-policies-image-set-expected.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<!DOCTYPE html>
-<style>
-div {
-    content: -webkit-image-set(url("http://127.0.0.1:8080/security/resources/green250x50.png") 1x);
-}
-</style>
-<body>
-<p>
-Checks that a CSS image that was created from an image-set before a referrer
-policy was set is loaded with the correct referrer, in this case, without a
-referrer.
-</p>
-<p>
-The test passes, if a green rectangle is displayed below.
-</p>
-<div></div>
-</body>
diff --git a/third_party/blink/web_tests/http/tests/security/referrer-policy-conflicting-policies-image-set.html b/third_party/blink/web_tests/http/tests/security/referrer-policy-conflicting-policies-image-set.html
deleted file mode 100644
index e0a896a..0000000
--- a/third_party/blink/web_tests/http/tests/security/referrer-policy-conflicting-policies-image-set.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<!DOCTYPE html>
-<script>
-if (window.testRunner)
-    testRunner.waitUntilDone();
-
-// For documentation on this test, see
-// referrer-policy-conflicting-policies.html.
-document.location = "https://127.0.0.1:8443/security/resources/referrer-policy-conflicting-policies-image-set.html";
-</script>
diff --git a/third_party/blink/web_tests/http/tests/security/referrer-policy-conflicting-policies.html b/third_party/blink/web_tests/http/tests/security/referrer-policy-conflicting-policies.html
index 25407a3d..380d564 100644
--- a/third_party/blink/web_tests/http/tests/security/referrer-policy-conflicting-policies.html
+++ b/third_party/blink/web_tests/http/tests/security/referrer-policy-conflicting-policies.html
@@ -2,14 +2,5 @@
 <script>
 if (window.testRunner)
     testRunner.waitUntilDone();
-
-// The following test works by loading a page over HTTPS, which requests a
-// resource over HTTP when the document has the default referrer policy
-// (interpreted as no-referrer-when-downgrade). After the request is
-// prepared/made, the document's referrer policy is set to 'origin'. The test
-// asserts that the referrer associated with the request when the document's
-// referrer policy was no-referrer-when-downgrade is empty, and not the origin.
-// This test is similar to
-// referrer-policy-conflicting-policies-{font-face,image-set}.html
 document.location = "https://127.0.0.1:8443/security/resources/referrer-policy-conflicting-policies.html";
 </script>
diff --git a/third_party/blink/web_tests/http/tests/security/resources/montez.woff2 b/third_party/blink/web_tests/http/tests/security/resources/montez.woff2
deleted file mode 100644
index 8d36846..0000000
--- a/third_party/blink/web_tests/http/tests/security/resources/montez.woff2
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/http/tests/security/resources/normal-font-if-no-referrer.php b/third_party/blink/web_tests/http/tests/security/resources/normal-font-if-no-referrer.php
deleted file mode 100644
index 9461235..0000000
--- a/third_party/blink/web_tests/http/tests/security/resources/normal-font-if-no-referrer.php
+++ /dev/null
@@ -1,10 +0,0 @@
-<?php
-header("Content-Type: font/woff2");
-header("Access-Control-Allow-Origin: *");
-if ($_SERVER['HTTP_REFERER'] != '') {
-    $font = 'montez.woff2';
-} else {
-    $font = 'opensans.woff2';
-}
-echo file_get_contents($font);
-?>
diff --git a/third_party/blink/web_tests/http/tests/security/resources/opensans.woff2 b/third_party/blink/web_tests/http/tests/security/resources/opensans.woff2
deleted file mode 100644
index 458c98d..0000000
--- a/third_party/blink/web_tests/http/tests/security/resources/opensans.woff2
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/http/tests/security/resources/referrer-policy-conflicting-policies-font-face.html b/third_party/blink/web_tests/http/tests/security/resources/referrer-policy-conflicting-policies-font-face.html
deleted file mode 100644
index 551dcd3..0000000
--- a/third_party/blink/web_tests/http/tests/security/resources/referrer-policy-conflicting-policies-font-face.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<!DOCTYPE html>
-<script>
-function done()
-{
-    if (window.testRunner)
-        testRunner.notifyDone();
-}
-</script>
-<style>
-@font-face {
-  font-family: 'Test Font';
-  src: url("http://127.0.0.1:8080/security/resources/normal-font-if-no-referrer.php") format('woff2');
-}
-
-body {
-  font-family: 'Test Font';
-}
-</style>
-<meta name="referrer" content="origin">
-<body onload="done();">
-<p>
-Checks that a font face that was created before a referrer policy was set is
-loaded with the correct referrer, in this case, without a referrer.
-</p>
-<p>
-The test passes, a normal font will be loaded.
-</p>
-</body>
diff --git a/third_party/blink/web_tests/http/tests/security/resources/referrer-policy-conflicting-policies-image-set.html b/third_party/blink/web_tests/http/tests/security/resources/referrer-policy-conflicting-policies-image-set.html
deleted file mode 100644
index 1750b22..0000000
--- a/third_party/blink/web_tests/http/tests/security/resources/referrer-policy-conflicting-policies-image-set.html
+++ /dev/null
@@ -1,25 +0,0 @@
-<!DOCTYPE html>
-<script>
-function done()
-{
-    if (window.testRunner)
-        testRunner.notifyDone();
-}
-</script>
-<style>
-div {
-    content: -webkit-image-set(url("http://127.0.0.1:8080/security/resources/green-if-no-referrer.php") 1x);
-}
-</style>
-<meta name="referrer" content="origin">
-<body onload="done();">
-<p>
-Checks that a CSS image that was created from an image-set before a referrer
-policy was set is loaded with the correct referrer, in this case, without a
-referrer.
-</p>
-<p>
-The test passes, if a green rectangle is displayed below.
-</p>
-<div></div>
-</body>
diff --git a/third_party/blink/web_tests/http/tests/security/resources/referrer-policy-conflicting-policies.html b/third_party/blink/web_tests/http/tests/security/resources/referrer-policy-conflicting-policies.html
index 3a38380..535cd46 100644
--- a/third_party/blink/web_tests/http/tests/security/resources/referrer-policy-conflicting-policies.html
+++ b/third_party/blink/web_tests/http/tests/security/resources/referrer-policy-conflicting-policies.html
@@ -11,7 +11,7 @@
     content: url("http://127.0.0.1:8080/security/resources/green-if-no-referrer.php");
 }
 </style>
-<meta name="referrer" content="origin">
+<meta name="referrer" content="origin" />
 <body onload="done();">
 <p>
 Checks that an CSS image that was created before a referrer policy was set is
diff --git a/third_party/blink/web_tests/virtual/insecure-device-sensor-events/http/tests/security/powerfulFeatureRestrictions/README.txt b/third_party/blink/web_tests/virtual/insecure-device-sensor-events/http/tests/security/powerfulFeatureRestrictions/README.txt
deleted file mode 100644
index 20dc340..0000000
--- a/third_party/blink/web_tests/virtual/insecure-device-sensor-events/http/tests/security/powerfulFeatureRestrictions/README.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-This directory is for running Device Sensor Event API tests with the runtime
-flag RestrictDeviceSensorEventsToSecureContexts disabled, to exercise the old
-behavior where the API was still exposed to non-secure browsing contexts.
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index c487a20..75b0b7b 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -861,6 +861,8 @@
 <enum name="AccessorySuggestionType">
   <int value="0" label="USERNAME"/>
   <int value="1" label="PASSWORD"/>
+  <int value="2" label="PAYMENT_INFO"/>
+  <int value="3" label="ADDRESS_INFO"/>
 </enum>
 
 <enum name="AccessPasswordInSettingsEvent">
@@ -21062,9 +21064,9 @@
   <int value="665" label="MixedContentFormPresent"/>
   <int value="666" label="GetUserMediaInsecureOrigin"/>
   <int value="667" label="GetUserMediaSecureOrigin"/>
-  <int value="668" label="DeviceMotionInsecureOrigin"/>
+  <int value="668" label="DeviceMotionInsecureOrigin_Obsolete"/>
   <int value="669" label="DeviceMotionSecureOrigin"/>
-  <int value="670" label="DeviceOrientationInsecureOrigin"/>
+  <int value="670" label="DeviceOrientationInsecureOrigin_Obsolete"/>
   <int value="671" label="DeviceOrientationSecureOrigin"/>
   <int value="672" label="SandboxViaIFrame"/>
   <int value="673" label="SandboxViaCSP"/>
@@ -21395,7 +21397,7 @@
   <int value="984" label="BluetoothDeviceInstanceId"/>
   <int value="985" label="HTMLLabelElementFormIDLAttribute"/>
   <int value="986" label="HTMLLabelElementFormContentAttribute"/>
-  <int value="987" label="DeviceOrientationAbsoluteInsecureOrigin"/>
+  <int value="987" label="DeviceOrientationAbsoluteInsecureOrigin_Obsolete"/>
   <int value="988" label="DeviceOrientationAbsoluteSecureOrigin"/>
   <int value="989" label="FontFaceConstructor"/>
   <int value="990" label="ServiceWorkerControlledPage"/>
@@ -23396,6 +23398,13 @@
   <int value="2903" label="NonPassiveTouchEventListener"/>
   <int value="2904" label="PassiveTouchEventListener"/>
   <int value="2905" label="CSSValueAppearanceSearchCancelForOthers2Rendered"/>
+  <int value="2906" label="WebXrFramebufferScale"/>
+  <int value="2907" label="WebXrIgnoreDepthValues"/>
+  <int value="2908" label="WebXrSessionCreated"/>
+  <int value="2909" label="V8XRReferenceSpace_GetOffsetReferenceSpace_Method"/>
+  <int value="2910" label="V8XRInputSource_Gamepad_AttributeGetter"/>
+  <int value="2911" label="V8XRSession_End_Method"/>
+  <int value="2912" label="V8XRWebGLLayer_Constructor"/>
 </enum>
 
 <enum name="FeaturePolicyFeature">
@@ -58727,6 +58736,8 @@
   <int value="20" label="OPENVR_UNKNOWN"/>
   <int value="21" label="OPENVR_VIVE"/>
   <int value="22" label="OPENVR_RIFT_CV1"/>
+  <int value="40" label="OCULUS_UNKNOWN"/>
+  <int value="60" label="WINDOWS_MIXED_REALITY_UNKNOWN"/>
 </enum>
 
 <enum name="VRVoiceSearchEndState">
@@ -61481,6 +61492,25 @@
   <int value="1" label="Invalidated"/>
 </enum>
 
+<enum name="XRDeviceId">
+  <int value="0" label="WEB_TEST_DEVICE_ID"/>
+  <int value="1" label="FAKE_DEVICE_ID"/>
+  <int value="2" label="ORIENTATION_DEVICE_ID"/>
+  <int value="3" label="GVR_DEVICE_ID"/>
+  <int value="4" label="OPENVR_DEVICE_ID"/>
+  <int value="5" label="OCULUS_DEVICE_ID"/>
+  <int value="6" label="WINDOWS_MIXED_REALITY_ID"/>
+  <int value="7" label="ARCORE_DEVICE_ID"/>
+</enum>
+
+<enum name="XRReferenceSpaceType">
+  <int value="0" label="Viewer"/>
+  <int value="1" label="Local"/>
+  <int value="2" label="LocalFloor"/>
+  <int value="3" label="BoundedFloor"/>
+  <int value="4" label="Unbounded"/>
+</enum>
+
 <enum name="XRRenderPath">
   <int value="0" label="ClientWait"/>
   <int value="1" label="GpuFence"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index f1a3731..10f2d95 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -146204,6 +146204,14 @@
   </summary>
 </histogram>
 
+<histogram name="XR.RuntimeUsed" enum="XRDeviceId">
+  <owner>billorr@chromium.org</owner>
+  <summary>
+    Indicates which XR runtime was used for a session. Recorded when the session
+    was successfully created.
+  </summary>
+</histogram>
+
 <histogram name="XR.VRSession.StartAction" enum="VRSessionStartAction">
   <owner>billorr@chromium.org</owner>
   <summary>
@@ -146260,6 +146268,22 @@
   </summary>
 </histogram>
 
+<histogram name="XR.WebXR.ReferenceSpace.Requested" enum="XRReferenceSpaceType">
+  <owner>billorr@chromium.org</owner>
+  <summary>
+    Records which reference space was requested when a site calls
+    XRSession.requestReferenceSpace().
+  </summary>
+</histogram>
+
+<histogram name="XR.WebXR.ReferenceSpace.Succeeded" enum="XRReferenceSpaceType">
+  <owner>billorr@chromium.org</owner>
+  <summary>
+    Records which reference spaces are successfully created when the promise
+    returned by XRSession.requestReferenceSpace() is resolved.
+  </summary>
+</histogram>
+
 <histogram name="XR.WebXR.RenderPath.Used" enum="XRRenderPath"
     expires_after="M77">
   <owner>klausw@chromium.org</owner>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index 267fd84..59c6639 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -333,7 +333,7 @@
   </metric>
   <metric name="AppType">
     <summary>
-      The type of app. 1: CHROME, 2: PLAY, 3: PWA.
+      The type of app. 1: CHROME, 2: PLAY, 3: PWA/Bookmark app.
     </summary>
   </metric>
   <metric name="ClicksEachHour00">
@@ -561,7 +561,8 @@
     from the suggestion chip, or from the grid of apps. The UKM metrics are not
     keyed by navigational urls. Instead, for Chrome apps the keys are based upon
     the app id, for Play apps the keys are based upon a hash of the package name
-    and for PWAs the keys are the urls associated with the PWA.
+    and for PWAs and bookmark apps the keys are the urls associated with the
+    PWA/bookmark.
   </summary>
   <metric name="AllClicksLast24Hours">
     <summary>
@@ -579,7 +580,7 @@
   </metric>
   <metric name="AppType">
     <summary>
-      The type of app. 1: CHROME, 2: PLAY, 3: PWA.
+      The type of app. 1: CHROME, 2: PLAY, 3: PWA/Bookmark app.
     </summary>
   </metric>
   <metric name="ClickMethod">
diff --git a/tools/perf/page_sets/system_health/accessibility_stories.py b/tools/perf/page_sets/system_health/accessibility_stories.py
index 6c88e8a..ee2f7e9 100644
--- a/tools/perf/page_sets/system_health/accessibility_stories.py
+++ b/tools/perf/page_sets/system_health/accessibility_stories.py
@@ -61,14 +61,6 @@
   TAGS = [story_tags.ACCESSIBILITY, story_tags.KEYBOARD_INPUT,
           story_tags.YEAR_2016]
 
-  # TODO(yoichio): Remove this flags when YouTube finish V0 migration.
-  # crbug.com/911943.
-  def __init__(self, story_set, take_memory_measurement):
-    super(AccessibilityYouTubeHomepageStory, self).__init__(
-        story_set, take_memory_measurement,
-        extra_browser_args=[
-          '--enable-blink-features=HTMLImports,CustomElementsV0'])
-
   def RunNavigateSteps(self, action_runner):
     action_runner.Navigate('https://www.youtube.com/')
     action_runner.tab.WaitForDocumentReadyStateToBeComplete()
diff --git a/tools/perf/page_sets/system_health/browsing_stories.py b/tools/perf/page_sets/system_health/browsing_stories.py
index 9fed8673..1ad3b0c 100644
--- a/tools/perf/page_sets/system_health/browsing_stories.py
+++ b/tools/perf/page_sets/system_health/browsing_stories.py
@@ -546,14 +546,6 @@
   PLATFORM_SPECIFIC = True
   TAGS = [story_tags.JAVASCRIPT_HEAVY, story_tags.YEAR_2018]
 
-  # TODO(yoichio): Remove this flags when YouTube finish V0 migration.
-  # crbug.com/911943.
-  def __init__(self, story_set, take_memory_measurement):
-    super(YouTubeDesktopStory2018, self).__init__(
-        story_set, take_memory_measurement,
-        extra_browser_args=[
-          '--enable-blink-features=HTMLImports,CustomElementsV0'])
-
 
 class YouTubeTVDesktopStory2019(_MediaBrowsingStory):
   """Load a typical YouTube TV video then navigate to a next few videos. Stop
diff --git a/tools/perf/page_sets/system_health/loading_stories.py b/tools/perf/page_sets/system_health/loading_stories.py
index e05d341..267b151 100644
--- a/tools/perf/page_sets/system_health/loading_stories.py
+++ b/tools/perf/page_sets/system_health/loading_stories.py
@@ -255,13 +255,6 @@
   TAGS = [story_tags.EMERGING_MARKET, story_tags.HEALTH_CHECK,
           story_tags.YEAR_2018]
 
-  # TODO(yoichio): Remove this flags when YouTube finishes V0 migration.
-  # crbug.com/911943.
-  def __init__(self, story_set, take_memory_measurement):
-    super(LoadYouTubeStory2018, self).__init__(
-        story_set, take_memory_measurement,
-        extra_browser_args=[
-          '--enable-blink-features=HTMLImports,CustomElementsV0'])
 
 class LoadDailymotionStory(_LoadingStory):
   # The side panel with related videos doesn't show on desktop due to
diff --git a/tools/perf/page_sets/system_health/media_stories.py b/tools/perf/page_sets/system_health/media_stories.py
index ce94ff3..33775d5b 100644
--- a/tools/perf/page_sets/system_health/media_stories.py
+++ b/tools/perf/page_sets/system_health/media_stories.py
@@ -77,13 +77,6 @@
     self._WaitForAndClickElementBySelector(action_runner,
                                            self.NAVIGATE_SELECTOR)
 
-  # TODO(yoichio): Remove this flags when the site finishes V0 migration.
-  # crbug.com/911943.
-  def __init__(self, story_set, take_memory_measurement):
-    super(GooglePlayMusicDesktopStory, self).__init__(
-        story_set, take_memory_measurement,
-        extra_browser_args=[
-          '--enable-blink-features=HTMLImports,CustomElementsV0'])
 
 class SoundCloudDesktopStory2018(_MediaStory):
   """Load soundcloud.com, search for "Smooth Jazz", then play a song."""
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.cc b/ui/accessibility/platform/ax_platform_node_auralinux.cc
index 01e3c02..389e5303 100644
--- a/ui/accessibility/platform/ax_platform_node_auralinux.cc
+++ b/ui/accessibility/platform/ax_platform_node_auralinux.cc
@@ -3734,11 +3734,6 @@
   }
 }
 
-bool AXPlatformNodeAuraLinux::IsTextOnlyObject() const {
-  return GetData().role == ax::mojom::Role::kListMarker ||
-         AXPlatformNodeBase::IsTextOnlyObject();
-}
-
 void AXPlatformNodeAuraLinux::AddAttributeToList(const char* name,
                                                  const char* value,
                                                  AtkAttributeSet** attributes) {
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.h b/ui/accessibility/platform/ax_platform_node_auralinux.h
index 4278784..1e559ad 100644
--- a/ui/accessibility/platform/ax_platform_node_auralinux.h
+++ b/ui/accessibility/platform/ax_platform_node_auralinux.h
@@ -143,7 +143,6 @@
   base::Optional<base::OffsetAdjuster::Adjustments> text_unicode_adjustments_ =
       base::nullopt;
 
-  bool IsTextOnlyObject() const override;
   void AddAttributeToList(const char* name,
                           const char* value,
                           PlatformAttributeList* attributes) override;
diff --git a/ui/accessibility/platform/ax_platform_node_base.h b/ui/accessibility/platform/ax_platform_node_base.h
index fb0cf46..abfb229 100644
--- a/ui/accessibility/platform/ax_platform_node_base.h
+++ b/ui/accessibility/platform/ax_platform_node_base.h
@@ -209,7 +209,7 @@
 
   // Returns true if this node has role of StaticText, LineBreak, or
   // InlineTextBox
-  virtual bool IsTextOnlyObject() const;
+  bool IsTextOnlyObject() const;
 
   // Returns true if the node is an editable text field.
   bool IsPlainTextField() const;
diff --git a/ui/base/win/system_media_controls/BUILD.gn b/ui/base/win/system_media_controls/BUILD.gn
index 41ca483..c205104 100644
--- a/ui/base/win/system_media_controls/BUILD.gn
+++ b/ui/base/win/system_media_controls/BUILD.gn
@@ -18,6 +18,10 @@
     "//base",
     "//ui/gfx",
   ]
+
+  public_deps = [
+    "//skia",
+  ]
 }
 
 static_library("test_support") {
diff --git a/ui/base/win/system_media_controls/mock_system_media_controls_service.h b/ui/base/win/system_media_controls/mock_system_media_controls_service.h
index 4f5c913..125a1ee 100644
--- a/ui/base/win/system_media_controls/mock_system_media_controls_service.h
+++ b/ui/base/win/system_media_controls/mock_system_media_controls_service.h
@@ -32,6 +32,12 @@
   MOCK_METHOD1(SetIsStopEnabled, void(bool value));
   MOCK_METHOD1(SetPlaybackStatus,
                void(ABI::Windows::Media::MediaPlaybackStatus status));
+  MOCK_METHOD1(SetTitle, void(const base::string16& title));
+  MOCK_METHOD1(SetArtist, void(const base::string16& artist));
+  MOCK_METHOD1(SetThumbnail, void(const SkBitmap& bitmap));
+  MOCK_METHOD0(ClearThumbnail, void());
+  MOCK_METHOD0(ClearMetadata, void());
+  MOCK_METHOD0(UpdateDisplay, void());
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockSystemMediaControlsService);
diff --git a/ui/base/win/system_media_controls/system_media_controls_service.h b/ui/base/win/system_media_controls/system_media_controls_service.h
index fe66681..55e6850 100644
--- a/ui/base/win/system_media_controls/system_media_controls_service.h
+++ b/ui/base/win/system_media_controls/system_media_controls_service.h
@@ -8,6 +8,8 @@
 #include <windows.media.control.h>
 
 #include "base/component_export.h"
+#include "base/strings/string16.h"
+#include "third_party/skia/include/core/SkBitmap.h"
 
 namespace system_media_controls {
 
@@ -40,6 +42,14 @@
   // Setters for metadata.
   virtual void SetPlaybackStatus(
       ABI::Windows::Media::MediaPlaybackStatus status) = 0;
+  virtual void SetTitle(const base::string16& title) = 0;
+  virtual void SetArtist(const base::string16& artist) = 0;
+  virtual void SetThumbnail(const SkBitmap& bitmap) = 0;
+
+  // Helpers for metadata.
+  virtual void ClearThumbnail() = 0;
+  virtual void ClearMetadata() = 0;
+  virtual void UpdateDisplay() = 0;
 
  protected:
   virtual ~SystemMediaControlsService();
diff --git a/ui/base/win/system_media_controls/system_media_controls_service_impl.cc b/ui/base/win/system_media_controls/system_media_controls_service_impl.cc
index 9d7a1a4..76fa9f4 100644
--- a/ui/base/win/system_media_controls/system_media_controls_service_impl.cc
+++ b/ui/base/win/system_media_controls/system_media_controls_service_impl.cc
@@ -13,6 +13,7 @@
 #include "base/win/core_winrt_util.h"
 #include "base/win/scoped_hstring.h"
 #include "ui/base/win/system_media_controls/system_media_controls_service_observer.h"
+#include "ui/gfx/codec/png_codec.h"
 #include "ui/gfx/win/singleton_hwnd.h"
 
 namespace system_media_controls {
@@ -24,6 +25,12 @@
 using ABI::Windows::Media::SystemMediaTransportControls;
 using ABI::Windows::Media::SystemMediaTransportControlsButton;
 using ABI::Windows::Media::SystemMediaTransportControlsButtonPressedEventArgs;
+using ABI::Windows::Storage::Streams::IDataWriter;
+using ABI::Windows::Storage::Streams::IDataWriterFactory;
+using ABI::Windows::Storage::Streams::IOutputStream;
+using ABI::Windows::Storage::Streams::IRandomAccessStream;
+using ABI::Windows::Storage::Streams::IRandomAccessStreamReference;
+using ABI::Windows::Storage::Streams::IRandomAccessStreamReferenceStatics;
 
 // static
 SystemMediaControlsServiceImpl* SystemMediaControlsServiceImpl::GetInstance() {
@@ -38,7 +45,7 @@
   if (has_valid_registration_token_) {
     DCHECK(system_media_controls_);
     system_media_controls_->remove_ButtonPressed(registration_token_);
-    system_media_controls_->put_IsEnabled(false);
+    ClearMetadata();
   }
 }
 
@@ -81,6 +88,22 @@
   if (FAILED(hr))
     return false;
 
+  hr = system_media_controls_->get_DisplayUpdater(&display_updater_);
+  if (FAILED(hr))
+    return false;
+
+  // The current MediaSession API implementation matches the SMTC music type
+  // most closely, since MediaSession has the artist property which the SMTC
+  // only presents to music playback types.
+  hr = display_updater_->put_Type(
+      ABI::Windows::Media::MediaPlaybackType::MediaPlaybackType_Music);
+  if (FAILED(hr))
+    return false;
+
+  hr = display_updater_->get_MusicProperties(&display_properties_);
+  if (FAILED(hr))
+    return false;
+
   initialized_ = true;
   return true;
 }
@@ -132,6 +155,138 @@
   DCHECK(SUCCEEDED(hr));
 }
 
+void SystemMediaControlsServiceImpl::SetTitle(const base::string16& title) {
+  DCHECK(initialized_);
+  DCHECK(display_properties_);
+  base::win::ScopedHString h_title = base::win::ScopedHString::Create(title);
+  HRESULT hr = display_properties_->put_Title(h_title.get());
+  DCHECK(SUCCEEDED(hr));
+}
+
+void SystemMediaControlsServiceImpl::SetArtist(const base::string16& artist) {
+  DCHECK(initialized_);
+  DCHECK(display_properties_);
+  base::win::ScopedHString h_artist = base::win::ScopedHString::Create(artist);
+  HRESULT hr = display_properties_->put_Artist(h_artist.get());
+  DCHECK(SUCCEEDED(hr));
+}
+
+void SystemMediaControlsServiceImpl::SetThumbnail(const SkBitmap& bitmap) {
+  DCHECK(initialized_);
+  DCHECK(display_updater_);
+  // Use |icon_data_writer_| to write the bitmap data into |icon_stream_| so we
+  // can populate |icon_stream_reference_| and then give it to the SMTC. All of
+  // these are member variables to avoid a race condition between them being
+  // destructed and the async operation completing.
+  base::win::ScopedHString id = base::win::ScopedHString::Create(
+      RuntimeClass_Windows_Storage_Streams_InMemoryRandomAccessStream);
+  HRESULT hr = base::win::RoActivateInstance(id.get(), &icon_stream_);
+  DCHECK(SUCCEEDED(hr));
+
+  Microsoft::WRL::ComPtr<IDataWriterFactory> data_writer_factory;
+  hr = base::win::GetActivationFactory<
+      IDataWriterFactory, RuntimeClass_Windows_Storage_Streams_DataWriter>(
+      &data_writer_factory);
+  DCHECK(SUCCEEDED(hr));
+
+  Microsoft::WRL::ComPtr<IOutputStream> output_stream;
+  hr = icon_stream_.As(&output_stream);
+  DCHECK(SUCCEEDED(hr));
+
+  hr = data_writer_factory->CreateDataWriter(output_stream.Get(),
+                                             &icon_data_writer_);
+  DCHECK(SUCCEEDED(hr));
+
+  std::vector<unsigned char> icon_png;
+  gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &icon_png);
+  hr = icon_data_writer_->WriteBytes(icon_png.size(), (BYTE*)icon_png.data());
+  DCHECK(SUCCEEDED(hr));
+
+  // Store the written bytes in the stream, an async operation.
+  Microsoft::WRL::ComPtr<
+      ABI::Windows::Foundation::IAsyncOperation<unsigned int>>
+      store_async_operation;
+  hr = icon_data_writer_->StoreAsync(&store_async_operation);
+  DCHECK(SUCCEEDED(hr));
+
+  // Make a callback that gives the icon to the SMTC once the bits make it into
+  // |icon_stream_|
+  auto store_async_callback = Microsoft::WRL::Callback<
+      ABI::Windows::Foundation::IAsyncOperationCompletedHandler<unsigned int>>(
+      [this](ABI::Windows::Foundation::IAsyncOperation<unsigned int>* async_op,
+             ABI::Windows::Foundation::AsyncStatus status) mutable {
+        // Check the async operation completed successfully.
+        ABI::Windows::Foundation::IAsyncInfo* async_info;
+        HRESULT hr = async_op->QueryInterface(
+            IID_IAsyncInfo, reinterpret_cast<void**>(&async_info));
+        DCHECK(SUCCEEDED(hr));
+        async_info->get_ErrorCode(&hr);
+        if (SUCCEEDED(hr) &&
+            status == ABI::Windows::Foundation::AsyncStatus::Completed) {
+          Microsoft::WRL::ComPtr<IRandomAccessStreamReferenceStatics>
+              reference_statics;
+          HRESULT hr = base::win::GetActivationFactory<
+              IRandomAccessStreamReferenceStatics,
+              RuntimeClass_Windows_Storage_Streams_RandomAccessStreamReference>(
+              &reference_statics);
+          DCHECK(SUCCEEDED(hr));
+
+          hr = reference_statics->CreateFromStream(icon_stream_.Get(),
+                                                   &icon_stream_reference_);
+          DCHECK(SUCCEEDED(hr));
+
+          hr = display_updater_->put_Thumbnail(icon_stream_reference_.Get());
+          DCHECK(SUCCEEDED(hr));
+
+          hr = display_updater_->Update();
+          DCHECK(SUCCEEDED(hr));
+        }
+        return hr;
+      });
+
+  hr = store_async_operation->put_Completed(store_async_callback.Get());
+  DCHECK(SUCCEEDED(hr));
+}
+
+void SystemMediaControlsServiceImpl::ClearThumbnail() {
+  DCHECK(initialized_);
+  DCHECK(display_updater_);
+  HRESULT hr = display_updater_->put_Thumbnail(nullptr);
+  DCHECK(SUCCEEDED(hr));
+
+  hr = display_updater_->Update();
+  DCHECK(SUCCEEDED(hr));
+}
+
+void SystemMediaControlsServiceImpl::ClearMetadata() {
+  DCHECK(initialized_);
+  DCHECK(display_updater_);
+  HRESULT hr = display_updater_->ClearAll();
+  DCHECK(SUCCEEDED(hr));
+
+  // To prevent disabled controls and the executable name from showing up in the
+  // SMTC, we need to tell them that we are disabled.
+  hr = system_media_controls_->put_IsEnabled(false);
+  DCHECK(SUCCEEDED(hr));
+}
+
+void SystemMediaControlsServiceImpl::UpdateDisplay() {
+  DCHECK(initialized_);
+  DCHECK(system_media_controls_);
+  DCHECK(display_updater_);
+  HRESULT hr = system_media_controls_->put_IsEnabled(true);
+  DCHECK(SUCCEEDED(hr));
+
+  // |ClearAll()| unsets the type, if we don't set it again then the artist
+  // won't be displayed.
+  hr = display_updater_->put_Type(
+      ABI::Windows::Media::MediaPlaybackType::MediaPlaybackType_Music);
+  DCHECK(SUCCEEDED(hr));
+
+  hr = display_updater_->Update();
+  DCHECK(SUCCEEDED(hr));
+}
+
 void SystemMediaControlsServiceImpl::OnPlay() {
   for (SystemMediaControlsServiceObserver& obs : observers_)
     obs.OnPlay();
diff --git a/ui/base/win/system_media_controls/system_media_controls_service_impl.h b/ui/base/win/system_media_controls/system_media_controls_service_impl.h
index fb10cde..57e71e1 100644
--- a/ui/base/win/system_media_controls/system_media_controls_service_impl.h
+++ b/ui/base/win/system_media_controls/system_media_controls_service_impl.h
@@ -44,6 +44,12 @@
   void SetIsStopEnabled(bool value) override;
   void SetPlaybackStatus(
       ABI::Windows::Media::MediaPlaybackStatus status) override;
+  void SetTitle(const base::string16& title) override;
+  void SetArtist(const base::string16& artist) override;
+  void SetThumbnail(const SkBitmap& bitmap) override;
+  void ClearThumbnail() override;
+  void ClearMetadata() override;
+  void UpdateDisplay() override;
 
  private:
   friend struct base::DefaultSingletonTraits<SystemMediaControlsServiceImpl>;
@@ -60,8 +66,22 @@
   void OnPrevious();
   void OnStop();
 
+  // Control and keep track of the metadata.
   Microsoft::WRL::ComPtr<ABI::Windows::Media::ISystemMediaTransportControls>
       system_media_controls_;
+  Microsoft::WRL::ComPtr<
+      ABI::Windows::Media::ISystemMediaTransportControlsDisplayUpdater>
+      display_updater_;
+  Microsoft::WRL::ComPtr<ABI::Windows::Media::IMusicDisplayProperties>
+      display_properties_;
+  Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IDataWriter>
+      icon_data_writer_;
+  Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IRandomAccessStream>
+      icon_stream_;
+  Microsoft::WRL::ComPtr<
+      ABI::Windows::Storage::Streams::IRandomAccessStreamReference>
+      icon_stream_reference_;
+
   EventRegistrationToken registration_token_;
 
   // True if we've already tried to connect to the SystemMediaTransportControls.
diff --git a/ui/events/devices/gamepad_device.h b/ui/events/devices/gamepad_device.h
index 2566ab7..5ef4a4b 100644
--- a/ui/events/devices/gamepad_device.h
+++ b/ui/events/devices/gamepad_device.h
@@ -16,6 +16,9 @@
 struct EVENTS_DEVICES_EXPORT GamepadDevice : public InputDevice {
   // Represents an axis of a gamepad e.g. an analog thumb stick.
   struct Axis {
+    // Gamepad axis index. Corresponds to |raw_code_| of GamepadEvent.
+    uint16_t code = 0;
+
     // See input_absinfo for the definition of these variables.
     int32_t min_value = 0;
     int32_t max_value = 0;
diff --git a/ui/events/ozone/evdev/gamepad_event_converter_evdev.cc b/ui/events/ozone/evdev/gamepad_event_converter_evdev.cc
index 5f6c5fba..6dd438d 100644
--- a/ui/events/ozone/evdev/gamepad_event_converter_evdev.cc
+++ b/ui/events/ozone/evdev/gamepad_event_converter_evdev.cc
@@ -135,6 +135,7 @@
     abs_info = devinfo.GetAbsInfoByCode(code);
     if (devinfo.HasAbsEvent(code)) {
       ui::GamepadDevice::Axis axis;
+      axis.code = code;
       axis.min_value = abs_info.minimum;
       axis.max_value = abs_info.maximum;
       axis.flat = abs_info.flat;
diff --git a/ui/file_manager/file_manager/foreground/css/file_manager.css b/ui/file_manager/file_manager/foreground/css/file_manager.css
index 31e8869..0f20c64 100644
--- a/ui/file_manager/file_manager/foreground/css/file_manager.css
+++ b/ui/file_manager/file_manager/foreground/css/file_manager.css
@@ -146,11 +146,6 @@
   width: calc(100% - 92px);
 }
 
-.tree-item .root-eject {
-  position: absolute;
-  right: 0;
-}
-
 #directory-tree .tree-row > .button {
   display: flex;
   min-width: 0;
@@ -223,16 +218,25 @@
   background-color: rgb(216, 223, 240);
 }
 
-#directory-tree .tree-row > .root-eject {
-  background: -webkit-image-set(
-      url(../images/files/ui/eject.png) 1x,
-      url(../images/files/ui/2x/eject.png) 2x) no-repeat center;
+#directory-tree .tree-row > .align-right-icon {
   border-style: none;
   cursor: pointer;
   flex: none;
   height: 40px;
+  position: absolute;
+  right: 0;
   width: 40px;
-  z-index: 1;  /* Make sure .root-eject is on upper layer than paper-ripple. */
+  z-index: 1;  /* Make sure the icon is on upper layer than paper-ripple. */
+}
+
+#directory-tree .tree-row > .external-link-icon {
+  background: url(../images/files/ui/external_link.svg) no-repeat center;
+}
+
+#directory-tree .tree-row > .root-eject {
+  background: -webkit-image-set(
+      url(../images/files/ui/eject.png) 1x,
+      url(../images/files/ui/2x/eject.png) 2x) no-repeat center;
 }
 
 #directory-tree .tree-row[selected] > .root-eject {
diff --git a/ui/file_manager/file_manager/foreground/images/files/ui/external_link.svg b/ui/file_manager/file_manager/foreground/images/files/ui/external_link.svg
new file mode 100644
index 0000000..35b5259
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/files/ui/external_link.svg
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <defs>
+        <path d="M10,10 L2,10 L2,2 L5.2,2 L5.2,0.4 L2,0.4 C1.2,0.4 0.4,1.2 0.4,2 C0.4,2.53333333 0.4,5.2 0.4,10 C0.4,10.8 1.2,11.6 2,11.6 L10,11.6 C10.8,11.6 11.6,10.8 11.6,10 L11.6,6.8 L10,6.8 L10,10 Z M6.8,0.4 L6.8,2 L8.8,2 L3.6,7.2 L4.8,8.4 L10,3.2 L10,5.2 L11.6,5.2 L11.6,0.4 L6.8,0.4 Z" id="path-1"></path>
+    </defs>
+    <g id="ic_launch_16" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="dense/action/launch" transform="translate(2.000000, 2.000000)">
+            <mask id="mask-2" fill="white">
+                <use xlink:href="#path-1"></use>
+            </mask>
+            <use id="↳Color-fill" fill="#4C4C4C" xlink:href="#path-1"></use>
+        </g>
+    </g>
+</svg>
diff --git a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
index 09d0544f..4623d83 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
@@ -652,7 +652,7 @@
     ejectButton.addEventListener('down', (event) => {
       event.stopPropagation();
     });
-    ejectButton.className = 'root-eject';
+    ejectButton.className = 'root-eject align-right-icon';
     ejectButton.setAttribute('aria-label', str('UNMOUNT_DEVICE_BUTTON_LABEL'));
     ejectButton.setAttribute('tabindex', '0');
     ejectButton.addEventListener('click', (event) => {
@@ -1606,15 +1606,19 @@
     /** @public {string} */
     this.label = modelItem.androidApp.name;
 
-    const icon = this.querySelector('.icon');
-    icon.classList.add('item-icon');
+    const appIcon = this.querySelector('.icon');
+    appIcon.classList.add('item-icon');
     if (modelItem.androidApp.iconSet) {
       const backgroundImage =
           util.iconSetToCSSBackgroundImageValue(modelItem.androidApp.iconSet);
       if (backgroundImage !== 'none') {
-        icon.setAttribute('style', 'background-image: ' + backgroundImage);
+        appIcon.setAttribute('style', 'background-image: ' + backgroundImage);
       }
     }
+
+    const externalLinkIcon = cr.doc.createElement('span');
+    externalLinkIcon.className = 'external-link-icon align-right-icon';
+    this.rowElement.appendChild(externalLinkIcon);
   }
 
   /**
diff --git a/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc b/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc
index 90e4e49..06c75ea 100644
--- a/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc
+++ b/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc
@@ -15,6 +15,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/trace_event/trace_event.h"
 #include "ui/gfx/buffer_format_util.h"
+#include "ui/gfx/buffer_usage_util.h"
 #include "ui/gfx/geometry/size_conversions.h"
 #include "ui/gfx/native_pixmap_handle.h"
 #include "ui/ozone/common/linux/drm_util_linux.h"
@@ -42,8 +43,7 @@
 bool GbmPixmapWayland::InitializeBuffer(gfx::Size size,
                                         gfx::BufferFormat format,
                                         gfx::BufferUsage usage) {
-  TRACE_EVENT1("wayland", "GbmPixmapWayland::InitializeBuffer", "size",
-               size.ToString());
+  TRACE_EVENT0("wayland", "GbmPixmapWayland::InitializeBuffer");
 
   if (!connection_->gbm_device())
     return false;
@@ -76,7 +76,9 @@
   const uint32_t fourcc_format = GetFourCCFormatFromBufferFormat(format);
   gbm_bo_ = connection_->gbm_device()->CreateBuffer(fourcc_format, size, flags);
   if (!gbm_bo_) {
-    LOG(FATAL) << "Cannot create bo";
+    LOG(ERROR) << "Cannot create bo with format= "
+               << gfx::BufferFormatToString(format) << " and usage "
+               << gfx::BufferUsageToString(usage);
     return false;
   }
 
diff --git a/ui/webui/resources/cr_components/chromeos/smb_shares/add_smb_share_dialog.js b/ui/webui/resources/cr_components/chromeos/smb_shares/add_smb_share_dialog.js
index 2103a9d..ba4c4812 100644
--- a/ui/webui/resources/cr_components/chromeos/smb_shares/add_smb_share_dialog.js
+++ b/ui/webui/resources/cr_components/chromeos/smb_shares/add_smb_share_dialog.js
@@ -15,8 +15,19 @@
     GENERAL_ERROR: 3,
   };
 
+  /**
+   * Regular expression that matches SMB share URLs of the form
+   * smb://server/share or \\server\share. This is a coarse regexp intended for
+   * quick UI feedback and does not reject all invalid URLs.
+   *
+   * @type {!RegExp}
+   */
+  const SMB_SHARE_URL_REGEX =
+      /^((smb:\/\/[^\/]+\/[^\/].*)|(\\\\[^\\]+\\[^\\].*))$/;
+
   return {
     MountErrorType: MountErrorType,
+    SMB_SHARE_URL_REGEX: SMB_SHARE_URL_REGEX,
   };
 });
 
@@ -154,7 +165,7 @@
    * @private
    */
   canAddShare_: function() {
-    return !!this.mountUrl_ && !this.inProgress_;
+    return !!this.mountUrl_ && !this.inProgress_ && this.isShareUrlValid_();
   },
 
   /**
@@ -281,4 +292,15 @@
   shouldShowPathError_: function() {
     return this.currentMountError_ == smb_shares.MountErrorType.PATH_ERROR;
   },
+
+  /**
+   * @return {boolean}
+   * @private
+   */
+  isShareUrlValid_: function() {
+    if (!this.mountUrl_) {
+      return false;
+    }
+    return smb_shares.SMB_SHARE_URL_REGEX.test(this.mountUrl_);
+  },
 });