diff --git a/DEPS b/DEPS
index 13952a28..b67f51d 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': '6bbeb4ab722279aa20f1b4c793dbe5fbc0afadcc',
+  'skia_revision': '90c300fb4ac9421b7274ba7c94c8c90f600766db',
   # 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': '46e13cfbf489c51c7dc5088a5a6d9f0dc91b39c0',
+  'v8_revision': 'fe77d58a6a3cd9385454aa0bc29330ec668e293a',
   # 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': 'c8f25d90ac2b3bc0e520409b9e71307b5ac77adf',
+  'swiftshader_revision': '900e1dac1b2da6fae567e8e2da7a36f7b2cbd625',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -189,7 +189,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
-  'freetype_revision': 'a41e560b213d72f36c37b7b25960839de7d29fd0',
+  'freetype_revision': '81445c034aca36040b6311dc71a2cbed9548b262',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling HarfBuzz
   # 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': '24b441ff93e89b23a6ee39e76d25f224a44f3ce7',
+  'catapult_revision': '6643ef1bddde64e223924eb23fabc47acc3da16c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # 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' + '@' + '385e9d4f27d34bf2d43030216041acce17f3519c',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'ec964f7b30c8c4066df0447c71540778d0ddd38b',
       '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' + '@' + 'd8ac0c37a3b2b13e26c458cc6efcceebbe52b3c7',
+      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + 'ed5a30c1446a23a0c98cc4623b260c03f9202aa8',
       'condition': 'checkout_linux',
   },
 
@@ -1187,7 +1187,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '7afb8a45a3894a2641f478fb2c69ee0721e3241a',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '764c50488ab39a447d304f6601941e229e2fe6c3',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1355,7 +1355,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '6f0b34abee8dba611c253738d955c59f703c147a',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'abf7eba8658c6facda98210399bf88d0c5f72036',
+    Var('webrtc_git') + '/src.git' + '@' + '9aa870a2d107560864f8e78a438789534f777734',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1396,7 +1396,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@13820f2a7ac9d98d6fd070dd861d1354f06162ee',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@fb91be137da68e75372d6c7a32b6d1991e6ba1a1',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AndroidScrollIntegrationTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AndroidScrollIntegrationTest.java
index 3f7d81b..965a771 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AndroidScrollIntegrationTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AndroidScrollIntegrationTest.java
@@ -850,8 +850,12 @@
     }
 
     @Test
-    @SmallTest
-    @Feature("AndroidWebView")
+    /**
+     * @SmallTest
+     * @Feature("AndroidWebView")
+     * BUG=977526
+     */
+    @DisabledTest
     public void testScrollOffsetAfterCapturePicture() throws Throwable {
         final TestAwContentsClient contentsClient = new TestAwContentsClient();
         final ScrollTestContainerView testContainerView =
diff --git a/apps/launcher.cc b/apps/launcher.cc
index fe8835f9..e7f1d8e 100644
--- a/apps/launcher.cc
+++ b/apps/launcher.cc
@@ -345,7 +345,8 @@
   // not kept as the extension may be unloaded and deleted during the course of
   // the launch.
   const std::string extension_id;
-  extensions::AppLaunchSource launch_source_ = extensions::SOURCE_FILE_HANDLER;
+  extensions::AppLaunchSource launch_source_ =
+      extensions::AppLaunchSource::kSourceFileHandler;
   std::unique_ptr<app_runtime::ActionData> action_data_;
   // A list of files and directories to be passed through to the app.
   std::vector<base::FilePath> entry_paths_;
@@ -446,7 +447,7 @@
   scoped_refptr<PlatformAppPathLauncher> launcher =
       new PlatformAppPathLauncher(context, app, file_path);
   launcher->set_action_data(std::move(action_data));
-  launcher->set_launch_source(extensions::AppLaunchSource::SOURCE_UNTRACKED);
+  launcher->set_launch_source(extensions::AppLaunchSource::kSourceUntracked);
   launcher->Launch();
 }
 
@@ -488,7 +489,7 @@
 
   if (listening_to_launch && had_windows) {
     AppRuntimeEventRouter::DispatchOnLaunchedEvent(
-        context, app, extensions::SOURCE_RESTART, nullptr);
+        context, app, extensions::AppLaunchSource::kSourceRestart, nullptr);
   }
 }
 
diff --git a/ash/app_list/model/folder_image.cc b/ash/app_list/model/folder_image.cc
index fb3d95ff..e15ebcae6 100644
--- a/ash/app_list/model/folder_image.cc
+++ b/ash/app_list/model/folder_image.cc
@@ -60,7 +60,7 @@
 };
 
 FolderImageSource::FolderImageSource(const Icons& icons, const gfx::Size& size)
-    : gfx::CanvasImageSource(size, false), icons_(icons), size_(size) {
+    : gfx::CanvasImageSource(size), icons_(icons), size_(size) {
   DCHECK(icons.size() <= FolderImage::kNumFolderTopItems);
 }
 
diff --git a/ash/app_list/views/app_list_item_view.cc b/ash/app_list/views/app_list_item_view.cc
index 5195f31..9580d73 100644
--- a/ash/app_list/views/app_list_item_view.cc
+++ b/ash/app_list/views/app_list_item_view.cc
@@ -101,8 +101,7 @@
 class ClippedFolderIconImageSource : public gfx::CanvasImageSource {
  public:
   explicit ClippedFolderIconImageSource(const gfx::ImageSkia& image)
-      : gfx::CanvasImageSource(AppListConfig::instance().folder_icon_size(),
-                               false),
+      : gfx::CanvasImageSource(AppListConfig::instance().folder_icon_size()),
         image_(image) {}
   ~ClippedFolderIconImageSource() override = default;
 
diff --git a/ash/public/cpp/network_icon_image_source.cc b/ash/public/cpp/network_icon_image_source.cc
index 3f06acf..5dfd2d0 100644
--- a/ash/public/cpp/network_icon_image_source.cc
+++ b/ash/public/cpp/network_icon_image_source.cc
@@ -44,7 +44,7 @@
 NetworkIconImageSource::NetworkIconImageSource(const gfx::Size& size,
                                                const gfx::ImageSkia& icon,
                                                const Badges& badges)
-    : CanvasImageSource(size, false), icon_(icon), badges_(badges) {}
+    : CanvasImageSource(size), icon_(icon), badges_(badges) {}
 
 NetworkIconImageSource::~NetworkIconImageSource() = default;
 
@@ -97,7 +97,7 @@
                                                      const gfx::Size& size,
                                                      int signal_strength,
                                                      int padding)
-    : CanvasImageSource(size, false /* is_opaque */),
+    : CanvasImageSource(size),
       image_type_(image_type),
       color_(color),
       signal_strength_(signal_strength),
diff --git a/ash/system/power/power_status.cc b/ash/system/power/power_status.cc
index 945ba63..2e818619 100644
--- a/ash/system/power/power_status.cc
+++ b/ash/system/power/power_status.cc
@@ -54,7 +54,7 @@
                      int height,
                      SkColor bg_color,
                      SkColor fg_color)
-      : gfx::CanvasImageSource(gfx::Size(height, height), false),
+      : gfx::CanvasImageSource(gfx::Size(height, height)),
         info_(info),
         bg_color_(bg_color),
         fg_color_(fg_color) {}
diff --git a/ash/system/unified/notification_counter_view.cc b/ash/system/unified/notification_counter_view.cc
index 9c1b299..610cdcd 100644
--- a/ash/system/unified/notification_counter_view.cc
+++ b/ash/system/unified/notification_counter_view.cc
@@ -53,8 +53,8 @@
 class NumberIconImageSource : public gfx::CanvasImageSource {
  public:
   explicit NumberIconImageSource(size_t count)
-      : CanvasImageSource(gfx::Size(kUnifiedTrayIconSize, kUnifiedTrayIconSize),
-                          false),
+      : CanvasImageSource(
+            gfx::Size(kUnifiedTrayIconSize, kUnifiedTrayIconSize)),
         count_(count) {
     DCHECK_LE(count_, kTrayNotificationMaxCount + 1);
   }
diff --git a/ash/wm/resize_shadow.cc b/ash/wm/resize_shadow.cc
index 1602847..3060182 100644
--- a/ash/wm/resize_shadow.cc
+++ b/ash/wm/resize_shadow.cc
@@ -34,8 +34,7 @@
 class ResizeShadowImageSource : public gfx::CanvasImageSource {
  public:
   ResizeShadowImageSource()
-      : gfx::CanvasImageSource(gfx::Size(kImageSide, kImageSide),
-                               false /* is opaque */) {}
+      : gfx::CanvasImageSource(gfx::Size(kImageSide, kImageSide)) {}
 
   ~ResizeShadowImageSource() override = default;
 
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index b52d9c8..9471121b 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-8910014653626698592
\ No newline at end of file
+8909799344739653680
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index fe0ebe4..15fa1102 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-8910019839789789120
\ No newline at end of file
+8909803436810455824
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ManageSyncPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ManageSyncPreferences.java
index faad1c2d..c78c629 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ManageSyncPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ManageSyncPreferences.java
@@ -227,7 +227,11 @@
     private void updateSyncStateFromSelectedModelTypes() {
         mProfileSyncService.setChosenDataTypes(
                 mSyncEverything.isChecked(), getSelectedModelTypes());
-        PersonalDataManager.setPaymentsIntegrationEnabled(mSyncPaymentsIntegration.isChecked());
+        // Note: mSyncPaymentsIntegration should be checked if mSyncEverything is checked, but if
+        // mSyncEverything was just enabled, then that state may not have propagated to
+        // mSyncPaymentsIntegration yet. See crbug.com/972863.
+        PersonalDataManager.setPaymentsIntegrationEnabled(
+                mSyncEverything.isChecked() || mSyncPaymentsIntegration.isChecked());
         // Some calls to setChosenDataTypes don't trigger syncStateChanged, so schedule update here.
         PostTask.postTask(UiThreadTaskTraits.DEFAULT, this::updateSyncPreferences);
     }
diff --git a/chrome/app/theme/chrome_unscaled_resources.grd b/chrome/app/theme/chrome_unscaled_resources.grd
index 096b39b..00fe281 100644
--- a/chrome/app/theme/chrome_unscaled_resources.grd
+++ b/chrome/app/theme/chrome_unscaled_resources.grd
@@ -37,9 +37,6 @@
         <if expr="is_macosx">
           <include name="IDR_STATUS_TRAY_ICON" file="google_chrome/product_logo_22_mono.png" type="BINDATA" />
         </if>
-        <if expr="not is_macosx and not is_win">
-          <include name="IDR_STATUS_TRAY_ICON" file="google_chrome/product_logo_22.png" type="BINDATA" />
-        </if>
         <if expr="chromeos">
           <include name="IDR_CHROME_APP_ICON_32" file="google_chrome/chromeos/chrome_app_icon_32.png" type="BINDATA" />
           <include name="IDR_CHROME_APP_ICON_192" file="google_chrome/chromeos/chrome_app_icon_192.png" type="BINDATA" />
@@ -72,9 +69,6 @@
         <if expr="is_macosx">
           <include name="IDR_STATUS_TRAY_ICON" file="chromium/product_logo_22_mono.png" type="BINDATA" />
         </if>
-        <if expr="not is_macosx and not is_win">
-          <include name="IDR_STATUS_TRAY_ICON" file="chromium/product_logo_22.png" type="BINDATA" />
-        </if>
         <if expr="chromeos">
           <include name="IDR_CHROME_APP_ICON_32" file="chromium/chromeos/chrome_app_icon_32.png" type="BINDATA" />
           <include name="IDR_CHROME_APP_ICON_192" file="chromium/chromeos/chrome_app_icon_192.png" type="BINDATA" />
diff --git a/chrome/app/theme/chromium/product_logo_22.png b/chrome/app/theme/chromium/product_logo_22.png
deleted file mode 100644
index 1d25e2a..0000000
--- a/chrome/app/theme/chromium/product_logo_22.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.cc b/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.cc
index 56f5522..91f82d2 100644
--- a/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.cc
+++ b/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.cc
@@ -322,12 +322,12 @@
   if (extension->is_hosted_app()) {
     OpenApplication(CreateAppLaunchParamsUserContainer(
         profile, extension, WindowOpenDisposition::NEW_FOREGROUND_TAB,
-        extensions::SOURCE_COMMAND_LINE));
+        extensions::AppLaunchSource::kSourceCommandLine));
     return;
   }
   if (files.empty()) {
-    apps::LaunchPlatformApp(
-        profile, extension, extensions::SOURCE_COMMAND_LINE);
+    apps::LaunchPlatformApp(profile, extension,
+                            extensions::AppLaunchSource::kSourceCommandLine);
   } else {
     for (std::vector<base::FilePath>::const_iterator it = files.begin();
          it != files.end(); ++it) {
diff --git a/chrome/browser/apps/intent_helper/apps_navigation_throttle.cc b/chrome/browser/apps/intent_helper/apps_navigation_throttle.cc
index 9e855c0c..dd090c0f 100644
--- a/chrome/browser/apps/intent_helper/apps_navigation_throttle.cc
+++ b/chrome/browser/apps/intent_helper/apps_navigation_throttle.cc
@@ -309,7 +309,7 @@
   const extensions::Extension* extension =
       extensions::util::GetInstalledPwaForUrl(
           web_contents->GetBrowserContext(), url,
-          extensions::LAUNCH_CONTAINER_WINDOW);
+          extensions::LaunchContainer::kLaunchContainerWindow);
 
   if (extension) {
     auto* menu_manager =
diff --git a/chrome/browser/apps/platform_apps/api/media_galleries/media_galleries_apitest.cc b/chrome/browser/apps/platform_apps/api/media_galleries/media_galleries_apitest.cc
index 38e5b5a5..b9b4d193 100644
--- a/chrome/browser/apps/platform_apps/api/media_galleries/media_galleries_apitest.cc
+++ b/chrome/browser/apps/platform_apps/api/media_galleries/media_galleries_apitest.cc
@@ -270,9 +270,10 @@
   ASSERT_TRUE(extension);
 
   extensions::ResultCatcher catcher;
-  AppLaunchParams params(
-      browser()->profile(), extension->id(), extensions::LAUNCH_CONTAINER_NONE,
-      WindowOpenDisposition::NEW_WINDOW, extensions::SOURCE_TEST);
+  AppLaunchParams params(browser()->profile(), extension->id(),
+                         extensions::LaunchContainer::kLaunchContainerNone,
+                         WindowOpenDisposition::NEW_WINDOW,
+                         extensions::AppLaunchSource::kSourceTest);
   params.command_line = *base::CommandLine::ForCurrentProcess();
   OpenApplication(params);
 
diff --git a/chrome/browser/apps/platform_apps/app_browsertest.cc b/chrome/browser/apps/platform_apps/app_browsertest.cc
index 9819327..ccdfcd0 100644
--- a/chrome/browser/apps/platform_apps/app_browsertest.cc
+++ b/chrome/browser/apps/platform_apps/app_browsertest.cc
@@ -225,9 +225,9 @@
     }
 
     AppLaunchParams params(browser()->profile(), extension->id(),
-                           extensions::LAUNCH_CONTAINER_NONE,
+                           extensions::LaunchContainer::kLaunchContainerNone,
                            WindowOpenDisposition::NEW_WINDOW,
-                           extensions::SOURCE_TEST);
+                           extensions::AppLaunchSource::kSourceTest);
     params.command_line = command_line;
     params.current_directory = test_data_dir_;
     OpenApplication(params);
@@ -864,9 +864,10 @@
     content::WindowedNotificationObserver app_loaded_observer(
         content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
         content::NotificationService::AllSources());
-    OpenApplication(AppLaunchParams(
-        browser()->profile(), extension->id(), LAUNCH_CONTAINER_NONE,
-        WindowOpenDisposition::NEW_WINDOW, extensions::SOURCE_TEST));
+    OpenApplication(AppLaunchParams(browser()->profile(), extension->id(),
+                                    LaunchContainer::kLaunchContainerNone,
+                                    WindowOpenDisposition::NEW_WINDOW,
+                                    extensions::AppLaunchSource::kSourceTest));
     app_loaded_observer.Wait();
     window = GetFirstAppWindow();
     ASSERT_TRUE(window);
@@ -1010,9 +1011,10 @@
   ASSERT_TRUE(should_install.seen());
 
   ExtensionTestMessageListener launched_listener("Launched", false);
-  OpenApplication(AppLaunchParams(
-      browser()->profile(), extension->id(), LAUNCH_CONTAINER_NONE,
-      WindowOpenDisposition::NEW_WINDOW, extensions::SOURCE_TEST));
+  OpenApplication(AppLaunchParams(browser()->profile(), extension->id(),
+                                  LaunchContainer::kLaunchContainerNone,
+                                  WindowOpenDisposition::NEW_WINDOW,
+                                  extensions::AppLaunchSource::kSourceTest));
 
   ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
 }
@@ -1032,9 +1034,10 @@
   ASSERT_TRUE(extension);
 
   ExtensionTestMessageListener launched_listener("Launched", false);
-  OpenApplication(AppLaunchParams(
-      browser()->profile(), extension->id(), LAUNCH_CONTAINER_NONE,
-      WindowOpenDisposition::NEW_WINDOW, extensions::SOURCE_TEST));
+  OpenApplication(AppLaunchParams(browser()->profile(), extension->id(),
+                                  LaunchContainer::kLaunchContainerNone,
+                                  WindowOpenDisposition::NEW_WINDOW,
+                                  extensions::AppLaunchSource::kSourceTest));
 
   ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
   ASSERT_FALSE(should_not_install.seen());
@@ -1070,9 +1073,10 @@
   ASSERT_TRUE(should_install.seen());
 
   ExtensionTestMessageListener launched_listener("Launched", false);
-  OpenApplication(AppLaunchParams(
-      browser()->profile(), extension->id(), LAUNCH_CONTAINER_NONE,
-      WindowOpenDisposition::NEW_WINDOW, extensions::SOURCE_TEST));
+  OpenApplication(AppLaunchParams(browser()->profile(), extension->id(),
+                                  LaunchContainer::kLaunchContainerNone,
+                                  WindowOpenDisposition::NEW_WINDOW,
+                                  extensions::AppLaunchSource::kSourceTest));
 
   ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
 }
@@ -1095,9 +1099,10 @@
 
   {
     ExtensionTestMessageListener launched_listener("Launched", false);
-    OpenApplication(AppLaunchParams(
-        browser()->profile(), extension->id(), LAUNCH_CONTAINER_NONE,
-        WindowOpenDisposition::NEW_WINDOW, extensions::SOURCE_TEST));
+    OpenApplication(AppLaunchParams(browser()->profile(), extension->id(),
+                                    LaunchContainer::kLaunchContainerNone,
+                                    WindowOpenDisposition::NEW_WINDOW,
+                                    extensions::AppLaunchSource::kSourceTest));
     ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
   }
 
@@ -1218,7 +1223,8 @@
 
   OpenApplication(CreateAppLaunchParamsUserContainer(
       incognito_profile, file_manager,
-      WindowOpenDisposition::NEW_FOREGROUND_TAB, extensions::SOURCE_TEST));
+      WindowOpenDisposition::NEW_FOREGROUND_TAB,
+      extensions::AppLaunchSource::kSourceTest));
 
   while (!base::Contains(opener_app_ids_, file_manager->id())) {
     content::RunAllPendingInMessageLoop();
diff --git a/chrome/browser/apps/platform_apps/app_browsertest_util.cc b/chrome/browser/apps/platform_apps/app_browsertest_util.cc
index e64772a..ad94228 100644
--- a/chrome/browser/apps/platform_apps/app_browsertest_util.cc
+++ b/chrome/browser/apps/platform_apps/app_browsertest_util.cc
@@ -154,16 +154,17 @@
 }
 
 void PlatformAppBrowserTest::LaunchPlatformApp(const Extension* extension) {
-  OpenApplication(AppLaunchParams(
-      browser()->profile(), extension->id(), LAUNCH_CONTAINER_NONE,
-      WindowOpenDisposition::NEW_WINDOW, extensions::SOURCE_TEST));
+  OpenApplication(AppLaunchParams(browser()->profile(), extension->id(),
+                                  LaunchContainer::kLaunchContainerNone,
+                                  WindowOpenDisposition::NEW_WINDOW,
+                                  extensions::AppLaunchSource::kSourceTest));
 }
 
 void PlatformAppBrowserTest::LaunchHostedApp(const Extension* extension) {
   OpenApplication(CreateAppLaunchParamsUserContainer(
       browser()->profile(), extension,
       WindowOpenDisposition::NEW_FOREGROUND_TAB,
-      extensions::SOURCE_COMMAND_LINE));
+      extensions::AppLaunchSource::kSourceCommandLine));
 }
 
 WebContents* PlatformAppBrowserTest::GetFirstAppWindowWebContents() {
diff --git a/chrome/browser/apps/platform_apps/app_load_service.cc b/chrome/browser/apps/platform_apps/app_load_service.cc
index 7bc1bad..e26c1ea 100644
--- a/chrome/browser/apps/platform_apps/app_load_service.cc
+++ b/chrome/browser/apps/platform_apps/app_load_service.cc
@@ -109,7 +109,8 @@
 
   switch (it->second.action_type) {
     case LAUNCH_FOR_RELOAD:
-      LaunchPlatformApp(context_, extension, extensions::SOURCE_RELOAD);
+      LaunchPlatformApp(context_, extension,
+                        extensions::AppLaunchSource::kSourceReload);
       break;
     case RESTART:
       RestartPlatformApp(context_, extension);
@@ -117,7 +118,7 @@
     case LAUNCH_FOR_LOAD_AND_LAUNCH:
       LaunchPlatformAppWithCommandLine(
           context_, extension, it->second.command_line, it->second.current_dir,
-          extensions::SOURCE_LOAD_AND_LAUNCH);
+          extensions::AppLaunchSource::kSourceLoadAndLaunch);
       break;
     default:
       NOTREACHED();
diff --git a/chrome/browser/apps/platform_apps/app_window_browsertest.cc b/chrome/browser/apps/platform_apps/app_window_browsertest.cc
index a766da452..6a4f36d 100644
--- a/chrome/browser/apps/platform_apps/app_window_browsertest.cc
+++ b/chrome/browser/apps/platform_apps/app_window_browsertest.cc
@@ -238,9 +238,11 @@
       test_data_dir_.AppendASCII("platform_apps").AppendASCII("window_api"));
   EXPECT_TRUE(extension);
 
-  OpenApplication(AppLaunchParams(
-      browser()->profile(), extension->id(), extensions::LAUNCH_CONTAINER_NONE,
-      WindowOpenDisposition::NEW_WINDOW, extensions::SOURCE_TEST));
+  OpenApplication(
+      AppLaunchParams(browser()->profile(), extension->id(),
+                      extensions::LaunchContainer::kLaunchContainerNone,
+                      WindowOpenDisposition::NEW_WINDOW,
+                      extensions::AppLaunchSource::kSourceTest));
 
   ExtensionTestMessageListener geometry_listener("ListenGeometryChange", true);
 
diff --git a/chrome/browser/apps/platform_apps/platform_app_launch.cc b/chrome/browser/apps/platform_apps/platform_app_launch.cc
index e7ff9ec..50077bc 100644
--- a/chrome/browser/apps/platform_apps/platform_app_launch.cc
+++ b/chrome/browser/apps/platform_apps/platform_app_launch.cc
@@ -72,14 +72,14 @@
   if (!GetAppLaunchContainer(profile, app_id, &app, &launch_container))
     return false;
 
-  if (launch_container == extensions::LAUNCH_CONTAINER_TAB)
+  if (launch_container == extensions::LaunchContainer::kLaunchContainerTab)
     return false;
 
   RecordCmdLineAppHistogram(app->GetType());
 
   ::AppLaunchParams params(profile, app_id, launch_container,
                            WindowOpenDisposition::NEW_WINDOW,
-                           extensions::SOURCE_COMMAND_LINE);
+                           extensions::AppLaunchSource::kSourceCommandLine);
   params.command_line = command_line;
   params.current_directory = current_directory;
   content::WebContents* tab_in_app_window = ::OpenApplication(params);
@@ -95,15 +95,15 @@
     return false;
 
   // If the user doesn't want to open a tab, fail.
-  if (launch_container != extensions::LAUNCH_CONTAINER_TAB)
+  if (launch_container != extensions::LaunchContainer::kLaunchContainerTab)
     return false;
 
   RecordCmdLineAppHistogram(app->GetType());
 
-  content::WebContents* app_tab = ::OpenApplication(
-      ::AppLaunchParams(profile, app_id, extensions::LAUNCH_CONTAINER_TAB,
-                        WindowOpenDisposition::NEW_FOREGROUND_TAB,
-                        extensions::SOURCE_COMMAND_LINE));
+  content::WebContents* app_tab = ::OpenApplication(::AppLaunchParams(
+      profile, app_id, extensions::LaunchContainer::kLaunchContainerTab,
+      WindowOpenDisposition::NEW_FOREGROUND_TAB,
+      extensions::AppLaunchSource::kSourceCommandLine));
   return app_tab != nullptr;
 }
 
@@ -116,9 +116,10 @@
     return false;
 
   RecordCmdLineAppHistogram(extensions::Manifest::TYPE_PLATFORM_APP);
-  ::AppLaunchParams params(profile, app_id, extensions::LAUNCH_CONTAINER_NONE,
+  ::AppLaunchParams params(profile, app_id,
+                           extensions::LaunchContainer::kLaunchContainerNone,
                            WindowOpenDisposition::NEW_WINDOW,
-                           extensions::SOURCE_COMMAND_LINE);
+                           extensions::AppLaunchSource::kSourceCommandLine);
   params.command_line = command_line;
   params.current_directory = current_directory;
   ::OpenApplicationWithReenablePrompt(params);
diff --git a/chrome/browser/background/background_mode_manager.cc b/chrome/browser/background/background_mode_manager.cc
index 7574b4f..684fa4c 100644
--- a/chrome/browser/background/background_mode_manager.cc
+++ b/chrome/browser/background/background_mode_manager.cc
@@ -344,7 +344,7 @@
     const Extension* extension) {
   OpenApplication(CreateAppLaunchParamsUserContainer(
       profile, extension, WindowOpenDisposition::NEW_FOREGROUND_TAB,
-      extensions::SOURCE_BACKGROUND));
+      extensions::AppLaunchSource::kSourceBackground));
 }
 
 // static
@@ -769,10 +769,15 @@
     return gfx::ImageSkia();
 
   return family->CreateExact(size).AsImageSkia();
-#else
-  // On other platforms, just get a static resource image.
+#elif defined(OS_LINUX)
+  return *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
+      IDR_PRODUCT_LOGO_128);
+#elif defined(OS_MACOSX)
   return *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
       IDR_STATUS_TRAY_ICON);
+#else
+  NOTREACHED();
+  return gfx::ImageSkia();
 #endif
 }
 
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index afc2129..e66f656 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -769,6 +769,8 @@
     "dbus/kiosk_info_service_provider.h",
     "dbus/libvda_service_provider.cc",
     "dbus/libvda_service_provider.h",
+    "dbus/machine_learning_decision_service_provider.cc",
+    "dbus/machine_learning_decision_service_provider.h",
     "dbus/metrics_event_service_provider.cc",
     "dbus/metrics_event_service_provider.h",
     "dbus/plugin_vm_service_provider.cc",
@@ -2124,6 +2126,8 @@
     "extensions/file_manager/private_api_tasks.h",
     "extensions/file_manager/private_api_util.cc",
     "extensions/file_manager/private_api_util.h",
+    "extensions/file_manager/select_file_dialog_extension_user_data.cc",
+    "extensions/file_manager/select_file_dialog_extension_user_data.h",
     "extensions/file_system_provider/file_system_provider_api.cc",
     "extensions/file_system_provider/file_system_provider_api.h",
     "extensions/file_system_provider/provider_function.cc",
@@ -2186,6 +2190,7 @@
     "dbus/org.chromium.DriveFileStreamService.conf",
     "dbus/org.chromium.KioskAppService.conf",
     "dbus/org.chromium.LibvdaService.conf",
+    "dbus/org.chromium.MachineLearningDecisionService.conf",
     "dbus/org.chromium.MetricsEventService.conf",
     "dbus/org.chromium.NetworkProxyService.conf",
     "dbus/org.chromium.PluginVmService.conf",
diff --git a/chrome/browser/chromeos/android_sms/android_sms_app_manager_impl.cc b/chrome/browser/chromeos/android_sms/android_sms_app_manager_impl.cc
index b02f67c..d1800dc 100644
--- a/chrome/browser/chromeos/android_sms/android_sms_app_manager_impl.cc
+++ b/chrome/browser/chromeos/android_sms/android_sms_app_manager_impl.cc
@@ -232,8 +232,9 @@
       setup_controller_
           ->GetPwa(GetAndroidMessagesURL(true /* use_install_url */, *domain))
           ->id(),
-      extensions::LAUNCH_CONTAINER_WINDOW, WindowOpenDisposition::NEW_WINDOW,
-      extensions::SOURCE_CHROME_INTERNAL));
+      apps::mojom::LaunchContainer::kLaunchContainerWindow,
+      WindowOpenDisposition::NEW_WINDOW,
+      apps::mojom::AppLaunchSource::kSourceChromeInternal));
 }
 
 void AndroidSmsAppManagerImpl::SetPwaDelegateForTesting(
diff --git a/chrome/browser/chromeos/app_mode/startup_app_launcher.cc b/chrome/browser/chromeos/app_mode/startup_app_launcher.cc
index 5294b73a..9e1086de 100644
--- a/chrome/browser/chromeos/app_mode/startup_app_launcher.cc
+++ b/chrome/browser/chromeos/app_mode/startup_app_launcher.cc
@@ -427,9 +427,11 @@
   SYSLOG(INFO) << "Attempt to launch app.";
 
   // Always open the app in a window.
-  OpenApplication(AppLaunchParams(
-      profile_, extension->id(), extensions::LAUNCH_CONTAINER_WINDOW,
-      WindowOpenDisposition::NEW_WINDOW, extensions::SOURCE_KIOSK));
+  OpenApplication(
+      AppLaunchParams(profile_, extension->id(),
+                      extensions::LaunchContainer::kLaunchContainerWindow,
+                      WindowOpenDisposition::NEW_WINDOW,
+                      extensions::AppLaunchSource::kSourceKiosk));
 
   KioskAppManager::Get()->InitSession(profile_, app_id_);
   session_manager::SessionManager::Get()->SessionStarted();
diff --git a/chrome/browser/chromeos/arc/arc_support_host.cc b/chrome/browser/chromeos/arc/arc_support_host.cc
index 4d3f6eb..909cbc2a 100644
--- a/chrome/browser/chromeos/arc/arc_support_host.cc
+++ b/chrome/browser/chromeos/arc/arc_support_host.cc
@@ -129,7 +129,7 @@
   DCHECK(extensions::util::IsAppLaunchable(arc::kPlayStoreAppId, profile));
   OpenApplication(CreateAppLaunchParamsUserContainer(
       profile, extension, WindowOpenDisposition::NEW_WINDOW,
-      extensions::SOURCE_CHROME_INTERNAL));
+      extensions::AppLaunchSource::kSourceChromeInternal));
 }
 
 std::ostream& operator<<(std::ostream& os, ArcSupportHost::UIPage ui_page) {
diff --git a/chrome/browser/chromeos/certificate_provider/certificate_provider_service.cc b/chrome/browser/chromeos/certificate_provider/certificate_provider_service.cc
index 98d5ecf6..04be5f4 100644
--- a/chrome/browser/chromeos/certificate_provider/certificate_provider_service.cc
+++ b/chrome/browser/chromeos/certificate_provider/certificate_provider_service.cc
@@ -409,6 +409,44 @@
   pin_dialog_manager_.ExtensionUnloaded(extension_id);
 }
 
+void CertificateProviderService::RequestSignatureBySpki(
+    const std::string& subject_public_key_info,
+    uint16_t algorithm,
+    base::span<const uint8_t> digest,
+    net::SSLPrivateKey::SignCallback callback) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  bool is_currently_provided = false;
+  CertificateInfo info;
+  std::string extension_id;
+  certificate_map_.LookUpCertificateBySpki(
+      subject_public_key_info, &is_currently_provided, &info, &extension_id);
+  if (!is_currently_provided) {
+    LOG(ERROR) << "no certificate with the specified spki was found";
+    std::move(callback).Run(net::ERR_FAILED, std::vector<uint8_t>());
+    return;
+  }
+
+  RequestSignatureFromExtension(extension_id, info.certificate, algorithm,
+                                digest, std::move(callback));
+}
+
+bool CertificateProviderService::GetSupportedAlgorithmsBySpki(
+    const std::string& subject_public_key_info,
+    std::vector<uint16_t>* supported_algorithms) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  bool is_currently_provided = false;
+  CertificateInfo info;
+  std::string extension_id;
+  certificate_map_.LookUpCertificateBySpki(
+      subject_public_key_info, &is_currently_provided, &info, &extension_id);
+  if (!is_currently_provided) {
+    LOG(ERROR) << "no certificate with the specified spki was found";
+    return false;
+  }
+  *supported_algorithms = info.supported_algorithms;
+  return true;
+}
+
 void CertificateProviderService::GetCertificatesFromExtensions(
     base::OnceCallback<void(net::ClientCertIdentityList)> callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/chrome/browser/chromeos/certificate_provider/certificate_provider_service.h b/chrome/browser/chromeos/certificate_provider/certificate_provider_service.h
index ed5bcf7..6748f4b 100644
--- a/chrome/browser/chromeos/certificate_provider/certificate_provider_service.h
+++ b/chrome/browser/chromeos/certificate_provider/certificate_provider_service.h
@@ -154,6 +154,26 @@
   // corresponding notification of the ExtensionRegistry is triggered.
   void OnExtensionUnloaded(const std::string& extension_id);
 
+  // Requests the extension which provided the certificate identified by
+  // |subject_public_key_info| to sign |digest| with the corresponding private
+  // key. |algorithm| is a TLS 1.3 SignatureScheme value. See net::SSLPrivateKey
+  // for details. |callback| will be run with the reply of the extension or an
+  // error.
+  void RequestSignatureBySpki(const std::string& subject_public_key_info,
+                              uint16_t algorithm,
+                              base::span<const uint8_t> digest,
+                              net::SSLPrivateKey::SignCallback callback);
+
+  // Looks up the certificate identified by |subject_public_key_info|. If any
+  // extension is currently providing such a certificate, fills
+  // *|supported_algorithms| with the algorithms supported for that certificate
+  // and returns true. Values used for |supported_algorithms| are TLS 1.3
+  // SignatureSchemes. See net::SSLPrivateKey for details. If no extension is
+  // currently providing such a certificate, returns false.
+  bool GetSupportedAlgorithmsBySpki(
+      const std::string& subject_public_key_info,
+      std::vector<uint16_t>* supported_algorithms);
+
   PinDialogManager* pin_dialog_manager() { return &pin_dialog_manager_; }
 
  private:
diff --git a/chrome/browser/chromeos/certificate_provider/certificate_provider_service_unittest.cc b/chrome/browser/chromeos/certificate_provider/certificate_provider_service_unittest.cc
index ac750bc..6833f16 100644
--- a/chrome/browser/chromeos/certificate_provider/certificate_provider_service_unittest.cc
+++ b/chrome/browser/chromeos/certificate_provider/certificate_provider_service_unittest.cc
@@ -8,15 +8,20 @@
 #include <set>
 #include <utility>
 
+#include "base/base64.h"
 #include "base/bind.h"
+#include "base/containers/span.h"
 #include "base/macros.h"
 #include "base/stl_util.h"
 #include "base/test/test_mock_time_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/chromeos/certificate_provider/certificate_provider.h"
 #include "net/base/net_errors.h"
+#include "net/cert/asn1_util.h"
+#include "net/cert/x509_util.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/test_data_directory.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/boringssl/src/include/openssl/ssl.h"
 
@@ -528,4 +533,53 @@
   EXPECT_EQ(net::ERR_FAILED, error);
 }
 
+// Try to sign data using key; using the Subject Public Key Info (SPKI) to
+// identify the key.
+TEST_F(CertificateProviderServiceTest, SignUsingSpkiAsIdentification) {
+  base::StringPiece client1_spki_piece;
+  ASSERT_TRUE(net::asn1::ExtractSPKIFromDERCert(
+      net::x509_util::CryptoBufferAsStringPiece(
+          cert_info1_.certificate->cert_buffer()),
+      &client1_spki_piece));
+  std::string client1_spki = client1_spki_piece.as_string();
+
+  std::unique_ptr<net::ClientCertIdentity> cert(ProvideDefaultCert());
+  ASSERT_TRUE(cert);
+
+  std::vector<uint16_t> supported_algorithms;
+  // If this fails, try to regenerate kClient1SpkiBase64 using the command shown
+  // above.
+  EXPECT_TRUE(service_->GetSupportedAlgorithmsBySpki(client1_spki,
+                                                     &supported_algorithms));
+  EXPECT_THAT(supported_algorithms,
+              testing::UnorderedElementsAre(SSL_SIGN_RSA_PKCS1_SHA256));
+
+  test_delegate_->ClearAndExpectRequest(TestDelegate::RequestType::SIGN);
+  std::vector<uint8_t> input{'d', 'a', 't', 'a'};
+  std::vector<uint8_t> received_signature;
+  service_->RequestSignatureBySpki(
+      client1_spki, SSL_SIGN_RSA_PKCS1_SHA256, input,
+      base::BindOnce(&ExpectOKAndStoreSignature, &received_signature));
+
+  task_runner_->RunUntilIdle();
+
+  const int sign_request_id = test_delegate_->last_sign_request_id_;
+  EXPECT_EQ(TestDelegate::RequestType::NONE,
+            test_delegate_->expected_request_type_);
+  EXPECT_TRUE(cert_info1_.certificate->EqualsExcludingChain(
+      test_delegate_->last_certificate_.get()));
+
+  // No signature received until the extension replied to the service.
+  EXPECT_TRUE(received_signature.empty());
+
+  std::vector<uint8_t> signature_reply;
+  signature_reply.push_back(5);
+  signature_reply.push_back(7);
+  signature_reply.push_back(8);
+  service_->ReplyToSignRequest(kExtension1, sign_request_id, signature_reply);
+
+  task_runner_->RunUntilIdle();
+  EXPECT_EQ(signature_reply, received_signature);
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/certificate_provider/thread_safe_certificate_map.cc b/chrome/browser/chromeos/certificate_provider/thread_safe_certificate_map.cc
index bddfc6e..b20b6e6 100644
--- a/chrome/browser/chromeos/certificate_provider/thread_safe_certificate_map.cc
+++ b/chrome/browser/chromeos/certificate_provider/thread_safe_certificate_map.cc
@@ -5,12 +5,24 @@
 #include "chrome/browser/chromeos/certificate_provider/thread_safe_certificate_map.h"
 
 #include "net/base/hash_value.h"
+#include "net/cert/asn1_util.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 
 namespace chromeos {
 namespace certificate_provider {
 namespace {
 
+std::string GetSubjectPublicKeyInfo(const net::X509Certificate& certificate) {
+  base::StringPiece spki_bytes;
+  if (!net::asn1::ExtractSPKIFromDERCert(
+          net::x509_util::CryptoBufferAsStringPiece(certificate.cert_buffer()),
+          &spki_bytes)) {
+    return {};
+  }
+  return spki_bytes.as_string();
+}
+
 void BuildFingerprintsMap(
     const std::map<std::string, certificate_provider::CertificateInfoList>&
         extension_to_certificates,
@@ -23,19 +35,39 @@
           net::X509Certificate::CalculateFingerprint256(
               cert_info.certificate->cert_buffer());
       fingerprint_to_cert->insert(std::make_pair(
-          fingerprint, std::make_unique<ThreadSafeCertificateMap::MapValue>(
-                           cert_info, extension_id)));
+          fingerprint,
+          std::make_unique<ThreadSafeCertificateMap::CertAndExtension>(
+              cert_info, extension_id)));
+    }
+  }
+}
+
+void BuildSpkiMap(
+    const std::map<std::string, certificate_provider::CertificateInfoList>&
+        extension_to_certificates,
+    ThreadSafeCertificateMap::SpkiToCertAndExtensionMap* spki_to_cert) {
+  for (const auto& entry : extension_to_certificates) {
+    const std::string& extension_id = entry.first;
+    for (const CertificateInfo& cert_info : entry.second) {
+      const std::string spki = GetSubjectPublicKeyInfo(*cert_info.certificate);
+      // If the same public key appears in the |extension_to_certificates| input
+      // multiple times, it is unspecified which (cert_info, extension_id) will
+      // end up in the output map.
+      spki_to_cert->insert(std::make_pair(
+          spki, std::make_unique<ThreadSafeCertificateMap::CertAndExtension>(
+                    cert_info, extension_id)));
     }
   }
 }
 
 }  // namespace
 
-ThreadSafeCertificateMap::MapValue::MapValue(const CertificateInfo& cert_info,
-                                             const std::string& extension_id)
+ThreadSafeCertificateMap::CertAndExtension::CertAndExtension(
+    const CertificateInfo& cert_info,
+    const std::string& extension_id)
     : cert_info(cert_info), extension_id(extension_id) {}
 
-ThreadSafeCertificateMap::MapValue::~MapValue() {}
+ThreadSafeCertificateMap::CertAndExtension::~CertAndExtension() {}
 
 ThreadSafeCertificateMap::ThreadSafeCertificateMap() {}
 
@@ -45,17 +77,27 @@
     const std::map<std::string, certificate_provider::CertificateInfoList>&
         extension_to_certificates) {
   FingerprintToCertAndExtensionMap new_fingerprint_map;
+  SpkiToCertAndExtensionMap new_spki_map;
   BuildFingerprintsMap(extension_to_certificates, &new_fingerprint_map);
+  BuildSpkiMap(extension_to_certificates, &new_spki_map);
 
   base::AutoLock auto_lock(lock_);
-  // Keep all old fingerprints from |fingerprint_to_cert_and_extension_| but
-  // remove the association to any extension.
+  // Keep all old keys from the old maps (|fingerprint_to_cert_and_extension_|
+  // and |spki_to_cert_and_extension_|), but remove the association to any
+  // extension.
   for (const auto& entry : fingerprint_to_cert_and_extension_) {
     const net::SHA256HashValue& fingerprint = entry.first;
     // This doesn't modify the map if it already contains the key |fingerprint|.
     new_fingerprint_map.insert(std::make_pair(fingerprint, nullptr));
   }
   fingerprint_to_cert_and_extension_.swap(new_fingerprint_map);
+
+  for (const auto& entry : spki_to_cert_and_extension_) {
+    const std::string& spki = entry.first;
+    // This doesn't modify the map if it already contains the key |spki|.
+    new_spki_map.insert(std::make_pair(spki, nullptr));
+  }
+  spki_to_cert_and_extension_.swap(new_spki_map);
 }
 
 bool ThreadSafeCertificateMap::LookUpCertificate(
@@ -72,7 +114,27 @@
   if (it == fingerprint_to_cert_and_extension_.end())
     return false;
 
-  MapValue* const value = it->second.get();
+  CertAndExtension* const value = it->second.get();
+  if (value) {
+    *is_currently_provided = true;
+    *info = value->cert_info;
+    *extension_id = value->extension_id;
+  }
+  return true;
+}
+
+bool ThreadSafeCertificateMap::LookUpCertificateBySpki(
+    const std::string& subject_public_key_info,
+    bool* is_currently_provided,
+    CertificateInfo* info,
+    std::string* extension_id) {
+  *is_currently_provided = false;
+  base::AutoLock auto_lock(lock_);
+  const auto it = spki_to_cert_and_extension_.find(subject_public_key_info);
+  if (it == spki_to_cert_and_extension_.end())
+    return false;
+
+  CertAndExtension* const value = it->second.get();
   if (value) {
     *is_currently_provided = true;
     *info = value->cert_info;
@@ -85,11 +147,19 @@
     const std::string& extension_id) {
   base::AutoLock auto_lock(lock_);
   for (auto& entry : fingerprint_to_cert_and_extension_) {
-    MapValue* const value = entry.second.get();
+    CertAndExtension* const value = entry.second.get();
     // Only remove the association of the fingerprint to the extension, but keep
     // the fingerprint.
     if (value && value->extension_id == extension_id)
-      fingerprint_to_cert_and_extension_[entry.first] = nullptr;
+      entry.second.reset();
+  }
+
+  for (auto& entry : spki_to_cert_and_extension_) {
+    CertAndExtension* const value = entry.second.get();
+    // Only remove the association of the SPKI to the extension, but keep the
+    // SPKI.
+    if (value && value->extension_id == extension_id)
+      entry.second.reset();
   }
 }
 
diff --git a/chrome/browser/chromeos/certificate_provider/thread_safe_certificate_map.h b/chrome/browser/chromeos/certificate_provider/thread_safe_certificate_map.h
index 4a7d6fc..8fa2c54 100644
--- a/chrome/browser/chromeos/certificate_provider/thread_safe_certificate_map.h
+++ b/chrome/browser/chromeos/certificate_provider/thread_safe_certificate_map.h
@@ -23,15 +23,19 @@
 
 class ThreadSafeCertificateMap {
  public:
-  struct MapValue {
-    MapValue(const CertificateInfo& cert_info, const std::string& extension_id);
-    ~MapValue();
+  struct CertAndExtension {
+    CertAndExtension(const CertificateInfo& cert_info,
+                     const std::string& extension_id);
+    ~CertAndExtension();
 
     CertificateInfo cert_info;
     std::string extension_id;
   };
   using FingerprintToCertAndExtensionMap =
-      std::map<net::SHA256HashValue, std::unique_ptr<MapValue>>;
+      std::map<net::SHA256HashValue, std::unique_ptr<CertAndExtension>>;
+  // A map that has a DER-encoded X.509 Subject Public Key Info as keys.
+  using SpkiToCertAndExtensionMap =
+      std::map<std::string, std::unique_ptr<CertAndExtension>>;
 
   ThreadSafeCertificateMap();
   ~ThreadSafeCertificateMap();
@@ -54,6 +58,21 @@
                          CertificateInfo* info,
                          std::string* extension_id);
 
+  // Looks up for certificate and extension_id based on
+  // |subject_public_key_info|, which is a DER-encoded X.509 Subject Public Key
+  // Info. If the certificate was added by previous Update() call, returns true.
+  // If this certificate was provided in the most recent Update() call,
+  // |is_currently_provided| will be set to true and |info| and |extension_id|
+  // will be populated according to the data that have been mapped to this
+  // |subject_public_key_info|. Otherwise, if this certificate was not provided
+  // in the most recent Update() call, sets |is_currently_provided| to false and
+  // doesn't modify |info| and |extension_id|. If multiple entries are found, it
+  // is unspecified which one will be returned.
+  bool LookUpCertificateBySpki(const std::string& subject_public_key_info,
+                               bool* is_currently_provided,
+                               CertificateInfo* info,
+                               std::string* extension_id);
+
   // Remove every association of stored certificates to the given extension.
   // The certificates themselves will be remembered.
   void RemoveExtension(const std::string& extension_id);
@@ -61,6 +80,7 @@
  private:
   base::Lock lock_;
   FingerprintToCertAndExtensionMap fingerprint_to_cert_and_extension_;
+  SpkiToCertAndExtensionMap spki_to_cert_and_extension_;
 
   DISALLOW_COPY_AND_ASSIGN(ThreadSafeCertificateMap);
 };
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index 8f384fe2..43dcafe 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -51,6 +51,7 @@
 #include "chrome/browser/chromeos/dbus/drive_file_stream_service_provider.h"
 #include "chrome/browser/chromeos/dbus/kiosk_info_service_provider.h"
 #include "chrome/browser/chromeos/dbus/libvda_service_provider.h"
+#include "chrome/browser/chromeos/dbus/machine_learning_decision_service_provider.h"
 #include "chrome/browser/chromeos/dbus/metrics_event_service_provider.h"
 #include "chrome/browser/chromeos/dbus/plugin_vm_service_provider.h"
 #include "chrome/browser/chromeos/dbus/proxy_resolution_service_provider.h"
@@ -90,7 +91,6 @@
 #include "chrome/browser/chromeos/power/freezer_cgroup_process_manager.h"
 #include "chrome/browser/chromeos/power/idle_action_warning_observer.h"
 #include "chrome/browser/chromeos/power/ml/adaptive_screen_brightness_manager.h"
-#include "chrome/browser/chromeos/power/ml/user_activity_controller.h"
 #include "chrome/browser/chromeos/power/power_data_collector.h"
 #include "chrome/browser/chromeos/power/power_metrics_reporter.h"
 #include "chrome/browser/chromeos/power/process_data_collector.h"
@@ -294,6 +294,9 @@
                                 ? nullptr
                                 : DBusThreadManager::Get()->GetSystemBus();
 
+    // See also PostBrowserStart() where machine_learning_decision_service_ is
+    // initialized.
+
     proxy_resolution_service_ = CrosDBusService::Create(
         system_bus, kNetworkProxyServiceName,
         dbus::ObjectPath(kNetworkProxyServicePath),
@@ -386,6 +389,19 @@
         OwnerSettingsServiceChromeOSFactory::GetInstance()->GetOwnerKeyUtil());
   }
 
+  void CreateMachineLearningDecisionProvider() {
+    dbus::Bus* system_bus = DBusThreadManager::Get()->IsUsingFakes()
+                                ? nullptr
+                                : DBusThreadManager::Get()->GetSystemBus();
+    // TODO(alanlxl): update Ml here to MachineLearning after powerd is
+    // uprevved.
+    machine_learning_decision_service_ = CrosDBusService::Create(
+        system_bus, machine_learning::kMlDecisionServiceName,
+        dbus::ObjectPath(machine_learning::kMlDecisionServicePath),
+        CrosDBusService::CreateServiceProviderList(
+            std::make_unique<MachineLearningDecisionServiceProvider>()));
+  }
+
   ~DBusServices() {
     NetworkHandler::Shutdown();
     cryptohome::AsyncMethodCaller::Shutdown();
@@ -402,6 +418,7 @@
     chrome_features_service_.reset();
     vm_applications_service_.reset();
     drive_file_stream_service_.reset();
+    machine_learning_decision_service_.reset();
     ProcessDataCollector::Shutdown();
     PowerDataCollector::Shutdown();
     PowerPolicyController::Shutdown();
@@ -420,6 +437,7 @@
   std::unique_ptr<CrosDBusService> vm_applications_service_;
   std::unique_ptr<CrosDBusService> drive_file_stream_service_;
   std::unique_ptr<CrosDBusService> libvda_service_;
+  std::unique_ptr<CrosDBusService> machine_learning_decision_service_;
 
   DISALLOW_COPY_AND_ASSIGN(DBusServices);
 };
@@ -1026,8 +1044,10 @@
   }
 
   if (base::FeatureList::IsEnabled(::features::kUserActivityEventLogging)) {
-    user_activity_controller_ =
-        std::make_unique<power::ml::UserActivityController>();
+    // MachineLearningDecisionServiceProvider needs to be created after
+    // UserActivityController which depends on UserActivityDetector, not
+    // available until PostBrowserStart.
+    dbus_services_->CreateMachineLearningDecisionProvider();
   }
 
   auto_screen_brightness_controller_ =
@@ -1098,7 +1118,6 @@
   ScreenLocker::ShutDownClass();
   low_disk_notification_.reset();
   demo_mode_resources_remover_.reset();
-  user_activity_controller_.reset();
   adaptive_screen_brightness_manager_.reset();
   scheduler_configuration_manager_.reset();
   auto_screen_brightness_controller_.reset();
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.h b/chrome/browser/chromeos/chrome_browser_main_chromeos.h
index b89d8bcb45..653ec18 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.h
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.h
@@ -70,7 +70,6 @@
 namespace power {
 namespace ml {
 class AdaptiveScreenBrightnessManager;
-class UserActivityController;
 }  // namespace ml
 
 namespace auto_screen_brightness {
@@ -156,7 +155,6 @@
   std::unique_ptr<power::ml::AdaptiveScreenBrightnessManager>
       adaptive_screen_brightness_manager_;
 
-  std::unique_ptr<power::ml::UserActivityController> user_activity_controller_;
   std::unique_ptr<power::auto_screen_brightness::Controller>
       auto_screen_brightness_controller_;
 
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.cc b/chrome/browser/chromeos/crostini/crostini_manager.cc
index b9d7cb3..af019cbb 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager.cc
+++ b/chrome/browser/chromeos/crostini/crostini_manager.cc
@@ -1530,8 +1530,10 @@
 AppLaunchParams CrostiniManager::GenerateTerminalAppLaunchParams(
     Profile* profile) {
   AppLaunchParams launch_params(
-      profile, kCrostiniCroshBuiltinAppId, extensions::LAUNCH_CONTAINER_WINDOW,
-      WindowOpenDisposition::NEW_WINDOW, extensions::SOURCE_APP_LAUNCHER);
+      profile, kCrostiniCroshBuiltinAppId,
+      apps::mojom::LaunchContainer::kLaunchContainerWindow,
+      WindowOpenDisposition::NEW_WINDOW,
+      apps::mojom::AppLaunchSource::kSourceAppLauncher);
   launch_params.override_app_name =
       AppNameFromCrostiniAppId(kCrostiniTerminalId);
   return launch_params;
diff --git a/chrome/browser/chromeos/dbus/machine_learning_decision_service_provider.cc b/chrome/browser/chromeos/dbus/machine_learning_decision_service_provider.cc
new file mode 100644
index 0000000..9f8b1fa
--- /dev/null
+++ b/chrome/browser/chromeos/dbus/machine_learning_decision_service_provider.cc
@@ -0,0 +1,65 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/dbus/machine_learning_decision_service_provider.h"
+
+#include "base/bind.h"
+#include "chrome/browser/chromeos/power/ml/user_activity_controller.h"
+#include "dbus/bus.h"
+#include "dbus/message.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+
+namespace chromeos {
+
+MachineLearningDecisionServiceProvider::MachineLearningDecisionServiceProvider()
+    : user_activity_controller_(
+          std::make_unique<power::ml::UserActivityController>()),
+      weak_ptr_factory_(this) {}
+
+MachineLearningDecisionServiceProvider::
+    ~MachineLearningDecisionServiceProvider() = default;
+
+void MachineLearningDecisionServiceProvider::Start(
+    scoped_refptr<dbus::ExportedObject> exported_object) {
+  exported_object->ExportMethod(
+      machine_learning::kMlDecisionServiceInterface,
+      machine_learning::kShouldDeferScreenDimMethod,
+      base::BindRepeating(
+          &MachineLearningDecisionServiceProvider::ShouldDeferScreenDim,
+          weak_ptr_factory_.GetWeakPtr()),
+      base::BindRepeating(&MachineLearningDecisionServiceProvider::OnExported,
+                          weak_ptr_factory_.GetWeakPtr()));
+}
+
+void MachineLearningDecisionServiceProvider::OnExported(
+    const std::string& interface_name,
+    const std::string& method_name,
+    bool success) {
+  if (!success) {
+    LOG(ERROR) << "Failed to export " << interface_name << "." << method_name;
+  }
+}
+
+void MachineLearningDecisionServiceProvider::ShouldDeferScreenDim(
+    dbus::MethodCall* method_call,
+    dbus::ExportedObject::ResponseSender response_sender) {
+  std::unique_ptr<dbus::Response> response =
+      dbus::Response::FromMethodCall(method_call);
+
+  user_activity_controller_->ShouldDeferScreenDim(base::BindOnce(
+      &MachineLearningDecisionServiceProvider::SendSmartDimDecision,
+      weak_ptr_factory_.GetWeakPtr(), std::move(response),
+      std::move(response_sender)));
+}
+
+void MachineLearningDecisionServiceProvider::SendSmartDimDecision(
+    std::unique_ptr<dbus::Response> response,
+    dbus::ExportedObject::ResponseSender response_sender,
+    bool defer_dimming) {
+  dbus::MessageWriter writer(response.get());
+  writer.AppendBool(defer_dimming);
+  response_sender.Run(std::move(response));
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/dbus/machine_learning_decision_service_provider.h b/chrome/browser/chromeos/dbus/machine_learning_decision_service_provider.h
new file mode 100644
index 0000000..74d479be
--- /dev/null
+++ b/chrome/browser/chromeos/dbus/machine_learning_decision_service_provider.h
@@ -0,0 +1,86 @@
+// 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_CHROMEOS_DBUS_MACHINE_LEARNING_DECISION_SERVICE_PROVIDER_H_
+#define CHROME_BROWSER_CHROMEOS_DBUS_MACHINE_LEARNING_DECISION_SERVICE_PROVIDER_H_
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "chromeos/dbus/services/cros_dbus_service.h"
+#include "dbus/exported_object.h"
+
+namespace dbus {
+
+class MethodCall;
+
+}  // namespace dbus
+
+namespace chromeos {
+namespace power {
+namespace ml {
+
+class UserActivityController;
+
+}  // namespace ml
+}  // namespace power
+
+// This class processes machine learning decision requests from Chrome OS side.
+//
+// ShouldDeferScreenDim:
+// % dbus-send --system --type=method_call --print-reply
+//     --dest=org.chromium.MlDecisionService
+//     /org/chromium/MlDecisionService
+//     org.chromium.MlDecisionService.ShouldDeferScreenDim
+//     boolean: true or false
+//
+// % (True means smart dim decides to defer the imminent screen dimming.)
+//
+// Now it only exports ShouldDeferScreenDim for powerd. New machine learning
+// related methods can be added when required.
+class MachineLearningDecisionServiceProvider
+    : public CrosDBusService::ServiceProviderInterface {
+ public:
+  MachineLearningDecisionServiceProvider();
+  ~MachineLearningDecisionServiceProvider() override;
+
+  // CrosDBusService::ServiceProviderInterface overrides:
+  void Start(scoped_refptr<dbus::ExportedObject> exported_object) override;
+
+ private:
+  // Called from ExportedObject when a handler is exported as a D-Bus
+  // method or failed to be exported.
+  void OnExported(const std::string& interface_name,
+                  const std::string& method_name,
+                  bool success);
+
+  // Called on UI thread in response to D-Bus requests.
+  void ShouldDeferScreenDim(
+      dbus::MethodCall* method_call,
+      dbus::ExportedObject::ResponseSender response_sender);
+
+  // Sends |defer_dimming| as the response to a ShouldDeferScreenDim method
+  // call.
+  void SendSmartDimDecision(
+      std::unique_ptr<dbus::Response> response,
+      dbus::ExportedObject::ResponseSender response_sender,
+      bool defer_dimming);
+
+  // The real provider of ShouldDeferScreenDim
+  std::unique_ptr<power::ml::UserActivityController> user_activity_controller_;
+
+  // Keep this last so that all weak pointers will be invalidated at the
+  // beginning of destruction.
+  base::WeakPtrFactory<MachineLearningDecisionServiceProvider>
+      weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(MachineLearningDecisionServiceProvider);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_DBUS_MACHINE_LEARNING_DECISION_SERVICE_PROVIDER_H_
diff --git a/chrome/browser/chromeos/dbus/org.chromium.MachineLearningDecisionService.conf b/chrome/browser/chromeos/dbus/org.chromium.MachineLearningDecisionService.conf
new file mode 100644
index 0000000..09f45ee
--- /dev/null
+++ b/chrome/browser/chromeos/dbus/org.chromium.MachineLearningDecisionService.conf
@@ -0,0 +1,29 @@
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+  "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<!--
+  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.
+-->
+<busconfig>
+  <policy user="chronos">
+    <allow own="org.chromium.MlDecisionService"/>
+  </policy>
+
+  <!--
+    powerd uses this service to ask Chrome whether to defer the imminent screen
+    dimming.
+  -->
+  <policy user="power">
+    <allow send_destination="org.chromium.MlDecisionService"
+           send_interface="org.chromium.MlDecisionService"/>
+  </policy>
+
+  <!--
+    upstart and tast run as root.
+  -->
+  <policy user="root">
+    <allow send_destination="org.chromium.MlDecisionService"
+           send_interface="org.chromium.MlDecisionService"/>
+  </policy>
+</busconfig>
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_dialog.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_dialog.cc
index 279ca919..1832a21 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_dialog.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_dialog.cc
@@ -9,11 +9,10 @@
 #include "base/bind.h"
 #include "chrome/browser/chromeos/arc/fileapi/arc_select_files_util.h"
 #include "chrome/browser/chromeos/extensions/file_manager/private_api_util.h"
+#include "chrome/browser/chromeos/extensions/file_manager/select_file_dialog_extension_user_data.h"
 #include "chrome/browser/chromeos/file_manager/file_tasks_notifier.h"
 #include "chrome/browser/extensions/chrome_extension_function_details.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/views/select_file_dialog_extension.h"
 #include "chrome/common/extensions/api/file_manager_private.h"
 #include "components/arc/arc_service_manager.h"
@@ -21,7 +20,6 @@
 #include "components/arc/intent_helper/arc_intent_helper_bridge.h"
 #include "components/arc/session/arc_bridge_service.h"
 #include "content/public/browser/browser_thread.h"
-#include "extensions/browser/extension_function_dispatcher.h"
 #include "net/base/mime_util.h"
 #include "ui/shell_dialogs/selected_file_info.h"
 
@@ -31,29 +29,11 @@
 
 namespace {
 
-// TODO(https://crbug.com/844654): This should be using something more
-// deterministic.
-content::WebContents* GetAssociatedWebContentsDeprecated(
-    UIThreadExtensionFunction* function) {
-  if (function->dispatcher()) {
-    content::WebContents* web_contents =
-        function->dispatcher()->GetAssociatedWebContents();
-    if (web_contents)
-      return web_contents;
-  }
-
-  Browser* browser =
-      ChromeExtensionFunctionDetails(function).GetCurrentBrowser();
-  if (!browser)
-    return nullptr;
-  return browser->tab_strip_model()->GetActiveWebContents();
-}
-
 // Computes the routing ID for SelectFileDialogExtension from the |function|.
 SelectFileDialogExtension::RoutingID GetFileDialogRoutingID(
     UIThreadExtensionFunction* function) {
-  return SelectFileDialogExtension::GetRoutingIDFromWebContents(
-      GetAssociatedWebContentsDeprecated(function));
+  return SelectFileDialogExtensionUserData::GetRoutingIdForWebContents(
+      function->GetSenderWebContents());
 }
 
 }  // namespace
diff --git a/chrome/browser/chromeos/extensions/file_manager/select_file_dialog_extension_user_data.cc b/chrome/browser/chromeos/extensions/file_manager/select_file_dialog_extension_user_data.cc
new file mode 100644
index 0000000..743d6ae
--- /dev/null
+++ b/chrome/browser/chromeos/extensions/file_manager/select_file_dialog_extension_user_data.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 "chrome/browser/chromeos/extensions/file_manager/select_file_dialog_extension_user_data.h"
+
+#include "content/public/browser/web_contents.h"
+
+const char kSelectFileDialogExtensionUserDataKey[] =
+    "SelectFileDialogExtensionUserDataKey";
+
+// static
+void SelectFileDialogExtensionUserData::SetRoutingIdForWebContents(
+    content::WebContents* web_contents,
+    const std::string& routing_id) {
+  DCHECK(web_contents);
+  web_contents->SetUserData(
+      kSelectFileDialogExtensionUserDataKey,
+      base::WrapUnique(new SelectFileDialogExtensionUserData(routing_id)));
+}
+
+// static
+std::string SelectFileDialogExtensionUserData::GetRoutingIdForWebContents(
+    content::WebContents* web_contents) {
+  DCHECK(web_contents);
+  SelectFileDialogExtensionUserData* data =
+      static_cast<SelectFileDialogExtensionUserData*>(
+          web_contents->GetUserData(kSelectFileDialogExtensionUserDataKey));
+  return data ? data->routing_id() : "";
+}
+
+SelectFileDialogExtensionUserData::SelectFileDialogExtensionUserData(
+    const std::string& routing_id)
+    : routing_id_(routing_id) {}
diff --git a/chrome/browser/chromeos/extensions/file_manager/select_file_dialog_extension_user_data.h b/chrome/browser/chromeos/extensions/file_manager/select_file_dialog_extension_user_data.h
new file mode 100644
index 0000000..29f2feea
--- /dev/null
+++ b/chrome/browser/chromeos/extensions/file_manager/select_file_dialog_extension_user_data.h
@@ -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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_MANAGER_SELECT_FILE_DIALOG_EXTENSION_USER_DATA_H_
+#define CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_MANAGER_SELECT_FILE_DIALOG_EXTENSION_USER_DATA_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "base/supports_user_data.h"
+
+namespace content {
+class WebContents;
+}
+
+// Used for attachingSelectFileDialogExtension's routing ID to its WebContents.
+class SelectFileDialogExtensionUserData : public base::SupportsUserData::Data {
+ public:
+  static void SetRoutingIdForWebContents(content::WebContents* web_contents,
+                                         const std::string& routing_id);
+  static std::string GetRoutingIdForWebContents(
+      content::WebContents* web_contents);
+
+ private:
+  explicit SelectFileDialogExtensionUserData(const std::string& routing_id);
+
+  const std::string& routing_id() const { return routing_id_; }
+
+  std::string routing_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(SelectFileDialogExtensionUserData);
+};
+
+#endif  // CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_MANAGER_SELECT_FILE_DIALOG_EXTENSION_USER_DATA_H_
diff --git a/chrome/browser/chromeos/file_manager/file_tasks.cc b/chrome/browser/chromeos/file_manager/file_tasks.cc
index e0ebb882..1d6aeb6 100644
--- a/chrome/browser/chromeos/file_manager/file_tasks.cc
+++ b/chrome/browser/chromeos/file_manager/file_tasks.cc
@@ -430,7 +430,7 @@
       AppLaunchParams params(extension_task_profile, task.app_id,
                              launch_container,
                              WindowOpenDisposition::NEW_FOREGROUND_TAB,
-                             extensions::AppLaunchSource::SOURCE_FILE_HANDLER);
+                             extensions::AppLaunchSource::kSourceFileHandler);
       params.override_url = GURL(task.action_id);
       OpenApplication(params);
     }
diff --git a/chrome/browser/chromeos/first_run/first_run.cc b/chrome/browser/chromeos/first_run/first_run.cc
index f69870c..762eea9 100644
--- a/chrome/browser/chromeos/first_run/first_run.cc
+++ b/chrome/browser/chromeos/first_run/first_run.cc
@@ -58,9 +58,11 @@
   if (!extension)
     return;
 
-  OpenApplication(AppLaunchParams(
-      profile, extension->id(), extensions::LAUNCH_CONTAINER_WINDOW,
-      WindowOpenDisposition::NEW_WINDOW, extensions::SOURCE_CHROME_INTERNAL));
+  OpenApplication(
+      AppLaunchParams(profile, extension->id(),
+                      extensions::LaunchContainer::kLaunchContainerWindow,
+                      WindowOpenDisposition::NEW_WINDOW,
+                      extensions::AppLaunchSource::kSourceChromeInternal));
   profile->GetPrefs()->SetBoolean(prefs::kFirstRunTutorialShown, true);
 }
 
diff --git a/chrome/browser/chromeos/kiosk_next_home/kiosk_next_home_browsertest.cc b/chrome/browser/chromeos/kiosk_next_home/kiosk_next_home_browsertest.cc
index 9b69211..6b8ba664 100644
--- a/chrome/browser/chromeos/kiosk_next_home/kiosk_next_home_browsertest.cc
+++ b/chrome/browser/chromeos/kiosk_next_home/kiosk_next_home_browsertest.cc
@@ -159,8 +159,8 @@
     ASSERT_TRUE(app);
 
     // Launch app and wait for its window.
-    apps::LaunchPlatformApp(
-        profile, app, extensions::AppLaunchSource::SOURCE_CHROME_INTERNAL);
+    apps::LaunchPlatformApp(profile, app,
+                            extensions::AppLaunchSource::kSourceChromeInternal);
     apps::AppWindowWaiter app_waiter(
         extensions::AppWindowRegistry::Get(profile),
         extension_misc::kKioskNextHomeAppId);
diff --git a/chrome/browser/chromeos/login/demo_mode/demo_app_launcher.cc b/chrome/browser/chromeos/login/demo_mode/demo_app_launcher.cc
index 0a8abd2..cbcd6ef 100644
--- a/chrome/browser/chromeos/login/demo_mode/demo_app_launcher.cc
+++ b/chrome/browser/chromeos/login/demo_mode/demo_app_launcher.cc
@@ -92,10 +92,11 @@
       NetworkTypePattern::Physical(), false,
       chromeos::network_handler::ErrorCallback());
 
-  OpenApplication(AppLaunchParams(profile, extension_id,
-                                  extensions::LAUNCH_CONTAINER_WINDOW,
-                                  WindowOpenDisposition::NEW_WINDOW,
-                                  extensions::SOURCE_CHROME_INTERNAL, true));
+  OpenApplication(AppLaunchParams(
+      profile, extension_id,
+      extensions::LaunchContainer::kLaunchContainerWindow,
+      WindowOpenDisposition::NEW_WINDOW,
+      extensions::AppLaunchSource::kSourceChromeInternal, true));
   KioskAppManager::Get()->InitSession(profile, extension_id);
 
   session_manager::SessionManager::Get()->SessionStarted();
diff --git a/chrome/browser/chromeos/login/demo_mode/demo_session.cc b/chrome/browser/chromeos/login/demo_mode/demo_session.cc
index c2f5585..f5e140d8 100644
--- a/chrome/browser/chromeos/login/demo_mode/demo_session.cc
+++ b/chrome/browser/chromeos/login/demo_mode/demo_session.cc
@@ -579,9 +579,11 @@
     return;
   Profile* profile = ProfileManager::GetActiveUserProfile();
   DCHECK(profile);
-  OpenApplication(AppLaunchParams(
-      profile, extension->id(), extensions::LAUNCH_CONTAINER_WINDOW,
-      WindowOpenDisposition::NEW_WINDOW, extensions::SOURCE_CHROME_INTERNAL));
+  OpenApplication(
+      AppLaunchParams(profile, extension->id(),
+                      extensions::LaunchContainer::kLaunchContainerWindow,
+                      WindowOpenDisposition::NEW_WINDOW,
+                      extensions::AppLaunchSource::kSourceChromeInternal));
 }
 
 void DemoSession::OnAppWindowActivated(extensions::AppWindow* app_window) {
diff --git a/chrome/browser/chromeos/login/screens/error_screen.cc b/chrome/browser/chromeos/login/screens/error_screen.cc
index d73b193..c53f7de 100644
--- a/chrome/browser/chromeos/login/screens/error_screen.cc
+++ b/chrome/browser/chromeos/login/screens/error_screen.cc
@@ -293,9 +293,11 @@
       IDR_CONNECTIVITY_DIAGNOSTICS_MANIFEST,
       base::FilePath(extension_misc::kConnectivityDiagnosticsPath));
 
-  OpenApplication(AppLaunchParams(
-      profile, extension_id, extensions::LAUNCH_CONTAINER_WINDOW,
-      WindowOpenDisposition::NEW_WINDOW, extensions::SOURCE_CHROME_INTERNAL));
+  OpenApplication(
+      AppLaunchParams(profile, extension_id,
+                      extensions::LaunchContainer::kLaunchContainerWindow,
+                      WindowOpenDisposition::NEW_WINDOW,
+                      extensions::AppLaunchSource::kSourceChromeInternal));
   KioskAppManager::Get()->InitSession(profile, extension_id);
 
   LoginDisplayHost::default_host()->Finalize(base::BindOnce(
diff --git a/chrome/browser/chromeos/login/session/user_session_manager.cc b/chrome/browser/chromeos/login/session/user_session_manager.cc
index 0ec141e3..0172d2b 100644
--- a/chrome/browser/chromeos/login/session/user_session_manager.cc
+++ b/chrome/browser/chromeos/login/session/user_session_manager.cc
@@ -317,7 +317,7 @@
   about_flags::ConvertFlagsToSwitches(&flags_storage, &user_flags,
                                       flags_ui::kAddSentinels);
 
-  UserSessionManager::MaybeAppendPolicySwitches(profile->GetPrefs(),
+  UserSessionManager::ApplyUserPolicyToSwitches(profile->GetPrefs(),
                                                 &user_flags);
 
   return user_flags;
@@ -448,31 +448,27 @@
 }
 
 // static
-void UserSessionManager::MaybeAppendPolicySwitches(
+void UserSessionManager::ApplyUserPolicyToSwitches(
     PrefService* user_profile_prefs,
     base::CommandLine* user_flags) {
   // Get target value for --site-per-process for the user session according to
-  // policy. Values from command-line flags should not be honored at this point,
-  // so check |IsManaged()|.
+  // policy. If it is supposed to be enabled, make sure it can not be disabled
+  // using flags-induced command-line switches.
   const PrefService::Preference* site_per_process_pref =
       user_profile_prefs->FindPreference(prefs::kSitePerProcess);
-  bool site_per_process = site_per_process_pref->IsManaged() &&
-                          site_per_process_pref->GetValue()->GetBool();
+  if (site_per_process_pref->IsManaged() &&
+      site_per_process_pref->GetValue()->GetBool()) {
+    user_flags->RemoveSwitch(::switches::kDisableSiteIsolation);
+  }
 
-  // Append sentinels indicating that these values originate from policy.
+  // Note: If a user policy is introduced again which translates to command-line
+  // switches, make sure to wrap the policy-added command-line switches in
+  // |"--policy-switches-begin"| / |"--policy-switches-end"| sentinels.
   // This is important, because only command-line switches between the
   // |"--policy-switches-begin"| / |"--policy-switches-end"| and the
   // |"--flag-switches-begin"| / |"--flag-switches-end"| sentinels will be
   // compared when comparing the current command line and the user session
   // command line in order to decide if chrome should be restarted.
-  // We use the policy-style sentinels because these values originate from
-  // policy, and because login_manager uses the same sentinels when adding the
-  // login-screen site isolation flags.
-  if (site_per_process) {
-    user_flags->AppendSwitch(chromeos::switches::kPolicySwitchesBegin);
-    user_flags->AppendSwitch(::switches::kSitePerProcess);
-    user_flags->AppendSwitch(chromeos::switches::kPolicySwitchesEnd);
-  }
 }
 
 UserSessionManager::UserSessionManager()
diff --git a/chrome/browser/chromeos/login/session/user_session_manager.h b/chrome/browser/chromeos/login/session/user_session_manager.h
index f01c06c..af9ce2c1d 100644
--- a/chrome/browser/chromeos/login/session/user_session_manager.h
+++ b/chrome/browser/chromeos/login/session/user_session_manager.h
@@ -162,9 +162,10 @@
   // Registers session related preferences.
   static void RegisterPrefs(PrefRegistrySimple* registry);
 
-  // Appends additional command switches to the given command line if
-  // SitePerProcess/IsolateOrigins policy is present.
-  static void MaybeAppendPolicySwitches(PrefService* user_profile_prefs,
+  // Applies user policies to |user_flags| .
+  // This could mean removing command-line switchis that have been added by the
+  // flag handling logic or appending additional switches due to policy.
+  static void ApplyUserPolicyToSwitches(PrefService* user_profile_prefs,
                                         base::CommandLine* user_flags);
 
   // Invoked after the tmpfs is successfully mounted.
diff --git a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
index 7fdc643..81d4125 100644
--- a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
@@ -1599,8 +1599,9 @@
   // Start the platform app, causing it to open a window.
   run_loop_.reset(new base::RunLoop);
   OpenApplication(AppLaunchParams(
-      profile, app->id(), extensions::LAUNCH_CONTAINER_NONE,
-      WindowOpenDisposition::NEW_WINDOW, extensions::SOURCE_TEST));
+      profile, app->id(), extensions::LaunchContainer::kLaunchContainerNone,
+      WindowOpenDisposition::NEW_WINDOW,
+      extensions::AppLaunchSource::kSourceTest));
   run_loop_->Run();
   EXPECT_EQ(1U, app_window_registry->app_windows().size());
 
diff --git a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
index e9421e1..6f01f1f 100644
--- a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
+++ b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
@@ -1145,17 +1145,6 @@
     }
   }
 
-  if (policy.has_device_login_screen_site_per_process()) {
-    const em::DeviceLoginScreenSitePerProcessProto& container(
-        policy.device_login_screen_site_per_process());
-    if (container.has_site_per_process()) {
-      policies->Set(
-          key::kDeviceLoginScreenSitePerProcess, POLICY_LEVEL_MANDATORY,
-          POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
-          std::make_unique<base::Value>(container.site_per_process()), nullptr);
-    }
-  }
-
   if (policy.has_virtual_machines_allowed()) {
     const em::VirtualMachinesAllowedProto& container(
         policy.virtual_machines_allowed());
diff --git a/chrome/browser/chromeos/policy/site_isolation_flag_handling_browsertest.cc b/chrome/browser/chromeos/policy/site_isolation_flag_handling_browsertest.cc
index 2caab012..d43054c 100644
--- a/chrome/browser/chromeos/policy/site_isolation_flag_handling_browsertest.cc
+++ b/chrome/browser/chromeos/policy/site_isolation_flag_handling_browsertest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include <ostream>
+#include <set>
 #include <string>
 #include <vector>
 
@@ -22,6 +23,7 @@
 #include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/policy/login_policy_test_base.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/chromeos/settings/scoped_testing_cros_settings.h"
 #include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h"
@@ -32,6 +34,7 @@
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "chromeos/settings/cros_settings_names.h"
+#include "components/flags_ui/pref_service_flags_storage.h"
 #include "components/policy/core/browser/browser_policy_connector.h"
 #include "components/policy/core/common/mock_configuration_policy_provider.h"
 #include "components/policy/core/common/policy_map.h"
@@ -52,59 +55,59 @@
 namespace {
 
 struct Params {
-  Params(bool login_screen_site_per_process,
-         std::string login_screen_isolate_origins,
-         bool user_policy_site_per_process,
+  Params(std::string login_screen_isolate_origins,
          std::string user_policy_isolate_origins,
+         bool user_policy_site_per_process,
+         std::vector<std::string> user_flag_internal_names,
          bool ephemeral_users,
          bool expected_request_restart,
-         std::vector<std::string> expected_flags_for_user,
+         std::vector<std::string> expected_switches_for_user,
          std::vector<std::string> expected_isolated_origins = {})
-      : login_screen_site_per_process(login_screen_site_per_process),
-        login_screen_isolate_origins(login_screen_isolate_origins),
-        user_policy_site_per_process(user_policy_site_per_process),
+      : login_screen_isolate_origins(login_screen_isolate_origins),
         user_policy_isolate_origins(user_policy_isolate_origins),
+        user_policy_site_per_process(user_policy_site_per_process),
+        user_flag_internal_names(std::move(user_flag_internal_names)),
         ephemeral_users(ephemeral_users),
         expected_request_restart(expected_request_restart),
-        expected_flags_for_user(expected_flags_for_user) {}
+        expected_switches_for_user(expected_switches_for_user),
+        expected_isolated_origins(expected_isolated_origins) {}
 
   friend std::ostream& operator<<(std::ostream& os, const Params& p) {
     os << "{" << std::endl
-       << "  login_screen_site_per_process: " << p.login_screen_site_per_process
-       << std::endl
        << "  login_screen_isolate_origins: " << p.login_screen_isolate_origins
        << std::endl
        << "  user_policy_site_per_process: " << p.user_policy_site_per_process
        << std::endl
        << "  user_policy_isolate_origins: " << p.user_policy_isolate_origins
        << std::endl
+       << "  user_flag_internal_names: "
+       << base::JoinString(p.user_flag_internal_names, ", ") << std::endl
        << "  ephemeral_users: " << p.ephemeral_users << std::endl
        << "  expected_request_restart: " << p.expected_request_restart
        << std::endl
-       << "  expected_flags_for_user: "
-       << base::JoinString(p.expected_flags_for_user, ", ") << std::endl
+       << "  expected_switches_for_user: "
+       << base::JoinString(p.expected_switches_for_user, ", ") << std::endl
        << "  expected_isolated_origins: "
        << base::JoinString(p.expected_isolated_origins, ", ") << std::endl
        << "}";
     return os;
   }
 
-  // If true, --site-per-process will be passed to the login manager chrome
-  // instance between policy flag sentinels.
-  // Note: On Chrome OS, login_manager evaluates device policy and does this.
-  bool login_screen_site_per_process;
   // If non-empty, --isolate-origins=|login_screen_isolate_origins| will be
   // passed to the login manager chrome instance between policy flag sentinels.
   // Note: On Chrome OS, login_manager evaluates device policy and does this.
   std::string login_screen_isolate_origins;
 
-  // If true, the SitePerProcess user policy will be simulated to be set to
-  // true.
-  bool user_policy_site_per_process;
   // If non-empty, the IsolateOrigins user policy will be simulated to be set
   // |user_policy_isolate_origins|.
   std::string user_policy_isolate_origins;
 
+  // If true, the SitePerProcess user policy will be simulated to be set to
+  // true.
+  bool user_policy_site_per_process;
+
+  std::vector<std::string> user_flag_internal_names;
+
   // If true, ephemeral users are enabled.
   bool ephemeral_users;
 
@@ -114,8 +117,8 @@
 
   // When a restart was requested, the test case verifies that the flags passed
   // to |SessionManagerClient::SetFlagsForUser| match
-  // |expected_flags_for_user|.
-  std::vector<std::string> expected_flags_for_user;
+  // |expected_switches_for_user|.
+  std::vector<std::string> expected_switches_for_user;
 
   // List of origins that should be isolated (via policy or via cmdline flag).
   std::vector<std::string> expected_isolated_origins;
@@ -124,141 +127,51 @@
 // Defines the test cases that will be executed.
 const Params kTestCases[] = {
     // 0. No site isolation in device or user policy - no restart expected.
-    Params(false /* login_screen_site_per_process */,
-           std::string() /* login_screen_isolate_origins */,
-           false /* user_policy_site_per_process */,
+    Params(std::string() /* login_screen_isolate_origins */,
            std::string() /* user_policy_isolate_origins */,
+           false /* user_policy_site_per_process */,
+           {} /* user_flag_internal_names */,
            false /* ephemeral_users */,
            false /* expected_request_restart */,
-           {} /* expected_flags_for_user */),
+           {} /* expected_switches_for_user */),
 
-    // 1. SitePerProcess in user policy only - restart expected with
-    //    additional --site-per-process flag.
-    Params(false /* login_screen_site_per_process */,
-           std::string() /* login_screen_isolate_origins */,
-           true /* user_policy_site_per_process */,
-           std::string() /* user_policy_isolate_origins */,
-           false /* ephemeral_users */,
-           true /* expected_request_restart */,
-           {"--policy-switches-begin", "--site-per-process",
-            "--policy-switches-end"} /* expected_flags_for_user */),
+    // 1. SitePerProcess opt-out through about://flags - restart expected.
+    Params(
+        std::string() /* login_screen_isolate_origins */,
+        std::string() /* user_policy_isolate_origins */,
+        false /* user_policy_site_per_process */,
+        {"site-isolation-trial-opt-out@1"} /* user_flag_internal_names */,
+        false /* ephemeral_users */,
+        true /* expected_request_restart */,
+        {"--disable-site-isolation-trials"} /* expected_switches_for_user */),
 
-    // 2. SitePerProcess in device and user policy - no restart expected.
-    Params(true /* login_screen_site_per_process */,
-           std::string() /* login_screen_isolate_origins */,
-           true /* user_policy_site_per_process */,
+    // 2. SitePerProcess forced through user policy - opt-out through
+    // about://flags entry expected to be ignored.
+    Params(std::string() /* login_screen_isolate_origins */,
            std::string() /* user_policy_isolate_origins */,
+           true /* user_policy_site_per_process */,
+           {"site-isolation-trial-opt-out@1"} /* user_flag_internal_names */,
            false /* ephemeral_users */,
            false /* expected_request_restart */,
-           {} /* expected_flags_for_user */),
+           {} /* expected_switches_for_user */),
 
-    // 3. SitePerProcess only in device policy - restart expected.
-    Params(true /* login_screen_site_per_process */,
-           std::string() /* login_screen_isolate_origins */,
-           false /* user_policy_site_per_process */,
-           std::string() /* user_policy_isolate_origins */,
-           false /* ephemeral_users */,
-           true /* expected_request_restart */,
-           {} /* expected_flags_for_user */),
-
-    // 4. IsolateOrigins in user policy only - no restart expected, because
+    // 3. IsolateOrigins in user policy only - no restart expected, because
     //    IsolateOrigins from the user policy should be picked up by
     //    SiteIsolationPrefsObserver (without requiring injection of the
     //    --isolate-origins cmdline switch).
-    Params(false /* login_screen_site_per_process */,
-           std::string() /* login_screen_isolate_origins */,
-           false /* user_policy_site_per_process */,
+    Params(std::string() /* login_screen_isolate_origins */,
            "https://example.com" /* user_policy_isolate_origins */,
+           false /* user_policy_site_per_process */,
+           {} /* user_flag_internal_names */,
            false /* ephemeral_users */,
            false /* expected_request_restart */,
-           {} /* expected_flags_for_user */,
-           {"https://example.com"} /* expected_isolated_origins */),
-
-    // 5. Situation that should not be encountered in practice - the
-    //    --isolate-origins switch should not be injected
-    //    (login_screen_isolate_origins should always be empty) after we tweak
-    //    CrOS:login_manager/device_policy_service.cc to avoid injecting
-    //    --isolate-origins switch but instead rely on
-    //    SiteIsolationPrefsObserver.
-    Params(false /* login_screen_site_per_process */,
-           "https://example.com" /* login_screen_isolate_origins */,
-           false /* user_policy_site_per_process */,
-           "https://example.com" /* user_policy_isolate_origins */,
-           false /* ephemeral_users */,
-           true /* expected_request_restart */,
-           {} /* expected_flags_for_user */,
-           {"https://example.com"} /* expected_isolated_origins */),
-
-    // 6. Similar to above - situation that should not be encountered in
-    // practice (login_screen_isolate_origins should always be empty).
-    Params(false /* login_screen_site_per_process */,
-           "https://example.com" /* login_screen_isolate_origins */,
-           false /* user_policy_site_per_process */,
-           "https://example2.com" /* user_policy_isolate_origins */,
-           false /* ephemeral_users */,
-           true /* expected_request_restart */,
-           {} /* expected_flags_for_user */,
-           {"https://example.com",
-            "https://example2.com"} /* expected_isolated_origins */),
-
-    // 7. Similar to above - situation that should not be encountered in
-    // practice (login_screen_isolate_origins should always be empty).
-    Params(true /* login_screen_site_per_process */,
-           "https://foo.example.com" /* login_screen_isolate_origins */,
-           false /* user_policy_site_per_process */,
-           std::string() /* user_policy_isolate_origins */,
-           false /* ephemeral_users */,
-           true /* expected_request_restart */,
-           {} /* expected_flags_for_user */,
-           {"https://foo.example.com"} /* expected_isolated_origins */),
-
-    // 8. SitePerProcess in device policy, IsolateOrigins in user policy -
-    //    restart expected, because site-per-process is present in device policy
-    //    but not in the user policy.
-    Params(true /* login_screen_site_per_process */,
-           std::string() /* login_screen_isolate_origins */,
-           false /* user_policy_site_per_process */,
-           "https://foo.example.com" /* user_policy_isolate_origins */,
-           false /* ephemeral_users */,
-           true /* expected_request_restart */,
-           {} /* expected_flags_for_user */,
-           {"https://foo.example.com"} /* expected_isolated_origins */),
-
-    // 9. With ephemeral users: No site isolation in device or user policy - no
-    //    restart expected.
-    Params(false /* login_screen_site_per_process */,
-           std::string() /* login_screen_isolate_origins */,
-           false /* user_policy_site_per_process */,
-           std::string() /* user_policy_isolate_origins */,
-           true /* ephemeral_users */,
-           false /* expected_request_restart */,
-           {} /* expected_flags_for_user */),
-
-    // 10. With ephemeral users: SitePerProcess in user policy only - restart
-    //     expected with additional --site-per-process flag.
-    Params(false /* login_screen_site_per_process */,
-           std::string() /* login_screen_isolate_origins */,
-           true /* user_policy_site_per_process */,
-           std::string() /* user_policy_isolate_origins */,
-           true /* ephemeral_users */,
-           true /* expected_request_restart */,
-           {"--profile-requires-policy=true", "--policy-switches-begin",
-            "--site-per-process",
-            "--policy-switches-end"} /* expected_flags_for_user */),
-
-    // 11. With ephemeral uses: SitePerProcess in device and user policy - no
-    //     restart expected.
-    Params(true /* login_screen_site_per_process */,
-           std::string() /* login_screen_isolate_origins */,
-           true /* user_policy_site_per_process */,
-           std::string() /* user_policy_isolate_origins */,
-           true /* ephemeral_users */,
-           false /* expected_request_restart */,
-           {} /* expected_flags_for_user */)};
+           {} /* expected_switches_for_user */,
+           {"https://example.com"} /* expected_isolated_origins */)};
 
 constexpr char kTestUserAccountId[] = "username@examle.com";
 constexpr char kTestUserGaiaId[] = "1111111111";
 constexpr char kTestUserPassword[] = "password";
+constexpr char kEmptyServices[] = "[]";
 
 class SiteIsolationFlagHandlingTest
     : public OobeBaseTest,
@@ -266,30 +179,6 @@
  protected:
   SiteIsolationFlagHandlingTest() = default;
 
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    OobeBaseTest::SetUpCommandLine(command_line);
-
-    // Simulate login_manager behavior: pass --site-per-process or
-    // --isolate-origins between policy flag sentinels according to test case
-    // parameters.
-    bool use_policy_switches_sentinels =
-        GetParam().login_screen_site_per_process ||
-        !GetParam().login_screen_isolate_origins.empty();
-    if (use_policy_switches_sentinels)
-      command_line->AppendSwitch(switches::kPolicySwitchesBegin);
-
-    if (GetParam().login_screen_site_per_process)
-      command_line->AppendSwitch(::switches::kSitePerProcess);
-    if (!GetParam().login_screen_isolate_origins.empty()) {
-      command_line->AppendSwitchASCII(::switches::kIsolateOrigins,
-                                      GetParam().login_screen_isolate_origins);
-    }
-
-    if (use_policy_switches_sentinels)
-      command_line->AppendSwitch(switches::kPolicySwitchesEnd);
-  }
-
-
   void SetUpInProcessBrowserTestFixture() override {
     SessionManagerClient::InitializeFakeInMemory();
 
@@ -399,6 +288,31 @@
 
 }  // namespace
 
+IN_PROC_BROWSER_TEST_P(SiteIsolationFlagHandlingTest, PRE_FlagHandlingTest) {
+  chromeos::LoginDisplayHost::default_host()
+      ->GetOobeUI()
+      ->GetView<chromeos::GaiaScreenHandler>()
+      ->ShowSigninScreenForTest(kTestUserAccountId, kTestUserPassword,
+                                kEmptyServices);
+
+  content::WindowedNotificationObserver(
+      chrome::NOTIFICATION_SESSION_STARTED,
+      content::NotificationService::AllSources())
+      .Wait();
+
+  if (!GetParam().user_flag_internal_names.empty()) {
+    Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUserUnsafe(
+        user_manager::UserManager::Get()->GetActiveUser());
+    ASSERT_TRUE(profile);
+    flags_ui::PrefServiceFlagsStorage flags_storage(profile->GetPrefs());
+    std::set<std::string> flags_to_set;
+    for (const std::string& flag_to_set : GetParam().user_flag_internal_names)
+      flags_to_set.insert(flag_to_set);
+    EXPECT_TRUE(flags_storage.SetFlags(flags_to_set));
+    flags_storage.CommitPendingWrites();
+  }
+}
+
 IN_PROC_BROWSER_TEST_P(SiteIsolationFlagHandlingTest, FlagHandlingTest) {
   // Start user sign-in. We can't use |LoginPolicyTestBase::LogIn|, because
   // it waits for a user session start unconditionally, which will not happen if
@@ -409,7 +323,8 @@
   LoginDisplayHost::default_host()
       ->GetOobeUI()
       ->GetView<GaiaScreenHandler>()
-      ->ShowSigninScreenForTest(kTestUserAccountId, kTestUserPassword, "[]");
+      ->ShowSigninScreenForTest(kTestUserAccountId, kTestUserPassword,
+                                kEmptyServices);
 
   // Wait for either the user session to start, or for restart to be requested
   // (whichever happens first).
@@ -430,18 +345,18 @@
   // Also verify flags if chrome was restarted.
   AccountId test_account_id =
       AccountId::FromUserEmailGaiaId(kTestUserAccountId, kTestUserGaiaId);
-  std::vector<std::string> flags_for_user;
-  bool has_flags_for_user = FakeSessionManagerClient::Get()->GetFlagsForUser(
+  std::vector<std::string> switches_for_user;
+  bool has_switches_for_user = FakeSessionManagerClient::Get()->GetFlagsForUser(
       cryptohome::CreateAccountIdentifierFromAccountId(test_account_id),
-      &flags_for_user);
-  EXPECT_TRUE(has_flags_for_user);
+      &switches_for_user);
+  EXPECT_TRUE(has_switches_for_user);
 
   // Remove flag sentinels. Keep whatever is between those sentinels, to
   // verify that we don't pass additional parameters in there.
-  base::EraseIf(flags_for_user, [](const std::string& flag) {
+  base::EraseIf(switches_for_user, [](const std::string& flag) {
     return flag == "--flag-switches-begin" || flag == "--flag-switches-end";
   });
-  EXPECT_EQ(GetParam().expected_flags_for_user, flags_for_user);
+  EXPECT_EQ(GetParam().expected_switches_for_user, switches_for_user);
 }
 
 INSTANTIATE_TEST_SUITE_P(,
diff --git a/chrome/browser/chromeos/power/ml/idle_event_notifier.cc b/chrome/browser/chromeos/power/ml/idle_event_notifier.cc
index ebfc464a..ac19405 100644
--- a/chrome/browser/chromeos/power/ml/idle_event_notifier.cc
+++ b/chrome/browser/chromeos/power/ml/idle_event_notifier.cc
@@ -92,16 +92,6 @@
   boot_clock_ = std::move(test_boot_clock);
 }
 
-void IdleEventNotifier::AddObserver(Observer* observer) {
-  DCHECK(observer);
-  observers_.AddObserver(observer);
-}
-
-void IdleEventNotifier::RemoveObserver(Observer* observer) {
-  DCHECK(observer);
-  observers_.RemoveObserver(observer);
-}
-
 void IdleEventNotifier::LidEventReceived(
     chromeos::PowerManagerClient::LidState state,
     const base::TimeTicks& /* timestamp */) {
@@ -119,15 +109,6 @@
   }
 }
 
-void IdleEventNotifier::ScreenDimImminent() {
-  // powerd should not dim the screen if video is playing.
-  DCHECK(!video_playing_);
-  const ActivityData data = ConvertActivityData(*internal_data_);
-
-  for (auto& observer : observers_)
-    observer.OnIdleEventObserved(data);
-  ResetTimestampsForRecentActivity();
-}
 
 void IdleEventNotifier::SuspendDone(const base::TimeDelta& sleep_duration) {
   // SuspendDone is triggered by user opening the lid (or other user
@@ -188,6 +169,16 @@
   UpdateActivityData(ActivityType::VIDEO);
 }
 
+IdleEventNotifier::ActivityData IdleEventNotifier::GetActivityDataAndReset() {
+  const ActivityData data = ConvertActivityData(*internal_data_);
+  ResetTimestampsForRecentActivity();
+  return data;
+}
+
+IdleEventNotifier::ActivityData IdleEventNotifier::GetActivityData() const {
+  return ConvertActivityData(*internal_data_);
+}
+
 IdleEventNotifier::ActivityData IdleEventNotifier::ConvertActivityData(
     const ActivityDataInternal& internal_data) const {
   const base::TimeDelta time_since_boot = boot_clock_->GetTimeSinceBoot();
diff --git a/chrome/browser/chromeos/power/ml/idle_event_notifier.h b/chrome/browser/chromeos/power/ml/idle_event_notifier.h
index cbd0adb..5b70648 100644
--- a/chrome/browser/chromeos/power/ml/idle_event_notifier.h
+++ b/chrome/browser/chromeos/power/ml/idle_event_notifier.h
@@ -95,15 +95,6 @@
     int touch_events_in_last_hour = 0;
   };
 
-  class Observer {
-   public:
-    // Called when an idle event is observed.
-    virtual void OnIdleEventObserved(const ActivityData& activity_data) = 0;
-
-   protected:
-    virtual ~Observer() {}
-  };
-
   IdleEventNotifier(PowerManagerClient* power_client,
                     ui::UserActivityDetector* detector,
                     viz::mojom::VideoDetectorObserverRequest request);
@@ -114,15 +105,10 @@
                           base::Clock* test_clock,
                           std::unique_ptr<BootClock> test_boot_clock);
 
-  // Adds or removes an observer.
-  void AddObserver(Observer* observer);
-  void RemoveObserver(Observer* observer);
-
   // chromeos::PowerManagerClient::Observer overrides:
   void LidEventReceived(chromeos::PowerManagerClient::LidState state,
                         const base::TimeTicks& timestamp) override;
   void PowerChanged(const power_manager::PowerSupplyProperties& proto) override;
-  void ScreenDimImminent() override;
   void SuspendDone(const base::TimeDelta& sleep_duration) override;
 
   // ui::UserActivityObserver overrides:
@@ -132,6 +118,14 @@
   void OnVideoActivityStarted() override;
   void OnVideoActivityEnded() override;
 
+  // Called in UserActivityController::ShouldDeferScreenDim to prepare activity
+  // data for making Smart Dim decision.
+  ActivityData GetActivityDataAndReset();
+
+  // Get activity data only, do not mutate the class, may be used by machine
+  // learning internal page.
+  ActivityData GetActivityData() const;
+
  private:
   FRIEND_TEST_ALL_PREFIXES(IdleEventNotifierTest, CheckInitialValues);
   friend class IdleEventNotifierTest;
diff --git a/chrome/browser/chromeos/power/ml/idle_event_notifier_unittest.cc b/chrome/browser/chromeos/power/ml/idle_event_notifier_unittest.cc
index 0cd10063..16d42a7 100644
--- a/chrome/browser/chromeos/power/ml/idle_event_notifier_unittest.cc
+++ b/chrome/browser/chromeos/power/ml/idle_event_notifier_unittest.cc
@@ -24,6 +24,19 @@
 
 namespace {
 
+base::TimeDelta GetTimeSinceMidnight(base::Time time) {
+  return time - time.LocalMidnight();
+}
+
+UserActivityEvent_Features_DayOfWeek GetDayOfWeek(base::Time time) {
+  base::Time::Exploded exploded;
+  time.LocalExplode(&exploded);
+  return static_cast<UserActivityEvent_Features_DayOfWeek>(
+      exploded.day_of_week);
+}
+
+}  // namespace
+
 bool operator==(const IdleEventNotifier::ActivityData& x,
                 const IdleEventNotifier::ActivityData& y) {
   return x.last_activity_day == y.last_activity_day &&
@@ -40,42 +53,6 @@
          x.touch_events_in_last_hour == y.touch_events_in_last_hour;
 }
 
-base::TimeDelta GetTimeSinceMidnight(base::Time time) {
-  return time - time.LocalMidnight();
-}
-
-UserActivityEvent_Features_DayOfWeek GetDayOfWeek(base::Time time) {
-  base::Time::Exploded exploded;
-  time.LocalExplode(&exploded);
-  return static_cast<UserActivityEvent_Features_DayOfWeek>(
-      exploded.day_of_week);
-}
-
-class TestObserver : public IdleEventNotifier::Observer {
- public:
-  TestObserver() : idle_event_count_(0) {}
-  ~TestObserver() override {}
-
-  int idle_event_count() const { return idle_event_count_; }
-  const IdleEventNotifier::ActivityData& activity_data() const {
-    return activity_data_;
-  }
-
-  // IdleEventNotifier::Observer overrides:
-  void OnIdleEventObserved(
-      const IdleEventNotifier::ActivityData& activity_data) override {
-    ++idle_event_count_;
-    activity_data_ = activity_data;
-  }
-
- private:
-  int idle_event_count_;
-  IdleEventNotifier::ActivityData activity_data_;
-  DISALLOW_COPY_AND_ASSIGN(TestObserver);
-};
-
-}  // namespace
-
 class IdleEventNotifierTest : public testing::Test {
  public:
   IdleEventNotifierTest()
@@ -97,7 +74,6 @@
         const_cast<base::Clock*>(scoped_task_env_.GetMockClock()),
         std::make_unique<FakeBootClock>(&scoped_task_env_,
                                         base::TimeDelta::FromSeconds(10)));
-    idle_event_notifier_->AddObserver(&test_observer_);
     ac_power_.set_external_power(
         power_manager::PowerSupplyProperties_ExternalPower_AC);
     disconnected_power_.set_external_power(
@@ -110,21 +86,8 @@
   }
 
  protected:
-  void ReportScreenDimImminent() {
-    FakePowerManagerClient::Get()->SendScreenDimImminent();
-  }
-
-  void ReportIdleEventAndCheckResults(
-      int expected_idle_count,
-      const IdleEventNotifier::ActivityData& expected_activity_data) {
-    ReportScreenDimImminent();
-    EXPECT_EQ(expected_idle_count, test_observer_.idle_event_count());
-    EXPECT_TRUE(expected_activity_data == test_observer_.activity_data());
-  }
-
   base::test::ScopedTaskEnvironment scoped_task_env_;
 
-  TestObserver test_observer_;
   std::unique_ptr<IdleEventNotifier> idle_event_notifier_;
   power_manager::PowerSupplyProperties ac_power_;
   power_manager::PowerSupplyProperties disconnected_power_;
@@ -151,7 +114,7 @@
   data.last_activity_time_of_day = time_of_day;
   data.last_user_activity_time_of_day = time_of_day;
   data.recent_time_active = base::TimeDelta();
-  ReportIdleEventAndCheckResults(1, data);
+  EXPECT_EQ(data, idle_event_notifier_->GetActivityDataAndReset());
 }
 
 // PowerChanged signal is received but source isn't changed, so it won't change
@@ -165,11 +128,11 @@
   data.last_activity_time_of_day = time_of_day;
   data.last_user_activity_time_of_day = time_of_day;
   data.recent_time_active = base::TimeDelta();
-  ReportIdleEventAndCheckResults(1, data);
+  EXPECT_EQ(data, idle_event_notifier_->GetActivityDataAndReset());
 
   scoped_task_env_.FastForwardBy(base::TimeDelta::FromSeconds(10));
   idle_event_notifier_->PowerChanged(ac_power_);
-  ReportIdleEventAndCheckResults(2, data);
+  EXPECT_EQ(data, idle_event_notifier_->GetActivityDataAndReset());
 }
 
 // PowerChanged signal is received and source is changed, so a different
@@ -183,7 +146,7 @@
   data_1.last_activity_time_of_day = time_of_day_1;
   data_1.last_user_activity_time_of_day = time_of_day_1;
   data_1.recent_time_active = base::TimeDelta();
-  ReportIdleEventAndCheckResults(1, data_1);
+  EXPECT_EQ(data_1, idle_event_notifier_->GetActivityDataAndReset());
 
   scoped_task_env_.FastForwardBy(base::TimeDelta::FromSeconds(100));
   base::Time now_2 = scoped_task_env_.GetMockClock()->Now();
@@ -194,7 +157,7 @@
   data_2.last_activity_time_of_day = time_of_day_2;
   data_2.last_user_activity_time_of_day = time_of_day_2;
   data_2.recent_time_active = base::TimeDelta();
-  ReportIdleEventAndCheckResults(2, data_2);
+  EXPECT_EQ(data_2, idle_event_notifier_->GetActivityDataAndReset());
 }
 
 // Short sleep duration does not break up recent time active.
@@ -215,7 +178,7 @@
   data.last_activity_time_of_day = time_of_day;
   data.last_user_activity_time_of_day = time_of_day;
   data.recent_time_active = now_2 - now_1;
-  ReportIdleEventAndCheckResults(1, data);
+  EXPECT_EQ(data, idle_event_notifier_->GetActivityDataAndReset());
 }
 
 // Long sleep duration recalc recent time active.
@@ -238,7 +201,7 @@
   data.last_activity_time_of_day = time_of_day;
   data.last_user_activity_time_of_day = time_of_day;
   data.recent_time_active = now_2 - now_1;
-  ReportIdleEventAndCheckResults(1, data);
+  EXPECT_EQ(data, idle_event_notifier_->GetActivityDataAndReset());
 }
 
 TEST_F(IdleEventNotifierTest, UserActivityKey) {
@@ -254,7 +217,7 @@
   data.time_since_last_key = base::TimeDelta::FromSeconds(10);
   data.key_events_in_last_hour = 1;
   scoped_task_env_.FastForwardBy(base::TimeDelta::FromSeconds(10));
-  ReportIdleEventAndCheckResults(1, data);
+  EXPECT_EQ(data, idle_event_notifier_->GetActivityDataAndReset());
 }
 
 TEST_F(IdleEventNotifierTest, UserActivityMouse) {
@@ -272,7 +235,7 @@
   data.time_since_last_mouse = base::TimeDelta::FromSeconds(10);
   data.mouse_events_in_last_hour = 1;
   scoped_task_env_.FastForwardBy(base::TimeDelta::FromSeconds(10));
-  ReportIdleEventAndCheckResults(1, data);
+  EXPECT_EQ(data, idle_event_notifier_->GetActivityDataAndReset());
 }
 
 TEST_F(IdleEventNotifierTest, UserActivityOther) {
@@ -288,7 +251,7 @@
   data.last_user_activity_time_of_day = time_of_day;
   data.recent_time_active = base::TimeDelta();
   scoped_task_env_.FastForwardBy(base::TimeDelta::FromSeconds(10));
-  ReportIdleEventAndCheckResults(1, data);
+  EXPECT_EQ(data, idle_event_notifier_->GetActivityDataAndReset());
 }
 
 // Two consecutive activities separated by 2sec only. Only 1 idle event with
@@ -316,7 +279,7 @@
   data.key_events_in_last_hour = 1;
   data.mouse_events_in_last_hour = 1;
   scoped_task_env_.FastForwardBy(base::TimeDelta::FromSeconds(10));
-  ReportIdleEventAndCheckResults(1, data);
+  EXPECT_EQ(data, idle_event_notifier_->GetActivityDataAndReset());
 }
 
 TEST_F(IdleEventNotifierTest, ActivityAfterVideoStarts) {
@@ -343,7 +306,7 @@
   data.time_since_video_ended = base::TimeDelta::FromSeconds(10);
   data.mouse_events_in_last_hour = 1;
   scoped_task_env_.FastForwardBy(base::TimeDelta::FromSeconds(10));
-  ReportIdleEventAndCheckResults(1, data);
+  EXPECT_EQ(data, idle_event_notifier_->GetActivityDataAndReset());
 }
 
 TEST_F(IdleEventNotifierTest, IdleEventFieldReset) {
@@ -368,7 +331,7 @@
   data_1.key_events_in_last_hour = 1;
   data_1.mouse_events_in_last_hour = 1;
   scoped_task_env_.FastForwardBy(base::TimeDelta::FromSeconds(10));
-  ReportIdleEventAndCheckResults(1, data_1);
+  EXPECT_EQ(data_1, idle_event_notifier_->GetActivityDataAndReset());
 
   idle_event_notifier_->PowerChanged(ac_power_);
   base::Time now_3 = scoped_task_env_.GetMockClock()->Now();
@@ -385,7 +348,7 @@
   data_2.key_events_in_last_hour = 1;
   data_2.mouse_events_in_last_hour = 1;
   scoped_task_env_.FastForwardBy(base::TimeDelta::FromSeconds(20));
-  ReportIdleEventAndCheckResults(2, data_2);
+  EXPECT_EQ(data_2, idle_event_notifier_->GetActivityDataAndReset());
 }
 
 TEST_F(IdleEventNotifierTest, TwoConsecutiveVideoPlaying) {
@@ -421,7 +384,7 @@
   data.time_since_video_ended =
       base::TimeDelta::FromSeconds(25) + now_3 - now_2;
   scoped_task_env_.FastForwardBy(base::TimeDelta::FromSeconds(25));
-  ReportIdleEventAndCheckResults(1, data);
+  EXPECT_EQ(data, idle_event_notifier_->GetActivityDataAndReset());
 }
 
 TEST_F(IdleEventNotifierTest, TwoVideoPlayingFarApartOneIdleEvent) {
@@ -456,7 +419,7 @@
   data.video_playing_time = now_3 - now_2;
   data.time_since_video_ended = base::TimeDelta::FromSeconds(25);
   scoped_task_env_.FastForwardBy(base::TimeDelta::FromSeconds(25));
-  ReportIdleEventAndCheckResults(1, data);
+  EXPECT_EQ(data, idle_event_notifier_->GetActivityDataAndReset());
 }
 
 TEST_F(IdleEventNotifierTest, TwoVideoPlayingFarApartTwoIdleEvents) {
@@ -478,7 +441,7 @@
       IdleEventNotifier::kIdleDelay + base::TimeDelta::FromSeconds(10);
   scoped_task_env_.FastForwardBy(IdleEventNotifier::kIdleDelay +
                                  base::TimeDelta::FromSeconds(10));
-  ReportIdleEventAndCheckResults(1, data_1);
+  EXPECT_EQ(data_1, idle_event_notifier_->GetActivityDataAndReset());
 
   base::Time now_3 = scoped_task_env_.GetMockClock()->Now();
   idle_event_notifier_->OnVideoActivityStarted();
@@ -492,7 +455,7 @@
   data_2.recent_time_active = now_4 - now_3;
   data_2.video_playing_time = now_4 - now_3;
   data_2.time_since_video_ended = base::TimeDelta();
-  ReportIdleEventAndCheckResults(2, data_2);
+  EXPECT_EQ(data_2, idle_event_notifier_->GetActivityDataAndReset());
 }
 
 TEST_F(IdleEventNotifierTest, TwoVideoPlayingSeparatedByAnIdleEvent) {
@@ -512,7 +475,7 @@
   data_1.video_playing_time = kNow2 - kNow1;
   data_1.time_since_video_ended = base::TimeDelta::FromSeconds(1);
   scoped_task_env_.FastForwardBy(base::TimeDelta::FromSeconds(1));
-  ReportIdleEventAndCheckResults(1, data_1);
+  EXPECT_EQ(data_1, idle_event_notifier_->GetActivityDataAndReset());
 
   const base::Time kNow3 = scoped_task_env_.GetMockClock()->Now();
   idle_event_notifier_->OnVideoActivityStarted();
@@ -526,7 +489,7 @@
   data_2.recent_time_active = kNow4 - kNow3;
   data_2.video_playing_time = kNow4 - kNow3;
   data_2.time_since_video_ended = base::TimeDelta();
-  ReportIdleEventAndCheckResults(2, data_2);
+  EXPECT_EQ(data_2, idle_event_notifier_->GetActivityDataAndReset());
 }
 
 TEST_F(IdleEventNotifierTest, VideoPlayingPausedByShortSuspend) {
@@ -548,7 +511,7 @@
   data.recent_time_active = now_3 - now_1;
   data.video_playing_time = now_3 - now_1;
   data.time_since_video_ended = base::TimeDelta();
-  ReportIdleEventAndCheckResults(1, data);
+  EXPECT_EQ(data, idle_event_notifier_->GetActivityDataAndReset());
 }
 
 TEST_F(IdleEventNotifierTest, VideoPlayingPausedByLongSuspend) {
@@ -569,7 +532,7 @@
   data.recent_time_active = now_2 - now_1;
   data.video_playing_time = now_2 - now_1;
   data.time_since_video_ended = base::TimeDelta();
-  ReportIdleEventAndCheckResults(1, data);
+  EXPECT_EQ(data, idle_event_notifier_->GetActivityDataAndReset());
 }
 
 TEST_F(IdleEventNotifierTest, UserInputEventsOneIdleEvent) {
@@ -632,7 +595,7 @@
   data.touch_events_in_last_hour = 3;
 
   scoped_task_env_.FastForwardBy(base::TimeDelta::FromSeconds(30));
-  ReportIdleEventAndCheckResults(1, data);
+  EXPECT_EQ(data, idle_event_notifier_->GetActivityDataAndReset());
 }
 
 TEST_F(IdleEventNotifierTest, UserInputEventsTwoIdleEvents) {
@@ -654,7 +617,7 @@
   data_1.time_since_last_key = base::TimeDelta::FromSeconds(30);
   data_1.key_events_in_last_hour = 1;
   scoped_task_env_.FastForwardBy(base::TimeDelta::FromSeconds(30));
-  ReportIdleEventAndCheckResults(1, data_1);
+  EXPECT_EQ(data_1, idle_event_notifier_->GetActivityDataAndReset());
 
   scoped_task_env_.FastForwardBy(base::TimeDelta::FromMinutes(11));
   base::Time last_key_time = scoped_task_env_.GetMockClock()->Now();
@@ -701,7 +664,7 @@
   data_2.mouse_events_in_last_hour = 2;
   data_2.touch_events_in_last_hour = 3;
 
-  ReportIdleEventAndCheckResults(2, data_2);
+  EXPECT_EQ(data_2, idle_event_notifier_->GetActivityDataAndReset());
 }
 
 }  // namespace ml
diff --git a/chrome/browser/chromeos/power/ml/user_activity_controller.cc b/chrome/browser/chromeos/power/ml/user_activity_controller.cc
index 32345e5..d4b1bb08 100644
--- a/chrome/browser/chromeos/power/ml/user_activity_controller.cc
+++ b/chrome/browser/chromeos/power/ml/user_activity_controller.cc
@@ -44,9 +44,8 @@
 
   viz::mojom::VideoDetectorObserverPtr video_observer_user_logger;
   user_activity_manager_ = std::make_unique<UserActivityManager>(
-      &user_activity_ukm_logger_, idle_event_notifier_.get(), detector,
-      power_manager_client, session_manager,
-      mojo::MakeRequest(&video_observer_user_logger),
+      &user_activity_ukm_logger_, detector, power_manager_client,
+      session_manager, mojo::MakeRequest(&video_observer_user_logger),
       chromeos::ChromeUserManager::Get(), &smart_dim_model_);
   aura::Env::GetInstance()
       ->context_factory_private()
@@ -56,6 +55,12 @@
 
 UserActivityController::~UserActivityController() = default;
 
+void UserActivityController::ShouldDeferScreenDim(
+    base::OnceCallback<void(bool)> callback) {
+  user_activity_manager_->UpdateAndGetSmartDimDecision(
+      idle_event_notifier_->GetActivityDataAndReset(), std::move(callback));
+}
+
 }  // namespace ml
 }  // namespace power
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/power/ml/user_activity_controller.h b/chrome/browser/chromeos/power/ml/user_activity_controller.h
index e1c3325..30e2ba0 100644
--- a/chrome/browser/chromeos/power/ml/user_activity_controller.h
+++ b/chrome/browser/chromeos/power/ml/user_activity_controller.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 
+#include "base/callback.h"
 #include "chrome/browser/chromeos/power/ml/idle_event_notifier.h"
 #include "chrome/browser/chromeos/power/ml/smart_dim/model_impl.h"
 #include "chrome/browser/chromeos/power/ml/user_activity_manager.h"
@@ -24,6 +25,10 @@
   UserActivityController();
   ~UserActivityController();
 
+  // Prepares features, makes smart dim decision and returns the result via
+  // |callback|.
+  void ShouldDeferScreenDim(base::OnceCallback<void(bool)> callback);
+
  private:
   std::unique_ptr<IdleEventNotifier> idle_event_notifier_;
   UserActivityUkmLoggerImpl user_activity_ukm_logger_;
diff --git a/chrome/browser/chromeos/power/ml/user_activity_manager.cc b/chrome/browser/chromeos/power/ml/user_activity_manager.cc
index aee7c9c..a752563 100644
--- a/chrome/browser/chromeos/power/ml/user_activity_manager.cc
+++ b/chrome/browser/chromeos/power/ml/user_activity_manager.cc
@@ -88,6 +88,9 @@
 
 }  // namespace
 
+// TODO(alanlxl): Fix the variable names and comments related to screen dim
+// imminent signals, because after powerd refactor (https://crrev.com/c/1601992)
+// ScreenDimImminent signals are deprecated.
 struct UserActivityManager::PreviousIdleEventData {
   // Gap between two ScreenDimImminent signals.
   base::TimeDelta dim_imminent_signal_interval;
@@ -101,7 +104,6 @@
 
 UserActivityManager::UserActivityManager(
     UserActivityUkmLogger* ukm_logger,
-    IdleEventNotifier* idle_event_notifier,
     ui::UserActivityDetector* detector,
     chromeos::PowerManagerClient* power_manager_client,
     session_manager::SessionManager* session_manager,
@@ -111,7 +113,6 @@
     : boot_clock_(std::make_unique<RealBootClock>()),
       ukm_logger_(ukm_logger),
       smart_dim_model_(smart_dim_model),
-      idle_event_observer_(this),
       user_activity_observer_(this),
       power_manager_client_observer_(this),
       session_manager_observer_(this),
@@ -121,8 +122,6 @@
       power_manager_client_(power_manager_client),
       weak_ptr_factory_(this) {
   DCHECK(ukm_logger_);
-  DCHECK(idle_event_notifier);
-  idle_event_observer_.Add(idle_event_notifier);
 
   DCHECK(detector);
   user_activity_observer_.Add(detector);
@@ -237,16 +236,17 @@
                 UserActivityEvent::Event::VIDEO_ACTIVITY);
 }
 
-void UserActivityManager::OnIdleEventObserved(
-    const IdleEventNotifier::ActivityData& activity_data) {
+void UserActivityManager::UpdateAndGetSmartDimDecision(
+    const IdleEventNotifier::ActivityData& activity_data,
+    base::OnceCallback<void(bool)> callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   base::TimeDelta now = boot_clock_->GetTimeSinceBoot();
   if (waiting_for_final_action_) {
     if (waiting_for_model_decision_) {
       CancelDimDecisionRequest();
     } else {
-      // ScreenDimImminent is received again after an earlier ScreenDimImminent
-      // event without any user action/suspend in between.
+      // Smart dim request comes again after an earlier request event without
+      // any user action/suspend in between.
       PopulatePreviousEventData(now);
     }
   }
@@ -273,13 +273,15 @@
     waiting_for_model_decision_ = true;
     time_dim_decision_requested_ = base::TimeTicks::Now();
     smart_dim_model_->RequestDimDecision(
-        features_, base::Bind(&UserActivityManager::ApplyDimDecision,
-                              weak_ptr_factory_.GetWeakPtr()));
+        features_,
+        base::BindOnce(&UserActivityManager::HandleSmartDimDecision,
+                       weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
   }
   waiting_for_final_action_ = true;
 }
 
-void UserActivityManager::ApplyDimDecision(
+void UserActivityManager::HandleSmartDimDecision(
+    base::OnceCallback<void(bool)> callback,
     UserActivityEvent::ModelPrediction prediction) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   waiting_for_model_decision_ = false;
@@ -291,7 +293,6 @@
   // previously deferred.
   if (prediction.response() == UserActivityEvent::ModelPrediction::NO_DIM &&
       !dim_deferred_) {
-    power_manager_client_->DeferScreenDim();
     dim_deferred_ = true;
     prediction.set_model_applied(true);
   } else {
@@ -301,8 +302,8 @@
                                      UserActivityEvent::ModelPrediction::DIM &&
                                  !dim_deferred_);
   }
-
   model_prediction_ = prediction;
+  std::move(callback).Run(dim_deferred_);
 }
 
 void UserActivityManager::OnSessionStateChanged() {
diff --git a/chrome/browser/chromeos/power/ml/user_activity_manager.h b/chrome/browser/chromeos/power/ml/user_activity_manager.h
index 7d72f605..d0f2a9b 100644
--- a/chrome/browser/chromeos/power/ml/user_activity_manager.h
+++ b/chrome/browser/chromeos/power/ml/user_activity_manager.h
@@ -74,13 +74,11 @@
 // Logs user activity after an idle event is observed.
 // TODO(renjieliu): Add power-related activity as well.
 class UserActivityManager : public ui::UserActivityObserver,
-                            public IdleEventNotifier::Observer,
                             public PowerManagerClient::Observer,
                             public viz::mojom::VideoDetectorObserver,
                             public session_manager::SessionManagerObserver {
  public:
   UserActivityManager(UserActivityUkmLogger* ukm_logger,
-                      IdleEventNotifier* idle_event_notifier,
                       ui::UserActivityDetector* detector,
                       chromeos::PowerManagerClient* power_manager_client,
                       session_manager::SessionManager* session_manager,
@@ -108,13 +106,15 @@
   void OnVideoActivityStarted() override;
   void OnVideoActivityEnded() override {}
 
-  // IdleEventNotifier::Observer overrides.
-  void OnIdleEventObserved(
-      const IdleEventNotifier::ActivityData& data) override;
+  // Called in UserActivityController::ShouldDeferScreenDim to make smart dim
+  // decision and response via |callback|.
+  void UpdateAndGetSmartDimDecision(const IdleEventNotifier::ActivityData& data,
+                                    base::OnceCallback<void(bool)> callback);
 
-  // Decides whether or not to instruct the power manager to dim the screen
-  // given a |prediction| from the Smart Dim predictor.
-  void ApplyDimDecision(UserActivityEvent::ModelPrediction prediction);
+  // Converts a Smart Dim model |prediction| into a yes/no decision about
+  // whether to defer the screen dim and provides the result via |callback|.
+  void HandleSmartDimDecision(base::OnceCallback<void(bool)> callback,
+                              UserActivityEvent::ModelPrediction prediction);
 
   // session_manager::SessionManagerObserver overrides:
   void OnSessionStateChanged() override;
@@ -193,8 +193,6 @@
 
   SmartDimModel* const smart_dim_model_;
 
-  ScopedObserver<IdleEventNotifier, IdleEventNotifier::Observer>
-      idle_event_observer_;
   ScopedObserver<ui::UserActivityDetector, ui::UserActivityObserver>
       user_activity_observer_;
   ScopedObserver<chromeos::PowerManagerClient,
diff --git a/chrome/browser/chromeos/power/ml/user_activity_manager_unittest.cc b/chrome/browser/chromeos/power/ml/user_activity_manager_unittest.cc
index 7e59d7a1c..97ccaa427 100644
--- a/chrome/browser/chromeos/power/ml/user_activity_manager_unittest.cc
+++ b/chrome/browser/chromeos/power/ml/user_activity_manager_unittest.cc
@@ -183,13 +183,10 @@
 
     PowerManagerClient::InitializeFake();
     viz::mojom::VideoDetectorObserverPtr observer;
-    idle_event_notifier_ = std::make_unique<IdleEventNotifier>(
-        PowerManagerClient::Get(), &user_activity_detector_,
-        mojo::MakeRequest(&observer));
     activity_logger_ = std::make_unique<UserActivityManager>(
-        &delegate_, idle_event_notifier_.get(), &user_activity_detector_,
-        PowerManagerClient::Get(), &session_manager_,
-        mojo::MakeRequest(&observer), &fake_user_manager_, &model_);
+        &delegate_, &user_activity_detector_, PowerManagerClient::Get(),
+        &session_manager_, mojo::MakeRequest(&observer), &fake_user_manager_,
+        &model_);
     activity_logger_->SetTaskRunnerForTesting(
         thread_bundle()->GetMainThreadTaskRunner(),
         std::make_unique<FakeBootClock>(thread_bundle(),
@@ -198,7 +195,6 @@
 
   void TearDown() override {
     activity_logger_.reset();
-    idle_event_notifier_.reset();
     PowerManagerClient::Shutdown();
     ChromeRenderViewHostTestHarness::TearDown();
   }
@@ -208,8 +204,17 @@
     activity_logger_->OnUserActivity(event);
   }
 
-  void ReportIdleEvent(const IdleEventNotifier::ActivityData& data) {
-    activity_logger_->OnIdleEventObserved(data);
+  // Requests a smart dim decision from UserActivityManager based on |data|.
+  // Populates |*should_defer| with the result once it is provided.
+  void ReportIdleEvent(const IdleEventNotifier::ActivityData& data,
+                       bool* should_defer = nullptr) {
+    activity_logger_->UpdateAndGetSmartDimDecision(
+        data, base::BindOnce(
+                  [](bool* should_defer, bool decision) {
+                    if (should_defer)
+                      *should_defer = decision;
+                  },
+                  should_defer));
   }
 
   void ReportLidEvent(chromeos::PowerManagerClient::LidState state) {
@@ -259,10 +264,6 @@
     FakePowerManagerClient::Get()->SetInactivityDelays(proto);
   }
 
-  int GetNumberOfDeferredDims() {
-    return FakePowerManagerClient::Get()->num_defer_screen_dim_calls();
-  }
-
   TabProperty UpdateOpenTabURL() {
     return activity_logger_->UpdateOpenTabURL();
   }
@@ -985,10 +986,11 @@
   model_.set_decision_threshold(65);
 
   const IdleEventNotifier::ActivityData data;
-  ReportIdleEvent(data);
+  bool should_defer = false;
+  ReportIdleEvent(data, &should_defer);
   thread_bundle()->RunUntilIdle();
   ReportUserActivity(nullptr);
-  EXPECT_EQ(1, GetNumberOfDeferredDims());
+  EXPECT_TRUE(should_defer);
 
   std::string histogram("PowerML.SmartDimModel.RequestCompleteDuration");
   histogram_tester.ExpectTotalCount(histogram, 1);
@@ -1025,9 +1027,10 @@
   model_.set_decision_threshold(65);
 
   const IdleEventNotifier::ActivityData data;
-  ReportIdleEvent(data);
+  bool should_defer = false;
+  ReportIdleEvent(data, &should_defer);
   thread_bundle()->RunUntilIdle();
-  EXPECT_EQ(1, GetNumberOfDeferredDims());
+  EXPECT_TRUE(should_defer);
 
   std::string histogram("PowerML.SmartDimModel.RequestCompleteDuration");
   histogram_tester.ExpectTotalCount(histogram, 1);
@@ -1050,12 +1053,13 @@
   model_.set_decision_threshold(65);
 
   const IdleEventNotifier::ActivityData data;
-  ReportIdleEvent(data);
+  bool should_defer = false;
+  ReportIdleEvent(data, &should_defer);
   // Report user activity immediately after the idle event, so that
   // the SmartDimModel doesn't get a chance to run.
   ReportUserActivity(nullptr);
   thread_bundle()->RunUntilIdle();
-  EXPECT_EQ(0, GetNumberOfDeferredDims());
+  EXPECT_FALSE(should_defer);
 
   std::string hist_complete("PowerML.SmartDimModel.RequestCompleteDuration");
   histogram_tester.ExpectTotalCount(hist_complete, 0);
@@ -1082,11 +1086,13 @@
   model_.set_decision_threshold(65);
 
   const IdleEventNotifier::ActivityData data;
-  ReportIdleEvent(data);
-  ReportIdleEvent(data);
+  bool should_defer_1 = false;
+  bool should_defer_2 = false;
+  ReportIdleEvent(data, &should_defer_1);
+  ReportIdleEvent(data, &should_defer_2);
   thread_bundle()->RunUntilIdle();
   ReportUserActivity(nullptr);
-  EXPECT_EQ(1, GetNumberOfDeferredDims());
+  EXPECT_NE(should_defer_1, should_defer_2);
 
   std::string hist_complete("PowerML.SmartDimModel.RequestCompleteDuration");
   histogram_tester.ExpectTotalCount(hist_complete, 1);
@@ -1125,10 +1131,11 @@
   model_.set_decision_threshold(50);
 
   const IdleEventNotifier::ActivityData data;
-  ReportIdleEvent(data);
+  bool should_defer = false;
+  ReportIdleEvent(data, &should_defer);
   thread_bundle()->RunUntilIdle();
   ReportUserActivity(nullptr);
-  EXPECT_EQ(0, GetNumberOfDeferredDims());
+  EXPECT_FALSE(should_defer);
 
   std::string histogram("PowerML.SmartDimModel.RequestCompleteDuration");
   histogram_tester.ExpectTotalCount(histogram, 1);
@@ -1158,9 +1165,10 @@
   model_.set_inactivity_score(40);
 
   const IdleEventNotifier::ActivityData data;
-  ReportIdleEvent(data);
+  bool should_defer = false;
+  ReportIdleEvent(data, &should_defer);
   thread_bundle()->RunUntilIdle();
-  EXPECT_EQ(1, GetNumberOfDeferredDims());
+  EXPECT_TRUE(should_defer);
 
   thread_bundle()->FastForwardBy(base::TimeDelta::FromSeconds(6));
   ReportSuspend(power_manager::SuspendImminent_Reason_IDLE,
@@ -1169,9 +1177,9 @@
   // 2nd ScreenDimImminent is not deferred despite model score says so.
   model_.set_inactivity_score(20);
   thread_bundle()->FastForwardBy(base::TimeDelta::FromSeconds(10));
-  ReportIdleEvent(data);
+  ReportIdleEvent(data, &should_defer);
   thread_bundle()->RunUntilIdle();
-  EXPECT_EQ(1, GetNumberOfDeferredDims());
+  EXPECT_FALSE(should_defer);
 
   std::string histogram("PowerML.SmartDimModel.RequestCompleteDuration");
   histogram_tester.ExpectTotalCount(histogram, 2);
@@ -1232,16 +1240,17 @@
   // 1st ScreenDimImminent gets deferred
   model_.set_inactivity_score(40);
   const IdleEventNotifier::ActivityData data;
-  ReportIdleEvent(data);
+  bool should_defer = false;
+  ReportIdleEvent(data, &should_defer);
   thread_bundle()->RunUntilIdle();
-  EXPECT_EQ(1, GetNumberOfDeferredDims());
+  EXPECT_TRUE(should_defer);
 
   // 2nd ScreenDimImminent is not deferred despite model score says so.
   model_.set_inactivity_score(20);
   thread_bundle()->FastForwardBy(base::TimeDelta::FromSeconds(10));
-  ReportIdleEvent(data);
+  ReportIdleEvent(data, &should_defer);
   thread_bundle()->RunUntilIdle();
-  EXPECT_EQ(1, GetNumberOfDeferredDims());
+  EXPECT_FALSE(should_defer);
 
   std::string histogram("PowerML.SmartDimModel.RequestCompleteDuration");
   histogram_tester.ExpectTotalCount(histogram, 2);
@@ -1298,10 +1307,11 @@
   model_.set_decision_threshold(65);
 
   const IdleEventNotifier::ActivityData data;
-  ReportIdleEvent(data);
+  bool should_defer = false;
+  ReportIdleEvent(data, &should_defer);
   thread_bundle()->RunUntilIdle();
   ReportUserActivity(nullptr);
-  EXPECT_EQ(0, GetNumberOfDeferredDims());
+  EXPECT_FALSE(should_defer);
 
   std::string histogram("PowerML.SmartDimModel.RequestCompleteDuration");
   histogram_tester.ExpectTotalCount(histogram, 1);
diff --git a/chrome/browser/chromeos/smb_client/smb_file_system.cc b/chrome/browser/chromeos/smb_client/smb_file_system.cc
index bd49601..a5cdc6e 100644
--- a/chrome/browser/chromeos/smb_client/smb_file_system.cc
+++ b/chrome/browser/chromeos/smb_client/smb_file_system.cc
@@ -185,9 +185,14 @@
     storage::AsyncFileUtil::StatusCallback callback) {
   auto reply = base::BindOnce(&SmbFileSystem::HandleRequestUnmountCallback,
                               AsWeakPtr(), std::move(callback));
-  SmbTask task =
-      base::BindOnce(&SmbProviderClient::Unmount, GetWeakSmbProviderClient(),
-                     GetMountId(), std::move(reply));
+
+  // RequestUnmount() is called as a result of the user removing the mount from
+  // the Files app. In this case, remove any stored password to clean up state
+  // and prevent the password from being used the next time the user adds the
+  // same share.
+  SmbTask task = base::BindOnce(&SmbProviderClient::Unmount,
+                                GetWeakSmbProviderClient(), GetMountId(),
+                                true /* remove_password */, std::move(reply));
 
   return EnqueueTaskAndGetCallback(std::move(task));
 }
diff --git a/chrome/browser/chromeos/smb_client/smb_service.cc b/chrome/browser/chromeos/smb_client/smb_service.cc
index f0653d34..e4a07d3 100644
--- a/chrome/browser/chromeos/smb_client/smb_service.cc
+++ b/chrome/browser/chromeos/smb_client/smb_service.cc
@@ -149,11 +149,13 @@
                        const std::string& password,
                        bool use_chromad_kerberos,
                        bool should_open_file_manager_after_mount,
+                       bool save_credentials,
                        MountResponse callback) {
   DCHECK(temp_file_manager_);
 
   CallMount(options, share_path, username, password, use_chromad_kerberos,
-            should_open_file_manager_after_mount, std::move(callback));
+            should_open_file_manager_after_mount, save_credentials,
+            std::move(callback));
 }
 
 void SmbService::GatherSharesInNetwork(HostDiscoveryResponse discovery_callback,
@@ -229,6 +231,7 @@
                            const std::string& password_input,
                            bool use_chromad_kerberos,
                            bool should_open_file_manager_after_mount,
+                           bool save_credentials,
                            MountResponse callback) {
   SmbUrl parsed_url(share_path.value());
   if (!parsed_url.IsValid() || parsed_url.GetShare().empty()) {
@@ -257,16 +260,16 @@
   std::string username;
   std::string password;
   std::string workgroup;
+
+  user_manager::User* user =
+      chromeos::ProfileHelper::Get()->GetUserByProfile(profile_);
+  DCHECK(user);
   if (use_chromad_kerberos) {
     RecordAuthenticationMethod(AuthMethod::kSSOKerberos);
     // Get the user's username and workgroup from their email address to be used
     // for Kerberos authentication.
-    user_manager::User* user =
-        chromeos::ProfileHelper::Get()->GetUserByProfile(profile_);
-    if (user) {
-      DCHECK(user->IsActiveDirectoryUser());
-      ParseUserPrincipalName(user->GetDisplayEmail(), &username, &workgroup);
-    }
+    DCHECK(user->IsActiveDirectoryUser());
+    ParseUserPrincipalName(user->GetDisplayEmail(), &username, &workgroup);
   } else {
     // Record authentication method metrics.
     if (!username_input.empty() && !password_input.empty()) {
@@ -292,16 +295,19 @@
   const base::FilePath mount_path(url);
 
   SmbProviderClient::MountOptions smb_mount_options;
+  smb_mount_options.original_path = parsed_url.ToString();
   smb_mount_options.username = username;
   smb_mount_options.workgroup = workgroup;
   smb_mount_options.ntlm_enabled = IsNTLMAuthenticationEnabled();
+  smb_mount_options.save_password = save_credentials && !use_chromad_kerberos;
+  smb_mount_options.account_hash = user->username_hash();
   GetSmbProviderClient()->Mount(
       mount_path, smb_mount_options,
       temp_file_manager_->WritePasswordToFile(password),
       base::BindOnce(&SmbService::OnMountResponse, AsWeakPtr(),
                      base::Passed(&callback), options, share_path,
-                     use_chromad_kerberos,
-                     should_open_file_manager_after_mount));
+                     use_chromad_kerberos, should_open_file_manager_after_mount,
+                     username, workgroup, save_credentials));
 
   profile_->GetPrefs()->SetString(prefs::kMostRecentlyUsedNetworkFileShareURL,
                                   share_path.value());
@@ -313,6 +319,9 @@
     const base::FilePath& share_path,
     bool is_kerberos_chromad,
     bool should_open_file_manager_after_mount,
+    const std::string& username,
+    const std::string& workgroup,
+    bool save_credentials,
     smbprovider::ErrorType error,
     int32_t mount_id) {
   if (error != smbprovider::ERROR_OK) {
@@ -323,8 +332,23 @@
   DCHECK_GE(mount_id, 0);
 
   file_system_provider::MountOptions mount_options(options);
-  mount_options.file_system_id =
-      CreateFileSystemId(share_path, is_kerberos_chromad);
+  if (is_kerberos_chromad) {
+    mount_options.file_system_id =
+        CreateFileSystemId(share_path, is_kerberos_chromad);
+  } else {
+    std::string full_username;
+    if (save_credentials) {
+      // Only save the username if the user request credentials be saved.
+      full_username = username;
+      if (!workgroup.empty()) {
+        DCHECK(!username.empty());
+        full_username.append("@");
+        full_username.append(workgroup);
+      }
+    }
+    mount_options.file_system_id =
+        CreateFileSystemIdForUser(share_path, full_username);
+  }
   mount_id_map_[mount_options.file_system_id] = mount_id;
 
   base::File::Error result =
@@ -422,10 +446,10 @@
   std::string workgroup;
   std::string username;
 
+  user_manager::User* user =
+      chromeos::ProfileHelper::Get()->GetUserByProfile(profile_);
+  DCHECK(user);
   if (is_kerberos_chromad) {
-    user_manager::User* user =
-        chromeos::ProfileHelper::Get()->GetUserByProfile(profile_);
-    DCHECK(user);
     DCHECK(user->IsActiveDirectoryUser());
 
     ParseUserPrincipalName(user->GetDisplayEmail(), &username, &workgroup);
@@ -456,10 +480,14 @@
   // which expects username & workgroup strings along with a password file
   // descriptor.
   SmbProviderClient::MountOptions smb_mount_options;
+  smb_mount_options.original_path = parsed_url.ToString();
   smb_mount_options.username = username;
   smb_mount_options.workgroup = workgroup;
   smb_mount_options.ntlm_enabled = IsNTLMAuthenticationEnabled();
   smb_mount_options.skip_connect = true;
+  smb_mount_options.restore_password =
+      !username.empty() && !is_kerberos_chromad;
+  smb_mount_options.account_hash = user->username_hash();
   GetSmbProviderClient()->Mount(
       mount_path, smb_mount_options,
       temp_file_manager_->WritePasswordToFile("" /* password */),
diff --git a/chrome/browser/chromeos/smb_client/smb_service.h b/chrome/browser/chromeos/smb_client/smb_service.h
index 7b2b7b1..03e02ab 100644
--- a/chrome/browser/chromeos/smb_client/smb_service.h
+++ b/chrome/browser/chromeos/smb_client/smb_service.h
@@ -76,6 +76,7 @@
              const std::string& password,
              bool use_chromad_kerberos,
              bool should_open_file_manager_after_mount,
+             bool save_credentials,
              MountResponse callback);
 
   // Completes the mounting of an SMB file system, passing |options| on to
@@ -86,6 +87,9 @@
                        const base::FilePath& share_path,
                        bool is_kerberos_chromad,
                        bool should_open_file_manager_after_mount,
+                       const std::string& username,
+                       const std::string& workgroup,
+                       bool save_credentials,
                        smbprovider::ErrorType error,
                        int32_t mount_id);
 
@@ -131,6 +135,7 @@
                  const std::string& password,
                  bool use_chromad_kerberos,
                  bool should_open_file_manager_after_mount,
+                 bool save_credentials,
                  MountResponse callback);
 
   // Retrieves the mount_id for |file_system_info|.
diff --git a/chrome/browser/chromeos/smb_client/smb_service_unittest.cc b/chrome/browser/chromeos/smb_client/smb_service_unittest.cc
index d632dc6..877fc040 100644
--- a/chrome/browser/chromeos/smb_client/smb_service_unittest.cc
+++ b/chrome/browser/chromeos/smb_client/smb_service_unittest.cc
@@ -40,6 +40,7 @@
 using ::testing::AllOf;
 using ::testing::Field;
 using ::testing::Invoke;
+using ::testing::Ne;
 using ::testing::WithArg;
 
 namespace chromeos {
@@ -130,6 +131,7 @@
                             "" /* username */, "" /* password */,
                             false /* use_chromad_kerberos */,
                             false /* should_open_file_manager_after_mount */,
+                            false /* save_credentials */,
                             base::BindOnce(&SaveMountResult, &result));
     EXPECT_EQ(result, SmbMountResult::INVALID_URL);
   }
@@ -140,10 +142,34 @@
                             "" /* username */, "" /* password */,
                             true /* use_chromad_kerberos */,
                             false /* should_open_file_manager_after_mount */,
+                            false /* save_credentials */,
                             base::BindOnce(&SaveMountResult, &result));
     EXPECT_EQ(result, SmbMountResult::INVALID_SSO_URL);
   }
 
+  void WaitForSetupComplete() {
+    {
+      base::RunLoop run_loop;
+      smb_service_->OnSetupCompleteForTesting(run_loop.QuitClosure());
+      run_loop.Run();
+    }
+    {
+      // Share gathering needs to complete at least once before a share can be
+      // mounted.
+      base::RunLoop run_loop;
+      smb_service_->GatherSharesInNetwork(
+          base::DoNothing(),
+          base::BindLambdaForTesting(
+              [&run_loop](const std::vector<SmbUrl>& shares_gathered,
+                          bool done) {
+                if (done) {
+                  run_loop.Quit();
+                }
+              }));
+      run_loop.Run();
+    }
+  }
+
   content::TestBrowserThreadBundle
       thread_bundle_;        // Included so tests magically don't crash.
   TestingProfile* profile_ = nullptr;     // Not owned.
@@ -187,36 +213,20 @@
 
 TEST_F(SmbServiceTest, Mount) {
   CreateFspRegistry(profile_);
-  {
-    CreateService(profile_);
-    base::RunLoop run_loop;
-    smb_service_->OnSetupCompleteForTesting(run_loop.QuitClosure());
-    run_loop.Run();
-  }
-  {
-    // Share gathering needs to complete at least once before a share can be
-    // mounted.
-    base::RunLoop run_loop;
-    smb_service_->GatherSharesInNetwork(
-        base::DoNothing(),
-        base::BindLambdaForTesting(
-            [&run_loop](const std::vector<SmbUrl>& shares_gathered, bool done) {
-              if (done) {
-                run_loop.Quit();
-              }
-            }));
-    run_loop.Run();
-  }
+  CreateService(profile_);
+  WaitForSetupComplete();
 
   base::RunLoop run_loop;
   EXPECT_CALL(
       *mock_client_,
-      Mount(base::FilePath(kMountPath),
-            AllOf(Field(&SmbProviderClient::MountOptions::username, kTestUser),
-                  Field(&SmbProviderClient::MountOptions::workgroup, ""),
-                  Field(&SmbProviderClient::MountOptions::ntlm_enabled, true),
-                  Field(&SmbProviderClient::MountOptions::skip_connect, false)),
-            _, _))
+      Mount(
+          base::FilePath(kMountPath),
+          AllOf(Field(&SmbProviderClient::MountOptions::username, kTestUser),
+                Field(&SmbProviderClient::MountOptions::workgroup, ""),
+                Field(&SmbProviderClient::MountOptions::ntlm_enabled, true),
+                Field(&SmbProviderClient::MountOptions::skip_connect, false),
+                Field(&SmbProviderClient::MountOptions::save_password, false)),
+          _, _))
       .WillOnce(
           WithArg<3>(Invoke([](SmbProviderClient::MountCallback callback) {
             std::move(callback).Run(smbprovider::ErrorType::ERROR_OK, 7);
@@ -226,12 +236,66 @@
       {}, base::FilePath(kSharePath), kTestUser, "password",
       false /* use_chromad_kerberos */,
       false /* should_open_file_manager_after_mount */,
+      false /* save_credentials */,
       base::BindLambdaForTesting([&run_loop](SmbMountResult result) {
         EXPECT_EQ(SmbMountResult::SUCCESS, result);
         run_loop.Quit();
       }));
   run_loop.Run();
 
+  // If |save_credentials| is false, then the username should not be saved in
+  // the file system id.
+  const std::string file_system_id =
+      registry_->file_system_info()->file_system_id();
+  EXPECT_FALSE(IsKerberosChromadFileSystemId(file_system_id));
+  EXPECT_FALSE(GetUserFromFileSystemId(file_system_id));
+
+  // Because the mock is potentially leaked, expectations needs to be manually
+  // verified.
+  EXPECT_TRUE(testing::Mock::VerifyAndClearExpectations(mock_client_));
+}
+
+TEST_F(SmbServiceTest, MountSaveCredentials) {
+  CreateFspRegistry(profile_);
+  CreateService(profile_);
+  WaitForSetupComplete();
+
+  base::RunLoop run_loop;
+  EXPECT_CALL(
+      *mock_client_,
+      Mount(
+          base::FilePath(kMountPath),
+          AllOf(Field(&SmbProviderClient::MountOptions::username, kTestUser),
+                Field(&SmbProviderClient::MountOptions::workgroup, ""),
+                Field(&SmbProviderClient::MountOptions::ntlm_enabled, true),
+                Field(&SmbProviderClient::MountOptions::skip_connect, false),
+                Field(&SmbProviderClient::MountOptions::save_password, true),
+                Field(&SmbProviderClient::MountOptions::account_hash, Ne(""))),
+          _, _))
+      .WillOnce(
+          WithArg<3>(Invoke([](SmbProviderClient::MountCallback callback) {
+            std::move(callback).Run(smbprovider::ErrorType::ERROR_OK, 7);
+          })));
+
+  smb_service_->Mount(
+      {}, base::FilePath(kSharePath), kTestUser, "password",
+      false /* use_chromad_kerberos */,
+      false /* should_open_file_manager_after_mount */,
+      true /* save_credentials */,
+      base::BindLambdaForTesting([&run_loop](SmbMountResult result) {
+        EXPECT_EQ(SmbMountResult::SUCCESS, result);
+        run_loop.Quit();
+      }));
+  run_loop.Run();
+
+  const std::string file_system_id =
+      registry_->file_system_info()->file_system_id();
+  EXPECT_FALSE(IsKerberosChromadFileSystemId(file_system_id));
+  base::Optional<std::string> saved_user =
+      GetUserFromFileSystemId(file_system_id);
+  ASSERT_TRUE(saved_user);
+  EXPECT_EQ(*saved_user, kTestUser);
+
   // Because the mock is potentially leaked, expectations needs to be manually
   // verified.
   EXPECT_TRUE(testing::Mock::VerifyAndClearExpectations(mock_client_));
@@ -253,7 +317,10 @@
   EXPECT_CALL(
       *mock_client_,
       Mount(base::FilePath(kMountPath),
-            Field(&SmbProviderClient::MountOptions::skip_connect, true), _, _))
+            AllOf(Field(&SmbProviderClient::MountOptions::skip_connect, true),
+                  Field(&SmbProviderClient::MountOptions::restore_password,
+                        false)),
+            _, _))
       .WillOnce(WithArg<3>(
           Invoke([&run_loop](SmbProviderClient::MountCallback callback) {
             std::move(callback).Run(smbprovider::ErrorType::ERROR_OK, 7);
@@ -295,7 +362,8 @@
           AllOf(
               Field(&SmbProviderClient::MountOptions::username, "ad-test-user"),
               Field(&SmbProviderClient::MountOptions::workgroup, kTestDomain),
-              Field(&SmbProviderClient::MountOptions::skip_connect, true)),
+              Field(&SmbProviderClient::MountOptions::skip_connect, true),
+              Field(&SmbProviderClient::MountOptions::restore_password, false)),
           _, _))
       .WillOnce(WithArg<3>(
           Invoke([&run_loop](SmbProviderClient::MountCallback callback) {
@@ -330,7 +398,9 @@
           base::FilePath(kMountPath),
           AllOf(Field(&SmbProviderClient::MountOptions::username, kTestUser),
                 Field(&SmbProviderClient::MountOptions::workgroup, kTestDomain),
-                Field(&SmbProviderClient::MountOptions::skip_connect, true)),
+                Field(&SmbProviderClient::MountOptions::skip_connect, true),
+                Field(&SmbProviderClient::MountOptions::restore_password, true),
+                Field(&SmbProviderClient::MountOptions::account_hash, Ne(""))),
           _, _))
       .WillOnce(WithArg<3>(
           Invoke([&run_loop](SmbProviderClient::MountCallback callback) {
@@ -365,7 +435,9 @@
       Mount(base::FilePath(kMountPath),
             AllOf(Field(&SmbProviderClient::MountOptions::username, ""),
                   Field(&SmbProviderClient::MountOptions::workgroup, ""),
-                  Field(&SmbProviderClient::MountOptions::skip_connect, true)),
+                  Field(&SmbProviderClient::MountOptions::skip_connect, true),
+                  Field(&SmbProviderClient::MountOptions::restore_password,
+                        false)),
             _, _))
       .WillOnce(WithArg<3>(
           Invoke([&run_loop](SmbProviderClient::MountCallback callback) {
diff --git a/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc b/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc
index c9aa19e..eca5cae 100644
--- a/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc
+++ b/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc
@@ -81,7 +81,7 @@
 class BlankImageSource : public gfx::CanvasImageSource {
  public:
   explicit BlankImageSource(const gfx::Size& size)
-     : gfx::CanvasImageSource(size, false) {}
+      : gfx::CanvasImageSource(size) {}
   ~BlankImageSource() override {}
 
   void Draw(gfx::Canvas* canvas) override {}
diff --git a/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc b/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc
index 356b2aae..3807fb8 100644
--- a/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc
+++ b/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc
@@ -258,10 +258,10 @@
   // returned.
   extensions::LaunchContainer launch_container =
       GetLaunchContainer(extensions::ExtensionPrefs::Get(context), extension);
-  OpenApplication(AppLaunchParams(Profile::FromBrowserContext(context),
-                                  extension->id(), launch_container,
-                                  WindowOpenDisposition::NEW_FOREGROUND_TAB,
-                                  extensions::SOURCE_MANAGEMENT_API));
+  OpenApplication(AppLaunchParams(
+      Profile::FromBrowserContext(context), extension->id(), launch_container,
+      WindowOpenDisposition::NEW_FOREGROUND_TAB,
+      extensions::AppLaunchSource::kSourceManagementApi));
 
 #if defined(OS_CHROMEOS)
   chromeos::DemoSession::RecordAppLaunchSourceIfInDemoMode(
diff --git a/chrome/browser/extensions/api/notifications/notifications_apitest.cc b/chrome/browser/extensions/api/notifications/notifications_apitest.cc
index 70674c4..4826ad1 100644
--- a/chrome/browser/extensions/api/notifications/notifications_apitest.cc
+++ b/chrome/browser/extensions/api/notifications/notifications_apitest.cc
@@ -205,10 +205,11 @@
   }
 
   void LaunchPlatformApp(const Extension* extension) {
-    OpenApplication(AppLaunchParams(browser()->profile(), extension->id(),
-                                    extensions::LAUNCH_CONTAINER_NONE,
-                                    WindowOpenDisposition::NEW_WINDOW,
-                                    extensions::SOURCE_TEST));
+    OpenApplication(
+        AppLaunchParams(browser()->profile(), extension->id(),
+                        extensions::LaunchContainer::kLaunchContainerNone,
+                        WindowOpenDisposition::NEW_WINDOW,
+                        extensions::AppLaunchSource::kSourceTest));
   }
 
   std::unique_ptr<NotificationDisplayServiceTester> display_service_tester_;
diff --git a/chrome/browser/extensions/bookmark_app_helper_unittest.cc b/chrome/browser/extensions/bookmark_app_helper_unittest.cc
index 654ddc2b..6a51f849 100644
--- a/chrome/browser/extensions/bookmark_app_helper_unittest.cc
+++ b/chrome/browser/extensions/bookmark_app_helper_unittest.cc
@@ -441,19 +441,19 @@
     const Extension* extension =
         service_->GetInstalledExtension(helper.extension()->id());
     EXPECT_TRUE(extension);
-    EXPECT_EQ(LAUNCH_CONTAINER_WINDOW,
+    EXPECT_EQ(LaunchContainer::kLaunchContainerWindow,
               GetLaunchContainer(ExtensionPrefs::Get(profile()), extension));
 
     // Mark the app as not locally installed and check that it now opens in a
     // tab.
     SetBookmarkAppIsLocallyInstalled(profile(), extension, false);
-    EXPECT_EQ(LAUNCH_CONTAINER_TAB,
+    EXPECT_EQ(LaunchContainer::kLaunchContainerTab,
               GetLaunchContainer(ExtensionPrefs::Get(profile()), extension));
 
     // Mark the app as locally installed and check that it now opens in a
     // window.
     SetBookmarkAppIsLocallyInstalled(profile(), extension, true);
-    EXPECT_EQ(LAUNCH_CONTAINER_WINDOW,
+    EXPECT_EQ(LaunchContainer::kLaunchContainerWindow,
               GetLaunchContainer(ExtensionPrefs::Get(profile()), extension));
   }
   {
@@ -472,7 +472,7 @@
     const Extension* extension =
         service_->GetInstalledExtension(helper.extension()->id());
     EXPECT_TRUE(extension);
-    EXPECT_EQ(LAUNCH_CONTAINER_TAB,
+    EXPECT_EQ(LaunchContainer::kLaunchContainerTab,
               GetLaunchContainer(ExtensionPrefs::Get(profile()), extension));
   }
 }
@@ -502,7 +502,7 @@
     content::RunAllTasksUntilIdle();
     ASSERT_TRUE(helper.extension());
     EXPECT_EQ(
-        LAUNCH_CONTAINER_TAB,
+        LaunchContainer::kLaunchContainerTab,
         GetLaunchContainer(ExtensionPrefs::Get(profile()), helper.extension()));
   }
   {
@@ -518,7 +518,7 @@
     content::RunAllTasksUntilIdle();
     ASSERT_TRUE(helper.extension());
     EXPECT_EQ(
-        LAUNCH_CONTAINER_WINDOW,
+        LaunchContainer::kLaunchContainerWindow,
         GetLaunchContainer(ExtensionPrefs::Get(profile()), helper.extension()));
   }
 }
diff --git a/chrome/browser/extensions/browsertest_util.cc b/chrome/browser/extensions/browsertest_util.cc
index 0dc9089..3fe5aba 100644
--- a/chrome/browser/extensions/browsertest_util.cc
+++ b/chrome/browser/extensions/browsertest_util.cc
@@ -97,9 +97,9 @@
 }
 
 Browser* LaunchAppBrowser(Profile* profile, const Extension* extension_app) {
-  EXPECT_TRUE(OpenApplication(
-      AppLaunchParams(profile, extension_app->id(), LAUNCH_CONTAINER_WINDOW,
-                      WindowOpenDisposition::CURRENT_TAB, SOURCE_TEST)));
+  EXPECT_TRUE(OpenApplication(AppLaunchParams(
+      profile, extension_app->id(), LaunchContainer::kLaunchContainerWindow,
+      WindowOpenDisposition::CURRENT_TAB, AppLaunchSource::kSourceTest)));
 
   Browser* browser = chrome::FindLastActive();
   bool is_correct_app_browser =
@@ -112,9 +112,9 @@
 
 Browser* LaunchBrowserForAppInTab(Profile* profile,
                                   const Extension* extension_app) {
-  content::WebContents* web_contents = OpenApplication(
-      AppLaunchParams(profile, extension_app->id(), LAUNCH_CONTAINER_TAB,
-                      WindowOpenDisposition::NEW_FOREGROUND_TAB, SOURCE_TEST));
+  content::WebContents* web_contents = OpenApplication(AppLaunchParams(
+      profile, extension_app->id(), LaunchContainer::kLaunchContainerTab,
+      WindowOpenDisposition::NEW_FOREGROUND_TAB, AppLaunchSource::kSourceTest));
   DCHECK(web_contents);
 
   web_app::WebAppTabHelperBase* tab_helper =
diff --git a/chrome/browser/extensions/chrome_app_icon.cc b/chrome/browser/extensions/chrome_app_icon.cc
index c318eb05..a9c1993 100644
--- a/chrome/browser/extensions/chrome_app_icon.cc
+++ b/chrome/browser/extensions/chrome_app_icon.cc
@@ -28,7 +28,7 @@
 class RoundedCornersImageSource : public gfx::CanvasImageSource {
  public:
   explicit RoundedCornersImageSource(const gfx::ImageSkia& icon)
-      : gfx::CanvasImageSource(icon.size(), false), icon_(icon) {}
+      : gfx::CanvasImageSource(icon.size()), icon_(icon) {}
   ~RoundedCornersImageSource() override {}
 
  private:
diff --git a/chrome/browser/extensions/cross_origin_read_blocking_browsertest.cc b/chrome/browser/extensions/cross_origin_read_blocking_browsertest.cc
index 3b55c6f..b55f9571 100644
--- a/chrome/browser/extensions/cross_origin_read_blocking_browsertest.cc
+++ b/chrome/browser/extensions/cross_origin_read_blocking_browsertest.cc
@@ -997,9 +997,10 @@
   content::WebContents* app_contents = nullptr;
   {
     content::WebContentsAddedObserver new_contents_observer;
-    OpenApplication(AppLaunchParams(
-        browser()->profile(), app->id(), LAUNCH_CONTAINER_NONE,
-        WindowOpenDisposition::NEW_WINDOW, extensions::SOURCE_TEST));
+    OpenApplication(AppLaunchParams(browser()->profile(), app->id(),
+                                    LaunchContainer::kLaunchContainerNone,
+                                    WindowOpenDisposition::NEW_WINDOW,
+                                    extensions::AppLaunchSource::kSourceTest));
     app_contents = new_contents_observer.GetWebContents();
   }
   ASSERT_TRUE(content::WaitForLoadStop(app_contents));
diff --git a/chrome/browser/extensions/extension_apitest.cc b/chrome/browser/extensions/extension_apitest.cc
index dfe81e4f..dce2c4e 100644
--- a/chrome/browser/extensions/extension_apitest.cc
+++ b/chrome/browser/extensions/extension_apitest.cc
@@ -294,8 +294,9 @@
       ui_test_utils::NavigateToURL(browser(), url);
   } else if (launch_platform_app) {
     AppLaunchParams params(browser()->profile(), extension->id(),
-                           LAUNCH_CONTAINER_NONE,
-                           WindowOpenDisposition::NEW_WINDOW, SOURCE_TEST);
+                           LaunchContainer::kLaunchContainerNone,
+                           WindowOpenDisposition::NEW_WINDOW,
+                           AppLaunchSource::kSourceTest);
     params.command_line = *base::CommandLine::ForCurrentProcess();
     OpenApplication(params);
   }
diff --git a/chrome/browser/extensions/extension_browsertest.cc b/chrome/browser/extensions/extension_browsertest.cc
index 4a50970..33571be4 100644
--- a/chrome/browser/extensions/extension_browsertest.cc
+++ b/chrome/browser/extensions/extension_browsertest.cc
@@ -424,8 +424,9 @@
   content::WindowedNotificationObserver app_loaded_observer(
       content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
       content::NotificationService::AllSources());
-  AppLaunchParams params(profile(), app->id(), LAUNCH_CONTAINER_NONE,
-                         WindowOpenDisposition::NEW_WINDOW, SOURCE_TEST);
+  AppLaunchParams params(
+      profile(), app->id(), LaunchContainer::kLaunchContainerNone,
+      WindowOpenDisposition::NEW_WINDOW, AppLaunchSource::kSourceTest);
   params.command_line = *base::CommandLine::ForCurrentProcess();
   OpenApplication(params);
   app_loaded_observer.Wait();
diff --git a/chrome/browser/extensions/launch_util.cc b/chrome/browser/extensions/launch_util.cc
index 73e84c8..06ad059 100644
--- a/chrome/browser/extensions/launch_util.cc
+++ b/chrome/browser/extensions/launch_util.cc
@@ -79,9 +79,11 @@
 
   base::Optional<LaunchContainer> result;
 
-  if (manifest_launch_container == LAUNCH_CONTAINER_PANEL_DEPRECATED) {
+  if (manifest_launch_container ==
+      LaunchContainer::kLaunchContainerPanelDeprecated) {
     result = manifest_launch_container;
-  } else if (manifest_launch_container == LAUNCH_CONTAINER_TAB) {
+  } else if (manifest_launch_container ==
+             LaunchContainer::kLaunchContainerTab) {
     // Look for prefs that indicate the user's choice of launch container. The
     // app's menu on the NTP provides a UI to set this preference.
     LaunchType prefs_launch_type = GetLaunchType(prefs, extension);
@@ -89,31 +91,31 @@
     if (prefs_launch_type == LAUNCH_TYPE_WINDOW) {
       // If the pref is set to launch a window (or no pref is set, and
       // window opening is the default), make the container a window.
-      result = LAUNCH_CONTAINER_WINDOW;
+      result = LaunchContainer::kLaunchContainerWindow;
 #if defined(OS_CHROMEOS)
     } else if (prefs_launch_type == LAUNCH_TYPE_FULLSCREEN) {
       // LAUNCH_TYPE_FULLSCREEN launches in a maximized app window in ash.
       // For desktop chrome AURA on all platforms we should open the
       // application in full screen mode in the current tab, on the same
       // lines as non AURA chrome.
-      result = LAUNCH_CONTAINER_WINDOW;
+      result = LaunchContainer::kLaunchContainerWindow;
 #endif
     } else {
       // All other launch types (tab, pinned, fullscreen) are
       // implemented as tabs in a window.
-      result = LAUNCH_CONTAINER_TAB;
+      result = LaunchContainer::kLaunchContainerTab;
     }
   } else {
     // If a new value for app.launch.container is added, logic for it should be
-    // added here. LAUNCH_CONTAINER_WINDOW is not present because there is no
-    // way to set it in a manifest.
+    // added here. LaunchContainer::kLaunchContainerWindow is not present
+    // because there is no way to set it in a manifest.
     NOTREACHED() << manifest_launch_container;
   }
 
   // All paths should set |result|.
   if (!result) {
     DLOG(FATAL) << "Failed to set a launch container.";
-    result = LAUNCH_CONTAINER_TAB;
+    result = LaunchContainer::kLaunchContainerTab;
   }
 
   return *result;
@@ -124,8 +126,8 @@
   int value = -1;
   LaunchContainer manifest_launch_container =
       AppLaunchInfo::GetLaunchContainer(extension);
-  return manifest_launch_container == LAUNCH_CONTAINER_TAB &&
-      prefs->ReadPrefAsInteger(extension->id(), kPrefLaunchType, &value);
+  return manifest_launch_container == LaunchContainer::kLaunchContainerTab &&
+         prefs->ReadPrefAsInteger(extension->id(), kPrefLaunchType, &value);
 }
 
 bool LaunchesInWindow(content::BrowserContext* context,
diff --git a/chrome/browser/page_load_metrics/observers/use_counter/ukm_features.cc b/chrome/browser/page_load_metrics/observers/use_counter/ukm_features.cc
index 3fbe1dfc..32e005e 100644
--- a/chrome/browser/page_load_metrics/observers/use_counter/ukm_features.cc
+++ b/chrome/browser/page_load_metrics/observers/use_counter/ukm_features.cc
@@ -100,6 +100,14 @@
           WebFeature::kTextFragmentAnchorMatchFound,
           WebFeature::kCookieNoSameSite,
           WebFeature::kCookieInsecureAndSameSiteNone,
+          WebFeature::kDeviceOrientationSecureOrigin,
+          WebFeature::kDeviceOrientationAbsoluteSecureOrigin,
+          WebFeature::kDeviceMotionSecureOrigin,
+          WebFeature::kRelativeOrientationSensorConstructor,
+          WebFeature::kAbsoluteOrientationSensorConstructor,
+          WebFeature::kLinearAccelerationSensorConstructor,
+          WebFeature::kAccelerometerConstructor,
+          WebFeature::kGyroscopeConstructor,
       }));
   return *opt_in_features;
 }
diff --git a/chrome/browser/plugins/plugin_prefs.cc b/chrome/browser/plugins/plugin_prefs.cc
index be469085..8ea5764 100644
--- a/chrome/browser/plugins/plugin_prefs.cc
+++ b/chrome/browser/plugins/plugin_prefs.cc
@@ -11,7 +11,6 @@
 #include "base/bind.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
-#include "base/metrics/histogram_macros.h"
 #include "base/path_service.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -19,7 +18,6 @@
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/plugins/plugin_finder.h"
 #include "chrome/browser/plugins/plugin_metadata.h"
 #include "chrome/browser/plugins/plugin_prefs_factory.h"
@@ -28,16 +26,12 @@
 #include "chrome/common/chrome_content_client.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/pref_names.h"
-#include "components/content_settings/core/browser/host_content_settings_map.h"
-#include "components/content_settings/core/common/content_settings.h"
-#include "components/content_settings/core/common/pref_names.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/plugin_service.h"
-#include "content/public/common/content_constants.h"
 #include "content/public/common/webplugininfo.h"
 
 using content::BrowserThread;
@@ -51,12 +45,6 @@
           base::ASCIIToUTF16(ChromeContentClient::kPDFInternalPluginName));
 }
 
-bool IsAdobeFlashPlayerPlugin(const base::string16& plugin_name) {
-  return (plugin_name == base::ASCIIToUTF16(content::kFlashPluginName) ||
-          plugin_name == base::ASCIIToUTF16(
-              PluginMetadata::kAdobeFlashPlayerGroupName));
-}
-
 }  // namespace
 
 // static
@@ -116,7 +104,6 @@
 void PluginPrefs::SetPrefs(PrefService* prefs) {
   prefs_ = prefs;
   bool update_internal_dir = false;
-  bool plugins_migrated = false;
   base::FilePath last_internal_dir =
       prefs_->GetFilePath(prefs::kPluginsLastInternalDirectory);
   base::FilePath cur_internal_dir;
@@ -138,25 +125,6 @@
           continue;  // Oops, don't know what to do with this item.
         }
 
-        bool enabled = true;
-        if (plugin->GetBoolean("enabled", &enabled))
-          plugin->Remove("enabled", nullptr);
-
-        // Migrate disabled plugins and re-enable them all internally.
-        // TODO(http://crbug.com/662006): Remove migration eventually.
-        if (!enabled) {
-          base::string16 name;
-          plugin->GetString("name", &name);
-          if (IsPDFViewerPlugin(name))
-            prefs->SetBoolean(prefs::kPluginsAlwaysOpenPdfExternally, true);
-          if (IsAdobeFlashPlayerPlugin(name)) {
-            HostContentSettingsMapFactory::GetForProfile(profile_)
-                ->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_PLUGINS,
-                                           CONTENT_SETTING_BLOCK);
-          }
-          plugins_migrated = true;
-        }
-
         base::FilePath::StringType path;
         // The plugin list constains all the plugin files in addition to the
         // plugin groups.
@@ -207,8 +175,6 @@
     }
   }  // Scoped update of prefs::kPluginsPluginsList.
 
-  UMA_HISTOGRAM_BOOLEAN("Plugin.EnabledStatusMigrationDone", plugins_migrated);
-
   always_open_pdf_externally_ =
       prefs_->GetBoolean(prefs::kPluginsAlwaysOpenPdfExternally);
 
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index 8d2cda8..e6c1886f 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -3619,9 +3619,11 @@
   // Launch an app that tries to open a fullscreen window.
   TestAddAppWindowObserver add_window_observer(
       extensions::AppWindowRegistry::Get(browser()->profile()));
-  OpenApplication(AppLaunchParams(
-      browser()->profile(), extension->id(), extensions::LAUNCH_CONTAINER_NONE,
-      WindowOpenDisposition::NEW_WINDOW, extensions::SOURCE_TEST));
+  OpenApplication(
+      AppLaunchParams(browser()->profile(), extension->id(),
+                      extensions::LaunchContainer::kLaunchContainerNone,
+                      WindowOpenDisposition::NEW_WINDOW,
+                      extensions::AppLaunchSource::kSourceTest));
   extensions::AppWindow* window = add_window_observer.WaitForAppWindow();
   ASSERT_TRUE(window);
 
diff --git a/chrome/browser/profiles/profile_avatar_icon_util.cc b/chrome/browser/profiles/profile_avatar_icon_util.cc
index b126966..60eefdc 100644
--- a/chrome/browser/profiles/profile_avatar_icon_util.cc
+++ b/chrome/browser/profiles/profile_avatar_icon_util.cc
@@ -104,7 +104,7 @@
                                      AvatarPosition position,
                                      AvatarBorder border,
                                      profiles::AvatarShape shape)
-    : gfx::CanvasImageSource(canvas_size, false),
+    : gfx::CanvasImageSource(canvas_size),
       canvas_size_(canvas_size),
       width_(width),
       height_(GetScaledAvatarHeightForWidth(width, avatar)),
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
index 7d0a88d..2b14fcf 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -2599,8 +2599,10 @@
     return;
 
   AppLaunchParams launch_params(
-      GetProfile(), pwa->id(), extensions::LAUNCH_CONTAINER_WINDOW,
-      WindowOpenDisposition::CURRENT_TAB, extensions::SOURCE_CONTEXT_MENU);
+      GetProfile(), pwa->id(),
+      extensions::LaunchContainer::kLaunchContainerWindow,
+      WindowOpenDisposition::CURRENT_TAB,
+      extensions::AppLaunchSource::kSourceContextMenu);
   launch_params.override_url = params_.link_url;
   OpenApplication(launch_params);
 }
diff --git a/chrome/browser/safe_browsing/BUILD.gn b/chrome/browser/safe_browsing/BUILD.gn
index b03d7a1..67f3c6e 100644
--- a/chrome/browser/safe_browsing/BUILD.gn
+++ b/chrome/browser/safe_browsing/BUILD.gn
@@ -98,8 +98,8 @@
       "//components/safe_browsing/browser",
       "//components/safe_browsing/common",
       "//components/safe_browsing/common:safe_browsing_prefs",
+      "//components/safe_browsing/db:allowlist_checker_client",
       "//components/safe_browsing/db:metadata_proto",
-      "//components/safe_browsing/db:whitelist_checker_client",
       "//components/safe_browsing/password_protection",
       "//components/safe_browsing/triggers",
       "//components/safe_browsing/triggers:ad_popup_trigger",
diff --git a/chrome/browser/safe_browsing/client_side_detection_host.cc b/chrome/browser/safe_browsing/client_side_detection_host.cc
index 9af27e4..c6c3831 100644
--- a/chrome/browser/safe_browsing/client_side_detection_host.cc
+++ b/chrome/browser/safe_browsing/client_side_detection_host.cc
@@ -25,8 +25,8 @@
 #include "components/prefs/pref_service.h"
 #include "components/safe_browsing/common/safe_browsing.mojom.h"
 #include "components/safe_browsing/common/safe_browsing_prefs.h"
+#include "components/safe_browsing/db/allowlist_checker_client.h"
 #include "components/safe_browsing/db/database_manager.h"
-#include "components/safe_browsing/db/whitelist_checker_client.h"
 #include "components/safe_browsing/proto/csd.pb.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
@@ -240,12 +240,12 @@
     }
 
     // Query the CSD Whitelist asynchronously. We're already on the IO thread so
-    // can call WhitelistCheckerClient directly.
+    // can call AllowlistCheckerClient directly.
     base::Callback<void(bool)> result_callback =
         base::Bind(&ClientSideDetectionHost::ShouldClassifyUrlRequest::
                        OnWhitelistCheckDoneOnIO,
                    this, url, phishing_reason, malware_reason);
-    WhitelistCheckerClient::StartCheckCsdWhitelist(database_manager_, url,
+    AllowlistCheckerClient::StartCheckCsdWhitelist(database_manager_, url,
                                                    result_callback);
   }
 
diff --git a/chrome/browser/sharing/sharing_service.cc b/chrome/browser/sharing/sharing_service.cc
index f1322f2..1e56494 100644
--- a/chrome/browser/sharing/sharing_service.cc
+++ b/chrome/browser/sharing/sharing_service.cc
@@ -13,11 +13,6 @@
 #include "components/sync_device_info/device_info.h"
 #include "components/sync_device_info/device_info_tracker.h"
 
-// Undefine SendMessage defined in Windows headers.
-#ifdef SendMessage
-#undef SendMessage
-#endif
-
 namespace {
 // TODO(knollr): Should this be configurable or shared between similar features?
 constexpr base::TimeDelta kDeviceExpiration = base::TimeDelta::FromDays(2);
@@ -67,7 +62,7 @@
   return device_candidates;
 }
 
-bool SharingService::SendMessage(
+bool SharingService::SendMessageToDevice(
     const std::string& device_guid,
     const chrome_browser_sharing::SharingMessage& message) {
   return true;
diff --git a/chrome/browser/sharing/sharing_service.h b/chrome/browser/sharing/sharing_service.h
index 1d26dd7c..4002fd6 100644
--- a/chrome/browser/sharing/sharing_service.h
+++ b/chrome/browser/sharing/sharing_service.h
@@ -35,8 +35,9 @@
       int required_capabilities) const;
 
   // Sends a message to the device specified by GUID.
-  bool SendMessage(const std::string& device_guid,
-                   const chrome_browser_sharing::SharingMessage& message);
+  bool SendMessageToDevice(
+      const std::string& device_guid,
+      const chrome_browser_sharing::SharingMessage& message);
 
   // Registers a handler of a given SharingMessage payload type.
   void RegisterHandler(
diff --git a/chrome/browser/themes/browser_theme_pack.cc b/chrome/browser/themes/browser_theme_pack.cc
index 9103e98..2173f5d 100644
--- a/chrome/browser/themes/browser_theme_pack.cc
+++ b/chrome/browser/themes/browser_theme_pack.cc
@@ -489,9 +489,8 @@
                            const gfx::ImageSkia& overlay,
                            const color_utils::HSL& hsl_shift,
                            int vertical_offset)
-      : gfx::CanvasImageSource(
-            image_to_tint.isNull() ? overlay.size() : image_to_tint.size(),
-            false),
+      : gfx::CanvasImageSource(image_to_tint.isNull() ? overlay.size()
+                                                      : image_to_tint.size()),
         background_color_(background_color),
         image_to_tint_(image_to_tint),
         overlay_(overlay),
@@ -542,7 +541,7 @@
   ControlButtonBackgroundImageSource(SkColor background_color,
                                      const gfx::ImageSkia& bg_image,
                                      const gfx::Size& dest_size)
-      : gfx::CanvasImageSource(dest_size, false),
+      : gfx::CanvasImageSource(dest_size),
         background_color_(background_color),
         bg_image_(bg_image) {
     DCHECK(!bg_image.isNull());
diff --git a/chrome/browser/ui/app_list/app_list_client_impl_browsertest.cc b/chrome/browser/ui/app_list/app_list_client_impl_browsertest.cc
index 01fc2faa..9d5f2ab 100644
--- a/chrome/browser/ui/app_list/app_list_client_impl_browsertest.cc
+++ b/chrome/browser/ui/app_list/app_list_client_impl_browsertest.cc
@@ -71,9 +71,11 @@
     content::WindowedNotificationObserver app_loaded_observer(
         content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
         content::NotificationService::AllSources());
-    OpenApplication(AppLaunchParams(
-        profile(), extension_app->id(), extensions::LAUNCH_CONTAINER_WINDOW,
-        WindowOpenDisposition::NEW_WINDOW, extensions::SOURCE_TEST));
+    OpenApplication(
+        AppLaunchParams(profile(), extension_app->id(),
+                        extensions::LaunchContainer::kLaunchContainerWindow,
+                        WindowOpenDisposition::NEW_WINDOW,
+                        extensions::AppLaunchSource::kSourceTest));
     app_loaded_observer.Wait();
   }
   EXPECT_TRUE(delegate->IsAppOpen(extension_app->id()));
diff --git a/chrome/browser/ui/app_list/internal_app/internal_app_metadata.cc b/chrome/browser/ui/app_list/internal_app/internal_app_metadata.cc
index b712f71..a37b08c 100644
--- a/chrome/browser/ui/app_list/internal_app/internal_app_metadata.cc
+++ b/chrome/browser/ui/app_list/internal_app/internal_app_metadata.cc
@@ -162,7 +162,8 @@
   if (extension) {
     AppListClientImpl* controller = AppListClientImpl::GetInstance();
     AppLaunchParams params = CreateAppLaunchParamsWithEventFlags(
-        profile, extension, event_flags, extensions::SOURCE_APP_LAUNCHER,
+        profile, extension, event_flags,
+        extensions::AppLaunchSource::kSourceAppLauncher,
         controller->GetAppListDisplayId());
     params.launch_id = ash::ShelfID(extension->id()).launch_id;
     OpenApplication(params);
diff --git a/chrome/browser/ui/app_list/search/arc/arc_app_data_search_result.cc b/chrome/browser/ui/app_list/search/arc/arc_app_data_search_result.cc
index a70c90a..724c931 100644
--- a/chrome/browser/ui/app_list/search/arc/arc_app_data_search_result.cc
+++ b/chrome/browser/ui/app_list/search/arc/arc_app_data_search_result.cc
@@ -52,7 +52,7 @@
 class AvatarImageSource : public gfx::CanvasImageSource {
  public:
   AvatarImageSource(gfx::ImageSkia avatar, int size)
-      : CanvasImageSource(gfx::Size(size, size), false), radius_(size / 2) {
+      : CanvasImageSource(gfx::Size(size, size)), radius_(size / 2) {
     avatar_ = gfx::ImageSkiaOperations::CreateResizedImage(
         avatar, skia::ImageOperations::RESIZE_BEST, gfx::Size(size, size));
   }
diff --git a/chrome/browser/ui/app_list/search/arc/arc_playstore_search_result.cc b/chrome/browser/ui/app_list/search/arc/arc_playstore_search_result.cc
index f513d72..5584176 100644
--- a/chrome/browser/ui/app_list/search/arc/arc_playstore_search_result.cc
+++ b/chrome/browser/ui/app_list/search/arc/arc_playstore_search_result.cc
@@ -40,7 +40,7 @@
 class BadgeBackgroundImageSource : public gfx::CanvasImageSource {
  public:
   explicit BadgeBackgroundImageSource(int size, float padding)
-      : CanvasImageSource(gfx::Size(size, size), false), padding_(padding) {}
+      : CanvasImageSource(gfx::Size(size, size)), padding_(padding) {}
   ~BadgeBackgroundImageSource() override = default;
 
  private:
diff --git a/chrome/browser/ui/app_list/search/launcher_search/launcher_search_icon_image_loader_unittest.cc b/chrome/browser/ui/app_list/search/launcher_search/launcher_search_icon_image_loader_unittest.cc
index 45e8c8ed..6cd5caf0 100644
--- a/chrome/browser/ui/app_list/search/launcher_search/launcher_search_icon_image_loader_unittest.cc
+++ b/chrome/browser/ui/app_list/search/launcher_search/launcher_search_icon_image_loader_unittest.cc
@@ -32,7 +32,7 @@
 class FillColorImageSource : public gfx::CanvasImageSource {
  public:
   FillColorImageSource(const gfx::Size& image_size, const SkColor fill_color)
-      : CanvasImageSource(image_size, false), fill_color_(fill_color) {}
+      : CanvasImageSource(image_size), fill_color_(fill_color) {}
 
   void Draw(gfx::Canvas* canvas) override {
     canvas->FillRect(gfx::Rect(size()), fill_color_);
diff --git a/chrome/browser/ui/app_list/search/mixer.cc b/chrome/browser/ui/app_list/search/mixer.cc
index 907b880..ad9e6a9 100644
--- a/chrome/browser/ui/app_list/search/mixer.cc
+++ b/chrome/browser/ui/app_list/search/mixer.cc
@@ -171,9 +171,11 @@
   return non_app_ranker_.get();
 }
 
-void Mixer::Train(const std::string& id, RankingItemType type) {
+void Mixer::Train(const std::string& query,
+                  const std::string& id,
+                  RankingItemType type) {
   if (non_app_ranker_)
-    non_app_ranker_->Train(id, type);
+    non_app_ranker_->Train(query, id, type);
 }
 
 }  // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/mixer.h b/chrome/browser/ui/app_list/search/mixer.h
index 93b766bd..cc7be061 100644
--- a/chrome/browser/ui/app_list/search/mixer.h
+++ b/chrome/browser/ui/app_list/search/mixer.h
@@ -8,6 +8,7 @@
 #include <stddef.h>
 
 #include <memory>
+#include <string>
 #include <vector>
 
 #include "base/gtest_prod_util.h"
@@ -59,7 +60,9 @@
   SearchResultRanker* GetNonAppSearchResultRanker();
 
   // Handle a training signal.
-  void Train(const std::string& id, RankingItemType type);
+  void Train(const std::string& query,
+             const std::string& id,
+             RankingItemType type);
 
   // Used for sorting and mixing results.
   struct SortData {
diff --git a/chrome/browser/ui/app_list/search/search_controller.cc b/chrome/browser/ui/app_list/search/search_controller.cc
index 5b7331f..7bdb8faa 100644
--- a/chrome/browser/ui/app_list/search/search_controller.cc
+++ b/chrome/browser/ui/app_list/search/search_controller.cc
@@ -215,7 +215,7 @@
 
   for (const auto& provider : providers_)
     provider->Train(id, type);
-  mixer_->Train(id, type);
+  mixer_->Train(base::UTF16ToUTF8(last_query_), id, type);
 }
 
 }  // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker_config.proto b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker_config.proto
index 856da67..2d5a700 100644
--- a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker_config.proto
+++ b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker_config.proto
@@ -13,17 +13,12 @@
 // Warning: this cannot contain any map fields, as they cannot be relied upon
 // for a consistent hash.
 message RecurrenceRankerConfigProto {
-  // Fields with IDs 1 (target_limit) and 2 (target_decay_coeff) have been
-  // deleted.
-  reserved 1;
-  reserved 2;
+  required uint32 min_seconds_between_saves = 1;
 
-  required uint32 min_seconds_between_saves = 3;
-
-  required uint32 target_limit = 4;
-  required float target_decay = 5;
-  required uint32 condition_limit = 6;
-  required float condition_decay = 7;
+  required uint32 target_limit = 2;
+  required float target_decay = 3;
+  required uint32 condition_limit = 4;
+  required float condition_decay = 5;
 
   // Config for a fake predictor, used for testing.
   message FakePredictorConfig {}
@@ -34,19 +29,17 @@
 
   // Config for a frecency predictor.
   message ZeroStateFrecencyPredictorConfig {
-    // Field 201 (target_limit) has been deleted.
-    reserved 201;
     // The frecency parameter used to control the frequency-recency tradeoff
     // that determines when targets are removed. Must be in [0.5, 1.0], with 0.5
     // meaning only-recency and 1.0 meaning only-frequency.
-    required float decay_coeff = 202;
+    required float decay_coeff = 1;
   }
 
   message ZeroStateHourBinPredictorConfig {
     // The decay coeffficient number that control the decay rate. The decay is
     // once a week.
-    required float weekly_decay_coeff = 301;
-    map<int32, float> bin_weights_map = 302;
+    required float weekly_decay_coeff = 1;
+    map<int32, float> bin_weights_map = 2;
   }
 
   // The choice of which kind of predictor to use, and its configuration.
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.cc b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.cc
index c040272..6e057dd 100644
--- a/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.cc
+++ b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.cc
@@ -189,7 +189,8 @@
   time_of_last_fetch_ = now;
 
   // TODO(931149): The passed |query| should be used to choose between ranking
-  // results with using a zero-state or query-based model.
+  // results with using a zero-state or query-based model. It may also be needed
+  // for rankings from the query model.
 
   if (results_list_group_ranker_) {
     group_ranks_.clear();
@@ -236,7 +237,11 @@
   }
 }
 
-void SearchResultRanker::Train(const std::string& id, RankingItemType type) {
+void SearchResultRanker::Train(const std::string& query,
+                               const std::string& id,
+                               RankingItemType type) {
+  // TODO(931149): Use the passed |query| as part of the training for the query
+  // model if it requires it.
   if (ModelForType(type) == Model::MIXED_TYPES) {
     if (results_list_group_ranker_) {
       results_list_group_ranker_->Record(
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.h b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.h
index 95f109d..acdcbfc 100644
--- a/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.h
+++ b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.h
@@ -47,10 +47,13 @@
   void Rank(Mixer::SortedResults* results);
 
   // Forwards the given training signal to the relevant models contained within
-  // the SearchResultRanker. |id| is the string ID of an item that is launched
-  // from the launcher, eg. an app ID or a filepath, and is derived from the
-  // relevant ChromeSearchResult's ID.
-  void Train(const std::string& id, RankingItemType type);
+  // the SearchResultRanker. |query| is the user's search string, which may be
+  // empty. |id| is the string ID of an item that is launched from the launcher,
+  // eg. an app ID or a filepath, and is derived from the relevant
+  // ChromeSearchResult's ID.
+  void Train(const std::string& query,
+             const std::string& id,
+             RankingItemType type);
 
   // file_manager::file_tasks::FileTaskObserver:
   void OnFilesOpened(const std::vector<FileOpenEvent>& file_opens) override;
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker_unittest.cc b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker_unittest.cc
index c1ea9fd..5593be0 100644
--- a/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker_unittest.cc
+++ b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker_unittest.cc
@@ -135,7 +135,7 @@
 TEST_F(SearchResultRankerTest, MixedTypesRankersAreDisabledWithFlag) {
   auto ranker = MakeRanker(false);
   for (int i = 0; i < 20; ++i)
-    ranker->Train("unused", RankingItemType::kFile);
+    ranker->Train("query", "unused", RankingItemType::kFile);
   ranker->FetchRankings(base::string16());
 
   auto results =
@@ -154,7 +154,7 @@
   auto ranker = MakeRanker(
       true, {{"use_category_model", "true"}, {"boost_coefficient", "1.0"}});
   for (int i = 0; i < 20; ++i)
-    ranker->Train("unused", RankingItemType::kFile);
+    ranker->Train("query", "unused", RankingItemType::kFile);
   ranker->FetchRankings(base::string16());
 
   auto results =
@@ -174,8 +174,8 @@
   auto ranker = MakeRanker(true, {{"boost_coefficient", "1.0"}});
 
   for (int i = 0; i < 10; ++i) {
-    ranker->Train("C", RankingItemType::kFile);
-    ranker->Train("D", RankingItemType::kFile);
+    ranker->Train("query", "C", RankingItemType::kFile);
+    ranker->Train("query", "D", RankingItemType::kFile);
   }
   ranker->FetchRankings(base::string16());
 
@@ -205,8 +205,8 @@
   auto ranker = MakeRanker(true, {{"boost_coefficient", "1.0"}});
 
   for (int i = 0; i < 5; ++i) {
-    ranker->Train(url_1, RankingItemType::kOmniboxHistory);
-    ranker->Train(url_3, RankingItemType::kOmniboxHistory);
+    ranker->Train("query", url_1, RankingItemType::kOmniboxHistory);
+    ranker->Train("query", url_3, RankingItemType::kOmniboxHistory);
   }
   ranker->FetchRankings(base::string16());
 
diff --git a/chrome/browser/ui/ash/chrome_new_window_client.cc b/chrome/browser/ui/ash/chrome_new_window_client.cc
index 813a6fe0..2ca790ff 100644
--- a/chrome/browser/ui/ash/chrome_new_window_client.cc
+++ b/chrome/browser/ui/ash/chrome_new_window_client.cc
@@ -362,7 +362,7 @@
       service->GetInstalledExtension(kFileManagerAppId);
   OpenApplication(CreateAppLaunchParamsUserContainer(
       profile, extension, WindowOpenDisposition::NEW_FOREGROUND_TAB,
-      extensions::SOURCE_KEYBOARD));
+      extensions::AppLaunchSource::kSourceKeyboard));
 }
 
 void ChromeNewWindowClient::OpenCrosh() {
@@ -460,7 +460,7 @@
 
   const extensions::Extension* extension =
       extensions::util::GetInstalledPwaForUrl(
-          profile, url, extensions::LAUNCH_CONTAINER_WINDOW);
+          profile, url, extensions::LaunchContainer::kLaunchContainerWindow);
   if (!extension) {
     OpenUrlFromArc(url);
     return;
@@ -468,7 +468,7 @@
 
   AppLaunchParams params = CreateAppLaunchParamsUserContainer(
       profile, extension, WindowOpenDisposition::NEW_WINDOW,
-      extensions::SOURCE_ARC);
+      extensions::AppLaunchSource::kSourceArc);
   params.override_url = url;
   content::WebContents* tab = OpenApplication(params);
   if (!tab)
diff --git a/chrome/browser/ui/ash/kiosk_next_shell_client.cc b/chrome/browser/ui/ash/kiosk_next_shell_client.cc
index 866454a..4f46a996 100644
--- a/chrome/browser/ui/ash/kiosk_next_shell_client.cc
+++ b/chrome/browser/ui/ash/kiosk_next_shell_client.cc
@@ -49,5 +49,5 @@
           extension_misc::kKioskNextHomeAppId);
   DCHECK(app);
   apps::LaunchPlatformApp(profile, app,
-                          extensions::AppLaunchSource::SOURCE_CHROME_INTERNAL);
+                          extensions::AppLaunchSource::kSourceChromeInternal);
 }
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
index f1d8bcc..a10ca99 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
@@ -225,7 +225,8 @@
     EXPECT_TRUE(extension);
 
     OpenApplication(AppLaunchParams(profile(), extension->id(), container,
-                                    disposition, extensions::SOURCE_TEST));
+                                    disposition,
+                                    extensions::AppLaunchSource::kSourceTest));
     return extension;
   }
 
@@ -886,7 +887,8 @@
 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, LaunchUnpinned) {
   TabStripModel* tab_strip = browser()->tab_strip_model();
   int tab_count = tab_strip->count();
-  LoadAndLaunchExtension("app1", extensions::LAUNCH_CONTAINER_TAB,
+  LoadAndLaunchExtension("app1",
+                         extensions::LaunchContainer::kLaunchContainerTab,
                          WindowOpenDisposition::NEW_FOREGROUND_TAB);
   EXPECT_EQ(++tab_count, tab_strip->count());
   ash::ShelfID shortcut_id = CreateShortcut("app1");
@@ -904,7 +906,8 @@
 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, LaunchInBackground) {
   TabStripModel* tab_strip = browser()->tab_strip_model();
   int tab_count = tab_strip->count();
-  LoadAndLaunchExtension("app1", extensions::LAUNCH_CONTAINER_TAB,
+  LoadAndLaunchExtension("app1",
+                         extensions::LaunchContainer::kLaunchContainerTab,
                          WindowOpenDisposition::NEW_BACKGROUND_TAB);
   EXPECT_EQ(++tab_count, tab_strip->count());
   controller_->LaunchApp(ash::ShelfID(last_loaded_extension_id()),
@@ -1129,9 +1132,9 @@
 // before it was closed.
 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, AppWindowRestoreBehaviorTest) {
   // Open an App, maximized its window, and close it.
-  const Extension* extension =
-      LoadAndLaunchExtension("app1", extensions::LAUNCH_CONTAINER_WINDOW,
-                             WindowOpenDisposition::NEW_WINDOW);
+  const Extension* extension = LoadAndLaunchExtension(
+      "app1", extensions::LaunchContainer::kLaunchContainerWindow,
+      WindowOpenDisposition::NEW_WINDOW);
   Browser* app_browser = FindBrowserForApp(extension->id());
   ASSERT_TRUE(app_browser);
   BrowserWindow* window = app_browser->window();
@@ -1141,9 +1144,9 @@
   CloseAppBrowserWindow(app_browser);
 
   // Reopen the App. It should start maximized. Un-maximize it and close it.
-  extension =
-      LoadAndLaunchExtension("app1", extensions::LAUNCH_CONTAINER_WINDOW,
-                             WindowOpenDisposition::NEW_WINDOW);
+  extension = LoadAndLaunchExtension(
+      "app1", extensions::LaunchContainer::kLaunchContainerWindow,
+      WindowOpenDisposition::NEW_WINDOW);
   app_browser = FindBrowserForApp(extension->id());
   ASSERT_TRUE(app_browser);
   window = app_browser->window();
@@ -1155,9 +1158,9 @@
   CloseAppBrowserWindow(app_browser);
 
   // Reopen the App. It should start un-maximized.
-  extension =
-      LoadAndLaunchExtension("app1", extensions::LAUNCH_CONTAINER_WINDOW,
-                             WindowOpenDisposition::NEW_WINDOW);
+  extension = LoadAndLaunchExtension(
+      "app1", extensions::LaunchContainer::kLaunchContainerWindow,
+      WindowOpenDisposition::NEW_WINDOW);
   app_browser = FindBrowserForApp(extension->id());
   ASSERT_TRUE(app_browser);
   window = app_browser->window();
@@ -1173,18 +1176,20 @@
   EXPECT_EQ(0u, items);
   EXPECT_EQ(0u, running_browser);
 
-  const Extension* extension =
-      LoadAndLaunchExtension("app1", extensions::LAUNCH_CONTAINER_WINDOW,
-                             WindowOpenDisposition::NEW_WINDOW);
+  const Extension* extension = LoadAndLaunchExtension(
+      "app1", extensions::LaunchContainer::kLaunchContainerWindow,
+      WindowOpenDisposition::NEW_WINDOW);
   ASSERT_TRUE(extension);
 
   // No new browser should get detected, even though one more is running.
   EXPECT_EQ(0u, NumberOfDetectedLauncherBrowsers(false));
   EXPECT_EQ(++running_browser, chrome::GetTotalBrowserCount());
 
-  OpenApplication(AppLaunchParams(
-      profile(), extension->id(), extensions::LAUNCH_CONTAINER_TAB,
-      WindowOpenDisposition::NEW_WINDOW, extensions::SOURCE_TEST));
+  OpenApplication(
+      AppLaunchParams(profile(), extension->id(),
+                      extensions::LaunchContainer::kLaunchContainerTab,
+                      WindowOpenDisposition::NEW_WINDOW,
+                      extensions::AppLaunchSource::kSourceTest));
 
   // A new browser should get detected and one more should be running.
   EXPECT_EQ(NumberOfDetectedLauncherBrowsers(false), 1u);
@@ -1195,20 +1200,23 @@
 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTestNoDefaultBrowser,
                        EnumerateAllBrowsersAndTabs) {
   // Create at least one browser.
-  LoadAndLaunchExtension("app1", extensions::LAUNCH_CONTAINER_TAB,
+  LoadAndLaunchExtension("app1",
+                         extensions::LaunchContainer::kLaunchContainerTab,
                          WindowOpenDisposition::NEW_WINDOW);
   size_t browsers = NumberOfDetectedLauncherBrowsers(false);
   size_t tabs = NumberOfDetectedLauncherBrowsers(true);
 
   // Create a second browser.
-  LoadAndLaunchExtension("app1", extensions::LAUNCH_CONTAINER_TAB,
+  LoadAndLaunchExtension("app1",
+                         extensions::LaunchContainer::kLaunchContainerTab,
                          WindowOpenDisposition::NEW_WINDOW);
 
   EXPECT_EQ(++browsers, NumberOfDetectedLauncherBrowsers(false));
   EXPECT_EQ(++tabs, NumberOfDetectedLauncherBrowsers(true));
 
   // Create only a tab.
-  LoadAndLaunchExtension("app1", extensions::LAUNCH_CONTAINER_TAB,
+  LoadAndLaunchExtension("app1",
+                         extensions::LaunchContainer::kLaunchContainerTab,
                          WindowOpenDisposition::NEW_FOREGROUND_TAB);
 
   EXPECT_EQ(browsers, NumberOfDetectedLauncherBrowsers(false));
@@ -1520,7 +1528,8 @@
   EXPECT_TRUE(browser1->window()->IsActive());
 
   // Create another app and make sure that none of our browsers is active.
-  LoadAndLaunchExtension("app1", extensions::LAUNCH_CONTAINER_TAB,
+  LoadAndLaunchExtension("app1",
+                         extensions::LaunchContainer::kLaunchContainerTab,
                          WindowOpenDisposition::NEW_WINDOW);
   EXPECT_FALSE(browser1->window()->IsActive());
   EXPECT_FALSE(browser2->window()->IsActive());
@@ -1700,8 +1709,9 @@
   // Create a windowed application.
   AppLaunchParams params = CreateAppLaunchParamsUserContainer(
       profile(), GetExtensionForAppID(extensions::kWebStoreAppId, profile()),
-      WindowOpenDisposition::NEW_FOREGROUND_TAB, extensions::SOURCE_TEST);
-  params.container = extensions::LAUNCH_CONTAINER_WINDOW;
+      WindowOpenDisposition::NEW_FOREGROUND_TAB,
+      extensions::AppLaunchSource::kSourceTest);
+  params.container = extensions::LaunchContainer::kLaunchContainerWindow;
   OpenApplication(params);
   EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(id)->status);
 
diff --git a/chrome/browser/ui/ash/launcher/launcher_controller_helper.cc b/chrome/browser/ui/ash/launcher/launcher_controller_helper.cc
index bdbba5e..5f118f0 100644
--- a/chrome/browser/ui/ash/launcher/launcher_controller_helper.cc
+++ b/chrome/browser/ui/ash/launcher/launcher_controller_helper.cc
@@ -252,8 +252,8 @@
 
   // The app will be created for the currently active profile.
   AppLaunchParams params = CreateAppLaunchParamsWithEventFlags(
-      profile_, extension, event_flags, extensions::SOURCE_APP_LAUNCHER,
-      display_id);
+      profile_, extension, event_flags,
+      extensions::AppLaunchSource::kSourceAppLauncher, display_id);
   if ((source == ash::LAUNCH_FROM_APP_LIST ||
        source == ash::LAUNCH_FROM_APP_LIST_SEARCH) &&
       app_id == extensions::kWebStoreAppId) {
diff --git a/chrome/browser/ui/ash/launcher/shelf_spinner_controller.cc b/chrome/browser/ui/ash/launcher/shelf_spinner_controller.cc
index 5aaf0a7..018cdf0 100644
--- a/chrome/browser/ui/ash/launcher/shelf_spinner_controller.cc
+++ b/chrome/browser/ui/ash/launcher/shelf_spinner_controller.cc
@@ -30,7 +30,7 @@
   SpinningEffectSource(const base::WeakPtr<ShelfSpinnerController>& host,
                        const std::string& app_id,
                        const gfx::ImageSkia& image)
-      : gfx::CanvasImageSource(image.size(), false /* is opaque */),
+      : gfx::CanvasImageSource(image.size()),
         host_(host),
         app_id_(app_id),
         image_(image) {}
diff --git a/chrome/browser/ui/ash/wallpaper_controller_client.cc b/chrome/browser/ui/ash/wallpaper_controller_client.cc
index e3b718e..95a43f3 100644
--- a/chrome/browser/ui/ash/wallpaper_controller_client.cc
+++ b/chrome/browser/ui/ash/wallpaper_controller_client.cc
@@ -450,9 +450,11 @@
   if (!extension)
     return;
 
-  OpenApplication(AppLaunchParams(
-      profile, extension->id(), extensions::LAUNCH_CONTAINER_WINDOW,
-      WindowOpenDisposition::NEW_WINDOW, extensions::SOURCE_CHROME_INTERNAL));
+  OpenApplication(
+      AppLaunchParams(profile, extension->id(),
+                      extensions::LaunchContainer::kLaunchContainerWindow,
+                      WindowOpenDisposition::NEW_WINDOW,
+                      extensions::AppLaunchSource::kSourceChromeInternal));
 }
 
 void WallpaperControllerClient::OnReadyToSetWallpaper() {
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc
index 29916d8..efa3a605 100644
--- a/chrome/browser/ui/browser_browsertest.cc
+++ b/chrome/browser/ui/browser_browsertest.cc
@@ -1254,10 +1254,11 @@
   const Extension* extension_app = GetExtension();
 
   // Launch it in a window, as AppLauncherHandler::HandleLaunchApp() would.
-  WebContents* app_window = OpenApplication(AppLaunchParams(
-      browser()->profile(), extension_app->id(),
-      extensions::LAUNCH_CONTAINER_WINDOW, WindowOpenDisposition::NEW_WINDOW,
-      extensions::SOURCE_TEST));
+  WebContents* app_window = OpenApplication(
+      AppLaunchParams(browser()->profile(), extension_app->id(),
+                      extensions::LaunchContainer::kLaunchContainerWindow,
+                      WindowOpenDisposition::NEW_WINDOW,
+                      extensions::AppLaunchSource::kSourceTest));
   ASSERT_TRUE(app_window);
 
   DevToolsWindow* devtools_window =
@@ -1423,10 +1424,11 @@
   ASSERT_TRUE(extension_app);
 
   // Launch it in a window, as AppLauncherHandler::HandleLaunchApp() would.
-  WebContents* app_window = OpenApplication(AppLaunchParams(
-      browser()->profile(), extension_app->id(),
-      extensions::LAUNCH_CONTAINER_WINDOW, WindowOpenDisposition::NEW_WINDOW,
-      extensions::SOURCE_TEST));
+  WebContents* app_window = OpenApplication(
+      AppLaunchParams(browser()->profile(), extension_app->id(),
+                      extensions::LaunchContainer::kLaunchContainerWindow,
+                      WindowOpenDisposition::NEW_WINDOW,
+                      extensions::AppLaunchSource::kSourceTest));
   ASSERT_TRUE(app_window);
 
   // Apps launched in a window from the NTP have an extensions tab helper with
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc
index 54e9b05..3b0b7635 100644
--- a/chrome/browser/ui/browser_commands.cc
+++ b/chrome/browser/ui/browser_commands.cc
@@ -597,7 +597,7 @@
   if (extension && extension->is_hosted_app()) {
     const auto app_launch_params = CreateAppLaunchParamsUserContainer(
         browser->profile(), extension, WindowOpenDisposition::NEW_WINDOW,
-        extensions::SOURCE_KEYBOARD);
+        extensions::AppLaunchSource::kSourceKeyboard);
     OpenApplicationWindow(
         app_launch_params,
         extensions::AppLaunchInfo::GetLaunchWebURL(extension));
diff --git a/chrome/browser/ui/browser_navigator.cc b/chrome/browser/ui/browser_navigator.cc
index f2e24a95..441d74e 100644
--- a/chrome/browser/ui/browser_navigator.cc
+++ b/chrome/browser/ui/browser_navigator.cc
@@ -146,7 +146,8 @@
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   if (params.open_pwa_window_if_possible) {
     const extensions::Extension* app = extensions::util::GetInstalledPwaForUrl(
-        profile, params.url, extensions::LAUNCH_CONTAINER_WINDOW);
+        profile, params.url,
+        extensions::LaunchContainer::kLaunchContainerWindow);
     if (app) {
       std::string app_name =
           web_app::GenerateApplicationNameFromAppId(app->id());
diff --git a/chrome/browser/ui/chrome_pages.cc b/chrome/browser/ui/chrome_pages.cc
index b31c47a..ea85962 100644
--- a/chrome/browser/ui/chrome_pages.cc
+++ b/chrome/browser/ui/chrome_pages.cc
@@ -102,16 +102,17 @@
         switches::kDisableDefaultApps));
     return;
   }
-  extensions::AppLaunchSource app_launch_source(extensions::SOURCE_UNTRACKED);
+  extensions::AppLaunchSource app_launch_source(
+      extensions::AppLaunchSource::kSourceUntracked);
   switch (source) {
     case HELP_SOURCE_KEYBOARD:
-      app_launch_source = extensions::SOURCE_KEYBOARD;
+      app_launch_source = extensions::AppLaunchSource::kSourceKeyboard;
       break;
     case HELP_SOURCE_MENU:
-      app_launch_source = extensions::SOURCE_SYSTEM_TRAY;
+      app_launch_source = extensions::AppLaunchSource::kSourceSystemTray;
       break;
     case HELP_SOURCE_WEBUI:
-      app_launch_source = extensions::SOURCE_ABOUT_PAGE;
+      app_launch_source = extensions::AppLaunchSource::kSourceAboutPage;
       break;
     default:
       NOTREACHED() << "Unhandled help source" << source;
diff --git a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm
index 423a790..ce6103d 100644
--- a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm
+++ b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm
@@ -59,9 +59,11 @@
       content::WindowedNotificationObserver app_loaded_observer(
           content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
           content::NotificationService::AllSources());
-      OpenApplication(AppLaunchParams(
-          profile(), app_->id(), extensions::LAUNCH_CONTAINER_NONE,
-          WindowOpenDisposition::NEW_WINDOW, extensions::SOURCE_TEST));
+      OpenApplication(
+          AppLaunchParams(profile(), app_->id(),
+                          extensions::LaunchContainer::kLaunchContainerNone,
+                          WindowOpenDisposition::NEW_WINDOW,
+                          extensions::AppLaunchSource::kSourceTest));
       app_loaded_observer.Wait();
     }
   }
diff --git a/chrome/browser/ui/extensions/app_launch_params.cc b/chrome/browser/ui/extensions/app_launch_params.cc
index 7683d3d..75bc932c 100644
--- a/chrome/browser/ui/extensions/app_launch_params.cc
+++ b/chrome/browser/ui/extensions/app_launch_params.cc
@@ -19,10 +19,10 @@
 using extensions::ExtensionPrefs;
 
 AppLaunchParams::AppLaunchParams(Profile* profile,
-                                 const web_app::AppId& app_id,
-                                 extensions::LaunchContainer container,
+                                 const std::string& app_id,
+                                 apps::mojom::LaunchContainer container,
                                  WindowOpenDisposition disposition,
-                                 extensions::AppLaunchSource source,
+                                 apps::mojom::AppLaunchSource source,
                                  int64_t display_id)
     : profile(profile),
       app_id(app_id),
@@ -41,10 +41,10 @@
     Profile* profile,
     const extensions::Extension* extension,
     WindowOpenDisposition disposition,
-    extensions::AppLaunchSource source) {
+    apps::mojom::AppLaunchSource source) {
   // Look up the app preference to find out the right launch container. Default
   // is to launch as a regular tab.
-  extensions::LaunchContainer container =
+  apps::mojom::LaunchContainer container =
       extensions::GetLaunchContainer(ExtensionPrefs::Get(profile), extension);
   return AppLaunchParams(profile, extension->id(), container, disposition,
                          source);
@@ -54,19 +54,19 @@
     Profile* profile,
     const extensions::Extension* extension,
     int event_flags,
-    extensions::AppLaunchSource source,
+    apps::mojom::AppLaunchSource source,
     int64_t display_id) {
   WindowOpenDisposition raw_disposition =
       ui::DispositionFromEventFlags(event_flags);
 
-  extensions::LaunchContainer container;
+  apps::mojom::LaunchContainer container;
   WindowOpenDisposition disposition;
   if (raw_disposition == WindowOpenDisposition::NEW_FOREGROUND_TAB ||
       raw_disposition == WindowOpenDisposition::NEW_BACKGROUND_TAB) {
-    container = extensions::LAUNCH_CONTAINER_TAB;
+    container = apps::mojom::LaunchContainer::kLaunchContainerTab;
     disposition = raw_disposition;
   } else if (raw_disposition == WindowOpenDisposition::NEW_WINDOW) {
-    container = extensions::LAUNCH_CONTAINER_WINDOW;
+    container = apps::mojom::LaunchContainer::kLaunchContainerWindow;
     disposition = raw_disposition;
   } else {
     // Look at preference to find the right launch container.  If no preference
diff --git a/chrome/browser/ui/extensions/app_launch_params.h b/chrome/browser/ui/extensions/app_launch_params.h
index ff3aad2c..9a9e17d 100644
--- a/chrome/browser/ui/extensions/app_launch_params.h
+++ b/chrome/browser/ui/extensions/app_launch_params.h
@@ -9,9 +9,7 @@
 
 #include "base/command_line.h"
 #include "base/files/file_path.h"
-#include "chrome/browser/web_applications/components/web_app_helpers.h"
-#include "chrome/common/extensions/extension_constants.h"
-#include "extensions/common/constants.h"
+#include "components/services/app_service/public/mojom/types.mojom.h"
 #include "ui/base/window_open_disposition.h"
 #include "ui/display/types/display_constants.h"
 #include "ui/gfx/geometry/rect.h"
@@ -29,10 +27,10 @@
 
 struct AppLaunchParams {
   AppLaunchParams(Profile* profile,
-                  const web_app::AppId& app_id,
-                  extensions::LaunchContainer container,
+                  const std::string& app_id,
+                  apps::mojom::LaunchContainer container,
                   WindowOpenDisposition disposition,
-                  extensions::AppLaunchSource source,
+                  apps::mojom::AppLaunchSource source,
                   int64_t display_id = display::kInvalidDisplayId);
 
   AppLaunchParams(const AppLaunchParams& other);
@@ -43,14 +41,14 @@
   Profile* profile;
 
   // The app to launch.
-  web_app::AppId app_id;
+  std::string app_id;
 
   // An id that can be passed to an app when launched in order to support
   // multiple shelf items per app.
   std::string launch_id;
 
   // The container type to launch the application in.
-  extensions::LaunchContainer container;
+  apps::mojom::LaunchContainer container;
 
   // If container is TAB, this field controls how the tab is opened.
   WindowOpenDisposition disposition;
@@ -75,7 +73,7 @@
 
   // Record where the app is launched from for tracking purpose.
   // Different app may have their own enumeration of sources.
-  extensions::AppLaunchSource source;
+  apps::mojom::AppLaunchSource source;
 
   // The id of the display from which the app is launched.
   // display::kInvalidDisplayId means that the display does not exist or is not
@@ -93,7 +91,7 @@
     Profile* profile,
     const extensions::Extension* extension,
     WindowOpenDisposition disposition,
-    extensions::AppLaunchSource source);
+    apps::mojom::AppLaunchSource source);
 
 // Helper to create AppLaunchParams using event flags that allows user to
 // override the user-configured container using modifier keys, falling back to
@@ -103,7 +101,7 @@
     Profile* profile,
     const extensions::Extension* extension,
     int event_flags,
-    extensions::AppLaunchSource source,
+    apps::mojom::AppLaunchSource source,
     int64_t display_id);
 
 #endif  // CHROME_BROWSER_UI_EXTENSIONS_APP_LAUNCH_PARAMS_H_
diff --git a/chrome/browser/ui/extensions/application_launch.cc b/chrome/browser/ui/extensions/application_launch.cc
index 420562c6..e94fad3f 100644
--- a/chrome/browser/ui/extensions/application_launch.cc
+++ b/chrome/browser/ui/extensions/application_launch.cc
@@ -160,7 +160,8 @@
     Profile* profile,
     extensions::LaunchContainer container,
     const Extension* extension) {
-  if (!extension || container != extensions::LAUNCH_CONTAINER_WINDOW)
+  if (!extension ||
+      container != extensions::LaunchContainer::kLaunchContainerWindow)
     return ui::SHOW_STATE_DEFAULT;
 
   if (chrome::IsRunningInForcedAppMode())
@@ -287,8 +288,7 @@
   }
 
   UMA_HISTOGRAM_ENUMERATION("Extensions.HostedAppLaunchContainer",
-                            params.container,
-                            extensions::NUM_LAUNCH_CONTAINERS);
+                            params.container);
 
   GURL url = UrlForExtension(extension, params.override_url);
 
@@ -297,16 +297,16 @@
   prefs->SetLastLaunchTime(extension->id(), base::Time::Now());
 
   switch (params.container) {
-    case extensions::LAUNCH_CONTAINER_NONE: {
+    case extensions::LaunchContainer::kLaunchContainerNone: {
       NOTREACHED();
       break;
     }
     // Panels are deprecated. Launch a normal window instead.
-    case extensions::LAUNCH_CONTAINER_PANEL_DEPRECATED:
-    case extensions::LAUNCH_CONTAINER_WINDOW:
+    case extensions::LaunchContainer::kLaunchContainerPanelDeprecated:
+    case extensions::LaunchContainer::kLaunchContainerWindow:
       tab = OpenApplicationWindow(params, url);
       break;
-    case extensions::LAUNCH_CONTAINER_TAB: {
+    case extensions::LaunchContainer::kLaunchContainerTab: {
       tab = OpenApplicationTab(params, url);
       break;
     }
@@ -317,11 +317,9 @@
 
   if (extension->from_bookmark()) {
     UMA_HISTOGRAM_ENUMERATION("Extensions.BookmarkAppLaunchSource",
-                              params.source,
-                              extensions::NUM_APP_LAUNCH_SOURCES);
+                              params.source);
     UMA_HISTOGRAM_ENUMERATION("Extensions.BookmarkAppLaunchContainer",
-                              params.container,
-                              extensions::NUM_LAUNCH_CONTAINERS);
+                              params.container);
 
     // Record the launch time in the site engagement service. A recent bookmark
     // app launch will provide an engagement boost to the origin.
@@ -465,11 +463,12 @@
 
 WebContents* OpenAppShortcutWindow(Profile* profile,
                                    const GURL& url) {
-  AppLaunchParams launch_params(profile,
-                                std::string(),  // this is a URL app. No app id.
-                                extensions::LAUNCH_CONTAINER_WINDOW,
-                                WindowOpenDisposition::NEW_WINDOW,
-                                extensions::SOURCE_COMMAND_LINE);
+  AppLaunchParams launch_params(
+      profile,
+      std::string(),  // this is a URL app. No app id.
+      extensions::LaunchContainer::kLaunchContainerWindow,
+      WindowOpenDisposition::NEW_WINDOW,
+      extensions::AppLaunchSource::kSourceCommandLine);
   launch_params.override_url = url;
 
   WebContents* tab = OpenApplicationWindow(launch_params, url);
diff --git a/chrome/browser/ui/extensions/extension_installed_notification.cc b/chrome/browser/ui/extensions/extension_installed_notification.cc
index d63de75..1546c55 100644
--- a/chrome/browser/ui/extensions/extension_installed_notification.cc
+++ b/chrome/browser/ui/extensions/extension_installed_notification.cc
@@ -74,6 +74,6 @@
 
   AppLaunchParams params = CreateAppLaunchParamsUserContainer(
       profile_, extension, WindowOpenDisposition::NEW_FOREGROUND_TAB,
-      extensions::SOURCE_INSTALLED_NOTIFICATION);
+      extensions::AppLaunchSource::kSourceInstalledNotification);
   OpenApplication(params);
 }
diff --git a/chrome/browser/ui/extensions/hosted_app_browser_controller.cc b/chrome/browser/ui/extensions/hosted_app_browser_controller.cc
index f73ab443..771fb2a 100644
--- a/chrome/browser/ui/extensions/hosted_app_browser_controller.cc
+++ b/chrome/browser/ui/extensions/hosted_app_browser_controller.cc
@@ -73,7 +73,7 @@
                  const GURL& page_url,
                  content::BrowserContext* profile) {
   const Extension* app_for_window = extensions::util::GetInstalledPwaForUrl(
-      profile, app_url, extensions::LAUNCH_CONTAINER_WINDOW);
+      profile, app_url, extensions::LaunchContainer::kLaunchContainerWindow);
 
   // We don't have a scope, fall back to same origin check.
   if (!app_for_window)
@@ -81,7 +81,8 @@
 
   return app_for_window ==
          extensions::util::GetInstalledPwaForUrl(
-             profile, page_url, extensions::LAUNCH_CONTAINER_WINDOW);
+             profile, page_url,
+             extensions::LaunchContainer::kLaunchContainerWindow);
 }
 
 // static
diff --git a/chrome/browser/ui/extensions/hosted_app_browsertest.cc b/chrome/browser/ui/extensions/hosted_app_browsertest.cc
index 72887321..fdf0aca 100644
--- a/chrome/browser/ui/extensions/hosted_app_browsertest.cc
+++ b/chrome/browser/ui/extensions/hosted_app_browsertest.cc
@@ -888,9 +888,9 @@
   const extensions::Extension* app = InstallBookmarkApp(web_app_info);
 
   AppLaunchParams params(browser()->profile(), app->id(),
-                         extensions::LaunchContainer::LAUNCH_CONTAINER_WINDOW,
+                         extensions::LaunchContainer::kLaunchContainerWindow,
                          WindowOpenDisposition::NEW_WINDOW,
-                         extensions::AppLaunchSource::SOURCE_FILE_HANDLER);
+                         extensions::AppLaunchSource::kSourceFileHandler);
 
   content::TestNavigationObserver navigation_observer(
       web_app_info.file_handler->action);
@@ -1374,7 +1374,7 @@
   // Installed PWAs should launch in their own window.
   EXPECT_EQ(extensions::GetLaunchContainer(
                 extensions::ExtensionPrefs::Get(browser()->profile()), app),
-            extensions::LAUNCH_CONTAINER_WINDOW);
+            extensions::LaunchContainer::kLaunchContainerWindow);
 
   EXPECT_EQ(1, user_action_tester.GetActionCount("InstallWebAppFromMenu"));
   EXPECT_EQ(0, user_action_tester.GetActionCount("CreateShortcut"));
@@ -1397,7 +1397,7 @@
   // Bookmark apps to PWAs should launch in a tab.
   EXPECT_EQ(extensions::GetLaunchContainer(
                 extensions::ExtensionPrefs::Get(browser()->profile()), app),
-            extensions::LAUNCH_CONTAINER_TAB);
+            extensions::LaunchContainer::kLaunchContainerTab);
 
   EXPECT_EQ(0, user_action_tester.GetActionCount("InstallWebAppFromMenu"));
   EXPECT_EQ(1, user_action_tester.GetActionCount("CreateShortcut"));
diff --git a/chrome/browser/ui/extensions/icon_with_badge_image_source.cc b/chrome/browser/ui/extensions/icon_with_badge_image_source.cc
index 6fbd107..c566b03 100644
--- a/chrome/browser/ui/extensions/icon_with_badge_image_source.cc
+++ b/chrome/browser/ui/extensions/icon_with_badge_image_source.cc
@@ -54,7 +54,7 @@
 IconWithBadgeImageSource::Badge::~Badge() {}
 
 IconWithBadgeImageSource::IconWithBadgeImageSource(const gfx::Size& size)
-    : gfx::CanvasImageSource(size, false) {}
+    : gfx::CanvasImageSource(size) {}
 
 IconWithBadgeImageSource::~IconWithBadgeImageSource() {}
 
diff --git a/chrome/browser/ui/permission_bubble/permission_bubble_browser_test_util.cc b/chrome/browser/ui/permission_bubble/permission_bubble_browser_test_util.cc
index b9d1fab..55829ae 100644
--- a/chrome/browser/ui/permission_bubble/permission_bubble_browser_test_util.cc
+++ b/chrome/browser/ui/permission_bubble/permission_bubble_browser_test_util.cc
@@ -59,10 +59,11 @@
       LoadExtension(test_data_dir_.AppendASCII("app_with_panel_container/"));
   CHECK(extension);
 
-  AppLaunchParams params(browser()->profile(), extension->id(),
-                         extensions::LAUNCH_CONTAINER_PANEL_DEPRECATED,
-                         WindowOpenDisposition::NEW_WINDOW,
-                         extensions::SOURCE_TEST);
+  AppLaunchParams params(
+      browser()->profile(), extension->id(),
+      extensions::LaunchContainer::kLaunchContainerPanelDeprecated,
+      WindowOpenDisposition::NEW_WINDOW,
+      extensions::AppLaunchSource::kSourceTest);
 
   content::WebContents* app_window = OpenApplication(params);
   CHECK(app_window);
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_drag_drop_views.cc b/chrome/browser/ui/views/bookmarks/bookmark_drag_drop_views.cc
index a1554c41..912bb51 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_drag_drop_views.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_drag_drop_views.cc
@@ -74,7 +74,7 @@
   BookmarkDragImageSource(const base::string16& title,
                           const gfx::ImageSkia& icon,
                           size_t count)
-      : gfx::CanvasImageSource(kBookmarkDragImageSize, false),
+      : gfx::CanvasImageSource(kBookmarkDragImageSize),
         title_(title),
         icon_(icon),
         count_(count) {}
diff --git a/chrome/browser/ui/views/frame/browser_window_property_manager_browsertest_win.cc b/chrome/browser/ui/views/frame/browser_window_property_manager_browsertest_win.cc
index ef8cb02..5b4818a 100644
--- a/chrome/browser/ui/views/frame/browser_window_property_manager_browsertest_win.cc
+++ b/chrome/browser/ui/views/frame/browser_window_property_manager_browsertest_win.cc
@@ -198,10 +198,11 @@
       LoadExtension(test_data_dir_.AppendASCII("app/"));
   EXPECT_TRUE(extension);
 
-  OpenApplication(AppLaunchParams(browser()->profile(), extension->id(),
-                                  extensions::LAUNCH_CONTAINER_WINDOW,
-                                  WindowOpenDisposition::NEW_FOREGROUND_TAB,
-                                  extensions::SOURCE_TEST));
+  OpenApplication(
+      AppLaunchParams(browser()->profile(), extension->id(),
+                      extensions::LaunchContainer::kLaunchContainerWindow,
+                      WindowOpenDisposition::NEW_FOREGROUND_TAB,
+                      extensions::AppLaunchSource::kSourceTest));
 
   // Check that the new browser has an app name.
   // The launch should have created a new browser.
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
index b40448e..aa6038b 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
@@ -67,9 +67,8 @@
                                      int dest_width,
                                      int dest_height,
                                      bool draw_mirrored)
-      : gfx::CanvasImageSource(
-            bg_image.isNull() ? gfx::Size(1, 1) : bg_image.size(),
-            false),
+      : gfx::CanvasImageSource(bg_image.isNull() ? gfx::Size(1, 1)
+                                                 : bg_image.size()),
         bg_image_(bg_image),
         source_x_(source_x),
         source_y_(source_y),
diff --git a/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.cc b/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.cc
index 49fdb1d..7c6b3c3a 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.cc
@@ -106,9 +106,7 @@
 
 PlaceholderImageSource::PlaceholderImageSource(const gfx::Size& canvas_size,
                                                SkColor color)
-    : gfx::CanvasImageSource(canvas_size, false),
-      color_(color),
-      size_(canvas_size) {}
+    : gfx::CanvasImageSource(canvas_size), color_(color), size_(canvas_size) {}
 
 PlaceholderImageSource::~PlaceholderImageSource() = default;
 
@@ -146,7 +144,7 @@
 EncircledImageSource::EncircledImageSource(const int radius,
                                            const SkColor color,
                                            const gfx::ImageSkia& image)
-    : gfx::CanvasImageSource(gfx::Size(radius * 2, radius * 2), false),
+    : gfx::CanvasImageSource(gfx::Size(radius * 2, radius * 2)),
       radius_(radius),
       color_(color),
       image_(image) {}
diff --git a/chrome/browser/ui/views/select_file_dialog_extension.cc b/chrome/browser/ui/views/select_file_dialog_extension.cc
index 509ecbc..9a63051 100644
--- a/chrome/browser/ui/views/select_file_dialog_extension.cc
+++ b/chrome/browser/ui/views/select_file_dialog_extension.cc
@@ -11,9 +11,11 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/singleton.h"
 #include "base/single_thread_task_runner.h"
+#include "base/strings/stringprintf.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/app_mode/app_mode_utils.h"
 #include "chrome/browser/apps/platform_apps/app_window_registry_util.h"
+#include "chrome/browser/chromeos/extensions/file_manager/select_file_dialog_extension_user_data.h"
 #include "chrome/browser/chromeos/file_manager/app_id.h"
 #include "chrome/browser/chromeos/file_manager/fileapi_util.h"
 #include "chrome/browser/chromeos/file_manager/select_file_dialog_util.h"
@@ -166,11 +168,9 @@
 // static
 SelectFileDialogExtension::RoutingID
 SelectFileDialogExtension::GetRoutingIDFromWebContents(
-    const content::WebContents* web_contents) {
-  // Use the raw pointer value as the identifier. Previously we have used the
-  // tab ID for the purpose, but some web_contents, especially those of the
-  // packaged apps, don't have tab IDs assigned.
-  return web_contents;
+    content::WebContents* web_contents) {
+  return base::StringPrintf("web.%d",
+                            web_contents->GetMainFrame()->GetFrameTreeNodeId());
 }
 
 // TODO(jamescook): Move this into a new file shell_dialogs_chromeos.cc
@@ -400,6 +400,9 @@
     return;
   }
 
+  SelectFileDialogExtensionUserData::SetRoutingIdForWebContents(
+      dialog->host()->host_contents(), routing_id);
+
   // Connect our listener to FileDialogFunction's per-tab callbacks.
   AddPending(routing_id);
 
diff --git a/chrome/browser/ui/views/select_file_dialog_extension.h b/chrome/browser/ui/views/select_file_dialog_extension.h
index af9a221..6c2e095 100644
--- a/chrome/browser/ui/views/select_file_dialog_extension.h
+++ b/chrome/browser/ui/views/select_file_dialog_extension.h
@@ -35,9 +35,9 @@
  public:
   // Opaque ID type for identifying the tab spawned each dialog, unique for
   // every WebContents.
-  typedef const void* RoutingID;
+  typedef std::string RoutingID;
   static RoutingID GetRoutingIDFromWebContents(
-      const content::WebContents* web_contents);
+      content::WebContents* web_contents);
 
   static SelectFileDialogExtension* Create(
       ui::SelectFileDialog::Listener* listener,
diff --git a/chrome/browser/ui/views/status_icons/status_icon_linux_wrapper.cc b/chrome/browser/ui/views/status_icons/status_icon_linux_wrapper.cc
index 09dbb2a..9745cf3 100644
--- a/chrome/browser/ui/views/status_icons/status_icon_linux_wrapper.cc
+++ b/chrome/browser/ui/views/status_icons/status_icon_linux_wrapper.cc
@@ -27,6 +27,20 @@
 // Prefix for app indicator ids
 const char kAppIndicatorIdPrefix[] = "chrome_app_indicator_";
 
+gfx::ImageSkia GetBestImageRep(const gfx::ImageSkia& image) {
+  float best_scale = 0.0f;
+  SkBitmap best_rep;
+  for (const auto& rep : image.image_reps()) {
+    if (rep.scale() > best_scale) {
+      best_scale = rep.scale();
+      best_rep = rep.GetBitmap();
+    }
+  }
+  // All status icon implementations want the image in pixel coordinates, so use
+  // a scale factor of 1.
+  return gfx::ImageSkia(gfx::ImageSkiaRep(best_rep, 1.0f));
+}
+
 }  // namespace
 
 StatusIconLinuxWrapper::StatusIconLinuxWrapper(
@@ -36,7 +50,7 @@
     const base::string16& tool_tip)
     : status_icon_(std::move(status_icon)),
       status_icon_type_(status_icon_type),
-      image_(image),
+      image_(GetBestImageRep(image)),
       tool_tip_(tool_tip),
       menu_model_(nullptr) {
   status_icon_->SetDelegate(this);
@@ -48,9 +62,9 @@
 }
 
 void StatusIconLinuxWrapper::SetImage(const gfx::ImageSkia& image) {
-  image_ = image;
+  image_ = GetBestImageRep(image);
   if (status_icon_)
-    status_icon_->SetIcon(image);
+    status_icon_->SetIcon(image_);
 }
 
 void StatusIconLinuxWrapper::SetToolTip(const base::string16& tool_tip) {
diff --git a/chrome/browser/ui/views/status_icons/status_icon_linux_x11.cc b/chrome/browser/ui/views/status_icons/status_icon_linux_x11.cc
index 6941b80..56dbca9 100644
--- a/chrome/browser/ui/views/status_icons/status_icon_linux_x11.cc
+++ b/chrome/browser/ui/views/status_icons/status_icon_linux_x11.cc
@@ -17,7 +17,10 @@
 #include "ui/aura/window_tree_host.h"
 #include "ui/base/x/x11_util.h"
 #include "ui/events/platform/x11/x11_event_source.h"
+#include "ui/gfx/canvas.h"
 #include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/scoped_canvas.h"
+#include "ui/gfx/transform.h"
 #include "ui/gfx/x/x11.h"
 #include "ui/gfx/x/x11_atom_cache.h"
 #include "ui/gfx/x/x11_error_tracker.h"
@@ -37,12 +40,12 @@
 
 }  // namespace
 
-StatusIconLinuxX11::StatusIconLinuxX11() : ImageButton(this) {}
+StatusIconLinuxX11::StatusIconLinuxX11() : Button(this) {}
 
 StatusIconLinuxX11::~StatusIconLinuxX11() = default;
 
 void StatusIconLinuxX11::SetIcon(const gfx::ImageSkia& image) {
-  SetImage(views::Button::STATE_NORMAL, image);
+  // Nothing to do.
 }
 
 void StatusIconLinuxX11::SetToolTip(const base::string16& tool_tip) {
@@ -71,7 +74,7 @@
 
   auto host = std::make_unique<views::DesktopWindowTreeHostX11>(
       widget_.get(), native_widget.get());
-  aura::WindowTreeHost* window_tree_host = host.get();
+  host_ = host.get();
 
   int visual_id;
   if (ui::GetIntProperty(manager, "_NET_SYSTEM_TRAY_VISUAL", &visual_id))
@@ -98,15 +101,14 @@
 
   widget_->Init(params);
 
-  Window window = window_tree_host->GetAcceleratedWidget();
+  Window window = host_->GetAcceleratedWidget();
   DCHECK(window);
 
   widget_->SetContentsView(this);
   set_owned_by_client();
 
+  SetBorder(nullptr);
   SetIcon(delegate_->GetImage());
-  SetImageHorizontalAlignment(ALIGN_CENTER);
-  SetImageVerticalAlignment(ALIGN_MIDDLE);
   SetTooltipText(delegate_->GetToolTip());
   set_context_menu_controller(this);
 
@@ -154,3 +156,29 @@
 void StatusIconLinuxX11::ButtonPressed(Button* sender, const ui::Event& event) {
   delegate_->OnClick();
 }
+
+void StatusIconLinuxX11::PaintButtonContents(gfx::Canvas* canvas) {
+  gfx::ScopedCanvas scoped_canvas(canvas);
+  canvas->UndoDeviceScaleFactor();
+
+  gfx::Rect bounds = host_->GetBoundsInPixels();
+  const gfx::ImageSkia& image = delegate_->GetImage();
+
+  // If the image fits in the window, center it.  But if it won't fit, downscale
+  // it preserving aspect ratio.
+  float scale =
+      std::min({1.0f, static_cast<float>(bounds.width()) / image.width(),
+                static_cast<float>(bounds.height()) / image.height()});
+  float x_offset = (bounds.width() - scale * image.width()) / 2.0f;
+  float y_offset = (bounds.height() - scale * image.height()) / 2.0f;
+
+  gfx::Transform transform;
+  transform.Translate(x_offset, y_offset);
+  transform.Scale(scale, scale);
+  canvas->Transform(transform);
+
+  cc::PaintFlags flags;
+  flags.setFilterQuality(kHigh_SkFilterQuality);
+  canvas->DrawImageInt(image, 0, 0, image.width(), image.height(), 0, 0,
+                       image.width(), image.height(), true, flags);
+}
diff --git a/chrome/browser/ui/views/status_icons/status_icon_linux_x11.h b/chrome/browser/ui/views/status_icons/status_icon_linux_x11.h
index 94732fd..6c73148dc 100644
--- a/chrome/browser/ui/views/status_icons/status_icon_linux_x11.h
+++ b/chrome/browser/ui/views/status_icons/status_icon_linux_x11.h
@@ -11,15 +11,18 @@
 #include "ui/gfx/x/x11_types.h"
 #include "ui/views/context_menu_controller.h"
 #include "ui/views/controls/button/button.h"
-#include "ui/views/controls/button/image_button.h"
 #include "ui/views/controls/menu/menu_runner.h"
 #include "ui/views/linux_ui/status_icon_linux.h"
 #include "ui/views/widget/widget.h"
 
+namespace aura {
+class WindowTreeHost;
+}
+
 // A status icon that uses the XEmbed protocol.
 // https://standards.freedesktop.org/xembed-spec/xembed-spec-latest.html
 class StatusIconLinuxX11 : public views::StatusIconLinux,
-                           public views::ImageButton,
+                           public views::Button,
                            public views::ContextMenuController,
                            public views::ButtonListener {
  public:
@@ -40,9 +43,14 @@
   // views::ButtonListener:
   void ButtonPressed(Button* sender, const ui::Event& event) override;
 
+  // views::Button:
+  void PaintButtonContents(gfx::Canvas* canvas) override;
+
  private:
   std::unique_ptr<views::Widget> widget_;
 
+  aura::WindowTreeHost* host_ = nullptr;
+
   std::unique_ptr<views::MenuRunner> menu_runner_;
 
   DISALLOW_COPY_AND_ASSIGN(StatusIconLinuxX11);
diff --git a/chrome/browser/ui/web_applications/system_web_app_ui_utils_chromeos.cc b/chrome/browser/ui/web_applications/system_web_app_ui_utils_chromeos.cc
index 637a0d3..0d13937 100644
--- a/chrome/browser/ui/web_applications/system_web_app_ui_utils_chromeos.cc
+++ b/chrome/browser/ui/web_applications/system_web_app_ui_utils_chromeos.cc
@@ -65,7 +65,7 @@
 
   // TODO(calamity): Plumb through better launch sources from callsites.
   AppLaunchParams params = CreateAppLaunchParamsWithEventFlags(
-      profile, extension, 0, extensions::SOURCE_CHROME_INTERNAL,
+      profile, extension, 0, extensions::AppLaunchSource::kSourceChromeInternal,
       display::kInvalidDisplayId);
   params.override_url = url;
 
diff --git a/chrome/browser/ui/web_applications/web_app_dialog_utils.cc b/chrome/browser/ui/web_applications/web_app_dialog_utils.cc
index 8d03069..d7d077c 100644
--- a/chrome/browser/ui/web_applications/web_app_dialog_utils.cc
+++ b/chrome/browser/ui/web_applications/web_app_dialog_utils.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/web_applications/components/install_manager.h"
+#include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/components/web_app_install_utils.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/common/chrome_features.h"
diff --git a/chrome/browser/ui/webui/chromeos/smb_shares/smb_handler.cc b/chrome/browser/ui/webui/chromeos/smb_shares/smb_handler.cc
index 0779b397..a92482d 100644
--- a/chrome/browser/ui/webui/chromeos/smb_shares/smb_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/smb_shares/smb_handler.cc
@@ -82,10 +82,11 @@
   auto mount_response =
       base::BindOnce(&SmbHandler::HandleSmbMountResponse,
                      weak_ptr_factory_.GetWeakPtr(), callback_id);
-  auto mount_call = base::BindOnce(
-      &smb_client::SmbService::Mount, base::Unretained(service), mo,
-      base::FilePath(mount_url), username, password, use_kerberos,
-      should_open_file_manager_after_mount, std::move(mount_response));
+  auto mount_call =
+      base::BindOnce(&smb_client::SmbService::Mount, base::Unretained(service),
+                     mo, base::FilePath(mount_url), username, password,
+                     use_kerberos, should_open_file_manager_after_mount,
+                     false /* save_credentials */, std::move(mount_response));
 
   if (host_discovery_done_) {
     std::move(mount_call).Run();
diff --git a/chrome/browser/ui/webui/flags_ui.cc b/chrome/browser/ui/webui/flags_ui.cc
index fb09bb6..3970a7c 100644
--- a/chrome/browser/ui/webui/flags_ui.cc
+++ b/chrome/browser/ui/webui/flags_ui.cc
@@ -248,9 +248,9 @@
                                       &user_flags,
                                       flags_ui::kAddSentinels);
 
-  // Apply additional switches from policy that should not be dropped when
-  // applying flags..
-  chromeos::UserSessionManager::MaybeAppendPolicySwitches(
+  // Adhere to policy-enforced command-line switch handling when
+  // applying modified flags..
+  chromeos::UserSessionManager::ApplyUserPolicyToSwitches(
       Profile::FromWebUI(web_ui())->GetPrefs(), &user_flags);
 
   base::CommandLine::StringVector flags;
diff --git a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
index 7566eb77..eb64fce 100644
--- a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
+++ b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
@@ -182,8 +182,10 @@
   value->SetString("icon_small", small_icon.spec());
   value->SetBoolean("icon_small_exists", has_non_default_small_icon);
 
-  value->SetInteger("launch_container",
-                    extensions::AppLaunchInfo::GetLaunchContainer(extension));
+  value->SetInteger(
+      "launch_container",
+      static_cast<int>(
+          extensions::AppLaunchInfo::GetLaunchContainer(extension)));
   ExtensionPrefs* prefs = ExtensionPrefs::Get(service->profile());
   value->SetInteger("launch_type", extensions::GetLaunchType(prefs, extension));
   value->SetBoolean("is_component",
@@ -521,11 +523,12 @@
       disposition == WindowOpenDisposition::NEW_BACKGROUND_TAB ||
       disposition == WindowOpenDisposition::NEW_WINDOW) {
     // TODO(jamescook): Proper support for background tabs.
-    AppLaunchParams params(profile, extension_id,
-                           disposition == WindowOpenDisposition::NEW_WINDOW
-                               ? extensions::LAUNCH_CONTAINER_WINDOW
-                               : extensions::LAUNCH_CONTAINER_TAB,
-                           disposition, extensions::SOURCE_NEW_TAB_PAGE);
+    AppLaunchParams params(
+        profile, extension_id,
+        disposition == WindowOpenDisposition::NEW_WINDOW
+            ? extensions::LaunchContainer::kLaunchContainerWindow
+            : extensions::LaunchContainer::kLaunchContainerTab,
+        disposition, extensions::AppLaunchSource::kSourceNewTabPage);
     params.override_url = override_url;
     OpenApplication(params);
   } else {
@@ -541,7 +544,7 @@
         profile, extension,
         old_contents ? WindowOpenDisposition::CURRENT_TAB
                      : WindowOpenDisposition::NEW_FOREGROUND_TAB,
-        extensions::SOURCE_NEW_TAB_PAGE);
+        extensions::AppLaunchSource::kSourceNewTabPage);
     params.override_url = override_url;
     WebContents* new_contents = OpenApplication(params);
 
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn
index 0e62a8cf..a79c0ccd 100644
--- a/chrome/browser/web_applications/BUILD.gn
+++ b/chrome/browser/web_applications/BUILD.gn
@@ -52,6 +52,8 @@
     deps += [
       "//ash/public/cpp:cpp",
       "//chromeos/constants",
+      "//components/arc:arc_base",
+      "//components/arc/common",
     ]
   }
 
@@ -128,7 +130,12 @@
   ]
 
   if (is_chromeos) {
-    deps += [ "//chrome/browser/chromeos" ]
+    deps += [
+      "//chrome/browser/chromeos",
+      "//components/arc:arc",
+      "//components/arc:arc_test_support",
+      "//components/arc/common",
+    ]
   }
 }
 
diff --git a/chrome/browser/web_applications/components/web_app_constants.h b/chrome/browser/web_applications/components/web_app_constants.h
index bbad365f..4ceadfc 100644
--- a/chrome/browser/web_applications/components/web_app_constants.h
+++ b/chrome/browser/web_applications/components/web_app_constants.h
@@ -39,7 +39,11 @@
   kInstallManagerDestroyed = 8,
   kWindowOpened = 9,
   kNotValidManifestForWebApp = 10,
-  kMaxValue = kNotValidManifestForWebApp,
+  // We have terminated the installation pipeline and intented to the Play
+  // Store, where the user still needs to accept the Play installation prompt to
+  // install.
+  kIntentToPlayStore = 11,
+  kMaxValue = kIntentToPlayStore
 };
 
 // Where an app was installed from. This affects what flags will be used when
diff --git a/chrome/browser/web_applications/components/web_app_icon_generator.cc b/chrome/browser/web_applications/components/web_app_icon_generator.cc
index b365af0..97d71cd 100644
--- a/chrome/browser/web_applications/components/web_app_icon_generator.cc
+++ b/chrome/browser/web_applications/components/web_app_icon_generator.cc
@@ -36,7 +36,7 @@
   explicit GeneratedIconImageSource(base::char16 letter,
                                     SkColor color,
                                     int output_size)
-      : gfx::CanvasImageSource(gfx::Size(output_size, output_size), false),
+      : gfx::CanvasImageSource(gfx::Size(output_size, output_size)),
         letter_(letter),
         color_(color),
         output_size_(output_size) {}
diff --git a/chrome/browser/web_applications/extensions/install_manager_bookmark_app_unittest.cc b/chrome/browser/web_applications/extensions/install_manager_bookmark_app_unittest.cc
index 18204a6..02486273 100644
--- a/chrome/browser/web_applications/extensions/install_manager_bookmark_app_unittest.cc
+++ b/chrome/browser/web_applications/extensions/install_manager_bookmark_app_unittest.cc
@@ -507,19 +507,19 @@
 
     const Extension* extension = InstallWebAppFromManifestWithFallback();
 
-    EXPECT_EQ(LAUNCH_CONTAINER_WINDOW,
+    EXPECT_EQ(LaunchContainer::kLaunchContainerWindow,
               GetLaunchContainer(ExtensionPrefs::Get(profile()), extension));
 
     // Mark the app as not locally installed and check that it now opens in a
     // tab.
     SetBookmarkAppIsLocallyInstalled(profile(), extension, false);
-    EXPECT_EQ(LAUNCH_CONTAINER_TAB,
+    EXPECT_EQ(LaunchContainer::kLaunchContainerTab,
               GetLaunchContainer(ExtensionPrefs::Get(profile()), extension));
 
     // Mark the app as locally installed and check that it now opens in a
     // window.
     SetBookmarkAppIsLocallyInstalled(profile(), extension, true);
-    EXPECT_EQ(LAUNCH_CONTAINER_WINDOW,
+    EXPECT_EQ(LaunchContainer::kLaunchContainerWindow,
               GetLaunchContainer(ExtensionPrefs::Get(profile()), extension));
   }
   {
@@ -529,7 +529,7 @@
 
     const Extension* extension = InstallWebAppFromManifestWithFallback();
 
-    EXPECT_EQ(LAUNCH_CONTAINER_TAB,
+    EXPECT_EQ(LaunchContainer::kLaunchContainerTab,
               GetLaunchContainer(ExtensionPrefs::Get(profile()), extension));
   }
 }
@@ -547,7 +547,7 @@
 
     const Extension* extension = InstallWebAppWithOptions(install_options);
 
-    EXPECT_EQ(LAUNCH_CONTAINER_TAB,
+    EXPECT_EQ(LaunchContainer::kLaunchContainerTab,
               GetLaunchContainer(ExtensionPrefs::Get(profile()), extension));
   }
   {
@@ -560,7 +560,7 @@
 
     const Extension* extension = InstallWebAppWithOptions(install_options);
 
-    EXPECT_EQ(LAUNCH_CONTAINER_WINDOW,
+    EXPECT_EQ(LaunchContainer::kLaunchContainerWindow,
               GetLaunchContainer(ExtensionPrefs::Get(profile()), extension));
   }
 }
diff --git a/chrome/browser/web_applications/web_app_install_task.cc b/chrome/browser/web_applications/web_app_install_task.cc
index a475c72..82517cb 100644
--- a/chrome/browser/web_applications/web_app_install_task.cc
+++ b/chrome/browser/web_applications/web_app_install_task.cc
@@ -21,9 +21,41 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/web_contents.h"
 #include "third_party/blink/public/common/manifest/manifest.h"
+#include "url/gurl.h"
+
+#if defined(OS_CHROMEOS)
+#include "base/feature_list.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/common/chrome_features.h"
+#include "components/arc/arc_service_manager.h"
+#include "components/arc/common/app.mojom.h"
+#include "components/arc/common/intent_helper.mojom.h"
+#include "components/arc/session/arc_bridge_service.h"
+#include "net/base/url_util.h"
+#endif
 
 namespace web_app {
 
+namespace {
+
+#if defined(OS_CHROMEOS)
+const char kChromeOsPlayPlatform[] = "chromeos_play";
+const char kPlayIntentPrefix[] =
+    "https://play.google.com/store/apps/details?id=";
+const char kPlayStorePackage[] = "com.android.vending";
+
+std::string ExtractQueryValueForName(const GURL& url, const std::string& name) {
+  for (net::QueryIterator it(url); !it.IsAtEnd(); it.Advance()) {
+    if (it.GetKey() == name)
+      return it.GetValue();
+  }
+  return std::string();
+}
+#endif  // defined(OS_CHROMEOS)
+
+}  // namespace
+
 WebAppInstallTask::WebAppInstallTask(
     Profile* profile,
     InstallFinalizer* install_finalizer,
@@ -257,6 +289,92 @@
   // If the manifest specified icons, don't use the page icons.
   const bool skip_page_favicons = !manifest.icons.empty();
 
+  CheckForPlayStoreIntentOrGetIcons(manifest, std::move(web_app_info),
+                                    std::move(icon_urls), for_installable_site,
+                                    skip_page_favicons);
+}
+
+void WebAppInstallTask::CheckForPlayStoreIntentOrGetIcons(
+    const blink::Manifest& manifest,
+    std::unique_ptr<WebApplicationInfo> web_app_info,
+    std::vector<GURL> icon_urls,
+    ForInstallableSite for_installable_site,
+    bool skip_page_favicons) {
+#if defined(OS_CHROMEOS)
+  // If we have install options, this is not a user-triggered install, and thus
+  // cannot be sent to the store.
+  if (base::FeatureList::IsEnabled(features::kApkWebAppInstalls) &&
+      for_installable_site == ForInstallableSite::kYes && !install_options_) {
+    for (const auto& application : manifest.related_applications) {
+      std::string id = base::UTF16ToUTF8(application.id.string());
+      if (!base::EqualsASCII(application.platform.string(),
+                             kChromeOsPlayPlatform)) {
+        continue;
+      }
+
+      std::string id_from_app_url =
+          ExtractQueryValueForName(application.url, "id");
+
+      if (id.empty()) {
+        if (id_from_app_url.empty())
+          continue;
+        id = id_from_app_url;
+      }
+
+      auto* arc_service_manager = arc::ArcServiceManager::Get();
+      if (arc_service_manager) {
+        auto* instance = ARC_GET_INSTANCE_FOR_METHOD(
+            arc_service_manager->arc_bridge_service()->app(), IsInstallable);
+        if (instance) {
+          // Attach the referrer value.
+          std::string referrer =
+              ExtractQueryValueForName(application.url, "referrer");
+          if (!referrer.empty())
+            referrer = "&referrer=" + referrer;
+
+          std::string intent = kPlayIntentPrefix + id + referrer;
+          instance->IsInstallable(
+              id,
+              base::BindOnce(&WebAppInstallTask::OnDidCheckForIntentToPlayStore,
+                             weak_ptr_factory_.GetWeakPtr(),
+                             std::move(web_app_info), std::move(icon_urls),
+                             for_installable_site, skip_page_favicons, intent));
+          return;
+        }
+      }
+    }
+  }
+
+#endif  // defined(OS_CHROMEOS)
+  OnDidCheckForIntentToPlayStore(std::move(web_app_info), std::move(icon_urls),
+                                 for_installable_site, skip_page_favicons,
+                                 /*intent=*/"",
+                                 /*should_intent_to_store=*/false);
+}
+
+void WebAppInstallTask::OnDidCheckForIntentToPlayStore(
+    std::unique_ptr<WebApplicationInfo> web_app_info,
+    std::vector<GURL> icon_urls,
+    ForInstallableSite for_installable_site,
+    bool skip_page_favicons,
+    const std::string& intent,
+    bool should_intent_to_store) {
+#if defined(OS_CHROMEOS)
+  if (should_intent_to_store && !intent.empty()) {
+    auto* arc_service_manager = arc::ArcServiceManager::Get();
+    if (arc_service_manager) {
+      auto* instance = ARC_GET_INSTANCE_FOR_METHOD(
+          arc_service_manager->arc_bridge_service()->intent_helper(),
+          HandleUrl);
+      if (instance) {
+        instance->HandleUrl(intent, kPlayStorePackage);
+        CallInstallCallback(AppId(), InstallResultCode::kIntentToPlayStore);
+        return;
+      }
+    }
+  }
+#endif  // defined(OS_CHROMEOS)
+
   data_retriever_->GetIcons(
       web_contents(), icon_urls, skip_page_favicons, install_source_,
       base::BindOnce(&WebAppInstallTask::OnIconsRetrievedShowDialog,
diff --git a/chrome/browser/web_applications/web_app_install_task.h b/chrome/browser/web_applications/web_app_install_task.h
index e17061d..590ddb4f 100644
--- a/chrome/browser/web_applications/web_app_install_task.h
+++ b/chrome/browser/web_applications/web_app_install_task.h
@@ -6,6 +6,8 @@
 #define CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_INSTALL_TASK_H_
 
 #include <memory>
+#include <string>
+#include <vector>
 
 #include "base/callback.h"
 #include "base/macros.h"
@@ -17,6 +19,7 @@
 #include "chrome/browser/web_applications/components/web_app_install_utils.h"
 #include "content/public/browser/web_contents_observer.h"
 
+class GURL;
 class Profile;
 struct WebApplicationInfo;
 
@@ -117,6 +120,26 @@
       const blink::Manifest& manifest,
       bool valid_manifest_for_web_app,
       bool is_installable);
+
+  // Either dispatches an asynchronous check for whether this installation
+  // should be stopped and
+  void CheckForPlayStoreIntentOrGetIcons(
+      const blink::Manifest& manifest,
+      std::unique_ptr<WebApplicationInfo> web_app_info,
+      std::vector<GURL> icon_urls,
+      ForInstallableSite for_installable_site,
+      bool skip_page_favicons);
+
+  // Called when the asynchronous check for whether an intent to the Play Store
+  // should be made returns.
+  void OnDidCheckForIntentToPlayStore(
+      std::unique_ptr<WebApplicationInfo> web_app_info,
+      std::vector<GURL> icon_urls,
+      ForInstallableSite for_installable_site,
+      bool skip_page_favicons,
+      const std::string& intent,
+      bool should_intent_to_store);
+
   void OnIconsRetrieved(std::unique_ptr<WebApplicationInfo> web_app_info,
                         bool is_locally_installed,
                         IconsMap icons_map);
diff --git a/chrome/browser/web_applications/web_app_install_task_unittest.cc b/chrome/browser/web_applications/web_app_install_task_unittest.cc
index 739d171..f157be5 100644
--- a/chrome/browser/web_applications/web_app_install_task_unittest.cc
+++ b/chrome/browser/web_applications/web_app_install_task_unittest.cc
@@ -38,6 +38,17 @@
 #include "ui/gfx/codec/png_codec.h"
 #include "url/gurl.h"
 
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/ui/app_list/arc/arc_app_test.h"
+#include "components/arc/arc_service_manager.h"
+#include "components/arc/common/intent_helper.mojom.h"
+#include "components/arc/intent_helper/arc_intent_helper_bridge.h"
+#include "components/arc/session/arc_bridge_service.h"
+#include "components/arc/test/connection_holder_util.h"
+#include "components/arc/test/fake_app_instance.h"
+#include "components/arc/test/fake_intent_helper_instance.h"
+#endif
+
 namespace web_app {
 
 namespace {
@@ -117,6 +128,33 @@
 
     install_task_ = std::make_unique<WebAppInstallTask>(
         profile(), install_finalizer_.get(), std::move(data_retriever));
+
+#if defined(OS_CHROMEOS)
+    arc_test_.SetUp(profile());
+
+    auto* arc_bridge_service =
+        arc_test_.arc_service_manager()->arc_bridge_service();
+    intent_helper_bridge_ = std::make_unique<arc::ArcIntentHelperBridge>(
+        profile(), arc_bridge_service);
+    fake_intent_helper_instance_ =
+        std::make_unique<arc::FakeIntentHelperInstance>();
+    arc_bridge_service->intent_helper()->SetInstance(
+        fake_intent_helper_instance_.get());
+    WaitForInstanceReady(arc_bridge_service->intent_helper());
+#endif
+  }
+
+  void TearDown() override {
+#if defined(OS_CHROMEOS)
+    arc_test_.arc_service_manager()
+        ->arc_bridge_service()
+        ->intent_helper()
+        ->CloseInstance(fake_intent_helper_instance_.get());
+    fake_intent_helper_instance_.reset();
+    intent_helper_bridge_.reset();
+    arc_test_.TearDown();
+#endif
+    WebAppTest::TearDown();
   }
 
   void CreateRendererAppInfo(const GURL& url,
@@ -160,6 +198,11 @@
     auto manifest = std::make_unique<blink::Manifest>();
     manifest->start_url = url;
     manifest->scope = scope;
+    blink::Manifest::RelatedApplication related_app;
+    related_app.platform =
+        base::NullableString16(base::ASCIIToUTF16("chromeos_play"));
+    related_app.id = base::NullableString16(base::ASCIIToUTF16("com.app.id"));
+    manifest->related_applications.push_back(std::move(related_app));
 
     data_retriever_->SetManifest(std::move(manifest), /*is_installable=*/true);
 
@@ -231,6 +274,12 @@
   TestFileUtils* file_utils_ = nullptr;
   TestDataRetriever* data_retriever_ = nullptr;
 
+#if defined(OS_CHROMEOS)
+  ArcAppTest arc_test_;
+  std::unique_ptr<arc::ArcIntentHelperBridge> intent_helper_bridge_;
+  std::unique_ptr<arc::FakeIntentHelperInstance> fake_intent_helper_instance_;
+#endif
+
  private:
   TestInstallFinalizer* test_install_finalizer_ = nullptr;
 };
@@ -936,4 +985,32 @@
   run_loop.Run();
 }
 
+#if defined(OS_CHROMEOS)
+TEST_F(WebAppInstallTaskTest, IntentToPlayStore) {
+  arc_test_.app_instance()->set_is_installable(true);
+
+  const GURL url("https://example.com/scope/path");
+  const std::string name = "Name";
+  const std::string description = "Description";
+  const GURL scope("https://example.com/scope");
+  const base::Optional<SkColor> theme_color = 0xAABBCCDD;
+
+  CreateDefaultDataToRetrieve(url, scope);
+  CreateRendererAppInfo(url, name, description, /*scope*/ GURL{}, theme_color);
+
+  base::RunLoop run_loop;
+  install_task_->InstallWebAppFromManifestWithFallback(
+      web_contents(), /*force_shortcut_app=*/false,
+      WebappInstallSource::MENU_BROWSER_TAB,
+      base::BindOnce(TestAcceptDialogCallback),
+      base::BindLambdaForTesting(
+          [&](const AppId& installed_app_id, InstallResultCode code) {
+            EXPECT_EQ(InstallResultCode::kIntentToPlayStore, code);
+            EXPECT_EQ(AppId(), installed_app_id);
+            run_loop.Quit();
+          }));
+  run_loop.Run();
+}
+#endif
+
 }  // namespace web_app
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
index 5c8e885..b82d3ee 100644
--- a/chrome/common/BUILD.gn
+++ b/chrome/common/BUILD.gn
@@ -620,6 +620,10 @@
     "//third_party/widevine/cdm:buildflags",
   ]
 
+  if (enable_extensions) {
+    public_deps += [ "//components/services/app_service/public/mojom" ]
+  }
+
   if (is_android) {
     # This dependency must only be added for Android.
     #
diff --git a/chrome/common/DEPS b/chrome/common/DEPS
index 5248be4..ed02109 100644
--- a/chrome/common/DEPS
+++ b/chrome/common/DEPS
@@ -39,6 +39,7 @@
   "+components/printing/common",
   "+components/safe_browsing/proto/csd.pb.h",
   "+components/safe_browsing/web_ui/constants.h",
+  "+components/services/app_service/public",
   "+components/strings/grit/components_strings.h",
   "+components/translate/core/common",
   "+components/url_formatter",
diff --git a/chrome/common/extensions/manifest_handlers/app_launch_info.cc b/chrome/common/extensions/manifest_handlers/app_launch_info.cc
index 9544f4d..7e12fb7 100644
--- a/chrome/common/extensions/manifest_handlers/app_launch_info.cc
+++ b/chrome/common/extensions/manifest_handlers/app_launch_info.cc
@@ -63,10 +63,9 @@
 }  // namespace
 
 AppLaunchInfo::AppLaunchInfo()
-    : launch_container_(LAUNCH_CONTAINER_TAB),
+    : launch_container_(LaunchContainer::kLaunchContainerTab),
       launch_width_(0),
-      launch_height_(0) {
-}
+      launch_height_(0) {}
 
 AppLaunchInfo::~AppLaunchInfo() {
 }
@@ -244,9 +243,9 @@
   }
 
   if (launch_container_string == values::kLaunchContainerPanelDeprecated) {
-    launch_container_ = LAUNCH_CONTAINER_PANEL_DEPRECATED;
+    launch_container_ = LaunchContainer::kLaunchContainerPanelDeprecated;
   } else if (launch_container_string == values::kLaunchContainerTab) {
-    launch_container_ = LAUNCH_CONTAINER_TAB;
+    launch_container_ = LaunchContainer::kLaunchContainerTab;
   } else {
     *error = base::ASCIIToUTF16(errors::kInvalidLaunchContainer);
     return false;
@@ -255,7 +254,7 @@
   // TODO(manucornet): Remove this special behavior now that panels are
   // deprecated.
   bool can_specify_initial_size =
-      launch_container_ == LAUNCH_CONTAINER_PANEL_DEPRECATED;
+      launch_container_ == LaunchContainer::kLaunchContainerPanelDeprecated;
 
   // Validate the container width if present.
   if (!ReadLaunchDimension(extension->manifest(),
diff --git a/chrome/common/extensions/manifest_tests/extension_manifests_launch_unittest.cc b/chrome/common/extensions/manifest_tests/extension_manifests_launch_unittest.cc
index e9e7c26..9da6ddb1 100644
--- a/chrome/common/extensions/manifest_tests/extension_manifests_launch_unittest.cc
+++ b/chrome/common/extensions/manifest_tests/extension_manifests_launch_unittest.cc
@@ -24,15 +24,15 @@
   scoped_refptr<Extension> extension;
 
   extension = LoadAndExpectSuccess("launch_tab.json");
-  EXPECT_EQ(LAUNCH_CONTAINER_TAB,
+  EXPECT_EQ(LaunchContainer::kLaunchContainerTab,
             AppLaunchInfo::GetLaunchContainer(extension.get()));
 
   extension = LoadAndExpectSuccess("launch_panel.json");
-  EXPECT_EQ(LAUNCH_CONTAINER_PANEL_DEPRECATED,
+  EXPECT_EQ(LaunchContainer::kLaunchContainerPanelDeprecated,
             AppLaunchInfo::GetLaunchContainer(extension.get()));
 
   extension = LoadAndExpectSuccess("launch_default.json");
-  EXPECT_EQ(LAUNCH_CONTAINER_TAB,
+  EXPECT_EQ(LaunchContainer::kLaunchContainerTab,
             AppLaunchInfo::GetLaunchContainer(extension.get()));
 
   extension = LoadAndExpectSuccess("launch_width.json");
diff --git a/chrome/common/extensions/manifest_tests/extension_manifests_validapp_unittest.cc b/chrome/common/extensions/manifest_tests/extension_manifests_validapp_unittest.cc
index cb8d50e..193ac81 100644
--- a/chrome/common/extensions/manifest_tests/extension_manifests_validapp_unittest.cc
+++ b/chrome/common/extensions/manifest_tests/extension_manifests_validapp_unittest.cc
@@ -19,7 +19,7 @@
   AddPattern(&expected_patterns, "http://www.google.com/mail/*");
   AddPattern(&expected_patterns, "http://www.google.com/foobar/*");
   EXPECT_EQ(expected_patterns, extension->web_extent());
-  EXPECT_EQ(extensions::LAUNCH_CONTAINER_TAB,
+  EXPECT_EQ(extensions::LaunchContainer::kLaunchContainerTab,
             extensions::AppLaunchInfo::GetLaunchContainer(extension.get()));
   EXPECT_EQ(GURL("http://www.google.com/mail/"),
             extensions::AppLaunchInfo::GetLaunchWebURL(extension.get()));
diff --git a/chrome/installer/linux/BUILD.gn b/chrome/installer/linux/BUILD.gn
index 05e0c5f..508e811 100644
--- a/chrome/installer/linux/BUILD.gn
+++ b/chrome/installer/linux/BUILD.gn
@@ -278,7 +278,6 @@
     "$branding_dir/BRANDING",
     "$branding_dir/linux/product_logo_32.xpm",
     "$branding_dir/product_logo_128.png",
-    "$branding_dir/product_logo_22.png",
     "$branding_dir/product_logo_24.png",
     "$branding_dir/product_logo_256.png",
     "$branding_dir/product_logo_48.png",
@@ -292,8 +291,6 @@
       "$branding_dir/linux/product_logo_32_dev.xpm",
       "$branding_dir/product_logo_128_beta.png",
       "$branding_dir/product_logo_128_dev.png",
-      "$branding_dir/product_logo_22_beta.png",
-      "$branding_dir/product_logo_22_dev.png",
       "$branding_dir/product_logo_24_beta.png",
       "$branding_dir/product_logo_24_dev.png",
       "$branding_dir/product_logo_256_beta.png",
diff --git a/chrome/services/cups_proxy/printer_installer.cc b/chrome/services/cups_proxy/printer_installer.cc
index 88a3ca6..b0262a6 100644
--- a/chrome/services/cups_proxy/printer_installer.cc
+++ b/chrome/services/cups_proxy/printer_installer.cc
@@ -19,49 +19,20 @@
 #include "chromeos/printing/printer_configuration.h"
 
 namespace cups_proxy {
-namespace {
 
-using CupsProxyServiceDelegate = chromeos::printing::CupsProxyServiceDelegate;
-
-class PrinterInstallerImpl : public PrinterInstaller {
- public:
-  explicit PrinterInstallerImpl(
-      base::WeakPtr<CupsProxyServiceDelegate> delegate);
-  ~PrinterInstallerImpl() override = default;
-
-  void InstallPrinterIfNeeded(ipp_t* ipp, InstallPrinterCallback cb) override;
-
- private:
-  void OnInstallPrinter(InstallPrinterCallback cb, bool success);
-
-  void Finish(InstallPrinterCallback cb, InstallPrinterResult res);
-
-  // Service delegate granting access to printing stack dependencies.
-  base::WeakPtr<CupsProxyServiceDelegate> delegate_;
-
-  SEQUENCE_CHECKER(sequence_checker_);
-  base::WeakPtrFactory<PrinterInstallerImpl> weak_factory_;
-};
-
-}  // namespace
-
-PrinterInstallerImpl::PrinterInstallerImpl(
-    base::WeakPtr<CupsProxyServiceDelegate> delegate)
-    : delegate_(std::move(delegate)), weak_factory_(this) {
+PrinterInstaller::PrinterInstaller(
+    base::WeakPtr<chromeos::printing::CupsProxyServiceDelegate> delegate)
+    : delegate_(std::move(delegate)) {
   DETACH_FROM_SEQUENCE(sequence_checker_);
 }
 
-void PrinterInstallerImpl::InstallPrinterIfNeeded(ipp_t* ipp,
-                                                  InstallPrinterCallback cb) {
+PrinterInstaller::~PrinterInstaller() = default;
+
+void PrinterInstaller::InstallPrinter(std::string printer_id,
+                                      InstallPrinterCallback cb) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  auto printer_uuid = GetPrinterId(ipp);
-  if (!printer_uuid) {
-    Finish(std::move(cb), InstallPrinterResult::kNoPrintersFound);
-    return;
-  }
-
-  auto printer = delegate_->GetPrinter(*printer_uuid);
+  auto printer = delegate_->GetPrinter(printer_id);
   if (!printer) {
     // If the requested printer DNE, we proxy to CUPSd and allow it to
     // handle the error.
@@ -76,14 +47,14 @@
 
   // Install printer.
   delegate_->SetupPrinter(
-      *printer, base::BindOnce(&PrinterInstallerImpl::OnInstallPrinter,
+      *printer, base::BindOnce(&PrinterInstaller::OnInstallPrinter,
                                weak_factory_.GetWeakPtr(), std::move(cb)));
 }
 
 // TODO(crbug.com/945409): Test whether we need to call
 // CupsPrintersManager::PrinterInstalled here.
-void PrinterInstallerImpl::OnInstallPrinter(InstallPrinterCallback cb,
-                                            bool success) {
+void PrinterInstaller::OnInstallPrinter(InstallPrinterCallback cb,
+                                        bool success) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   Finish(std::move(cb),
@@ -91,16 +62,10 @@
                  : InstallPrinterResult::kPrinterInstallationFailure);
 }
 
-void PrinterInstallerImpl::Finish(InstallPrinterCallback cb,
-                                  InstallPrinterResult res) {
+void PrinterInstaller::Finish(InstallPrinterCallback cb,
+                              InstallPrinterResult res) {
   base::SequencedTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindOnce(std::move(cb), res));
 }
 
-// static
-std::unique_ptr<PrinterInstaller> PrinterInstaller::Create(
-    base::WeakPtr<CupsProxyServiceDelegate> delegate) {
-  return std::make_unique<PrinterInstallerImpl>(std::move(delegate));
-}
-
 }  // namespace cups_proxy
diff --git a/chrome/services/cups_proxy/printer_installer.h b/chrome/services/cups_proxy/printer_installer.h
index 27fef78..08a9941 100644
--- a/chrome/services/cups_proxy/printer_installer.h
+++ b/chrome/services/cups_proxy/printer_installer.h
@@ -8,6 +8,7 @@
 #include <cups/cups.h>
 
 #include <memory>
+#include <string>
 
 #include "base/callback_forward.h"
 #include "base/memory/weak_ptr.h"
@@ -18,9 +19,6 @@
 enum class InstallPrinterResult {
   kSuccess = 0,
 
-  // Couldn't find any printers referenced by the incoming request.
-  kNoPrintersFound,
-
   // Referenced printer is unknown to Chrome.
   kUnknownPrinterFound,
   kPrinterInstallationFailure,
@@ -34,16 +32,23 @@
 // sequenced context.
 class PrinterInstaller {
  public:
-  // Factory function.
-  static std::unique_ptr<PrinterInstaller> Create(
+  explicit PrinterInstaller(
       base::WeakPtr<chromeos::printing::CupsProxyServiceDelegate> delegate);
-
-  virtual ~PrinterInstaller() = default;
+  ~PrinterInstaller();
 
   // Pre-installs any printers required by |ipp| into the CUPS daemon, as
   // needed. |cb| will be run on this instance's sequenced context.
-  virtual void InstallPrinterIfNeeded(ipp_t* ipp,
-                                      InstallPrinterCallback cb) = 0;
+  void InstallPrinter(std::string printer_id, InstallPrinterCallback cb);
+
+ private:
+  void OnInstallPrinter(InstallPrinterCallback cb, bool success);
+  void Finish(InstallPrinterCallback cb, InstallPrinterResult res);
+
+  // Service delegate granting access to printing stack dependencies.
+  base::WeakPtr<chromeos::printing::CupsProxyServiceDelegate> delegate_;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+  base::WeakPtrFactory<PrinterInstaller> weak_factory_{this};
 };
 
 }  // namespace cups_proxy
diff --git a/chrome/services/cups_proxy/printer_installer_unittest.cc b/chrome/services/cups_proxy/printer_installer_unittest.cc
index 9aee45f2..ae5effc6 100644
--- a/chrome/services/cups_proxy/printer_installer_unittest.cc
+++ b/chrome/services/cups_proxy/printer_installer_unittest.cc
@@ -37,6 +37,8 @@
     installed_printers_.insert({printer.id(), false});
   }
 
+  void FailSetupPrinter() { fail_printer_setup_ = true; }
+
   // Service delegate overrides.
   bool IsPrinterInstalled(const Printer& printer) override {
     if (!base::Contains(installed_printers_, printer.id())) {
@@ -57,6 +59,10 @@
   void SetupPrinter(
       const Printer& printer,
       chromeos::printing::PrinterSetupCallback callback) override {
+    if (fail_printer_setup_) {
+      return std::move(callback).Run(false);
+    }
+
     // PrinterInstaller is expected to have checked if |printer| is already
     // installed before trying setup.
     if (IsPrinterInstalled(printer)) {
@@ -70,43 +76,42 @@
 
  private:
   std::map<std::string, bool> installed_printers_;
+
+  // Conditions whether calls to SetupPrinter succeed.
+  bool fail_printer_setup_ = false;
 };
 
 class PrinterInstallerTest : public testing::Test {
  public:
   PrinterInstallerTest() : weak_factory_(this) {
     delegate_ = std::make_unique<FakeServiceDelegate>();
-    printer_installer_ = PrinterInstaller::Create(delegate_->GetWeakPtr());
+    printer_installer_ =
+        std::make_unique<PrinterInstaller>(delegate_->GetWeakPtr());
   }
 
   ~PrinterInstallerTest() override = default;
 
-  bool RunInstallPrinterIfNeeded(ipp_t* ipp, Printer to_install) {
-    bool success = false;
-    printer_installer_->InstallPrinterIfNeeded(
-        ipp, base::BindOnce(&PrinterInstallerTest::OnRunInstallPrinterIfNeeded,
-                            weak_factory_.GetWeakPtr(), &success,
-                            std::move(to_install)));
-    scoped_task_environment_.RunUntilIdle();
-    return success;
+  InstallPrinterResult RunInstallPrinter(std::string printer_id) {
+    InstallPrinterResult ret;
+
+    base::RunLoop run_loop;
+    printer_installer_->InstallPrinter(
+        printer_id, base::BindOnce(&PrinterInstallerTest::OnRunInstallPrinter,
+                                   weak_factory_.GetWeakPtr(),
+                                   run_loop.QuitClosure(), &ret));
+
+    run_loop.Run();
+    return ret;
   }
 
  protected:
   base::test::ScopedTaskEnvironment scoped_task_environment_;
 
-  void OnRunInstallPrinterIfNeeded(bool* ret,
-                                   Printer to_install,
-                                   InstallPrinterResult result) {
-    if (result != InstallPrinterResult::kSuccess) {
-      return;
-    }
-
-    // If printer wasn't installed, fail.
-    if (!delegate_->IsPrinterInstalled(to_install)) {
-      return;
-    }
-
-    *ret = true;
+  void OnRunInstallPrinter(base::OnceClosure finish_cb,
+                           InstallPrinterResult* ret,
+                           InstallPrinterResult result) {
+    *ret = result;
+    std::move(finish_cb).Run();
   }
 
   // Backend fake driving the PrinterInstaller.
@@ -119,33 +124,23 @@
   base::WeakPtrFactory<PrinterInstallerTest> weak_factory_;
 };
 
-// Return a valid ScopedIppPtr that correctly references |id| in
-// the printer-uri field.
-::printing::ScopedIppPtr MakeIppReferencingPrinters(const std::string& id) {
-  ::printing::ScopedIppPtr ret = ::printing::WrapIpp(ippNew());
-
-  std::string uri = "ipp://localhost/printers/" + id;
-  ippAddString(ret.get(), IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uri", NULL,
-               uri.c_str());
-
-  return ret;
-}
-
 // Standard install known printer workflow.
 TEST_F(PrinterInstallerTest, SimpleSanityTest) {
   Printer to_install(kGenericGUID);
   delegate_->AddPrinter(to_install);
 
-  auto ipp = MakeIppReferencingPrinters(to_install.id());
-  EXPECT_TRUE(RunInstallPrinterIfNeeded(ipp.get(), std::move(to_install)));
+  auto ret = RunInstallPrinter(kGenericGUID);
+  EXPECT_EQ(ret, InstallPrinterResult::kSuccess);
+  EXPECT_TRUE(delegate_->IsPrinterInstalled(to_install));
 }
 
 // Should fail to install an unknown(previously unseen) printer.
 TEST_F(PrinterInstallerTest, UnknownPrinter) {
   Printer to_install(kGenericGUID);
 
-  auto ipp = MakeIppReferencingPrinters(to_install.id());
-  EXPECT_FALSE(RunInstallPrinterIfNeeded(ipp.get(), std::move(to_install)));
+  auto ret = RunInstallPrinter(kGenericGUID);
+  EXPECT_EQ(ret, InstallPrinterResult::kUnknownPrinterFound);
+  EXPECT_FALSE(delegate_->IsPrinterInstalled(to_install));
 }
 
 // Ensure we never setup a printer that's already installed.
@@ -153,12 +148,23 @@
   Printer to_install(kGenericGUID);
   delegate_->AddPrinter(to_install);
 
-  auto ipp = MakeIppReferencingPrinters(to_install.id());
-  EXPECT_TRUE(RunInstallPrinterIfNeeded(ipp.get(), to_install));
+  auto ret = RunInstallPrinter(kGenericGUID);
+  EXPECT_EQ(ret, InstallPrinterResult::kSuccess);
 
   // |printer_installer_| should notice printer is already installed and bail
   // out. If it attempts setup, FakeServiceDelegate will fail the request.
-  EXPECT_TRUE(RunInstallPrinterIfNeeded(ipp.get(), to_install));
+  ret = RunInstallPrinter(kGenericGUID);
+  EXPECT_EQ(ret, InstallPrinterResult::kSuccess);
+}
+
+// Checks for correct response to failed SetupPrinter call.
+TEST_F(PrinterInstallerTest, SetupPrinterFailure) {
+  Printer to_install(kGenericGUID);
+  delegate_->AddPrinter(to_install);
+  delegate_->FailSetupPrinter();
+
+  auto ret = RunInstallPrinter(kGenericGUID);
+  EXPECT_EQ(ret, InstallPrinterResult::kPrinterInstallationFailure);
 }
 
 }  // namespace
diff --git a/chrome/services/cups_proxy/public/cpp/cups_util.h b/chrome/services/cups_proxy/public/cpp/cups_util.h
index 75e40f7..55d393f 100644
--- a/chrome/services/cups_proxy/public/cpp/cups_util.h
+++ b/chrome/services/cups_proxy/public/cpp/cups_util.h
@@ -23,6 +23,7 @@
 // If |ipp| refers to a printer, we return the associated printer_id.
 // Note: Expects the printer id to be embedded in the resource field of the
 // 'printer-uri' IPP attribute.
+// TODO(crbug.com/945409): Add testing suite.
 base::Optional<std::string> GetPrinterId(ipp_t* ipp);
 
 }  // namespace cups_proxy
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 092cf43..f3e2a09a6 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -4285,10 +4285,15 @@
       "../renderer/media/cast_ipc_dispatcher_unittest.cc",
       "../utility/image_writer/image_writer_unittest.cc",
     ]
-    allow_circular_includes_from =
-        [ "//chrome/browser/web_applications/extensions:unit_tests" ]
+
+    allow_circular_includes_from = [
+      "//chrome/browser/web_applications:web_applications_unit_tests",
+      "//chrome/browser/web_applications/extensions:unit_tests",
+    ]
+
     deps += [
       "//chrome/browser/web_applications:unit_tests",
+      "//chrome/browser/web_applications:web_applications_unit_tests",
       "//chrome/browser/web_applications/extensions:unit_tests",
       "//chrome/common/extensions/api",
       "//extensions:extensions_resources",
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index 8fa03ef..fc9e5c3 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -4222,8 +4222,7 @@
   },
 
   "DeviceLoginScreenSitePerProcess": {
-    "os": ["chromeos"],
-    "note": "Chrome OS device policy used by session_manager only"
+    "note": "This policy has been removed in Chrome 77, see https://crbug.com/964068 ."
   },
 
   "VirtualMachinesAllowed": {
diff --git a/chrome/test/ppapi/ppapi_browsertest.cc b/chrome/test/ppapi/ppapi_browsertest.cc
index 6fedd1a..1ef561c 100644
--- a/chrome/test/ppapi/ppapi_browsertest.cc
+++ b/chrome/test/ppapi/ppapi_browsertest.cc
@@ -2182,9 +2182,9 @@
     ASSERT_TRUE(extension);
 
     AppLaunchParams params(browser()->profile(), extension->id(),
-                           extensions::LAUNCH_CONTAINER_NONE,
+                           extensions::LaunchContainer::kLaunchContainerNone,
                            WindowOpenDisposition::NEW_WINDOW,
-                           extensions::SOURCE_TEST);
+                           extensions::AppLaunchSource::kSourceTest);
     params.command_line = *base::CommandLine::ForCurrentProcess();
     OpenApplication(params);
   }
diff --git a/chrome/test/remoting/remote_desktop_browsertest.cc b/chrome/test/remoting/remote_desktop_browsertest.cc
index 388f6da0..34345ab3 100644
--- a/chrome/test/remoting/remote_desktop_browsertest.cc
+++ b/chrome/test/remoting/remote_desktop_browsertest.cc
@@ -222,11 +222,11 @@
     window_open_disposition = WindowOpenDisposition::NEW_WINDOW;
   }
 
-  OpenApplication(
-      AppLaunchParams(browser()->profile(), extension_->id(),
-                      is_platform_app() ? extensions::LAUNCH_CONTAINER_NONE
-                                        : extensions::LAUNCH_CONTAINER_TAB,
-                      window_open_disposition, extensions::SOURCE_TEST));
+  OpenApplication(AppLaunchParams(
+      browser()->profile(), extension_->id(),
+      is_platform_app() ? extensions::LaunchContainer::kLaunchContainerNone
+                        : extensions::LaunchContainer::kLaunchContainerTab,
+      window_open_disposition, extensions::AppLaunchSource::kSourceTest));
 
   observer.Wait();
 
diff --git a/chromecast/browser/extensions/cast_extension_system.cc b/chromecast/browser/extensions/cast_extension_system.cc
index 9c7ae096..40f0fa3a 100644
--- a/chromecast/browser/extensions/cast_extension_system.cc
+++ b/chromecast/browser/extensions/cast_extension_system.cc
@@ -174,8 +174,8 @@
   const Extension* extension = ExtensionRegistry::Get(browser_context_)
                                    ->enabled_extensions()
                                    .GetByID(extension_id);
-  AppRuntimeEventRouter::DispatchOnLaunchedEvent(browser_context_, extension,
-                                                 SOURCE_UNTRACKED, nullptr);
+  AppRuntimeEventRouter::DispatchOnLaunchedEvent(
+      browser_context_, extension, AppLaunchSource::kSourceUntracked, nullptr);
 }
 
 void CastExtensionSystem::Shutdown() {}
diff --git a/chromecast/device/bluetooth/le/remote_device_impl.cc b/chromecast/device/bluetooth/le/remote_device_impl.cc
index 680e663..96881c367 100644
--- a/chromecast/device/bluetooth/le/remote_device_impl.cc
+++ b/chromecast/device/bluetooth/le/remote_device_impl.cc
@@ -545,7 +545,10 @@
 
 void RemoteDeviceImpl::NotifyQueueOperationComplete() {
   DCHECK(io_task_runner_->BelongsToCurrentThread());
-  DCHECK(!command_queue_.empty());
+  if (command_queue_.empty()) {
+    LOG(ERROR) << "Command queue is empty, device might be disconnected";
+    return;
+  }
   command_queue_.pop_front();
   command_timeout_timer_.Stop();
 
@@ -557,7 +560,10 @@
 
 void RemoteDeviceImpl::RunNextOperation() {
   DCHECK(io_task_runner_->BelongsToCurrentThread());
-  DCHECK(!command_queue_.empty());
+  if (command_queue_.empty()) {
+    LOG(ERROR) << "Command queue is empty, device might be disconnected";
+    return;
+  }
   auto& front = command_queue_.front();
   command_timeout_timer_.Start(
       FROM_HERE, kCommandTimeout,
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 49e4e2521..51b61a1 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-12286.0.0
\ No newline at end of file
+12292.0.0
\ No newline at end of file
diff --git a/chromeos/dbus/auth_policy/fake_auth_policy_client_unittest.cc b/chromeos/dbus/auth_policy/fake_auth_policy_client_unittest.cc
index 1a39402..b1bc869 100644
--- a/chromeos/dbus/auth_policy/fake_auth_policy_client_unittest.cc
+++ b/chromeos/dbus/auth_policy/fake_auth_policy_client_unittest.cc
@@ -5,8 +5,8 @@
 #include "chromeos/dbus/auth_policy/fake_auth_policy_client.h"
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
 #include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "chromeos/tpm/stub_install_attributes.h"
 #include "components/account_id/account_id.h"
@@ -98,7 +98,7 @@
 
  private:
   ScopedStubInstallAttributes install_attributes_;
-  base::MessageLoop loop_;
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
 
   DISALLOW_COPY_AND_ASSIGN(FakeAuthPolicyClientTest);
 };
diff --git a/chromeos/dbus/fake_smb_provider_client.cc b/chromeos/dbus/fake_smb_provider_client.cc
index 0464f0c..e0cbb03 100644
--- a/chromeos/dbus/fake_smb_provider_client.cc
+++ b/chromeos/dbus/fake_smb_provider_client.cc
@@ -55,7 +55,9 @@
       FROM_HERE, base::BindOnce(std::move(callback), smbprovider::ERROR_OK, 1));
 }
 
-void FakeSmbProviderClient::Unmount(int32_t mount_id, StatusCallback callback) {
+void FakeSmbProviderClient::Unmount(int32_t mount_id,
+                                    bool remove_password,
+                                    StatusCallback callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindOnce(std::move(callback), smbprovider::ERROR_OK));
 }
diff --git a/chromeos/dbus/fake_smb_provider_client.h b/chromeos/dbus/fake_smb_provider_client.h
index 76d25741..9fcb1a8a 100644
--- a/chromeos/dbus/fake_smb_provider_client.h
+++ b/chromeos/dbus/fake_smb_provider_client.h
@@ -35,7 +35,9 @@
              base::ScopedFD password_fd,
              MountCallback callback) override;
 
-  void Unmount(int32_t mount_id, StatusCallback callback) override;
+  void Unmount(int32_t mount_id,
+               bool remove_password,
+               StatusCallback callback) override;
   void ReadDirectory(int32_t mount_id,
                      const base::FilePath& directory_path,
                      ReadDirectoryCallback callback) override;
diff --git a/chromeos/dbus/power/fake_power_manager_client.cc b/chromeos/dbus/power/fake_power_manager_client.cc
index 39cdc6c..bb424c32 100644
--- a/chromeos/dbus/power/fake_power_manager_client.cc
+++ b/chromeos/dbus/power/fake_power_manager_client.cc
@@ -361,10 +361,6 @@
       FROM_HERE, base::BindOnce(std::move(callback), true));
 }
 
-void FakePowerManagerClient::DeferScreenDim() {
-  num_defer_screen_dim_calls_++;
-}
-
 bool FakePowerManagerClient::PopVideoActivityReport() {
   CHECK(!video_activity_reports_.empty());
   bool fullscreen = video_activity_reports_.front();
@@ -418,11 +414,6 @@
     observer.PowerButtonEventReceived(down, timestamp);
 }
 
-void FakePowerManagerClient::SendScreenDimImminent() {
-  for (auto& observer : observers_)
-    observer.ScreenDimImminent();
-}
-
 void FakePowerManagerClient::SetLidState(LidState state,
                                          const base::TimeTicks& timestamp) {
   lid_state_ = state;
diff --git a/chromeos/dbus/power/fake_power_manager_client.h b/chromeos/dbus/power/fake_power_manager_client.h
index 82c5c528..4095117 100644
--- a/chromeos/dbus/power/fake_power_manager_client.h
+++ b/chromeos/dbus/power/fake_power_manager_client.h
@@ -52,7 +52,6 @@
   int num_set_is_projecting_calls() const {
     return num_set_is_projecting_calls_;
   }
-  int num_defer_screen_dim_calls() const { return num_defer_screen_dim_calls_; }
   int num_wake_notification_calls() const {
     return num_wake_notification_calls_;
   }
@@ -128,7 +127,6 @@
                      VoidDBusMethodCallback callback) override;
   void DeleteArcTimers(const std::string& tag,
                        VoidDBusMethodCallback callback) override;
-  void DeferScreenDim() override;
 
   // Pops the first report from |video_activity_reports_|, returning whether the
   // activity was fullscreen or not. There must be at least one report.
@@ -153,9 +151,6 @@
   // Notifies observers that the power button has been pressed or released.
   void SendPowerButtonEvent(bool down, const base::TimeTicks& timestamp);
 
-  // Notifies observers that the screen is about to be dimmed.
-  void SendScreenDimImminent();
-
   // Sets |lid_state_| or |tablet_mode_| and notifies |observers_| about the
   // change.
   void SetLidState(LidState state, const base::TimeTicks& timestamp);
@@ -224,7 +219,6 @@
   int num_set_policy_calls_ = 0;
   int num_set_is_projecting_calls_ = 0;
   int num_set_backlights_forced_off_calls_ = 0;
-  int num_defer_screen_dim_calls_ = 0;
   int num_wake_notification_calls_ = 0;
 
   // Number of pending suspend readiness callbacks.
diff --git a/chromeos/dbus/power/power_manager_client.cc b/chromeos/dbus/power/power_manager_client.cc
index 1209b65..06ab167d 100644
--- a/chromeos/dbus/power/power_manager_client.cc
+++ b/chromeos/dbus/power/power_manager_client.cc
@@ -192,8 +192,6 @@
          &PowerManagerClientImpl::SuspendDoneReceived},
         {power_manager::kDarkSuspendImminentSignal,
          &PowerManagerClientImpl::DarkSuspendImminentReceived},
-        {power_manager::kScreenDimImminentSignal,
-         &PowerManagerClientImpl::ScreenDimImminentReceived},
         {power_manager::kIdleActionImminentSignal,
          &PowerManagerClientImpl::IdleActionImminentReceived},
         {power_manager::kIdleActionDeferredSignal,
@@ -539,10 +537,6 @@
         base::BindOnce(&OnVoidDBusMethod, std::move(callback)));
   }
 
-  void DeferScreenDim() override {
-    SimpleMethodCallToPowerManager(power_manager::kDeferScreenDimMethod);
-  }
-
  private:
   // Returns true if the current thread is the origin thread.
   bool OnOriginThread() {
@@ -921,11 +915,6 @@
     base::PowerMonitorDeviceSource::HandleSystemResumed();
   }
 
-  void ScreenDimImminentReceived(dbus::Signal* signal) {
-    for (auto& observer : observers_)
-      observer.ScreenDimImminent();
-  }
-
   void IdleActionImminentReceived(dbus::Signal* signal) {
     dbus::MessageReader reader(signal);
     power_manager::IdleActionImminent proto;
diff --git a/chromeos/dbus/power/power_manager_client.h b/chromeos/dbus/power/power_manager_client.h
index b6f3a967a..9bd84f5d 100644
--- a/chromeos/dbus/power/power_manager_client.h
+++ b/chromeos/dbus/power/power_manager_client.h
@@ -145,9 +145,6 @@
     virtual void TabletModeEventReceived(TabletMode mode,
                                          const base::TimeTicks& timestamp) {}
 
-    // Called just before the screen is dimmed in response to user inactivity.
-    virtual void ScreenDimImminent() {}
-
     // Called when the idle action will be performed after
     // |time_until_idle_action|.
     virtual void IdleActionImminent(
@@ -321,11 +318,6 @@
   virtual void DeleteArcTimers(const std::string& tag,
                                VoidDBusMethodCallback callback) = 0;
 
-  // Instructs powerd to defer dimming the screen. This only has an effect when
-  // called shortly (i.e. seconds) after observers have received
-  // ScreenDimImminent notifications.
-  virtual void DeferScreenDim() = 0;
-
   PowerManagerClient();
   virtual ~PowerManagerClient();
 
diff --git a/chromeos/dbus/smb_provider_client.cc b/chromeos/dbus/smb_provider_client.cc
index 8804a65..f54eb83 100644
--- a/chromeos/dbus/smb_provider_client.cc
+++ b/chromeos/dbus/smb_provider_client.cc
@@ -78,9 +78,13 @@
              MountCallback callback) override {
     smbprovider::MountOptionsProto options_proto;
     options_proto.set_path(share_path.value());
+    options_proto.set_original_path(options.original_path);
     options_proto.set_workgroup(options.workgroup);
     options_proto.set_username(options.username);
     options_proto.set_skip_connect(options.skip_connect);
+    options_proto.set_account_hash(options.account_hash);
+    options_proto.set_save_password(options.save_password);
+    options_proto.set_restore_password(options.restore_password);
 
     std::unique_ptr<smbprovider::MountConfigProto> config =
         CreateMountConfigProto(options.ntlm_enabled);
@@ -95,9 +99,12 @@
                &callback);
   }
 
-  void Unmount(int32_t mount_id, StatusCallback callback) override {
+  void Unmount(int32_t mount_id,
+               bool remove_password,
+               StatusCallback callback) override {
     smbprovider::UnmountOptionsProto options;
     options.set_mount_id(mount_id);
+    options.set_remove_password(remove_password);
     CallDefaultMethod(smbprovider::kUnmountMethod, options, &callback);
   }
 
@@ -701,6 +708,10 @@
 
 }  // namespace
 
+SmbProviderClient::MountOptions::MountOptions() = default;
+
+SmbProviderClient::MountOptions::~MountOptions() = default;
+
 SmbProviderClient::SmbProviderClient() = default;
 
 SmbProviderClient::~SmbProviderClient() = default;
diff --git a/chromeos/dbus/smb_provider_client.h b/chromeos/dbus/smb_provider_client.h
index a857789..838cb246 100644
--- a/chromeos/dbus/smb_provider_client.h
+++ b/chromeos/dbus/smb_provider_client.h
@@ -56,14 +56,25 @@
 
   // Optional arguments to pass to Mount().
   struct MountOptions {
+    MountOptions();
+    ~MountOptions();
+
+    std::string original_path;
     std::string username;
     std::string workgroup;
+    std::string account_hash;
 
     // Enable NTLM Authentication.
     bool ntlm_enabled = false;
 
-    // Do no attempt to connect to and authenticate the mounted share.
+    // Do not attempt to connect to and authenticate the mounted share.
     bool skip_connect = false;
+
+    // Save the password for this share if it is successfully mounted.
+    bool save_password = false;
+
+    // Use a saved password for authenticating the share.
+    bool restore_password = false;
   };
 
   ~SmbProviderClient() override;
@@ -83,7 +94,9 @@
 
   // Calls Unmount. This removes the corresponding mount of |mount_id| from
   // the list of valid mounts. Subsequent operations on |mount_id| will fail.
-  virtual void Unmount(int32_t mount_id, StatusCallback callback) = 0;
+  virtual void Unmount(int32_t mount_id,
+                       bool remove_password,
+                       StatusCallback callback) = 0;
 
   // Calls ReadDirectory. Using the corresponding mount of |mount_id|, this
   // reads the directory on a given |directory_path| and passes the
diff --git a/components/arc/test/fake_app_instance.cc b/components/arc/test/fake_app_instance.cc
index 15903e9..b83ae89 100644
--- a/components/arc/test/fake_app_instance.cc
+++ b/components/arc/test/fake_app_instance.cc
@@ -487,7 +487,7 @@
 
 void FakeAppInstance::IsInstallable(const std::string& package_name,
                                     IsInstallableCallback callback) {
-  std::move(callback).Run(false);
+  std::move(callback).Run(is_installable_);
 }
 
 void FakeAppInstance::LaunchIntentDeprecated(
diff --git a/components/arc/test/fake_app_instance.h b/components/arc/test/fake_app_instance.h
index 47489d6..0da84463 100644
--- a/components/arc/test/fake_app_instance.h
+++ b/components/arc/test/fake_app_instance.h
@@ -247,6 +247,10 @@
   void SetAppReinstallCandidates(
       const std::vector<arc::mojom::AppReinstallCandidatePtr>& candidates);
 
+  void set_is_installable(bool is_installable) {
+    is_installable_ = is_installable;
+  }
+
  private:
   using TaskIdToInfo = std::map<int32_t, std::unique_ptr<Request>>;
   // Mojo endpoints.
@@ -282,6 +286,8 @@
   // Keeps latest generated icons per icon dimension.
   std::map<int, std::string> icon_responses_;
 
+  bool is_installable_ = false;
+
   // Keeps the binding alive so that calls to this class can be correctly
   // routed.
   mojom::AppHostPtr host_;
diff --git a/components/chromeos_camera/BUILD.gn b/components/chromeos_camera/BUILD.gn
index a9677b1..d633801 100644
--- a/components/chromeos_camera/BUILD.gn
+++ b/components/chromeos_camera/BUILD.gn
@@ -144,6 +144,7 @@
       "//media:test_support",
       "//media/capture:chromeos_test_utils",
       "//media/gpu:buildflags",
+      "//media/gpu/chromeos:video_frame_mapper",
       "//media/gpu/test:helpers",
       "//media/parsers",
       "//mojo/core/embedder",
diff --git a/components/chromeos_camera/jpeg_encode_accelerator_unittest.cc b/components/chromeos_camera/jpeg_encode_accelerator_unittest.cc
index c62d7fd..a37f3759 100644
--- a/components/chromeos_camera/jpeg_encode_accelerator_unittest.cc
+++ b/components/chromeos_camera/jpeg_encode_accelerator_unittest.cc
@@ -28,6 +28,7 @@
 #include "media/base/test_data_util.h"
 #include "media/capture/video/chromeos/local_gpu_memory_buffer_manager.h"
 #include "media/gpu/buildflags.h"
+#include "media/gpu/chromeos/generic_dmabuf_video_frame_mapper.h"
 #include "media/gpu/test/video_accelerator_unittest_helpers.h"
 #include "media/parsers/jpeg_parser.h"
 #include "mojo/core/embedder/embedder.h"
@@ -53,6 +54,7 @@
 
 const double kMeanDiffThreshold = 10.0;
 const int kJpegDefaultQuality = 90;
+const int kJpegMaxSize = 1024 * 1024 * 13;
 
 // Environment to create test data for all test cases.
 class JpegEncodeAcceleratorTestEnvironment;
@@ -330,6 +332,8 @@
   std::unique_ptr<base::SharedMemory> hw_out_shm_;
   // Mapped memory of output buffer from software encoder.
   std::unique_ptr<base::SharedMemory> sw_out_shm_;
+  // Output for DMA-buf based encoding.
+  scoped_refptr<media::VideoFrame> hw_out_frame_;
 
   // Used to create Gpu memory buffer for DMA-buf encoding tests.
   std::unique_ptr<gpu::GpuMemoryBufferManager> gpu_memory_buffer_manager_;
@@ -394,6 +398,13 @@
     test_image = test_images_[buffer_id - test_aligned_images_.size()];
   }
 
+  if (hw_out_frame_ && !hw_out_frame_->IsMappable()) {
+    // |hw_out_frame_| should only be mapped once.
+    auto mapper =
+        media::GenericDmaBufVideoFrameMapper::Create(hw_out_frame_->format());
+    hw_out_frame_ = mapper->Map(hw_out_frame_);
+  }
+
   size_t sw_encoded_size = 0;
   base::TimeDelta elapsed_sw;
   LOG_ASSERT(GetSoftwareEncodeResult(test_image->visible_size.width(),
@@ -459,9 +470,12 @@
   int y_stride = width;
   int u_stride = width / 2;
   int v_stride = u_stride;
+
+  const uint8_t* out_mem = static_cast<const uint8_t*>(
+      hw_out_frame_ ? hw_out_frame_->data(0) : hw_out_shm_->memory());
   if (libyuv::ConvertToI420(
-          static_cast<const uint8_t*>(hw_out_shm_->memory()), hw_encoded_size,
-          hw_yuv_result, y_stride, hw_yuv_result + y_stride * height, u_stride,
+          out_mem, hw_encoded_size, hw_yuv_result, y_stride,
+          hw_yuv_result + y_stride * height, u_stride,
           hw_yuv_result + y_stride * height + u_stride * height / 2, v_stride,
           0, 0, width, height, width, height, libyuv::kRotate0,
           libyuv::FOURCC_MJPG)) {
@@ -546,6 +560,8 @@
     LOG_ASSERT(sw_out_shm_->CreateAndMapAnonymous(test_image->output_size));
   }
   memset(sw_out_shm_->memory(), 0, test_image->output_size);
+
+  hw_out_frame_ = nullptr;
 }
 
 void JpegClient::SetState(ClientState new_state) {
@@ -565,10 +581,13 @@
   base::FilePath out_filename_hw = test_image->output_filename;
   LOG(INFO) << "Writing HW encode results to "
             << out_filename_hw.MaybeAsASCII();
+
   ASSERT_EQ(
       static_cast<int>(hw_size),
       base::WriteFile(out_filename_hw,
-                      static_cast<char*>(hw_out_shm_->memory()), hw_size));
+                      static_cast<char*>(hw_out_frame_ ? hw_out_frame_->data(0)
+                                                       : hw_out_shm_->memory()),
+                      hw_size));
 
   base::FilePath out_filename_sw = out_filename_hw.InsertBeforeExtension("_sw");
   LOG(INFO) << "Writing SW encode results to "
@@ -609,27 +628,37 @@
   TestImage* test_image = GetTestImage(bitstream_buffer_id);
   test_image->output_size =
       encoder_->GetMaxCodedBufferSize(test_image->visible_size);
+  PrepareMemory(bitstream_buffer_id);
 
   auto input_buffer = gpu_memory_buffer_manager_->CreateGpuMemoryBuffer(
       test_image->visible_size, gfx::BufferFormat::YUV_420_BIPLANAR,
       gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE, gpu::kNullSurfaceHandle);
   ASSERT_EQ(input_buffer->Map(), true);
-  memcpy(input_buffer->memory(0), test_image->image_data.data(),
-         test_image->image_data.size());
+
+  uint8_t* plane_buf[2] = {static_cast<uint8_t*>(input_buffer->memory(0)),
+                           static_cast<uint8_t*>(input_buffer->memory(1))};
+  uint8_t* src = test_image->image_data.data();
+  int width = test_image->visible_size.width();
+  int height = test_image->visible_size.height();
+
+  libyuv::I420ToNV12(src, width, src + width * height, width / 2,
+                     src + width * height * 5 / 4, width / 2, plane_buf[0],
+                     width, plane_buf[1], width, width, height);
+
   auto input_frame = GetVideoFrameFromGpuMemoryBuffer(
       input_buffer.get(), test_image->visible_size, media::PIXEL_FORMAT_NV12);
   LOG_ASSERT(input_frame.get());
 
   auto output_buffer = gpu_memory_buffer_manager_->CreateGpuMemoryBuffer(
-      test_image->visible_size, gfx::BufferFormat::R_8,
+      gfx::Size(kJpegMaxSize, 1), gfx::BufferFormat::R_8,
       gfx::BufferUsage::CAMERA_AND_CPU_READ_WRITE, gpu::kNullSurfaceHandle);
   ASSERT_EQ(output_buffer->Map(), true);
-  auto output_frame = GetVideoFrameFromGpuMemoryBuffer(
+  hw_out_frame_ = GetVideoFrameFromGpuMemoryBuffer(
       output_buffer.get(), test_image->visible_size, media::PIXEL_FORMAT_MJPEG);
-  LOG_ASSERT(output_frame.get());
+  LOG_ASSERT(hw_out_frame_.get());
 
   buffer_id_to_start_time_[bitstream_buffer_id] = base::TimeTicks::Now();
-  encoder_->EncodeWithDmaBuf(input_frame, output_frame, kJpegDefaultQuality,
+  encoder_->EncodeWithDmaBuf(input_frame, hw_out_frame_, kJpegDefaultQuality,
                              bitstream_buffer_id, nullptr);
 }
 
@@ -637,7 +666,7 @@
  protected:
   JpegEncodeAcceleratorTest() {}
 
-  void TestEncode(size_t num_concurrent_encoders);
+  void TestEncode(size_t num_concurrent_encoders, bool is_dma);
 
   // This is needed to allow the usage of methods in post_task.h in
   // JpegEncodeAccelerator implementations.
@@ -652,7 +681,8 @@
   DISALLOW_COPY_AND_ASSIGN(JpegEncodeAcceleratorTest);
 };
 
-void JpegEncodeAcceleratorTest::TestEncode(size_t num_concurrent_encoders) {
+void JpegEncodeAcceleratorTest::TestEncode(size_t num_concurrent_encoders,
+                                           bool is_dma) {
   base::Thread encoder_thread("EncoderThread");
   ASSERT_TRUE(encoder_thread.Start());
 
@@ -677,18 +707,20 @@
             << ",width:" << test_aligned_images_[index]->visible_size.width();
     VLOG(3) << index
             << ",height:" << test_aligned_images_[index]->visible_size.height();
-    for (size_t i = 0; i < num_concurrent_encoders; i++) {
-      encoder_thread.task_runner()->PostTask(
-          FROM_HERE, base::BindOnce(&JpegClient::StartEncode,
-                                    base::Unretained(clients[i].get()), index));
-    }
-    for (size_t i = 0; i < num_concurrent_encoders; i++) {
-      ASSERT_EQ(notes[i]->Wait(), ClientState::ENCODE_PASS);
-    }
-    for (size_t i = 0; i < num_concurrent_encoders; i++) {
-      encoder_thread.task_runner()->PostTask(
-          FROM_HERE, base::BindOnce(&JpegClient::StartEncodeDmaBuf,
-                                    base::Unretained(clients[i].get()), index));
+    if (!is_dma) {
+      for (size_t i = 0; i < num_concurrent_encoders; i++) {
+        encoder_thread.task_runner()->PostTask(
+            FROM_HERE,
+            base::BindOnce(&JpegClient::StartEncode,
+                           base::Unretained(clients[i].get()), index));
+      }
+    } else {
+      for (size_t i = 0; i < num_concurrent_encoders; i++) {
+        encoder_thread.task_runner()->PostTask(
+            FROM_HERE,
+            base::BindOnce(&JpegClient::StartEncodeDmaBuf,
+                           base::Unretained(clients[i].get()), index));
+      }
     }
     for (size_t i = 0; i < num_concurrent_encoders; i++) {
       ASSERT_EQ(notes[i]->Wait(), ClientState::ENCODE_PASS);
@@ -705,24 +737,22 @@
             << ",width:" << test_images_[index]->visible_size.width();
     VLOG(3) << buffer_id
             << ",height:" << test_images_[index]->visible_size.height();
-    for (size_t i = 0; i < num_concurrent_encoders; i++) {
-      encoder_thread.task_runner()->PostTask(
-          FROM_HERE,
-          base::BindOnce(&JpegClient::StartEncode,
-                         base::Unretained(clients[i].get()), buffer_id));
-    }
 
-    for (size_t i = 0; i < num_concurrent_encoders; i++) {
-      ASSERT_EQ(notes[i]->Wait(), ClientState::ENCODE_PASS);
+    if (!is_dma) {
+      for (size_t i = 0; i < num_concurrent_encoders; i++) {
+        encoder_thread.task_runner()->PostTask(
+            FROM_HERE,
+            base::BindOnce(&JpegClient::StartEncode,
+                           base::Unretained(clients[i].get()), buffer_id));
+      }
+    } else {
+      for (size_t i = 0; i < num_concurrent_encoders; i++) {
+        encoder_thread.task_runner()->PostTask(
+            FROM_HERE,
+            base::BindOnce(&JpegClient::StartEncodeDmaBuf,
+                           base::Unretained(clients[i].get()), buffer_id));
+      }
     }
-
-    for (size_t i = 0; i < num_concurrent_encoders; i++) {
-      encoder_thread.task_runner()->PostTask(
-          FROM_HERE,
-          base::BindOnce(&JpegClient::StartEncodeDmaBuf,
-                         base::Unretained(clients[i].get()), buffer_id));
-    }
-
     for (size_t i = 0; i < num_concurrent_encoders; i++) {
       ASSERT_EQ(notes[i]->Wait(), ClientState::ENCODE_PASS);
     }
@@ -744,33 +774,68 @@
       test_images_.push_back(image.get());
     }
   }
-  TestEncode(1);
+  TestEncode(1, false);
 }
 
 TEST_F(JpegEncodeAcceleratorTest, MultipleEncoders) {
   for (auto& image : g_env->image_data_user_) {
     test_images_.push_back(image.get());
   }
-  TestEncode(3);
+  TestEncode(3, false);
 }
 
 TEST_F(JpegEncodeAcceleratorTest, ResolutionChange) {
   test_images_.push_back(g_env->image_data_640x368_black_.get());
   test_images_.push_back(g_env->image_data_640x360_black_.get());
   test_aligned_images_.push_back(g_env->image_data_1280x720_white_.get());
-  TestEncode(1);
+  TestEncode(1, false);
 }
 
 TEST_F(JpegEncodeAcceleratorTest, AlignedSizes) {
   test_aligned_images_.push_back(g_env->image_data_2560x1920_white_.get());
   test_aligned_images_.push_back(g_env->image_data_1280x720_white_.get());
   test_aligned_images_.push_back(g_env->image_data_640x480_black_.get());
-  TestEncode(1);
+  TestEncode(1, false);
 }
 
 TEST_F(JpegEncodeAcceleratorTest, CodedSizeAlignment) {
   test_images_.push_back(g_env->image_data_640x360_black_.get());
-  TestEncode(1);
+  TestEncode(1, false);
+}
+
+TEST_F(JpegEncodeAcceleratorTest, SimpleDmaEncode) {
+  for (size_t i = 0; i < g_env->repeat_; i++) {
+    for (auto& image : g_env->image_data_user_) {
+      test_images_.push_back(image.get());
+    }
+  }
+  TestEncode(1, true);
+}
+
+TEST_F(JpegEncodeAcceleratorTest, MultipleDmaEncoders) {
+  for (auto& image : g_env->image_data_user_) {
+    test_images_.push_back(image.get());
+  }
+  TestEncode(3, true);
+}
+
+TEST_F(JpegEncodeAcceleratorTest, ResolutionChangeDma) {
+  test_images_.push_back(g_env->image_data_640x368_black_.get());
+  test_images_.push_back(g_env->image_data_640x360_black_.get());
+  test_aligned_images_.push_back(g_env->image_data_1280x720_white_.get());
+  TestEncode(1, true);
+}
+
+TEST_F(JpegEncodeAcceleratorTest, AlignedSizesDma) {
+  test_aligned_images_.push_back(g_env->image_data_2560x1920_white_.get());
+  test_aligned_images_.push_back(g_env->image_data_1280x720_white_.get());
+  test_aligned_images_.push_back(g_env->image_data_640x480_black_.get());
+  TestEncode(1, true);
+}
+
+TEST_F(JpegEncodeAcceleratorTest, CodedSizeAlignmentDma) {
+  test_images_.push_back(g_env->image_data_640x360_black_.get());
+  TestEncode(1, true);
 }
 
 }  // namespace
diff --git a/components/chromeos_camera/mjpeg_decode_accelerator_unittest.cc b/components/chromeos_camera/mjpeg_decode_accelerator_unittest.cc
index 1bd1f73..640b324 100644
--- a/components/chromeos_camera/mjpeg_decode_accelerator_unittest.cc
+++ b/components/chromeos_camera/mjpeg_decode_accelerator_unittest.cc
@@ -835,7 +835,8 @@
 
   // Needed to enable DVLOG through --vmodule.
   logging::LoggingSettings settings;
-  settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
+  settings.logging_dest =
+      logging::LOG_TO_SYSTEM_DEBUG_LOG | logging::LOG_TO_STDERR;
   LOG_ASSERT(logging::InitLogging(settings));
 
   const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
diff --git a/components/exo/pointer.cc b/components/exo/pointer.cc
index cb524cc..9e0bbed 100644
--- a/components/exo/pointer.cc
+++ b/components/exo/pointer.cc
@@ -193,15 +193,20 @@
 }
 
 void Pointer::SetGesturePinchDelegate(PointerGesturePinchDelegate* delegate) {
+  // For the |pinch_delegate_| (and |relative_pointer_delegate_| below) it is
+  // possible to bind multiple extensions to the same pointer interface (not
+  // that this is a particularly reasonable thing to do). When that happens we
+  // choose to only keep a single binding alive, so we simulate pointer
+  // destruction for the previous binding.
+  if (pinch_delegate_)
+    pinch_delegate_->OnPointerDestroying(this);
   pinch_delegate_ = delegate;
 }
 
 void Pointer::RegisterRelativePointerDelegate(
     RelativePointerDelegate* delegate) {
-  // It does not seem that wayland forbids multiple relative pointer interfaces
-  // being registered against the same pointer, though that is not really
-  // reasonable behaviour.
-  DCHECK(!relative_pointer_delegate_);
+  if (relative_pointer_delegate_)
+    relative_pointer_delegate_->OnPointerDestroying(this);
   relative_pointer_delegate_ = delegate;
 }
 
@@ -334,8 +339,7 @@
 
   TRACE_EXO_INPUT_EVENT(event);
 
-  if (event->IsMouseEvent() &&
-      event->type() != ui::ET_MOUSE_EXITED &&
+  if (event->IsMouseEvent() && event->type() != ui::ET_MOUSE_EXITED &&
       event->type() != ui::ET_MOUSE_CAPTURE_CHANGED) {
     // Generate motion event if location changed. We need to check location
     // here as mouse movement can generate both "moved" and "entered" events
diff --git a/components/exo/wayland/fuzzer/harness.cc.tmpl b/components/exo/wayland/fuzzer/harness.cc.tmpl
index d9723c0..2e2857a 100644
--- a/components/exo/wayland/fuzzer/harness.cc.tmpl
+++ b/components/exo/wayland/fuzzer/harness.cc.tmpl
@@ -78,6 +78,8 @@
             if (!{{arg.name}})
 	      return;
           {% endif %}
+	{% elif arg.type == 'fd' %}
+	  int {{arg.name}} = harness->GetFileDescriptor(action.{{arg.name}}());
         {% endif %}
       {% endfor %}
       {% if request.is_constructor %}
@@ -85,7 +87,7 @@
       {% endif %}
       {{interface.name}}_{{request.name}}(receiver
         {% for arg in request.args %}
-          {% if arg.type == 'object' %}
+          {% if arg.type == 'object' or arg.type == 'fd' %}
             , {{arg.name}}
           {% elif arg.type != 'new_id' %}
             , action.{{arg.name}}(){% if arg.type == 'string' %}.c_str(){% endif %}
@@ -181,5 +183,15 @@
   }
 }
 
+int Harness::GetFileDescriptor(int id) {
+  if (shared_memory_map_.count(id) == 0) {
+    auto shared_mem = std::make_unique<base::SharedMemory>();
+    shared_mem->CreateAndMapAnonymous(1);
+    shared_memory_map_.emplace(id, std::move(shared_mem));
+  }
+  return base::SharedMemory::GetFdFromSharedMemoryHandle(
+    base::SharedMemory::DuplicateHandle(shared_memory_map_[id]->handle()));
+}
+
 }  // namespace wayland_fuzzer
 }  // namespace exo
diff --git a/components/exo/wayland/fuzzer/harness.h.tmpl b/components/exo/wayland/fuzzer/harness.h.tmpl
index da2d22a..8831e05 100644
--- a/components/exo/wayland/fuzzer/harness.h.tmpl
+++ b/components/exo/wayland/fuzzer/harness.h.tmpl
@@ -6,8 +6,10 @@
 #define COMPONENTS_EXO_WAYLAND_FUZZER_HARNESS_H_
 
 #include <memory>
+#include <map>
 
 #include "base/macros.h"
+#include "base/memory/shared_memory.h"
 #include "components/exo/wayland/fuzzer/actions.pb.h"
 
 // Forwards declarations for the wayland-defined structs.
@@ -54,7 +56,11 @@
     {% endif %}
   {% endfor %}
 
+  int GetFileDescriptor(int id);
+
  private:
+  std::map<int, std::unique_ptr<base::SharedMemory>> shared_memory_map_;
+
   DISALLOW_COPY_AND_ASSIGN(Harness);
 };
 
diff --git a/components/exo/wayland/fuzzer/wayland_templater.py b/components/exo/wayland/fuzzer/wayland_templater.py
index b62e1537..30412d9 100644
--- a/components/exo/wayland/fuzzer/wayland_templater.py
+++ b/components/exo/wayland/fuzzer/wayland_templater.py
@@ -21,7 +21,7 @@
     'int': 'int32',
     'uint': 'uint32',
     'string': 'string',
-    'fd': 'uint32',
+    'fd': 'small_value',
 }
 
 cpp_type_conversions = {
@@ -30,7 +30,7 @@
     'fixed': 'wl_fixed_t',
     'string': 'const char*',
     'array': 'struct wl_array*',
-    'fd': 'int32_t',
+    'fd': 'int',
 }
 
 
diff --git a/components/favicon/core/features.cc b/components/favicon/core/features.cc
index d018a51..d75b6777 100644
--- a/components/favicon/core/features.cc
+++ b/components/favicon/core/features.cc
@@ -14,6 +14,6 @@
     "EnableHistoryFaviconsGoogleServerQuery", base::FEATURE_DISABLED_BY_DEFAULT};
 const base::Feature kNotifySessionsOfMostRecentIconUrlChange{
     "NotifySessionsOfMostRecentIconUrlChange",
-    base::FEATURE_DISABLED_BY_DEFAULT};
+    base::FEATURE_ENABLED_BY_DEFAULT};
 
 }  // namespace favicon
diff --git a/components/gwp_asan/crash_handler/BUILD.gn b/components/gwp_asan/crash_handler/BUILD.gn
index 1152d51f..466c06f 100644
--- a/components/gwp_asan/crash_handler/BUILD.gn
+++ b/components/gwp_asan/crash_handler/BUILD.gn
@@ -8,9 +8,6 @@
   sources = [
     "crash_analyzer.cc",
     "crash_analyzer.h",
-    "crash_analyzer_linux.cc",
-    "crash_analyzer_mac.cc",
-    "crash_analyzer_win.cc",
     "crash_handler.cc",
     "crash_handler.h",
   ]
diff --git a/components/gwp_asan/crash_handler/crash_analyzer.cc b/components/gwp_asan/crash_handler/crash_analyzer.cc
index 9d42882..25cf682 100644
--- a/components/gwp_asan/crash_handler/crash_analyzer.cc
+++ b/components/gwp_asan/crash_handler/crash_analyzer.cc
@@ -8,6 +8,7 @@
 #include <algorithm>
 #include <memory>
 #include <string>
+#include <vector>
 
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
@@ -25,6 +26,14 @@
 #include "third_party/crashpad/crashpad/snapshot/process_snapshot.h"
 #include "third_party/crashpad/crashpad/util/process/process_memory.h"
 
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+#include <signal.h>
+#elif defined(OS_MACOSX)
+#include <mach/exception_types.h>
+#elif defined(OS_WIN)
+#include <windows.h>
+#endif
+
 namespace gwp_asan {
 namespace internal {
 
@@ -70,6 +79,29 @@
   return false;
 }
 
+crashpad::VMAddress CrashAnalyzer::GetAccessAddress(
+    const crashpad::ExceptionSnapshot& exception) {
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+  if (exception.Exception() == SIGSEGV || exception.Exception() == SIGBUS)
+    return exception.ExceptionAddress();
+#elif defined(OS_MACOSX)
+  if (exception.Exception() == EXC_BAD_ACCESS)
+    return exception.ExceptionAddress();
+#elif defined(OS_WIN)
+  if (exception.Exception() == EXCEPTION_ACCESS_VIOLATION) {
+    const std::vector<uint64_t>& codes = exception.Codes();
+    if (codes.size() < 2)
+      DLOG(FATAL) << "Exception array is too small! " << codes.size();
+    else
+      return codes[1];
+  }
+#else
+#error "Unknown platform"
+#endif
+
+  return 0;
+}
+
 crashpad::VMAddress CrashAnalyzer::GetAllocatorAddress(
     const crashpad::ProcessSnapshot& process_snapshot,
     const char* annotation_name) {
diff --git a/components/gwp_asan/crash_handler/crash_analyzer_linux.cc b/components/gwp_asan/crash_handler/crash_analyzer_linux.cc
deleted file mode 100644
index 4f44f0e..0000000
--- a/components/gwp_asan/crash_handler/crash_analyzer_linux.cc
+++ /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.
-
-#include "components/gwp_asan/crash_handler/crash_analyzer.h"
-
-#include <signal.h>
-
-#include "third_party/crashpad/crashpad/snapshot/exception_snapshot.h"
-
-namespace gwp_asan {
-namespace internal {
-
-crashpad::VMAddress CrashAnalyzer::GetAccessAddress(
-    const crashpad::ExceptionSnapshot& exception) {
-  if (exception.Exception() != SIGSEGV && exception.Exception() != SIGBUS)
-    return 0;
-
-  return exception.ExceptionAddress();
-}
-
-}  // namespace internal
-}  // namespace gwp_asan
diff --git a/components/gwp_asan/crash_handler/crash_analyzer_mac.cc b/components/gwp_asan/crash_handler/crash_analyzer_mac.cc
deleted file mode 100644
index e3450a5..0000000
--- a/components/gwp_asan/crash_handler/crash_analyzer_mac.cc
+++ /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.
-
-#include "components/gwp_asan/crash_handler/crash_analyzer.h"
-
-#include <mach/exception_types.h>
-
-#include "third_party/crashpad/crashpad/snapshot/exception_snapshot.h"
-
-namespace gwp_asan {
-namespace internal {
-
-crashpad::VMAddress CrashAnalyzer::GetAccessAddress(
-    const crashpad::ExceptionSnapshot& exception) {
-  if (exception.Exception() != EXC_BAD_ACCESS)
-    return 0;
-
-  return exception.ExceptionAddress();
-}
-
-}  // namespace internal
-}  // namespace gwp_asan
diff --git a/components/gwp_asan/crash_handler/crash_analyzer_win.cc b/components/gwp_asan/crash_handler/crash_analyzer_win.cc
deleted file mode 100644
index 5c2d14d..0000000
--- a/components/gwp_asan/crash_handler/crash_analyzer_win.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/gwp_asan/crash_handler/crash_analyzer.h"
-
-#include <windows.h>
-
-#include "base/logging.h"
-#include "third_party/crashpad/crashpad/snapshot/exception_snapshot.h"
-
-namespace gwp_asan {
-namespace internal {
-
-crashpad::VMAddress CrashAnalyzer::GetAccessAddress(
-    const crashpad::ExceptionSnapshot& exception) {
-  if (exception.Exception() != EXCEPTION_ACCESS_VIOLATION)
-    return 0;
-
-  const std::vector<uint64_t>& codes = exception.Codes();
-  if (codes.size() < 2) {
-    DLOG(FATAL) << "Exception array is too small! " << codes.size();
-    return 0;
-  }
-
-  return codes[1];
-}
-
-}  // namespace internal
-}  // namespace gwp_asan
diff --git a/components/password_manager/core/browser/BUILD.gn b/components/password_manager/core/browser/BUILD.gn
index 477ccec..487e65bd 100644
--- a/components/password_manager/core/browser/BUILD.gn
+++ b/components/password_manager/core/browser/BUILD.gn
@@ -397,7 +397,6 @@
     "//url:url",
   ]
   deps = [
-    ":csv_unittests",
     "//base",
     "//components/autofill/core/common",
     "//net:net",
@@ -533,6 +532,7 @@
   }
 
   deps = [
+    ":csv_unittests",
     ":hash_password_manager",
     ":password_generator",
     ":password_hash_data",
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 79305a6..d65ddbf 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -12733,7 +12733,7 @@
       If the policy is enabled, users will be unable to opt out of the default behavior where each site runs in its own process.
       If the policy is not configured or disabled, the user will be able to opt out of site isolation
       (e.g. using "Disable site isolation" entry in chrome://flags).  Setting the policy to disabled and/or not configuring the policy does not turn off Site Isolation.
-      On <ph name="PRODUCT_OS_NAME">$2<ex>Google Chrome OS</ex></ph>, it is recommended to also set the <ph name="DEVICE_LOGIN_SCREEN_SITE_PER_PROCESS_POLICY_NAME">DeviceLoginScreenSitePerProcess</ph> device policy to the same value. If the values specified by the two policies don't match, a delay may be incurred when entering a user session while the value specified by user policy is being applied.
+      On <ph name="PRODUCT_OS_NAME">$2<ex>Google Chrome OS</ex></ph> version 76 and earlier, it is recommended to also set the <ph name="DEVICE_LOGIN_SCREEN_SITE_PER_PROCESS_POLICY_NAME">DeviceLoginScreenSitePerProcess</ph> device policy to the same value. If the values specified by the two policies don't match, a delay may be incurred when entering a user session while the value specified by user policy is being applied.
 
       NOTE: This policy does not apply on Android. To enable SitePerProcess on Android, use the SitePerProcessAndroid policy setting.
       ''',
@@ -12762,7 +12762,7 @@
       'name': 'DeviceLoginScreenSitePerProcess',
       'type': 'main',
       'schema': { 'type': 'boolean' },
-      'supported_on': ['chrome_os:66-'],
+      'supported_on': ['chrome_os:66-76'],
       'device_only': True,
       'features': {
         'dynamic_refresh': False,
@@ -12774,9 +12774,6 @@
       'tags': ['system-security'],
       'desc': '''
       This policy applies to the sign-in screen. Please see also the <ph name="SITE_PER_PROCESS_POLICY_NAME">SitePerProcess</ph> policy which applies to the user session. It is recommended to set both policies to the same value. If the values don't match, a delay may be incurred when entering a user session while the value specified by user policy is being applied.
-      This setting, DeviceLoginScreenSitePerProcess, may be used to disallow users from opting out of the default behavior of isolating all sites. Note that the DeviceLoginScreenIsolateOrigins policy may also be useful for isolating additional, finer-grained origins.
-      If the policy is enabled, users will be unable to opt out of the default behavior where each site runs in its own process.
-      If the policy is not configured or disabled, the user will be able to change this setting (e.g. using "Disable site isolation" entry in chrome://flags).
       ''',
     },
     {
@@ -15353,6 +15350,7 @@
         'dynamic_refresh': True,
         'per_profile': False,
       },
+      'future': True,
       'example_value': False,
       'id': 532,
       'caption': '''Allows wilco diagnostics and telemetry controller''',
@@ -15402,6 +15400,7 @@
         'dynamic_refresh': True,
         'per_profile': False,
       },
+      'future': True,
       'example_value': {
         "url": "https://example.com/wilcodtcconfig",
         "hash": "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
diff --git a/components/safe_browsing/db/BUILD.gn b/components/safe_browsing/db/BUILD.gn
index 96fe817..1a51f76 100644
--- a/components/safe_browsing/db/BUILD.gn
+++ b/components/safe_browsing/db/BUILD.gn
@@ -362,13 +362,14 @@
 source_set("unit_tests_shared") {
   testonly = true
   sources = [
+    "allowlist_checker_client_unittest.cc",
     "database_manager_unittest.cc",
     "util_unittest.cc",
     "v4_get_hash_protocol_manager_unittest.cc",
     "v4_protocol_manager_util_unittest.cc",
-    "whitelist_checker_client_unittest.cc",
   ]
   deps = [
+    ":allowlist_checker_client",
     ":database_manager",
     ":safebrowsing_proto",
     ":test_database_manager",
@@ -376,7 +377,6 @@
     ":v4_get_hash_protocol_manager",
     ":v4_protocol_manager_util",
     ":v4_test_util",
-    ":whitelist_checker_client",
     "//base",
     "//content/public/browser",
     "//content/test:test_support",
@@ -430,10 +430,10 @@
   }
 }
 
-static_library("whitelist_checker_client") {
+static_library("allowlist_checker_client") {
   sources = [
-    "whitelist_checker_client.cc",
-    "whitelist_checker_client.h",
+    "allowlist_checker_client.cc",
+    "allowlist_checker_client.h",
   ]
   deps = [
     ":database_manager",
@@ -441,15 +441,15 @@
   ]
 }
 
-source_set("whitelist_checker_client_unittest") {
+source_set("allowlist_checker_client_unittest") {
   testonly = true
   sources = [
-    "whitelist_checker_client_unittest.cc",
+    "allowlist_checker_client_unittest.cc",
   ]
   deps = [
+    ":allowlist_checker_client",
     ":database_manager",
     ":test_database_manager",
-    ":whitelist_checker_client",
     "//base:base",
     "//base/test:test_support",
     "//content/public/browser",
diff --git a/components/safe_browsing/db/whitelist_checker_client.cc b/components/safe_browsing/db/allowlist_checker_client.cc
similarity index 67%
rename from components/safe_browsing/db/whitelist_checker_client.cc
rename to components/safe_browsing/db/allowlist_checker_client.cc
index 8bfcb204..cb909af 100644
--- a/components/safe_browsing/db/whitelist_checker_client.cc
+++ b/components/safe_browsing/db/allowlist_checker_client.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/safe_browsing/db/whitelist_checker_client.h"
+#include "components/safe_browsing/db/allowlist_checker_client.h"
 
 #include <memory>
 
@@ -11,29 +11,29 @@
 namespace safe_browsing {
 
 // Static
-void WhitelistCheckerClient::StartCheckCsdWhitelist(
+void AllowlistCheckerClient::StartCheckCsdWhitelist(
     scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
     const GURL& url,
     base::Callback<void(bool)> callback_for_result) {
   // TODO(nparker): Maybe also call SafeBrowsingDatabaseManager::CanCheckUrl()
   if (!url.is_valid()) {
-    callback_for_result.Run(true /* is_whitelisted */);
+    callback_for_result.Run(true /* did_match_allowlist */);
     return;
   }
 
   // Make a client for each request. The caller could have several in
   // flight at once.
-  std::unique_ptr<WhitelistCheckerClient> client =
-      std::make_unique<WhitelistCheckerClient>(callback_for_result,
+  std::unique_ptr<AllowlistCheckerClient> client =
+      std::make_unique<AllowlistCheckerClient>(callback_for_result,
                                                database_manager);
   AsyncMatch match = database_manager->CheckCsdWhitelistUrl(url, client.get());
 
   switch (match) {
     case AsyncMatch::MATCH:
-      callback_for_result.Run(true /* is_whitelisted */);
+      callback_for_result.Run(true /* did_match_allowlist */);
       break;
     case AsyncMatch::NO_MATCH:
-      callback_for_result.Run(false /* is_whitelisted */);
+      callback_for_result.Run(false /* did_match_allowlist */);
       break;
     case AsyncMatch::ASYNC:
       // Client is now self-owned. When it gets called back with the result,
@@ -43,7 +43,7 @@
   }
 }
 
-WhitelistCheckerClient::WhitelistCheckerClient(
+AllowlistCheckerClient::AllowlistCheckerClient(
     base::Callback<void(bool)> callback_for_result,
     scoped_refptr<SafeBrowsingDatabaseManager> database_manager)
     : callback_for_result_(callback_for_result),
@@ -52,25 +52,26 @@
   // Set a timer to fail open, i.e. call it "whitelisted", if the full
   // check takes too long.
   auto timeout_callback =
-      base::Bind(&WhitelistCheckerClient::OnCheckWhitelistUrlTimeout,
+      base::Bind(&AllowlistCheckerClient::OnCheckWhitelistUrlTimeout,
                  weak_factory_.GetWeakPtr());
   timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kTimeoutMsec),
                timeout_callback);
 }
 
-WhitelistCheckerClient::~WhitelistCheckerClient() {}
+AllowlistCheckerClient::~AllowlistCheckerClient() {}
 
 // SafeBrowsingDatabaseMananger::Client impl
-void WhitelistCheckerClient::OnCheckWhitelistUrlResult(bool is_whitelisted) {
+void AllowlistCheckerClient::OnCheckWhitelistUrlResult(
+    bool did_match_allowlist) {
   timer_.Stop();
-  callback_for_result_.Run(is_whitelisted);
+  callback_for_result_.Run(did_match_allowlist);
   // This method is invoked only if we're already self-owned.
   delete this;
 }
 
-void WhitelistCheckerClient::OnCheckWhitelistUrlTimeout() {
+void AllowlistCheckerClient::OnCheckWhitelistUrlTimeout() {
   database_manager_->CancelCheck(this);
-  this->OnCheckWhitelistUrlResult(true /* is_whitelisted */);
+  this->OnCheckWhitelistUrlResult(true /* did_match_allowlist */);
 }
 
 }  // namespace safe_browsing
diff --git a/components/safe_browsing/db/whitelist_checker_client.h b/components/safe_browsing/db/allowlist_checker_client.h
similarity index 78%
rename from components/safe_browsing/db/whitelist_checker_client.h
rename to components/safe_browsing/db/allowlist_checker_client.h
index be0dd689..957bd5c4 100644
--- a/components/safe_browsing/db/whitelist_checker_client.h
+++ b/components/safe_browsing/db/allowlist_checker_client.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_SAFE_BROWSING_DB_WHITELIST_CHECKER_CLIENT_H_
-#define COMPONENTS_SAFE_BROWSING_DB_WHITELIST_CHECKER_CLIENT_H_
+#ifndef COMPONENTS_SAFE_BROWSING_DB_ALLOWLIST_CHECKER_CLIENT_H_
+#define COMPONENTS_SAFE_BROWSING_DB_ALLOWLIST_CHECKER_CLIENT_H_
 
 #include "base/memory/weak_ptr.h"
 #include "base/timer/timer.h"
@@ -15,7 +15,7 @@
 // SafeBrowsingDatabaseManager::CheckCsdWhitelistUrl() for callers that
 // don't want to track their own clients.
 
-class WhitelistCheckerClient : public SafeBrowsingDatabaseManager::Client {
+class AllowlistCheckerClient : public SafeBrowsingDatabaseManager::Client {
  public:
   using BoolCallback = base::Callback<void(bool /* is_whitelisted */)>;
 
@@ -27,10 +27,10 @@
       const GURL& url,
       BoolCallback callback_for_result);
 
-  WhitelistCheckerClient(
+  AllowlistCheckerClient(
       BoolCallback callback_for_result,
       scoped_refptr<SafeBrowsingDatabaseManager> database_manager);
-  ~WhitelistCheckerClient() override;
+  ~AllowlistCheckerClient() override;
 
   // SafeBrowsingDatabaseMananger::Client impl
   void OnCheckWhitelistUrlResult(bool is_whitelisted) override;
@@ -40,10 +40,10 @@
   base::OneShotTimer timer_;
   BoolCallback callback_for_result_;
   scoped_refptr<SafeBrowsingDatabaseManager> database_manager_;
-  base::WeakPtrFactory<WhitelistCheckerClient> weak_factory_;
+  base::WeakPtrFactory<AllowlistCheckerClient> weak_factory_;
 
  private:
-  WhitelistCheckerClient();
+  AllowlistCheckerClient();
 
   // Called when the call to CheckCsdWhitelistUrl times out.
   void OnCheckWhitelistUrlTimeout();
@@ -51,4 +51,4 @@
 
 }  // namespace safe_browsing
 
-#endif  // COMPONENTS_SAFE_BROWSING_DB_WHITELIST_CHECKER_CLIENT_H_
+#endif  // COMPONENTS_SAFE_BROWSING_DB_ALLOWLIST_CHECKER_CLIENT_H_
diff --git a/components/safe_browsing/db/whitelist_checker_client_unittest.cc b/components/safe_browsing/db/allowlist_checker_client_unittest.cc
similarity index 78%
rename from components/safe_browsing/db/whitelist_checker_client_unittest.cc
rename to components/safe_browsing/db/allowlist_checker_client_unittest.cc
index 1ef5d18..c094cabf 100644
--- a/components/safe_browsing/db/whitelist_checker_client_unittest.cc
+++ b/components/safe_browsing/db/allowlist_checker_client_unittest.cc
@@ -1,7 +1,7 @@
 // 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 "components/safe_browsing/db/whitelist_checker_client.h"
+#include "components/safe_browsing/db/allowlist_checker_client.h"
 
 #include <memory>
 
@@ -23,7 +23,7 @@
 using testing::Return;
 using testing::SaveArg;
 
-using BoolCallback = base::Callback<void(bool /* is_whitelisted */)>;
+using BoolCallback = base::Callback<void(bool /* did_match_allowlist */)>;
 using MockBoolCallback = testing::StrictMock<base::MockCallback<BoolCallback>>;
 
 namespace {
@@ -44,9 +44,9 @@
 };
 }  // namespace
 
-class WhitelistCheckerClientTest : public testing::Test {
+class AllowlistCheckerClientTest : public testing::Test {
  public:
-  WhitelistCheckerClientTest()
+  AllowlistCheckerClientTest()
       : thread_bundle_(
             base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME),
         target_url_("http://foo.bar") {}
@@ -72,54 +72,54 @@
   scoped_refptr<MockSafeBrowsingDatabaseManager> database_manager_;
 };
 
-TEST_F(WhitelistCheckerClientTest, TestMatch) {
+TEST_F(AllowlistCheckerClientTest, TestMatch) {
   EXPECT_CALL(*database_manager_, CheckCsdWhitelistUrl(target_url_, _))
       .WillOnce(Return(AsyncMatch::MATCH));
 
   MockBoolCallback callback;
-  EXPECT_CALL(callback, Run(true /* is_whitelisted */));
-  WhitelistCheckerClient::StartCheckCsdWhitelist(database_manager_, target_url_,
+  EXPECT_CALL(callback, Run(true /* did_match_allowlist */));
+  AllowlistCheckerClient::StartCheckCsdWhitelist(database_manager_, target_url_,
                                                  callback.Get());
 }
 
-TEST_F(WhitelistCheckerClientTest, TestNoMatch) {
+TEST_F(AllowlistCheckerClientTest, TestNoMatch) {
   EXPECT_CALL(*database_manager_, CheckCsdWhitelistUrl(target_url_, _))
       .WillOnce(Return(AsyncMatch::NO_MATCH));
 
   MockBoolCallback callback;
-  EXPECT_CALL(callback, Run(false /* is_whitelisted */));
-  WhitelistCheckerClient::StartCheckCsdWhitelist(database_manager_, target_url_,
+  EXPECT_CALL(callback, Run(false /* did_match_allowlist */));
+  AllowlistCheckerClient::StartCheckCsdWhitelist(database_manager_, target_url_,
                                                  callback.Get());
 }
 
-TEST_F(WhitelistCheckerClientTest, TestAsyncNoMatch) {
+TEST_F(AllowlistCheckerClientTest, TestAsyncNoMatch) {
   SafeBrowsingDatabaseManager::Client* client;
   EXPECT_CALL(*database_manager_, CheckCsdWhitelistUrl(target_url_, _))
       .WillOnce(DoAll(SaveArg<1>(&client), Return(AsyncMatch::ASYNC)));
 
   MockBoolCallback callback;
-  WhitelistCheckerClient::StartCheckCsdWhitelist(database_manager_, target_url_,
+  AllowlistCheckerClient::StartCheckCsdWhitelist(database_manager_, target_url_,
                                                  callback.Get());
   // Callback should not be called yet.
 
-  EXPECT_CALL(callback, Run(false /* is_whitelisted */));
+  EXPECT_CALL(callback, Run(false /* did_match_allowlist */));
   // The self-owned client deletes itself here.
   client->OnCheckWhitelistUrlResult(false);
 }
 
-TEST_F(WhitelistCheckerClientTest, TestAsyncTimeout) {
+TEST_F(AllowlistCheckerClientTest, TestAsyncTimeout) {
   SafeBrowsingDatabaseManager::Client* client;
   EXPECT_CALL(*database_manager_, CheckCsdWhitelistUrl(target_url_, _))
       .WillOnce(DoAll(SaveArg<1>(&client), Return(AsyncMatch::ASYNC)));
   EXPECT_CALL(*database_manager_, CancelCheck(_)).Times(1);
 
   MockBoolCallback callback;
-  WhitelistCheckerClient::StartCheckCsdWhitelist(database_manager_, target_url_,
+  AllowlistCheckerClient::StartCheckCsdWhitelist(database_manager_, target_url_,
                                                  callback.Get());
   thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(1));
   // No callback yet.
 
-  EXPECT_CALL(callback, Run(true /* is_whitelisted */));
+  EXPECT_CALL(callback, Run(true /* did_match_allowlist */));
   thread_bundle_.FastForwardBy(base::TimeDelta::FromSeconds(5));
 }
 
diff --git a/components/safe_browsing/db/database_manager.h b/components/safe_browsing/db/database_manager.h
index b53ee6f..a211cab 100644
--- a/components/safe_browsing/db/database_manager.h
+++ b/components/safe_browsing/db/database_manager.h
@@ -88,12 +88,12 @@
 
     // Called when the result of checking a whitelist is known.
     // Currently only used for CSD whitelist.
-    virtual void OnCheckWhitelistUrlResult(bool is_whitelisted) {}
+    virtual void OnCheckWhitelistUrlResult(bool did_match_allowlist) {}
 
     // Called when the result of checking the high-confidence allowlist is
     // known.
-    virtual void OnCheckUrlForHighConfidenceAllowlist(bool is_high_confidence) {
-    }
+    virtual void OnCheckUrlForHighConfidenceAllowlist(
+        bool did_match_allowlist) {}
   };
 
   //
diff --git a/components/safe_browsing/password_protection/BUILD.gn b/components/safe_browsing/password_protection/BUILD.gn
index 9b536d1f..6025f637 100644
--- a/components/safe_browsing/password_protection/BUILD.gn
+++ b/components/safe_browsing/password_protection/BUILD.gn
@@ -32,9 +32,9 @@
       "//components/safe_browsing/common:common",
       "//components/safe_browsing/common:interfaces",
       "//components/safe_browsing/common:safe_browsing_prefs",
+      "//components/safe_browsing/db:allowlist_checker_client",
       "//components/safe_browsing/db:database_manager",
       "//components/safe_browsing/db:v4_protocol_manager_util",
-      "//components/safe_browsing/db:whitelist_checker_client",
       "//components/safe_browsing/web_ui:web_ui",
       "//components/sessions",
       "//components/zoom",
diff --git a/components/safe_browsing/password_protection/password_protection_request.cc b/components/safe_browsing/password_protection/password_protection_request.cc
index 4011c88..5abb19c 100644
--- a/components/safe_browsing/password_protection/password_protection_request.cc
+++ b/components/safe_browsing/password_protection/password_protection_request.cc
@@ -14,7 +14,7 @@
 #include "base/time/time.h"
 #include "components/password_manager/core/browser/password_reuse_detector.h"
 #include "components/safe_browsing/common/safe_browsing.mojom.h"
-#include "components/safe_browsing/db/whitelist_checker_client.h"
+#include "components/safe_browsing/db/allowlist_checker_client.h"
 #include "components/safe_browsing/password_protection/metrics_util.h"
 #include "components/safe_browsing/password_protection/password_protection_navigation_throttle.h"
 #include "components/safe_browsing/password_protection/visual_utils.h"
@@ -125,7 +125,7 @@
   tracker_.PostTask(
       base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::IO}).get(),
       FROM_HERE,
-      base::BindOnce(&WhitelistCheckerClient::StartCheckCsdWhitelist,
+      base::BindOnce(&AllowlistCheckerClient::StartCheckCsdWhitelist,
                      password_protection_service_->database_manager(),
                      main_frame_url_, result_callback));
 }
diff --git a/components/safe_browsing/password_protection/password_protection_service.cc b/components/safe_browsing/password_protection/password_protection_service.cc
index b84eaf47..e00adaa 100644
--- a/components/safe_browsing/password_protection/password_protection_service.cc
+++ b/components/safe_browsing/password_protection/password_protection_service.cc
@@ -23,7 +23,6 @@
 #include "components/password_manager/core/browser/password_reuse_detector.h"
 #include "components/safe_browsing/common/utils.h"
 #include "components/safe_browsing/db/database_manager.h"
-#include "components/safe_browsing/db/whitelist_checker_client.h"
 #include "components/safe_browsing/password_protection/password_protection_navigation_throttle.h"
 #include "components/safe_browsing/password_protection/password_protection_request.h"
 #include "components/zoom/zoom_controller.h"
diff --git a/components/security_interstitials/content/origin_policy_interstitial_page.cc b/components/security_interstitials/content/origin_policy_interstitial_page.cc
index 3697645..5008b3d 100644
--- a/components/security_interstitials/content/origin_policy_interstitial_page.cc
+++ b/components/security_interstitials/content/origin_policy_interstitial_page.cc
@@ -117,7 +117,8 @@
 }
 
 void OriginPolicyInterstitialPage::OnProceed() {
-  content::OriginPolicyAddExceptionFor(request_url());
+  content::OriginPolicyAddExceptionFor(web_contents()->GetBrowserContext(),
+                                       request_url());
   web_contents()->GetController().Reload(content::ReloadType::NORMAL, true);
 }
 
diff --git a/components/services/app_service/OWNERS b/components/services/app_service/OWNERS
new file mode 100644
index 0000000..04b484a
--- /dev/null
+++ b/components/services/app_service/OWNERS
@@ -0,0 +1,2 @@
+dominickn@chromium.org
+nigeltao@chromium.org
diff --git a/components/services/app_service/README.md b/components/services/app_service/README.md
new file mode 100644
index 0000000..0c212347
--- /dev/null
+++ b/components/services/app_service/README.md
@@ -0,0 +1,5 @@
+This directory houses the App Service.
+
+A future CL will move the App Service from its current home in
+//chrome/services/app_service to here to allow the App Service
+to be used from targets that cannot depend on //chrome (notably, //ash).
diff --git a/components/services/app_service/public/mojom/BUILD.gn b/components/services/app_service/public/mojom/BUILD.gn
new file mode 100644
index 0000000..b08a3b4
--- /dev/null
+++ b/components/services/app_service/public/mojom/BUILD.gn
@@ -0,0 +1,11 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("mojom") {
+  sources = [
+    "types.mojom",
+  ]
+}
diff --git a/components/services/app_service/public/mojom/OWNERS b/components/services/app_service/public/mojom/OWNERS
new file mode 100644
index 0000000..08850f4
--- /dev/null
+++ b/components/services/app_service/public/mojom/OWNERS
@@ -0,0 +1,2 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/components/services/app_service/public/mojom/types.mojom b/components/services/app_service/public/mojom/types.mojom
new file mode 100644
index 0000000..5e4aaa6
--- /dev/null
+++ b/components/services/app_service/public/mojom/types.mojom
@@ -0,0 +1,48 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module apps.mojom;
+
+// Enumeration of possible app launch sources.
+// This should be kept in sync with LaunchSource in
+// extensions/common/api/app_runtime.idl, and GetLaunchSourceEnum() in
+// extensions/browser/api/app_runtime/app_runtime_api.cc.
+// Note the enumeration is used in UMA histogram so entries
+// should not be re-ordered or removed.
+enum AppLaunchSource {
+  kSourceNone = 0,
+  kSourceUntracked = 1,
+  kSourceAppLauncher = 2,
+  kSourceNewTabPage = 3,
+  kSourceReload = 4,
+  kSourceRestart = 5,
+  kSourceLoadAndLaunch = 6,
+  kSourceCommandLine = 7,
+  kSourceFileHandler = 8,
+  kSourceUrlHandler = 9,
+  kSourceSystemTray = 10,
+  kSourceAboutPage = 11,
+  kSourceKeyboard = 12,
+  kSourceExtensionsPage = 13,
+  kSourceManagementApi = 14,
+  kSourceEphemeralAppDeprecated = 15,
+  kSourceBackground = 16,
+  kSourceKiosk = 17,
+  kSourceChromeInternal = 18,
+  kSourceTest = 19,
+  kSourceInstalledNotification = 20,
+  kSourceContextMenu = 21,
+  kSourceArc = 22,
+};
+
+// Don't remove items or change the order of this enum.  It's used in
+// histograms and preferences.
+enum LaunchContainer {
+  kLaunchContainerWindow = 0,
+  kLaunchContainerPanelDeprecated = 1,
+  kLaunchContainerTab = 2,
+  // For platform apps, which don't actually have a container (they just get a
+  // "onLaunched" event).
+  kLaunchContainerNone = 3,
+};
diff --git a/components/signin/core/browser/mutable_profile_oauth2_token_service_delegate_unittest.cc b/components/signin/core/browser/mutable_profile_oauth2_token_service_delegate_unittest.cc
index 4f090dd0..e509eb7 100644
--- a/components/signin/core/browser/mutable_profile_oauth2_token_service_delegate_unittest.cc
+++ b/components/signin/core/browser/mutable_profile_oauth2_token_service_delegate_unittest.cc
@@ -39,6 +39,7 @@
 #include "google_apis/gaia/gaia_urls.h"
 #include "google_apis/gaia/google_service_auth_error.h"
 #include "google_apis/gaia/oauth2_access_token_consumer.h"
+#include "google_apis/gaia/oauth2_access_token_fetcher.h"
 #include "google_apis/gaia/oauth2_token_service_test_util.h"
 #include "net/http/http_status_code.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
diff --git a/components/signin/core/browser/profile_oauth2_token_service_delegate_chromeos_unittest.cc b/components/signin/core/browser/profile_oauth2_token_service_delegate_chromeos_unittest.cc
index 1847b04..95ca553d 100644
--- a/components/signin/core/browser/profile_oauth2_token_service_delegate_chromeos_unittest.cc
+++ b/components/signin/core/browser/profile_oauth2_token_service_delegate_chromeos_unittest.cc
@@ -23,6 +23,7 @@
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "google_apis/gaia/oauth2_access_token_consumer.h"
+#include "google_apis/gaia/oauth2_access_token_fetcher.h"
 #include "google_apis/gaia/oauth2_token_service.h"
 #include "google_apis/gaia/oauth2_token_service_test_util.h"
 #include "services/network/test/test_network_connection_tracker.h"
diff --git a/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate_unittest.mm b/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate_unittest.mm
index 2999689..1bb5ef3 100644
--- a/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate_unittest.mm
+++ b/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate_unittest.mm
@@ -16,6 +16,7 @@
 #include "components/signin/ios/browser/fake_profile_oauth2_token_service_ios_provider.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "google_apis/gaia/oauth2_access_token_consumer.h"
+#include "google_apis/gaia/oauth2_access_token_fetcher.h"
 #include "google_apis/gaia/oauth2_token_service_test_util.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 518027c0..cb30b4fb 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -1338,6 +1338,8 @@
     "native_file_system/native_file_system_directory_handle_impl.h",
     "native_file_system/native_file_system_file_handle_impl.cc",
     "native_file_system/native_file_system_file_handle_impl.h",
+    "native_file_system/native_file_system_file_writer_impl.cc",
+    "native_file_system/native_file_system_file_writer_impl.h",
     "native_file_system/native_file_system_handle_base.cc",
     "native_file_system/native_file_system_handle_base.h",
     "native_file_system/native_file_system_manager_impl.cc",
diff --git a/content/browser/do_not_track_browsertest.cc b/content/browser/do_not_track_browsertest.cc
index 957c0f84..4177c35c 100644
--- a/content/browser/do_not_track_browsertest.cc
+++ b/content/browser/do_not_track_browsertest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/barrier_closure.h"
 #include "base/bind.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
@@ -181,7 +182,8 @@
   EXPECT_TRUE(header_map.find("DNT") != header_map.end());
   EXPECT_EQ("1", header_map["DNT"]);
 
-  // Wait until the worker script is loaded.
+  // Wait until the worker script is loaded to stop the test from crashing
+  // during destruction.
   EXPECT_EQ("DONE", EvalJs(shell(), "waitForMessage();"));
 }
 
@@ -212,13 +214,14 @@
   EXPECT_TRUE(header_map.find("DNT") != header_map.end());
   EXPECT_EQ("1", header_map["DNT"]);
 
-  // Wait until the worker script is loaded.
+  // Wait until the worker script is loaded to stop the test from crashing
+  // during destruction.
   EXPECT_EQ("DONE", EvalJs(shell(), "waitForMessage();"));
 }
 
 // Checks that the DNT header is sent in a request for a service worker
 // script.
-IN_PROC_BROWSER_TEST_F(DoNotTrackTest, ServiceWorker) {
+IN_PROC_BROWSER_TEST_F(DoNotTrackTest, ServiceWorker_Register) {
   const std::string kWorkerScript = "// empty";
   net::test_server::HttpRequest::HeaderMap header_map;
   base::RunLoop loop;
@@ -241,6 +244,35 @@
   // been completed.
 }
 
+// Checks that the DNT header is sent in a request for a service worker
+// script during update checking.
+IN_PROC_BROWSER_TEST_F(DoNotTrackTest, ServiceWorker_Update) {
+  const std::string kWorkerScript = "// empty";
+  net::test_server::HttpRequest::HeaderMap header_map;
+  base::RunLoop loop;
+  // Wait for two requests to capture the request header for updating.
+  embedded_test_server()->RegisterRequestHandler(base::BindRepeating(
+      &CaptureHeaderHandlerAndReturnScript, "/capture", &header_map,
+      kWorkerScript, base::BarrierClosure(2, loop.QuitClosure())));
+  ASSERT_TRUE(embedded_test_server()->Start());
+  if (!EnableDoNotTrack())
+    return;
+
+  // Register a service worker, trigger update, then wait until the handler sees
+  // the second request.
+  NavigateToURL(shell(), GetURL("/service_worker/create_service_worker.html"));
+  EXPECT_EQ("DONE", EvalJs(shell(), "register('/capture');"));
+  EXPECT_EQ("DONE", EvalJs(shell(), "update();"));
+  loop.Run();
+
+  EXPECT_TRUE(header_map.find("DNT") != header_map.end());
+  EXPECT_EQ("1", header_map["DNT"]);
+
+  // Service worker doesn't have to wait for onmessage event because
+  // waiting for a promise by registration.update() can ensure that the script
+  // load has been completed.
+}
+
 // Checks that the DNT header is preserved when fetching from a dedicated
 // worker.
 IN_PROC_BROWSER_TEST_F(DoNotTrackTest, FetchFromWorker) {
diff --git a/content/browser/frame_host/back_forward_cache.cc b/content/browser/frame_host/back_forward_cache.cc
index f55125e1..6957bd9 100644
--- a/content/browser/frame_host/back_forward_cache.cc
+++ b/content/browser/frame_host/back_forward_cache.cc
@@ -4,10 +4,15 @@
 
 #include "content/browser/frame_host/back_forward_cache.h"
 
+#include "content/browser/frame_host/frame_tree_node.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/browser/renderer_host/render_view_host_impl.h"
+#include "content/common/page_messages.h"
 #include "content/public/common/navigation_policy.h"
 #include "third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h"
 
+#include <unordered_set>
+
 namespace content {
 
 namespace {
@@ -44,6 +49,34 @@
         WebSchedulerTrackedFeature::kRequestedBackgroundWorkPermission) |
     ToFeatureBit(WebSchedulerTrackedFeature::kBroadcastChannel) |
     ToFeatureBit(WebSchedulerTrackedFeature::kIndexedDBConnection);
+
+void SetPageFrozenImpl(
+    RenderFrameHostImpl* render_frame_host,
+    bool freeze,
+    std::unordered_set<RenderViewHostImpl*>* render_view_hosts) {
+  RenderViewHostImpl* render_view_host = render_frame_host->render_view_host();
+  // (Un)Freeze the root frame's page if it is not (un)frozen yet.
+  if (render_view_hosts->find(render_view_host) == render_view_hosts->end()) {
+    if (freeze) {
+      render_view_host->Send(
+          new PageMsg_WasHidden(render_view_host->GetRoutingID()));
+    } else {
+      render_view_host->Send(
+          new PageMsg_WasShown(render_view_host->GetRoutingID()));
+    }
+
+    render_view_host->Send(
+        new PageMsg_SetPageFrozen(render_view_host->GetRoutingID(), freeze));
+    render_view_hosts->insert(render_view_host);
+  }
+  // Recurse on |render_frame_host|'s children.
+  for (size_t index = 0; index < render_frame_host->child_count(); ++index) {
+    RenderFrameHostImpl* child_frame_host =
+        render_frame_host->child_at(index)->current_frame_host();
+    SetPageFrozenImpl(child_frame_host, freeze, render_view_hosts);
+  }
+}
+
 }  // namespace
 
 BackForwardCache::BackForwardCache() = default;
@@ -82,6 +115,21 @@
   }
 }
 
+void BackForwardCache::Freeze(RenderFrameHostImpl* main_rfh) {
+  // Several RenderFrameHost can live under the same RenderViewHost.
+  // |frozen_render_view_hosts| keeps track of the ones that freezing has been
+  // applied to.
+  std::unordered_set<RenderViewHostImpl*> frozen_render_view_hosts;
+  SetPageFrozenImpl(main_rfh, true /*freeze*/, &frozen_render_view_hosts);
+}
+
+void BackForwardCache::UnFreeze(RenderFrameHostImpl* main_rfh) {
+  // |unfrozen_render_view_hosts| keeps track of the ones that unfreezing has
+  // been applied to.
+  std::unordered_set<RenderViewHostImpl*> unfrozen_render_view_hosts;
+  SetPageFrozenImpl(main_rfh, false /*unfreeze*/, &unfrozen_render_view_hosts);
+}
+
 std::unique_ptr<RenderFrameHostImpl> BackForwardCache::RestoreDocument(
     int navigation_entry_id) {
   // Select the RenderFrameHostImpl matching the navigation entry.
diff --git a/content/browser/frame_host/back_forward_cache.h b/content/browser/frame_host/back_forward_cache.h
index 06175232..a5929f64 100644
--- a/content/browser/frame_host/back_forward_cache.h
+++ b/content/browser/frame_host/back_forward_cache.h
@@ -37,6 +37,11 @@
   // Precondition: CanStoreDocument(render_frame_host).
   void StoreDocument(std::unique_ptr<RenderFrameHostImpl>);
 
+  // Iterates all the RenderViewHost inside |main_rfh| and freeze or unfreeze
+  // them.
+  static void Freeze(RenderFrameHostImpl* main_rfh);
+  static void UnFreeze(RenderFrameHostImpl* main_rfh);
+
   // During a history navigation, move a document out of the BackForwardCache
   // knowing its navigation entry ID. Returns nullptr when none is found.
   std::unique_ptr<RenderFrameHostImpl> RestoreDocument(int navigation_entry_id);
diff --git a/content/browser/frame_host/back_forward_cache_metrics_browsertest.cc b/content/browser/frame_host/back_forward_cache_metrics_browsertest.cc
index 90ae4798..f5a279a 100644
--- a/content/browser/frame_host/back_forward_cache_metrics_browsertest.cc
+++ b/content/browser/frame_host/back_forward_cache_metrics_browsertest.cc
@@ -14,6 +14,7 @@
 #include "content/public/test/test_navigation_observer.h"
 #include "content/shell/browser/shell.h"
 #include "net/dns/mock_host_resolver.h"
+#include "services/device/public/cpp/test/scoped_geolocation_overrider.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h"
@@ -22,12 +23,16 @@
 
 namespace {
 
-constexpr int kPageShowFeature = static_cast<int>(
+constexpr uint64_t kPageShowFeature = static_cast<uint64_t>(
     blink::scheduler::WebSchedulerTrackedFeature::kPageShowEventListener);
 
-constexpr int kHasScriptableFramesInMultipleTabsFeature =
-    static_cast<int>(blink::scheduler::WebSchedulerTrackedFeature::
-                         kHasScriptableFramesInMultipleTabs);
+constexpr uint64_t kHasScriptableFramesInMultipleTabsFeature =
+    static_cast<uint64_t>(blink::scheduler::WebSchedulerTrackedFeature::
+                              kHasScriptableFramesInMultipleTabs);
+
+constexpr uint64_t kRequestedGeolocationPermissionFeature =
+    static_cast<uint64_t>(blink::scheduler::WebSchedulerTrackedFeature::
+                              kRequestedGeolocationPermission);
 
 ukm::SourceId ToSourceId(int64_t navigation_id) {
   return ukm::ConvertToSourceId(navigation_id,
@@ -80,6 +85,12 @@
 
 class BackForwardCacheMetricsBrowserTest : public ContentBrowserTest,
                                            public WebContentsObserver {
+ public:
+  BackForwardCacheMetricsBrowserTest() {
+    geolocation_override_ =
+        std::make_unique<device::ScopedGeolocationOverrider>(1.0, 1.0);
+  }
+
  protected:
   void SetUpOnMainThread() override {
     host_resolver()->AddRule("*", "127.0.0.1");
@@ -92,8 +103,10 @@
     navigation_ids_.push_back(navigation_handle->GetNavigationId());
   }
 
- protected:
   std::vector<int64_t> navigation_ids_;
+
+ private:
+  std::unique_ptr<device::ScopedGeolocationOverrider> geolocation_override_;
 };
 
 IN_PROC_BROWSER_TEST_F(BackForwardCacheMetricsBrowserTest, UKM) {
@@ -598,4 +611,21 @@
                   id3, 1 << kHasScriptableFramesInMultipleTabsFeature, 0, 0}));
 }
 
+IN_PROC_BROWSER_TEST_F(BackForwardCacheMetricsBrowserTest, Geolocation) {
+  const GURL url1(embedded_test_server()->GetURL("/title1.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), url1));
+
+  RenderFrameHostImpl* main_frame = static_cast<RenderFrameHostImpl*>(
+      shell()->web_contents()->GetMainFrame());
+  EXPECT_EQ("success", EvalJs(main_frame, R"(
+    new Promise(resolve => {
+      navigator.geolocation.getCurrentPosition(
+        resolve.bind(this, "success"),
+        resolve.bind(this, "failure"))
+      });
+  )"));
+  EXPECT_TRUE(main_frame->scheduler_tracked_features() &
+              (1 << kRequestedGeolocationPermissionFeature));
+}
+
 }  // namespace content
diff --git a/content/browser/frame_host/origin_policy_throttle.cc b/content/browser/frame_host/origin_policy_throttle.cc
index 68d6799a..6ebefe68 100644
--- a/content/browser/frame_host/origin_policy_throttle.cc
+++ b/content/browser/frame_host/origin_policy_throttle.cc
@@ -16,7 +16,6 @@
 #include "content/browser/frame_host/navigation_handle_impl.h"
 #include "content/browser/frame_host/navigation_request.h"
 #include "content/browser/storage_partition_impl.h"
-#include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/origin_policy_error_reason.h"
@@ -35,20 +34,15 @@
 static constexpr const char* kDeletePolicy = "0";
 static constexpr const char* kReportTo = "report-to";
 static constexpr const char* kPolicy = "policy";
-
-// Marker for (temporarily) exempted origins.
-// TODO(vogelheim): Make sure this is outside the value space for policy
-//                  names. A name with a comma in it shouldn't be allowed, but
-//                  I don't think we presently check this anywhere.
-static constexpr const char* kExemptedOriginPolicyVersion = "exception,";
 }  // namespace
 
 namespace content {
 
 // Implement the public "API" from
 // content/public/browser/origin_policy_commands.h:
-void OriginPolicyAddExceptionFor(const GURL& url) {
-  OriginPolicyThrottle::AddExceptionFor(url);
+void OriginPolicyAddExceptionFor(BrowserContext* browser_context,
+                                 const GURL& url) {
+  OriginPolicyThrottle::AddExceptionFor(browser_context, url);
 }
 
 // static
@@ -87,8 +81,15 @@
 }
 
 // static
-void OriginPolicyThrottle::AddExceptionFor(const GURL& url) {
-  GetKnownVersions()[url::Origin::Create(url)] = kExemptedOriginPolicyVersion;
+void OriginPolicyThrottle::AddExceptionFor(BrowserContext* browser_context,
+                                           const GURL& url) {
+  DCHECK(browser_context);
+  StoragePartitionImpl* storage_partition = static_cast<StoragePartitionImpl*>(
+      BrowserContext::GetStoragePartitionForSite(browser_context, url));
+  network::mojom::OriginPolicyManager* origin_policy_manager =
+      storage_partition->GetOriginPolicyManagerForBrowserProcess();
+
+  origin_policy_manager->AddExceptionFor(url::Origin::Create(url));
 }
 
 OriginPolicyThrottle::~OriginPolicyThrottle() {}
@@ -114,80 +115,24 @@
   if (!navigation_handle()->GetResponseHeaders())
     return NavigationThrottle::PROCEED;
 
-  // TODO(andypaicu):
-  // This entire logic needs to be moved to OriginPolicyManager with the
-  // store migration.
-
-  // This determines whether and which policy version applies and fetches it.
-  //
-  // Inputs are the kSecOriginPolicy HTTP header, and the version
-  // we've last seen from this particular origin.
-  //
-  // - header with kDeletePolicy received: No policy applies, and delete the
-  //       last-known policy for this origin.
-  // - header received: Use header version and update last-known policy.
-  // - no header received, last-known version exists: Use last-known version
-  // - no header, no last-known version: No policy applies.
-
-  std::string response_version =
-      GetRequestedPolicyAndReportGroupFromHeader().policy_version;
-  bool header_found = !response_version.empty();
-
-  url::Origin origin = GetRequestOrigin();
-  DCHECK(!origin.Serialize().empty());
-  DCHECK(!origin.opaque());
-  KnownVersionMap& versions = GetKnownVersions();
-  auto iter = versions.find(origin);
-
-  // Process policy deletion first!
-  if (header_found && response_version == kDeletePolicy) {
-    if (iter != versions.end())
-      versions.erase(iter);
-    return NavigationThrottle::PROCEED;
-  }
-
-  // Process policy exceptions.
-  if (iter != versions.end() && iter->second == kExemptedOriginPolicyVersion) {
-    return NavigationThrottle::PROCEED;
-  }
-
-  // No policy applies to this request?
-  if (!header_found && iter == versions.end()) {
-    return NavigationThrottle::PROCEED;
-  }
-
   std::string header;
   navigation_handle()->GetResponseHeaders()->GetNormalizedHeader(
       net::HttpRequestHeaders::kSecOriginPolicy, &header);
 
-  if (!header_found) {
-    // TODO(andypaicu):
-    // This is an absolute hack that will go away when we move the in-memory
-    // store to the network service OriginPolicyManager. Until then, if we have
-    // a cached policy version and we receive a request with no header set, we
-    // build this artificial header to let OriginPolicyManager know where to
-    // retrieve the policy from.
-    header = base::StrCat({"policy=", iter->second});
-  } else if (iter == versions.end()) {
-    versions.insert(std::make_pair(origin, response_version));
-  } else {
-    iter->second = response_version;
-  }
-
   network::OriginPolicyManager::RetrieveOriginPolicyCallback
       origin_policy_manager_done = base::BindOnce(
           &OriginPolicyThrottle::OnOriginPolicyManagerRetrieveDone,
-          base::Unretained(this));
+          weak_factory_.GetWeakPtr());
+
   SiteInstance* site_instance = navigation_handle()->GetStartingSiteInstance();
   StoragePartitionImpl* storage_partition =
       static_cast<StoragePartitionImpl*>(BrowserContext::GetStoragePartition(
           site_instance->GetBrowserContext(), site_instance));
-
   network::mojom::OriginPolicyManager* origin_policy_manager =
       storage_partition->GetOriginPolicyManagerForBrowserProcess();
 
   origin_policy_manager->RetrieveOriginPolicy(
-      origin, header, std::move(origin_policy_manager_done));
+      GetRequestOrigin(), header, std::move(origin_policy_manager_done));
 
   return NavigationThrottle::DEFER;
 }
@@ -196,27 +141,11 @@
   return "OriginPolicyThrottle";
 }
 
-// static
-OriginPolicyThrottle::KnownVersionMap&
-OriginPolicyThrottle::GetKnownVersionsForTesting() {
-  return GetKnownVersions();
-}
-
 OriginPolicyThrottle::OriginPolicyThrottle(NavigationHandle* handle)
-    : NavigationThrottle(handle) {}
+    : NavigationThrottle(handle), weak_factory_(this) {}
 
-OriginPolicyThrottle::KnownVersionMap&
-OriginPolicyThrottle::GetKnownVersions() {
-  static base::NoDestructor<KnownVersionMap> map_instance;
-  return *map_instance;
-}
-
-OriginPolicyThrottle::PolicyVersionAndReportTo OriginPolicyThrottle::
-    GetRequestedPolicyAndReportGroupFromHeaderStringForTesting(
-        const std::string& header) {
-  return GetRequestedPolicyAndReportGroupFromHeaderString(header);
-}
-
+// TODO(andypaicu): Remove when we have moved reporting logic to the network
+// service.
 OriginPolicyThrottle::PolicyVersionAndReportTo
 OriginPolicyThrottle::GetRequestedPolicyAndReportGroupFromHeader() const {
   std::string header;
@@ -317,30 +246,38 @@
                                   const GURL& policy_url) {}
 #endif  // BUILDFLAG(ENABLE_REPORTING)
 
-bool OriginPolicyThrottle::IsExemptedForTesting(const url::Origin& origin) {
-  KnownVersionMap& versions = GetKnownVersions();
-  auto iter = versions.find(origin);
-  if (iter != versions.end())
-    return iter->second == kExemptedOriginPolicyVersion;
-
-  return false;
-}
-
 void OriginPolicyThrottle::OnOriginPolicyManagerRetrieveDone(
     const network::mojom::OriginPolicyPtr origin_policy) {
-  if (origin_policy->state != network::mojom::OriginPolicyState::kLoaded) {
-    CancelNavigation(OriginPolicyErrorReason::kCannotLoadPolicy,
-                     origin_policy->policy_url);
-    return;
-  }
+  switch (origin_policy->state) {
+    case network::mojom::OriginPolicyState::kCannotLoadPolicy:
+      // TODO(andypaicu): OriginPolicyErrorReason is obsolete and we should use
+      // network::mojom::OriginPolicyState instead.
+      CancelNavigation(OriginPolicyErrorReason::kCannotLoadPolicy,
+                       origin_policy->policy_url);
+      return;
 
-  DCHECK(origin_policy->contents);
-  // TODO(vogelheim): Determine whether we need to parse or sanity check
-  //                  the policy content at this point.
-  static_cast<NavigationHandleImpl*>(navigation_handle())
-      ->navigation_request()
-      ->SetOriginPolicy(origin_policy->contents->raw_policy);
-  Resume();
+    case network::mojom::OriginPolicyState::kInvalidRedirect:
+      // TODO(andypaicu): OriginPolicyErrorReason is obsolete and we should use
+      // network::mojom::OriginPolicyState instead.
+      CancelNavigation(OriginPolicyErrorReason::kPolicyShouldNotRedirect,
+                       origin_policy->policy_url);
+      return;
+
+    case network::mojom::OriginPolicyState::kNoPolicyApplies:
+      Resume();
+      return;
+
+    case network::mojom::OriginPolicyState::kLoaded:
+      DCHECK(origin_policy->contents);
+      static_cast<NavigationHandleImpl*>(navigation_handle())
+          ->navigation_request()
+          ->SetOriginPolicy(origin_policy->contents->raw_policy);
+      Resume();
+      return;
+
+    default:
+      NOTREACHED();
+  }
 }
 
 }  // namespace content
diff --git a/content/browser/frame_host/origin_policy_throttle.h b/content/browser/frame_host/origin_policy_throttle.h
index 1b984824..bffbe55 100644
--- a/content/browser/frame_host/origin_policy_throttle.h
+++ b/content/browser/frame_host/origin_policy_throttle.h
@@ -12,6 +12,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/memory/scoped_refptr.h"
+#include "content/public/browser/browser_context.h"
 #include "content/public/browser/navigation_throttle.h"
 #include "services/network/public/mojom/origin_policy_manager.mojom.h"
 
@@ -59,7 +60,7 @@
   // otherwise invalid) policy. This is meant to be called by the security
   // interstitial.
   // This will exempt the entire origin, rather than only the given URL.
-  static void AddExceptionFor(const GURL& url);
+  static void AddExceptionFor(BrowserContext* browser_context, const GURL& url);
 
   ~OriginPolicyThrottle() override;
 
@@ -70,20 +71,11 @@
   using KnownVersionMap = std::map<url::Origin, std::string>;
   static KnownVersionMap& GetKnownVersionsForTesting();
 
-  // TODO(andypaicu): Remove this when we move the store to the network
-  // service layer.
-  static PolicyVersionAndReportTo
-  GetRequestedPolicyAndReportGroupFromHeaderStringForTesting(
-      const std::string& header);
-
-  static bool IsExemptedForTesting(const url::Origin& origin);
-
  private:
   explicit OriginPolicyThrottle(NavigationHandle* handle);
 
-  static KnownVersionMap& GetKnownVersions();
-
-  // Get the policy name and the reporting group from the header string.
+  // TODO(andypaicu): Remove when we have moved reporting logic to the network
+  // service.
   PolicyVersionAndReportTo GetRequestedPolicyAndReportGroupFromHeader() const;
   static PolicyVersionAndReportTo
   GetRequestedPolicyAndReportGroupFromHeaderString(const std::string& header);
@@ -97,6 +89,8 @@
   void OnOriginPolicyManagerRetrieveDone(
       const network::mojom::OriginPolicyPtr origin_policy);
 
+  base::WeakPtrFactory<OriginPolicyThrottle> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(OriginPolicyThrottle);
 };
 
diff --git a/content/browser/frame_host/origin_policy_throttle_unittest.cc b/content/browser/frame_host/origin_policy_throttle_unittest.cc
index 6e1cc94..703a82b8 100644
--- a/content/browser/frame_host/origin_policy_throttle_unittest.cc
+++ b/content/browser/frame_host/origin_policy_throttle_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "content/browser/frame_host/origin_policy_throttle.h"
 
+#include <set>
 #include <utility>
 
 #include "base/feature_list.h"
@@ -40,10 +41,8 @@
     features_.InitWithFeatureState(features::kOriginPolicy, GetParam());
 
     RenderViewHostTestHarness::SetUp();
-    OriginPolicyThrottle::GetKnownVersionsForTesting().clear();
   }
   void TearDown() override {
-    OriginPolicyThrottle::GetKnownVersionsForTesting().clear();
     nav_handle_.reset();
     RenderViewHostTestHarness::TearDown();
   }
@@ -72,20 +71,28 @@
                             const std::string& header_value,
                             RetrieveOriginPolicyCallback callback) override {
     auto result = network::mojom::OriginPolicy::New();
-    result->state = network::mojom::OriginPolicyState::kLoaded;
-    result->contents = network::mojom::OriginPolicyContents::New();
-    result->contents->raw_policy = kExampleManifestString;
-    result->policy_url = origin.GetURL();
+
+    if (origin_exceptions_.find(origin) == origin_exceptions_.end()) {
+      result->state = network::mojom::OriginPolicyState::kLoaded;
+      result->contents = network::mojom::OriginPolicyContents::New();
+      result->contents->raw_policy = kExampleManifestString;
+      result->policy_url = origin.GetURL();
+    } else {
+      result->state = network::mojom::OriginPolicyState::kNoPolicyApplies;
+      result->policy_url = origin.GetURL();
+    }
 
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(&TestOriginPolicyManager::RunCallback,
                                   base::Unretained(this), std::move(callback),
                                   std::move(result)));
   }
+
   void RunCallback(RetrieveOriginPolicyCallback callback,
                    network::mojom::OriginPolicyPtr result) {
     std::move(callback).Run(std::move(result));
   }
+
   network::mojom::OriginPolicyManagerPtr GetPtr() {
     network::mojom::OriginPolicyManagerPtr ptr;
     auto request = mojo::MakeRequest(&ptr);
@@ -95,7 +102,14 @@
 
     return ptr;
   }
+
+  void AddExceptionFor(const url::Origin& origin) override {
+    origin_exceptions_.insert(origin);
+  }
+
+ private:
   std::unique_ptr<mojo::Binding<network::mojom::OriginPolicyManager>> binding_;
+  std::set<url::Origin> origin_exceptions_;
 };
 
 INSTANTIATE_TEST_SUITE_P(OriginPolicyThrottleTests,
@@ -182,25 +196,10 @@
       ->ResetOriginPolicyManagerForBrowserProcessForTesting();
 }
 
-TEST_P(OriginPolicyThrottleTest, AddException) {
-  if (!enabled())
-    return;
-
-  GURL url("https://example.org/bla");
-  OriginPolicyThrottle::GetKnownVersionsForTesting()[url::Origin::Create(url)] =
-      "abcd";
-
-  OriginPolicyThrottle::AddExceptionFor(url);
-  EXPECT_TRUE(
-      OriginPolicyThrottle::IsExemptedForTesting(url::Origin::Create(url)));
-}
-
 TEST_P(OriginPolicyThrottleTest, AddExceptionEndToEnd) {
   if (!enabled())
     return;
 
-  OriginPolicyThrottle::AddExceptionFor(GURL("https://example.org/blubb"));
-
   // Start the navigation.
   auto navigation = NavigationSimulator::CreateBrowserInitiated(
       GURL("https://example.org/bla"), web_contents());
@@ -210,88 +209,47 @@
   EXPECT_EQ(NavigationThrottle::PROCEED,
             navigation->GetLastThrottleCheckResult().action());
 
+  // We set a test origin policy manager as during unit tests we can't reach
+  // the network service to retrieve a valid origin policy manager.
+  TestOriginPolicyManager test_origin_policy_manager;
+  test_origin_policy_manager.AddExceptionFor(
+      url::Origin::Create(GURL("https://example.org/blubb")));
+  NavigationHandleImpl* nav_handle =
+      static_cast<NavigationHandleImpl*>(navigation->GetNavigationHandle());
+  SiteInstance* site_instance = nav_handle->GetStartingSiteInstance();
+  static_cast<StoragePartitionImpl*>(
+      BrowserContext::GetStoragePartition(site_instance->GetBrowserContext(),
+                                          site_instance))
+      ->SetOriginPolicyManagerForBrowserProcessForTesting(
+          test_origin_policy_manager.GetPtr());
+
   // Fake a response with a policy header.
   const char* raw_headers =
       "HTTP/1.1 200 OK\nSec-Origin-Policy: policy=policy-1\n\n";
   auto headers = base::MakeRefCounted<net::HttpResponseHeaders>(
       net::HttpUtil::AssembleRawHeaders(raw_headers));
-  NavigationHandleImpl* nav_handle =
-      static_cast<NavigationHandleImpl*>(navigation->GetNavigationHandle());
   nav_handle->set_response_headers_for_testing(headers);
   navigation->ReadyToCommit();
 
-  // Due to the exception, we expect the policy to not defer.
-  EXPECT_FALSE(navigation->IsDeferred());
+  // The policy manager has to be called even though this is an exception
+  // because the throttle has no way of knowing that.
+  EXPECT_TRUE(navigation->IsDeferred());
+  OriginPolicyThrottle* policy_throttle = static_cast<OriginPolicyThrottle*>(
+      nav_handle->GetDeferringThrottleForTesting());
+  EXPECT_TRUE(policy_throttle);
 
-  // Also check that the header policy did not overwrite the exemption:
-  EXPECT_TRUE(OriginPolicyThrottle::IsExemptedForTesting(
-      url::Origin::Create(GURL("https://example.org/bla"))));
-}
+  // Wait until the navigation has been allowed to proceed.
+  navigation->Wait();
 
-TEST(OriginPolicyThrottleTest, ParseHeaders) {
-  const struct {
-    const char* header;
-    const char* policy_version;
-    const char* report_to;
-  } testcases[] = {
-      // The common cases: We expect >99% of headers to look like these:
-      {"policy=policy", "policy", ""},
-      {"policy=policy, report-to=endpoint", "policy", "endpoint"},
+  // At the end of the navigation, the navigation handle should have no policy
+  // as this origin should be exempted.
+  EXPECT_EQ("",
+            nav_handle->navigation_request()->common_params().origin_policy);
 
-      // Delete a policy. This better work.
-      {"0", "0", ""},
-      {"policy=0", "0", ""},
-      {"policy=\"0\"", "0", ""},
-      {"policy=0, report-to=endpoint", "0", "endpoint"},
-
-      // Order, please!
-      {"policy=policy, report-to=endpoint", "policy", "endpoint"},
-      {"report-to=endpoint, policy=policy", "policy", "endpoint"},
-
-      // Quoting:
-      {"policy=\"policy\"", "policy", ""},
-      {"policy=\"policy\", report-to=endpoint", "policy", "endpoint"},
-      {"policy=\"policy\", report-to=\"endpoint\"", "policy", "endpoint"},
-      {"policy=policy, report-to=\"endpoint\"", "policy", "endpoint"},
-
-      // Whitespace, and funky but valid syntax:
-      {"  policy  =   policy  ", "policy", ""},
-      {" policy = \t policy ", "policy", ""},
-      {" policy \t= \t \"policy\"  ", "policy", ""},
-      {" policy = \" policy \" ", "policy", ""},
-      {" , policy = policy , report-to=endpoint , ", "policy", "endpoint"},
-
-      // Valid policy, invalid report-to:
-      {"policy=policy, report-to endpoint", "", ""},
-      {"policy=policy, report-to=here, report-to=there", "", ""},
-      {"policy=policy, \"report-to\"=endpoint", "", ""},
-
-      // Invalid policy, valid report-to:
-      {"policy=policy1, policy=policy2", "", ""},
-      {"policy, report-to=r", "", ""},
-      {"report-to=endpoint", "", "endpoint"},
-
-      // Invalid everything:
-      {"one two three", "", ""},
-      {"one, two, three", "", ""},
-      {"policy report-to=endpoint", "", ""},
-      {"policy=policy report-to=endpoint", "", ""},
-
-      // Forward compatibility, ignore unknown keywords:
-      {"policy=pol, report-to=endpoint, unknown=keyword", "pol", "endpoint"},
-      {"unknown=keyword, policy=pol, report-to=endpoint", "pol", "endpoint"},
-      {"policy=pol, unknown=keyword", "pol", ""},
-      {"policy=policy, report_to=endpoint", "policy", ""},
-      {"policy=policy, reportto=endpoint", "policy", ""},
-  };
-  for (const auto& testcase : testcases) {
-    SCOPED_TRACE(testcase.header);
-    const auto result = OriginPolicyThrottle::
-        GetRequestedPolicyAndReportGroupFromHeaderStringForTesting(
-            testcase.header);
-    EXPECT_EQ(result.policy_version, testcase.policy_version);
-    EXPECT_EQ(result.report_to, testcase.report_to);
-  }
+  static_cast<StoragePartitionImpl*>(
+      BrowserContext::GetStoragePartition(site_instance->GetBrowserContext(),
+                                          site_instance))
+      ->ResetOriginPolicyManagerForBrowserProcessForTesting();
 }
 
 }  // namespace content
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index c205895..cb17b89 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -2254,8 +2254,17 @@
 
 void RenderFrameHostImpl::UpdateActiveSchedulerTrackedFeatures(
     uint64_t features_mask) {
-  scheduler_tracked_features_ = features_mask;
+  TRACE_EVENT0("toplevel", "UpdateActiveSchedulerTrackedFeatures");
+  renderer_reported_scheduler_tracked_features_ = features_mask;
 }
+
+void RenderFrameHostImpl::OnSchedulerTrackedFeatureUsed(
+    blink::scheduler::WebSchedulerTrackedFeature feature) {
+  TRACE_EVENT0("toplevel", "OnSchedulerTrackedFeatureUsed");
+  browser_reported_scheduler_tracked_features_ |=
+      1 << static_cast<uint64_t>(feature);
+}
+
 void RenderFrameHostImpl::DidFailProvisionalLoadWithError(
     const GURL& url,
     int error_code,
@@ -6741,9 +6750,10 @@
                                               is_same_document_navigation);
 
   if (!is_same_document_navigation) {
-    scheduler_tracked_features_ = 0;
     cookie_no_samesite_deprecation_url_hashes_.clear();
     cookie_samesite_none_insecure_deprecation_url_hashes_.clear();
+    renderer_reported_scheduler_tracked_features_ = 0;
+    browser_reported_scheduler_tracked_features_ = 0;
   }
 
   return true;
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index 2316121..f4007e0 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -935,7 +935,8 @@
   // Scheduler-relevant features this frame is using, for use in metrics.
   // See comments at |scheduler_tracked_features_|.
   uint64_t scheduler_tracked_features() const {
-    return scheduler_tracked_features_;
+    return renderer_reported_scheduler_tracked_features_ |
+           browser_reported_scheduler_tracked_features_;
   }
 
   // Returns a PrefetchedSignedExchangeCache which is attached to |this| iff
@@ -956,6 +957,12 @@
       const std::string& cookie_url,
       net::CanonicalCookie::CookieInclusionStatus status);
 
+  // Notify the scheduler that this frame used a feature which impacts the
+  // scheduling policy (e.g. whether the frame can be frozen or put into the
+  // back-forward cache).
+  void OnSchedulerTrackedFeatureUsed(
+      blink::scheduler::WebSchedulerTrackedFeature feature);
+
  protected:
   friend class RenderFrameHostFactory;
 
@@ -2162,8 +2169,13 @@
   // Mask of the active features tracked by the scheduler used by this frame.
   // This is used only for metrics.
   // See blink::SchedulingPolicy::Feature for the meaning.
-  // This value should be cleared on document commit.
-  uint64_t scheduler_tracked_features_ = 0;
+  // These values should be cleared on document commit.
+  // Both are needed as some features are tracked in the renderer process and
+  // some in the browser process, depending on the design of each individual
+  // feature. They are tracked separately, because when the renderer updates the
+  // set of features, the browser ones should persist.
+  uint64_t renderer_reported_scheduler_tracked_features_ = 0;
+  uint64_t browser_reported_scheduler_tracked_features_ = 0;
 
   // Holds prefetched signed exchanges for SignedExchangeSubresourcePrefetch.
   // They will be passed to the next navigation.
diff --git a/content/browser/frame_host/render_frame_host_impl_browsertest.cc b/content/browser/frame_host/render_frame_host_impl_browsertest.cc
index dd8a6188..70f10609 100644
--- a/content/browser/frame_host/render_frame_host_impl_browsertest.cc
+++ b/content/browser/frame_host/render_frame_host_impl_browsertest.cc
@@ -2438,4 +2438,35 @@
   EXPECT_EQ(console_observer.messages()[1], console_observer.messages()[2]);
 }
 
+IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest,
+                       SchedulerTrackedFeatures) {
+  EXPECT_TRUE(
+      NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
+  RenderFrameHostImpl* main_frame = reinterpret_cast<RenderFrameHostImpl*>(
+      shell()->web_contents()->GetMainFrame());
+  // Simulate getting 0b1 as a feature vector from the renderer.
+  static_cast<mojom::FrameHost*>(main_frame)
+      ->UpdateActiveSchedulerTrackedFeatures(0b1u);
+  DCHECK_EQ(main_frame->scheduler_tracked_features(), 0b1u);
+  // Simulate the browser side reporting a feature usage.
+  main_frame->OnSchedulerTrackedFeatureUsed(
+      static_cast<blink::scheduler::WebSchedulerTrackedFeature>(1));
+  DCHECK_EQ(main_frame->scheduler_tracked_features(), 0b11u);
+  // Simulate a feature vector being updated from the renderer with some
+  // features being activated and some being deactivated.
+  static_cast<mojom::FrameHost*>(main_frame)
+      ->UpdateActiveSchedulerTrackedFeatures(0b100u);
+  DCHECK_EQ(main_frame->scheduler_tracked_features(), 0b110u);
+
+  // Navigate away and expect that no values persist the navigation.
+  // Note that we are still simulating the renderer call, otherwise features
+  // like "document loaded" will show up here.
+  EXPECT_TRUE(
+      NavigateToURL(shell(), embedded_test_server()->GetURL("/title2.html")));
+  main_frame = reinterpret_cast<RenderFrameHostImpl*>(
+      shell()->web_contents()->GetMainFrame());
+  static_cast<mojom::FrameHost*>(main_frame)
+      ->UpdateActiveSchedulerTrackedFeatures(0b0u);
+}
+
 }  // namespace content
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
index 1a54254..84484b0 100644
--- a/content/browser/frame_host/render_frame_host_manager.cc
+++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -461,6 +461,7 @@
   BackForwardCache& back_forward_cache =
       delegate_->GetControllerForRenderManager().back_forward_cache();
   if (back_forward_cache.CanStoreDocument(old_render_frame_host.get())) {
+    back_forward_cache.Freeze(old_render_frame_host.get());
     back_forward_cache.StoreDocument(std::move(old_render_frame_host));
     return;
   }
@@ -538,6 +539,9 @@
 
 void RenderFrameHostManager::RestoreFromBackForwardCache(
     std::unique_ptr<RenderFrameHostImpl> rfh) {
+  delegate_->GetControllerForRenderManager().back_forward_cache().UnFreeze(
+      rfh.get());
+
   rfh->GetProcess()->AddPendingView();  // Matched in CommitPending().
   CommitPending(std::move(rfh));
 }
diff --git a/content/browser/native_file_system/native_file_system_file_handle_impl.cc b/content/browser/native_file_system/native_file_system_file_handle_impl.cc
index 5c1f6dc..d4e78dc6 100644
--- a/content/browser/native_file_system/native_file_system_file_handle_impl.cc
+++ b/content/browser/native_file_system/native_file_system_file_handle_impl.cc
@@ -127,6 +127,21 @@
       std::move(callback));
 }
 
+void NativeFileSystemFileHandleImpl::CreateFileWriter(
+    CreateFileWriterCallback callback) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  RunWithWritePermission(
+      base::BindOnce(&NativeFileSystemFileHandleImpl::CreateFileWriterImpl,
+                     weak_factory_.GetWeakPtr()),
+      base::BindOnce([](CreateFileWriterCallback callback) {
+        std::move(callback).Run(
+            NativeFileSystemError::New(base::File::FILE_ERROR_ACCESS_DENIED),
+            nullptr);
+      }),
+      std::move(callback));
+}
+
 void NativeFileSystemFileHandleImpl::Transfer(
     blink::mojom::NativeFileSystemTransferTokenRequest token) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -260,6 +275,17 @@
           std::move(callback)));
 }
 
+void NativeFileSystemFileHandleImpl::CreateFileWriterImpl(
+    CreateFileWriterCallback callback) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_EQ(GetWritePermissionStatus(),
+            blink::mojom::PermissionStatus::GRANTED);
+
+  std::move(callback).Run(
+      NativeFileSystemError::New(base::File::FILE_OK),
+      manager()->CreateFileWriter(context(), url(), handle_state()));
+}
+
 base::WeakPtr<NativeFileSystemHandleBase>
 NativeFileSystemFileHandleImpl::AsWeakPtr() {
   return weak_factory_.GetWeakPtr();
diff --git a/content/browser/native_file_system/native_file_system_file_handle_impl.h b/content/browser/native_file_system/native_file_system_file_handle_impl.h
index f2801fbe..a16ab53 100644
--- a/content/browser/native_file_system/native_file_system_file_handle_impl.h
+++ b/content/browser/native_file_system/native_file_system_file_handle_impl.h
@@ -55,6 +55,7 @@
                    mojo::ScopedDataPipeConsumerHandle stream,
                    WriteStreamCallback callback) override;
   void Truncate(uint64_t length, TruncateCallback callback) override;
+  void CreateFileWriter(CreateFileWriterCallback callback) override;
   void Transfer(
       blink::mojom::NativeFileSystemTransferTokenRequest token) override;
 
@@ -84,6 +85,7 @@
                 bool complete);
 
   void TruncateImpl(uint64_t length, TruncateCallback callback);
+  void CreateFileWriterImpl(CreateFileWriterCallback callback);
 
   base::WeakPtr<NativeFileSystemHandleBase> AsWeakPtr() override;
 
diff --git a/content/browser/native_file_system/native_file_system_file_writer_impl.cc b/content/browser/native_file_system/native_file_system_file_writer_impl.cc
new file mode 100644
index 0000000..d4422fe
--- /dev/null
+++ b/content/browser/native_file_system/native_file_system_file_writer_impl.cc
@@ -0,0 +1,46 @@
+// 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/native_file_system/native_file_system_file_writer_impl.h"
+#include "content/browser/native_file_system/native_file_system_manager_impl.h"
+
+using blink::mojom::NativeFileSystemError;
+
+namespace content {
+
+NativeFileSystemFileWriterImpl::NativeFileSystemFileWriterImpl(
+    NativeFileSystemManagerImpl* manager,
+    const BindingContext& context,
+    const storage::FileSystemURL& url,
+    const SharedHandleState& handle_state)
+    : NativeFileSystemHandleBase(manager, context, url, handle_state) {}
+
+NativeFileSystemFileWriterImpl::~NativeFileSystemFileWriterImpl() = default;
+
+void NativeFileSystemFileWriterImpl::Close(CloseCallback callback) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  RunWithWritePermission(
+      base::BindOnce(&NativeFileSystemFileWriterImpl::CloseImpl,
+                     weak_factory_.GetWeakPtr()),
+      base::BindOnce([](CloseCallback callback) {
+        std::move(callback).Run(
+            NativeFileSystemError::New(base::File::FILE_ERROR_ACCESS_DENIED));
+      }),
+      std::move(callback));
+}
+
+void NativeFileSystemFileWriterImpl::CloseImpl(CloseCallback callback) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_EQ(GetWritePermissionStatus(),
+            blink::mojom::PermissionStatus::GRANTED);
+  std::move(callback).Run(NativeFileSystemError::New(base::File::FILE_OK));
+}
+
+base::WeakPtr<NativeFileSystemHandleBase>
+NativeFileSystemFileWriterImpl::AsWeakPtr() {
+  return weak_factory_.GetWeakPtr();
+}
+
+}  // namespace content
diff --git a/content/browser/native_file_system/native_file_system_file_writer_impl.h b/content/browser/native_file_system/native_file_system_file_writer_impl.h
new file mode 100644
index 0000000..d06c9e6
--- /dev/null
+++ b/content/browser/native_file_system/native_file_system_file_writer_impl.h
@@ -0,0 +1,54 @@
+// 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_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_FILE_WRITER_IMPL_H_
+#define CONTENT_BROWSER_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_FILE_WRITER_IMPL_H_
+
+#include "base/memory/weak_ptr.h"
+#include "components/services/filesystem/public/interfaces/types.mojom.h"
+#include "content/browser/native_file_system/native_file_system_file_handle_impl.h"
+#include "content/browser/native_file_system/native_file_system_handle_base.h"
+#include "content/common/content_export.h"
+#include "storage/browser/fileapi/file_system_url.h"
+#include "third_party/blink/public/mojom/native_file_system/native_file_system_file_writer.mojom.h"
+
+namespace content {
+
+// This is the browser side implementation of the
+// NativeFileSystemFileWriter mojom interface. Instances of this class are
+// owned by the NativeFileSystemManagerImpl instance passed in to the
+// constructor.
+//
+// This class is not thread safe, all methods should be called on the IO thread.
+// The link to the IO thread is due to its dependencies on both the blob system
+// (via storage::BlobStorageContext) and the file system backends (via
+// storage::FileSystemContext and storage::FileSystemOperationRunner, which both
+// expect some of their methods to always be called on the IO thread).
+// See https://crbug.com/957249 for some thoughts about the blob system aspect
+// of this.
+class CONTENT_EXPORT NativeFileSystemFileWriterImpl
+    : public NativeFileSystemHandleBase,
+      public blink::mojom::NativeFileSystemFileWriter {
+ public:
+  NativeFileSystemFileWriterImpl(NativeFileSystemManagerImpl* manager,
+                                 const BindingContext& context,
+                                 const storage::FileSystemURL& url,
+                                 const SharedHandleState& handle_state);
+  ~NativeFileSystemFileWriterImpl() override;
+
+  void Close(CloseCallback callback) override;
+
+ private:
+  void CloseImpl(CloseCallback callback);
+
+  base::WeakPtr<NativeFileSystemHandleBase> AsWeakPtr() override;
+
+  base::WeakPtrFactory<NativeFileSystemFileWriterImpl> weak_factory_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(NativeFileSystemFileWriterImpl);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_FILE_WRITER_IMPL_H_
diff --git a/content/browser/native_file_system/native_file_system_manager_impl.cc b/content/browser/native_file_system/native_file_system_manager_impl.cc
index f3aa7aed..7fa7ce8 100644
--- a/content/browser/native_file_system/native_file_system_manager_impl.cc
+++ b/content/browser/native_file_system/native_file_system_manager_impl.cc
@@ -10,6 +10,7 @@
 #include "content/browser/native_file_system/fixed_native_file_system_permission_grant.h"
 #include "content/browser/native_file_system/native_file_system_directory_handle_impl.h"
 #include "content/browser/native_file_system/native_file_system_file_handle_impl.h"
+#include "content/browser/native_file_system/native_file_system_file_writer_impl.h"
 #include "content/browser/native_file_system/native_file_system_transfer_token_impl.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
@@ -139,6 +140,20 @@
   return result;
 }
 
+blink::mojom::NativeFileSystemFileWriterPtr
+NativeFileSystemManagerImpl::CreateFileWriter(
+    const BindingContext& binding_context,
+    const storage::FileSystemURL& url,
+    const SharedHandleState& handle_state) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  blink::mojom::NativeFileSystemFileWriterPtr result;
+  writer_bindings_.AddBinding(std::make_unique<NativeFileSystemFileWriterImpl>(
+                                  this, binding_context, url, handle_state),
+                              mojo::MakeRequest(&result));
+  return result;
+}
+
 blink::mojom::NativeFileSystemEntryPtr
 NativeFileSystemManagerImpl::CreateFileEntryFromPath(
     const BindingContext& binding_context,
@@ -363,4 +378,4 @@
   return result;
 }
 
-}  // namespace content
\ No newline at end of file
+}  // namespace content
diff --git a/content/browser/native_file_system/native_file_system_manager_impl.h b/content/browser/native_file_system/native_file_system_manager_impl.h
index 9ec1aed2f..8fc6c5ae 100644
--- a/content/browser/native_file_system/native_file_system_manager_impl.h
+++ b/content/browser/native_file_system/native_file_system_manager_impl.h
@@ -16,6 +16,7 @@
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "mojo/public/cpp/bindings/strong_binding_set.h"
 #include "storage/browser/fileapi/file_system_url.h"
+#include "third_party/blink/public/mojom/native_file_system/native_file_system_file_writer.mojom.h"
 #include "third_party/blink/public/mojom/native_file_system/native_file_system_manager.mojom.h"
 #include "third_party/blink/public/mojom/permissions/permission_status.mojom.h"
 
@@ -106,6 +107,13 @@
       const storage::FileSystemURL& url,
       const SharedHandleState& handle_state);
 
+  // Creates a new NativeFileSystemFileWriterImpl for a given url. Assumes the
+  // passed in URL is valid and represents a file.
+  blink::mojom::NativeFileSystemFileWriterPtr CreateFileWriter(
+      const BindingContext& binding_context,
+      const storage::FileSystemURL& url,
+      const SharedHandleState& handle_state);
+
   // Creates a new NativeFileSystemEntryPtr from the path to a file. Assumes the
   // passed in path is valid and represents a file.
   blink::mojom::NativeFileSystemEntryPtr CreateFileEntryFromPath(
@@ -199,6 +207,8 @@
       file_bindings_;
   mojo::StrongBindingSet<blink::mojom::NativeFileSystemDirectoryHandle>
       directory_bindings_;
+  mojo::StrongBindingSet<blink::mojom::NativeFileSystemFileWriter>
+      writer_bindings_;
 
   // Transfer token bindings are stored in what is effectively a
   // StrongBindingMap. The Binding instances own the implementation, and tokens
diff --git a/content/browser/permissions/permission_controller_impl.cc b/content/browser/permissions/permission_controller_impl.cc
index 9025fcf3..e077653 100644
--- a/content/browser/permissions/permission_controller_impl.cc
+++ b/content/browser/permissions/permission_controller_impl.cc
@@ -7,6 +7,7 @@
 
 #include "content/browser/permissions/permission_controller_impl.h"
 #include "base/bind.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/permission_controller_delegate.h"
@@ -29,6 +30,62 @@
   return blink::mojom::PermissionStatus::GRANTED;
 }
 
+base::Optional<blink::scheduler::WebSchedulerTrackedFeature>
+PermissionToSchedulingFeature(PermissionType permission_name) {
+  switch (permission_name) {
+    case PermissionType::GEOLOCATION:
+      return blink::scheduler::WebSchedulerTrackedFeature::
+          kRequestedGeolocationPermission;
+    case PermissionType::NOTIFICATIONS:
+      return blink::scheduler::WebSchedulerTrackedFeature::
+          kRequestedNotificationsPermission;
+    case PermissionType::MIDI:
+    case PermissionType::MIDI_SYSEX:
+      return blink::scheduler::WebSchedulerTrackedFeature::
+          kRequestedMIDIPermission;
+    case PermissionType::AUDIO_CAPTURE:
+      return blink::scheduler::WebSchedulerTrackedFeature::
+          kRequestedAudioCapturePermission;
+    case PermissionType::VIDEO_CAPTURE:
+      return blink::scheduler::WebSchedulerTrackedFeature::
+          kRequestedVideoCapturePermission;
+    case PermissionType::SENSORS:
+      return blink::scheduler::WebSchedulerTrackedFeature::
+          kRequestedSensorsPermission;
+    case PermissionType::BACKGROUND_SYNC:
+    case PermissionType::BACKGROUND_FETCH:
+    case PermissionType::PERIODIC_BACKGROUND_SYNC:
+      return blink::scheduler::WebSchedulerTrackedFeature::
+          kRequestedBackgroundWorkPermission;
+    case PermissionType::PROTECTED_MEDIA_IDENTIFIER:
+    case PermissionType::DURABLE_STORAGE:
+    case PermissionType::FLASH:
+    case PermissionType::ACCESSIBILITY_EVENTS:
+    case PermissionType::CLIPBOARD_READ:
+    case PermissionType::CLIPBOARD_WRITE:
+    case PermissionType::PAYMENT_HANDLER:
+    case PermissionType::IDLE_DETECTION:
+    case PermissionType::WAKE_LOCK_SCREEN:
+    case PermissionType::WAKE_LOCK_SYSTEM:
+    case PermissionType::NUM:
+      return base::nullopt;
+  }
+}
+
+void NotifySchedulerAboutPermissionRequest(RenderFrameHost* render_frame_host,
+                                           PermissionType permission_name) {
+  DCHECK(render_frame_host);
+
+  base::Optional<blink::scheduler::WebSchedulerTrackedFeature> feature =
+      PermissionToSchedulingFeature(permission_name);
+
+  if (!feature)
+    return;
+
+  static_cast<RenderFrameHostImpl*>(render_frame_host)
+      ->OnSchedulerTrackedFeatureUsed(feature.value());
+}
+
 }  // namespace
 
 PermissionControllerImpl::PermissionControllerImpl(
@@ -121,6 +178,8 @@
     const GURL& requesting_origin,
     bool user_gesture,
     const base::Callback<void(blink::mojom::PermissionStatus)>& callback) {
+  NotifySchedulerAboutPermissionRequest(render_frame_host, permission);
+
   auto it = devtools_permission_overrides_.find(requesting_origin.GetOrigin());
   if (it != devtools_permission_overrides_.end()) {
     callback.Run(GetPermissionOverrideStatus(it->second, permission));
@@ -144,6 +203,9 @@
     bool user_gesture,
     const base::Callback<
         void(const std::vector<blink::mojom::PermissionStatus>&)>& callback) {
+  for (PermissionType permission : permissions)
+    NotifySchedulerAboutPermissionRequest(render_frame_host, permission);
+
   auto it = devtools_permission_overrides_.find(requesting_origin.GetOrigin());
   if (it != devtools_permission_overrides_.end()) {
     std::vector<blink::mojom::PermissionStatus> result;
diff --git a/content/public/browser/origin_policy_commands.h b/content/public/browser/origin_policy_commands.h
index 358f1f7..7533193 100644
--- a/content/public/browser/origin_policy_commands.h
+++ b/content/public/browser/origin_policy_commands.h
@@ -11,11 +11,14 @@
 
 namespace content {
 
+class BrowserContext;
+
 // Instruct the Origin Policy throttle to disregard errors for the given URL.
 //
 // Intended use: This should be called by the browser when the user selects
 // "proceed" on the security interstitial page for the given URL.
-CONTENT_EXPORT void OriginPolicyAddExceptionFor(const GURL& url);
+CONTENT_EXPORT void OriginPolicyAddExceptionFor(BrowserContext* browser_context,
+                                                const GURL& url);
 
 }  // namespace content
 
diff --git a/content/public/browser/render_frame_host.h b/content/public/browser/render_frame_host.h
index 667bea1b..6e92678d 100644
--- a/content/public/browser/render_frame_host.h
+++ b/content/public/browser/render_frame_host.h
@@ -21,6 +21,7 @@
 #include "third_party/blink/public/common/feature_policy/feature_policy.h"
 #include "third_party/blink/public/common/frame/frame_owner_element_type.h"
 #include "third_party/blink/public/common/frame/sandbox_flags.h"
+#include "third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h"
 #include "third_party/blink/public/mojom/devtools/console_message.mojom.h"
 #include "third_party/blink/public/mojom/loader/pause_subresource_loading_handle.mojom-forward.h"
 #include "third_party/blink/public/platform/web_sudden_termination_disabler_type.h"
diff --git a/content/shell/test_runner/test_runner_for_specific_view.cc b/content/shell/test_runner/test_runner_for_specific_view.cc
index 280bce0..13c95efe 100644
--- a/content/shell/test_runner/test_runner_for_specific_view.cc
+++ b/content/shell/test_runner/test_runner_for_specific_view.cc
@@ -36,6 +36,7 @@
 #include "gin/wrappable.h"
 #include "third_party/blink/public/mojom/frame/find_in_page.mojom.h"
 #include "third_party/blink/public/platform/web_data.h"
+#include "third_party/blink/public/platform/web_isolated_world_ids.h"
 #include "third_party/blink/public/platform/web_isolated_world_info.h"
 #include "third_party/blink/public/platform/web_point.h"
 #include "third_party/blink/public/platform/web_url.h"
@@ -625,6 +626,8 @@
     int world_id,
     v8::Local<v8::Value> security_origin,
     v8::Local<v8::Value> content_security_policy) {
+  if (world_id >= blink::IsolatedWorldId::kEmbedderWorldIdLimit)
+    return;
   if (!security_origin->IsString() && !security_origin->IsNull())
     return;
 
diff --git a/content/test/data/service_worker/create_service_worker.html b/content/test/data/service_worker/create_service_worker.html
index 1dbb35b6..76bc0da 100644
--- a/content/test/data/service_worker/create_service_worker.html
+++ b/content/test/data/service_worker/create_service_worker.html
@@ -11,5 +11,15 @@
     return `${error}`;
   }
 }
+
+async function update() {
+  try {
+    const registration = await navigator.serviceWorker.ready;
+    await registration.update();
+    return 'DONE';
+  } catch (error) {
+    return `${error}`;
+  }
+}
 </script>
 </html>
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
index d232205..f2cdc037 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
@@ -569,6 +569,7 @@
 
 # Linux Intel
 crbug.com/950552 [ linux intel ] conformance2/textures/misc/tex-base-level-bug.html [ Failure ]
+crbug.com/950552 [ linux intel ] conformance2/textures/misc/tex-3d-size-limit.html [ Failure ]
 
 # Already fixed with Mesa 17.2.3
 crbug.com/905011 [ linux intel ] conformance2/textures/misc/tex-subimage3d-pixel-buffer-bug.html [ Failure ]
diff --git a/extensions/browser/api/app_runtime/app_runtime_api.cc b/extensions/browser/api/app_runtime/app_runtime_api.cc
index 95b1f84..778ee696 100644
--- a/extensions/browser/api/app_runtime/app_runtime_api.cc
+++ b/extensions/browser/api/app_runtime/app_runtime_api.cc
@@ -76,41 +76,40 @@
       ->SetLastLaunchTime(extension_id, base::Time::Now());
 }
 
-#define ASSERT_ENUM_EQUAL(Name) ASSERT_ENUM_EQUAL_FULL(Name, Name)
-
-#define ASSERT_ENUM_EQUAL_FULL(Name, Name2)                        \
-  static_assert(static_cast<int>(extensions::Name) ==              \
-                    static_cast<int>(app_runtime::LAUNCH_##Name2), \
-                "The value of extensions::" #Name                  \
+#define ASSERT_ENUM_EQUAL(Name, Name2)                                 \
+  static_assert(static_cast<int>(extensions::AppLaunchSource::Name) == \
+                    static_cast<int>(app_runtime::LAUNCH_##Name2),     \
+                "The value of extensions::" #Name                      \
                 " and app_runtime::LAUNCH_" #Name2 " should be the same");
 
 app_runtime::LaunchSource GetLaunchSourceEnum(
     extensions::AppLaunchSource source) {
-  ASSERT_ENUM_EQUAL(SOURCE_NONE);
-  ASSERT_ENUM_EQUAL(SOURCE_UNTRACKED);
-  ASSERT_ENUM_EQUAL(SOURCE_APP_LAUNCHER);
-  ASSERT_ENUM_EQUAL(SOURCE_NEW_TAB_PAGE);
-  ASSERT_ENUM_EQUAL(SOURCE_RELOAD);
-  ASSERT_ENUM_EQUAL(SOURCE_RESTART);
-  ASSERT_ENUM_EQUAL(SOURCE_LOAD_AND_LAUNCH);
-  ASSERT_ENUM_EQUAL(SOURCE_COMMAND_LINE);
-  ASSERT_ENUM_EQUAL(SOURCE_FILE_HANDLER);
-  ASSERT_ENUM_EQUAL(SOURCE_URL_HANDLER);
-  ASSERT_ENUM_EQUAL(SOURCE_SYSTEM_TRAY);
-  ASSERT_ENUM_EQUAL(SOURCE_ABOUT_PAGE);
-  ASSERT_ENUM_EQUAL(SOURCE_KEYBOARD);
-  ASSERT_ENUM_EQUAL(SOURCE_EXTENSIONS_PAGE);
-  ASSERT_ENUM_EQUAL(SOURCE_MANAGEMENT_API);
-  ASSERT_ENUM_EQUAL_FULL(SOURCE_EPHEMERAL_APP_DEPRECATED, SOURCE_EPHEMERAL_APP);
-  ASSERT_ENUM_EQUAL(SOURCE_BACKGROUND);
-  ASSERT_ENUM_EQUAL(SOURCE_KIOSK);
-  ASSERT_ENUM_EQUAL(SOURCE_CHROME_INTERNAL);
-  ASSERT_ENUM_EQUAL(SOURCE_TEST);
-  ASSERT_ENUM_EQUAL(SOURCE_INSTALLED_NOTIFICATION);
-  ASSERT_ENUM_EQUAL(SOURCE_CONTEXT_MENU);
-  ASSERT_ENUM_EQUAL(SOURCE_ARC);
-  static_assert(extensions::NUM_APP_LAUNCH_SOURCES ==
-                    app_runtime::LaunchSource::LAUNCH_SOURCE_LAST + 1,
+  ASSERT_ENUM_EQUAL(kSourceNone, SOURCE_NONE);
+  ASSERT_ENUM_EQUAL(kSourceUntracked, SOURCE_UNTRACKED);
+  ASSERT_ENUM_EQUAL(kSourceAppLauncher, SOURCE_APP_LAUNCHER);
+  ASSERT_ENUM_EQUAL(kSourceNewTabPage, SOURCE_NEW_TAB_PAGE);
+  ASSERT_ENUM_EQUAL(kSourceReload, SOURCE_RELOAD);
+  ASSERT_ENUM_EQUAL(kSourceRestart, SOURCE_RESTART);
+  ASSERT_ENUM_EQUAL(kSourceLoadAndLaunch, SOURCE_LOAD_AND_LAUNCH);
+  ASSERT_ENUM_EQUAL(kSourceCommandLine, SOURCE_COMMAND_LINE);
+  ASSERT_ENUM_EQUAL(kSourceFileHandler, SOURCE_FILE_HANDLER);
+  ASSERT_ENUM_EQUAL(kSourceUrlHandler, SOURCE_URL_HANDLER);
+  ASSERT_ENUM_EQUAL(kSourceSystemTray, SOURCE_SYSTEM_TRAY);
+  ASSERT_ENUM_EQUAL(kSourceAboutPage, SOURCE_ABOUT_PAGE);
+  ASSERT_ENUM_EQUAL(kSourceKeyboard, SOURCE_KEYBOARD);
+  ASSERT_ENUM_EQUAL(kSourceExtensionsPage, SOURCE_EXTENSIONS_PAGE);
+  ASSERT_ENUM_EQUAL(kSourceManagementApi, SOURCE_MANAGEMENT_API);
+  ASSERT_ENUM_EQUAL(kSourceEphemeralAppDeprecated, SOURCE_EPHEMERAL_APP);
+  ASSERT_ENUM_EQUAL(kSourceBackground, SOURCE_BACKGROUND);
+  ASSERT_ENUM_EQUAL(kSourceKiosk, SOURCE_KIOSK);
+  ASSERT_ENUM_EQUAL(kSourceChromeInternal, SOURCE_CHROME_INTERNAL);
+  ASSERT_ENUM_EQUAL(kSourceTest, SOURCE_TEST);
+  ASSERT_ENUM_EQUAL(kSourceInstalledNotification,
+                    SOURCE_INSTALLED_NOTIFICATION);
+  ASSERT_ENUM_EQUAL(kSourceContextMenu, SOURCE_CONTEXT_MENU);
+  ASSERT_ENUM_EQUAL(kSourceArc, SOURCE_ARC);
+  static_assert(static_cast<int>(extensions::AppLaunchSource::kMaxValue) ==
+                    app_runtime::LaunchSource::LAUNCH_SOURCE_LAST,
                 "");
 
   return static_cast<app_runtime::LaunchSource>(source);
diff --git a/extensions/browser/extension_icon_image.cc b/extensions/browser/extension_icon_image.cc
index db134ea..879b92f 100644
--- a/extensions/browser/extension_icon_image.cc
+++ b/extensions/browser/extension_icon_image.cc
@@ -57,8 +57,7 @@
 class BlankImageSource : public gfx::CanvasImageSource {
  public:
   explicit BlankImageSource(const gfx::Size& size_in_dip)
-      : CanvasImageSource(size_in_dip, /*is_opaque =*/ false) {
-  }
+      : CanvasImageSource(size_in_dip) {}
   ~BlankImageSource() override {}
 
  private:
diff --git a/extensions/browser/extension_icon_placeholder.cc b/extensions/browser/extension_icon_placeholder.cc
index a803a833..5465183d 100644
--- a/extensions/browser/extension_icon_placeholder.cc
+++ b/extensions/browser/extension_icon_placeholder.cc
@@ -70,7 +70,7 @@
 ExtensionIconPlaceholder::ExtensionIconPlaceholder(
     extension_misc::ExtensionIcons size,
     const std::string& name)
-    : gfx::CanvasImageSource(gfx::Size(size, size), false),
+    : gfx::CanvasImageSource(gfx::Size(size, size)),
       icon_size_(size),
       base_image_(GetBackgroundImageForIconSize(size)) {
   // Remove RTL formatting characters, if any, that may pad the extension name.
diff --git a/extensions/common/BUILD.gn b/extensions/common/BUILD.gn
index 93439e9a..398214af 100644
--- a/extensions/common/BUILD.gn
+++ b/extensions/common/BUILD.gn
@@ -22,6 +22,7 @@
 
   deps = [
     "//base",
+    "//components/services/app_service/public/mojom",
     "//ui/base",
   ]
 
diff --git a/extensions/common/DEPS b/extensions/common/DEPS
index 2179e703..61bac3b 100644
--- a/extensions/common/DEPS
+++ b/extensions/common/DEPS
@@ -2,6 +2,7 @@
   "+components/crx_file",
   "+components/url_formatter",
   "+components/nacl/common/buildflags.h",
+  "+components/services/app_service/public/mojom",
   "+device/bluetooth",  # For BluetoothPermission
   "+grit/extensions_strings.h",
   "+libxml",
diff --git a/extensions/common/constants.h b/extensions/common/constants.h
index 081f62f..0c3fe3fd 100644
--- a/extensions/common/constants.h
+++ b/extensions/common/constants.h
@@ -8,6 +8,7 @@
 #include "base/files/file_path.h"
 #include "base/logging.h"
 #include "base/strings/string_piece_forward.h"
+#include "components/services/app_service/public/mojom/types.mojom.h"
 #include "ui/base/layout.h"
 
 namespace extensions {
@@ -116,38 +117,8 @@
 // from a non-service worker context
 extern const int kMainThreadId;
 
-// Enumeration of possible app launch sources.
-// This should be kept in sync with LaunchSource in
-// extensions/common/api/app_runtime.idl, and GetLaunchSourceEnum() in
-// extensions/browser/api/app_runtime/app_runtime_api.cc.
-// Note the enumeration is used in UMA histogram so entries
-// should not be re-ordered or removed.
-enum AppLaunchSource {
-  SOURCE_NONE,
-  SOURCE_UNTRACKED,
-  SOURCE_APP_LAUNCHER,
-  SOURCE_NEW_TAB_PAGE,
-  SOURCE_RELOAD,
-  SOURCE_RESTART,
-  SOURCE_LOAD_AND_LAUNCH,
-  SOURCE_COMMAND_LINE,
-  SOURCE_FILE_HANDLER,
-  SOURCE_URL_HANDLER,
-  SOURCE_SYSTEM_TRAY,
-  SOURCE_ABOUT_PAGE,
-  SOURCE_KEYBOARD,
-  SOURCE_EXTENSIONS_PAGE,
-  SOURCE_MANAGEMENT_API,
-  SOURCE_EPHEMERAL_APP_DEPRECATED,
-  SOURCE_BACKGROUND,
-  SOURCE_KIOSK,
-  SOURCE_CHROME_INTERNAL,
-  SOURCE_TEST,
-  SOURCE_INSTALLED_NOTIFICATION,
-  SOURCE_CONTEXT_MENU,
-  SOURCE_ARC,
-  NUM_APP_LAUNCH_SOURCES
-};
+using apps::mojom::AppLaunchSource;
+using apps::mojom::LaunchContainer;
 
 // This enum is used for the launch type the user wants to use for an
 // application.
@@ -168,18 +139,6 @@
   LAUNCH_TYPE_DEFAULT = LAUNCH_TYPE_REGULAR
 };
 
-// Don't remove items or change the order of this enum.  It's used in
-// histograms and preferences.
-enum LaunchContainer {
-  LAUNCH_CONTAINER_WINDOW,
-  LAUNCH_CONTAINER_PANEL_DEPRECATED,
-  LAUNCH_CONTAINER_TAB,
-  // For platform apps, which don't actually have a container (they just get a
-  // "onLaunched" event).
-  LAUNCH_CONTAINER_NONE,
-  NUM_LAUNCH_CONTAINERS
-};
-
 // The origin of injected CSS.
 enum CSSOrigin { CSS_ORIGIN_AUTHOR, CSS_ORIGIN_USER };
 static const CSSOrigin CSS_ORIGIN_LAST = CSS_ORIGIN_USER;
diff --git a/extensions/shell/browser/default_shell_browser_main_delegate.cc b/extensions/shell/browser/default_shell_browser_main_delegate.cc
index a08bcc0..4cd40de0 100644
--- a/extensions/shell/browser/default_shell_browser_main_delegate.cc
+++ b/extensions/shell/browser/default_shell_browser_main_delegate.cc
@@ -74,7 +74,7 @@
     base::PathService::Get(base::DIR_CURRENT, &current_directory);
     apps::LaunchPlatformAppWithCommandLine(browser_context, launch_app,
                                            *command_line, current_directory,
-                                           SOURCE_COMMAND_LINE);
+                                           AppLaunchSource::kSourceCommandLine);
   } else {
     LOG(ERROR) << "Could not load any apps.";
   }
diff --git a/extensions/shell/browser/shell_extension_loader.cc b/extensions/shell/browser/shell_extension_loader.cc
index 6b4c562..603ed8c 100644
--- a/extensions/shell/browser/shell_extension_loader.cc
+++ b/extensions/shell/browser/shell_extension_loader.cc
@@ -109,7 +109,8 @@
     // open its first window.
     // Launch the app now.
     if (extension->is_platform_app())
-      apps::LaunchPlatformApp(browser_context_, extension.get(), SOURCE_RELOAD);
+      apps::LaunchPlatformApp(browser_context_, extension.get(),
+                              AppLaunchSource::kSourceReload);
   }
 
   // Whether or not the reload succeeded, we should stop waiting for it.
diff --git a/extensions/shell/browser/shell_extension_system.cc b/extensions/shell/browser/shell_extension_system.cc
index e778a0c..d9e6ea2 100644
--- a/extensions/shell/browser/shell_extension_system.cc
+++ b/extensions/shell/browser/shell_extension_system.cc
@@ -69,7 +69,8 @@
   const Extension* extension = ExtensionRegistry::Get(browser_context_)
                                    ->enabled_extensions()
                                    .GetByID(extension_id);
-  apps::LaunchPlatformApp(browser_context_, extension, SOURCE_UNTRACKED);
+  apps::LaunchPlatformApp(browser_context_, extension,
+                          AppLaunchSource::kSourceUntracked);
 }
 
 void ShellExtensionSystem::ReloadExtension(const ExtensionId& extension_id) {
diff --git a/google_apis/gaia/oauth2_access_token_manager.cc b/google_apis/gaia/oauth2_access_token_manager.cc
index 1d1a974..cb41f11e 100644
--- a/google_apis/gaia/oauth2_access_token_manager.cc
+++ b/google_apis/gaia/oauth2_access_token_manager.cc
@@ -4,12 +4,311 @@
 
 #include "google_apis/gaia/oauth2_access_token_manager.h"
 
+#include "base/metrics/histogram_macros.h"
+#include "base/rand_util.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "google_apis/gaia/gaia_urls.h"
+#include "google_apis/gaia/oauth2_access_token_fetcher.h"
 #include "google_apis/gaia/oauth2_token_service_delegate.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
+int OAuth2AccessTokenManager::max_fetch_retry_num_ = 5;
+
+// Class that fetches an OAuth2 access token for a given account id and set of
+// scopes.
+//
+// It aims to meet OAuth2AccessTokenManager's requirements on token fetching.
+// Retry mechanism is used to handle failures.
+//
+// To use this class, call CreateAndStart() to create and start a Fetcher.
+//
+// The Fetcher will call back the token manager by calling
+// OAuth2AccessTokenManager::OnFetchComplete() when it completes fetching, if
+// it is not destroyed before it completes fetching; if the Fetcher is destroyed
+// before it completes fetching, the token manager will never be called back.
+// The Fetcher destroys itself after calling back the manager when it finishes
+// fetching.
+//
+// Requests that are waiting for the fetching results of this Fetcher can be
+// added to the Fetcher by calling
+// OAuth2AccessTokenManager::Fetcher::AddWaitingRequest() before the Fetcher
+// completes fetching.
+//
+// The waiting requests are taken as weak pointers and they can be deleted.
+// They will be called back with the result when either the Fetcher completes
+// fetching or is destroyed, whichever comes first. In the latter case, the
+// waiting requests will be called back with an error.
+//
+// The OAuth2AccessTokenManager and the waiting requests will never be called
+// back on the same turn of the message loop as when the fetcher is started,
+// even if an immediate error occurred.
+class OAuth2AccessTokenManager::Fetcher : public OAuth2AccessTokenConsumer {
+ public:
+  // Creates a Fetcher and starts fetching an OAuth2 access token for
+  // |account_id| and |scopes| in the request context obtained by |getter|.
+  // The given |oauth2_access_token_manager| will be informed when fetching is
+  // done.
+  static std::unique_ptr<OAuth2AccessTokenManager::Fetcher> CreateAndStart(
+      OAuth2AccessTokenManager* oauth2_access_token_manager,
+      const std::string& account_id,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+      const std::string& client_id,
+      const std::string& client_secret,
+      const OAuth2TokenService::ScopeSet& scopes,
+      base::WeakPtr<OAuth2TokenService::RequestImpl> waiting_request);
+  ~Fetcher() override;
+
+  // Add a request that is waiting for the result of this Fetcher.
+  void AddWaitingRequest(
+      base::WeakPtr<OAuth2TokenService::RequestImpl> waiting_request);
+
+  // Returns count of waiting requests.
+  size_t GetWaitingRequestCount() const;
+
+  const std::vector<base::WeakPtr<OAuth2TokenService::RequestImpl>>&
+  waiting_requests() const {
+    return waiting_requests_;
+  }
+
+  void Cancel();
+
+  const OAuth2TokenService::ScopeSet& GetScopeSet() const;
+  const std::string& GetClientId() const;
+  const std::string& GetAccountId() const;
+
+  // The error result from this fetcher.
+  const GoogleServiceAuthError& error() const { return error_; }
+
+ protected:
+  // OAuth2AccessTokenConsumer
+  void OnGetTokenSuccess(
+      const OAuth2AccessTokenConsumer::TokenResponse& token_response) override;
+  void OnGetTokenFailure(const GoogleServiceAuthError& error) override;
+
+ private:
+  Fetcher(OAuth2AccessTokenManager* oauth2_access_token_manager,
+          const std::string& account_id,
+          scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+          const std::string& client_id,
+          const std::string& client_secret,
+          const OAuth2TokenService::ScopeSet& scopes,
+          base::WeakPtr<OAuth2TokenService::RequestImpl> waiting_request);
+  void Start();
+  void InformWaitingRequests();
+  void InformWaitingRequestsAndDelete();
+  bool ShouldRetry(const GoogleServiceAuthError& error) const;
+  int64_t ComputeExponentialBackOffMilliseconds(int retry_num);
+
+  // Attempts to retry the fetch if possible.  This is possible if the retry
+  // count has not been exceeded.  Returns true if a retry has been restarted
+  // and false otherwise.
+  bool RetryIfPossible(const GoogleServiceAuthError& error);
+
+  // |oauth2_access_token_manager_| remains valid for the life of this
+  // Fetcher, since this Fetcher is destructed in the dtor of the
+  // OAuth2AccessTokenManager or is scheduled for deletion at the end of
+  // OnGetTokenFailure/OnGetTokenSuccess (whichever comes first).
+  OAuth2AccessTokenManager* const oauth2_access_token_manager_;
+  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
+  const std::string account_id_;
+  const OAuth2TokenService::ScopeSet scopes_;
+  std::vector<base::WeakPtr<OAuth2TokenService::RequestImpl>> waiting_requests_;
+
+  int retry_number_;
+  base::OneShotTimer retry_timer_;
+  std::unique_ptr<OAuth2AccessTokenFetcher> fetcher_;
+
+  // Variables that store fetch results.
+  // Initialized to be GoogleServiceAuthError::SERVICE_UNAVAILABLE to handle
+  // destruction.
+  GoogleServiceAuthError error_;
+  OAuth2AccessTokenConsumer::TokenResponse token_response_;
+
+  // OAuth2 client id and secret.
+  std::string client_id_;
+  std::string client_secret_;
+
+  DISALLOW_COPY_AND_ASSIGN(Fetcher);
+};
+
+// static
+std::unique_ptr<OAuth2AccessTokenManager::Fetcher>
+OAuth2AccessTokenManager::Fetcher::CreateAndStart(
+    OAuth2AccessTokenManager* oauth2_access_token_manager,
+    const std::string& account_id,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+    const std::string& client_id,
+    const std::string& client_secret,
+    const OAuth2TokenService::ScopeSet& scopes,
+    base::WeakPtr<OAuth2TokenService::RequestImpl> waiting_request) {
+  std::unique_ptr<OAuth2AccessTokenManager::Fetcher> fetcher = base::WrapUnique(
+      new Fetcher(oauth2_access_token_manager, account_id, url_loader_factory,
+                  client_id, client_secret, scopes, waiting_request));
+
+  fetcher->Start();
+  return fetcher;
+}
+
+OAuth2AccessTokenManager::Fetcher::Fetcher(
+    OAuth2AccessTokenManager* oauth2_access_token_manager,
+    const std::string& account_id,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+    const std::string& client_id,
+    const std::string& client_secret,
+    const OAuth2TokenService::ScopeSet& scopes,
+    base::WeakPtr<OAuth2TokenService::RequestImpl> waiting_request)
+    : oauth2_access_token_manager_(oauth2_access_token_manager),
+      url_loader_factory_(url_loader_factory),
+      account_id_(account_id),
+      scopes_(scopes),
+      retry_number_(0),
+      error_(GoogleServiceAuthError::SERVICE_UNAVAILABLE),
+      client_id_(client_id),
+      client_secret_(client_secret) {
+  DCHECK(oauth2_access_token_manager_);
+  waiting_requests_.push_back(waiting_request);
+}
+
+OAuth2AccessTokenManager::Fetcher::~Fetcher() {
+  // Inform the waiting requests if it has not done so.
+  if (waiting_requests_.size())
+    InformWaitingRequests();
+}
+
+void OAuth2AccessTokenManager::Fetcher::Start() {
+  fetcher_ = oauth2_access_token_manager_->CreateAccessTokenFetcher(
+      account_id_, url_loader_factory_, this);
+  DCHECK(fetcher_);
+
+  // Stop the timer before starting the fetch, as defense in depth against the
+  // fetcher calling us back synchronously (which might restart the timer).
+  retry_timer_.Stop();
+  fetcher_->Start(client_id_, client_secret_,
+                  std::vector<std::string>(scopes_.begin(), scopes_.end()));
+}
+
+void OAuth2AccessTokenManager::Fetcher::OnGetTokenSuccess(
+    const OAuth2AccessTokenConsumer::TokenResponse& token_response) {
+  fetcher_.reset();
+
+  // Fetch completes.
+  error_ = GoogleServiceAuthError::AuthErrorNone();
+  token_response_ = token_response;
+
+  // Delegates may override this method to skip caching in some cases, but
+  // we still inform all waiting Consumers of a successful token fetch below.
+  // This is intentional -- some consumers may need the token for cleanup
+  // tasks. https://chromiumcodereview.appspot.com/11312124/
+  oauth2_access_token_manager_->RegisterTokenResponse(client_id_, account_id_,
+                                                      scopes_, token_response_);
+  InformWaitingRequestsAndDelete();
+}
+
+void OAuth2AccessTokenManager::Fetcher::OnGetTokenFailure(
+    const GoogleServiceAuthError& error) {
+  fetcher_.reset();
+
+  if (ShouldRetry(error) && RetryIfPossible(error))
+    return;
+
+  UMA_HISTOGRAM_ENUMERATION("Signin.OAuth2TokenGetFailure", error.state(),
+                            GoogleServiceAuthError::NUM_STATES);
+  error_ = error;
+  InformWaitingRequestsAndDelete();
+}
+
+// Returns an exponential backoff in milliseconds including randomness less than
+// 1000 ms when retrying fetching an OAuth2 access token.
+int64_t
+OAuth2AccessTokenManager::Fetcher::ComputeExponentialBackOffMilliseconds(
+    int retry_num) {
+  DCHECK(retry_num < oauth2_access_token_manager_->max_fetch_retry_num_);
+  int exponential_backoff_in_seconds = 1 << retry_num;
+  // Returns a backoff with randomness < 1000ms
+  return (exponential_backoff_in_seconds + base::RandDouble()) * 1000;
+}
+
+bool OAuth2AccessTokenManager::Fetcher::RetryIfPossible(
+    const GoogleServiceAuthError& error) {
+  if (retry_number_ < oauth2_access_token_manager_->max_fetch_retry_num_) {
+    base::TimeDelta backoff = base::TimeDelta::FromMilliseconds(
+        ComputeExponentialBackOffMilliseconds(retry_number_));
+    ++retry_number_;
+    UMA_HISTOGRAM_ENUMERATION("Signin.OAuth2TokenGetRetry", error.state(),
+                              GoogleServiceAuthError::NUM_STATES);
+    retry_timer_.Stop();
+    retry_timer_.Start(FROM_HERE, backoff, this,
+                       &OAuth2AccessTokenManager::Fetcher::Start);
+    return true;
+  }
+
+  return false;
+}
+
+bool OAuth2AccessTokenManager::Fetcher::ShouldRetry(
+    const GoogleServiceAuthError& error) const {
+  GoogleServiceAuthError::State error_state = error.state();
+  bool should_retry =
+      error_state == GoogleServiceAuthError::CONNECTION_FAILED ||
+      error_state == GoogleServiceAuthError::REQUEST_CANCELED ||
+      error_state == GoogleServiceAuthError::SERVICE_UNAVAILABLE;
+
+  // Give the delegate a chance to correct the error first.  This is a best
+  // effort only.
+  return should_retry || oauth2_access_token_manager_->GetDelegate()
+                             ->FixRequestErrorIfPossible();
+}
+
+void OAuth2AccessTokenManager::Fetcher::InformWaitingRequests() {
+  for (const base::WeakPtr<OAuth2TokenService::RequestImpl>& request :
+       waiting_requests_) {
+    if (request)
+      request->InformConsumer(error_, token_response_);
+  }
+  waiting_requests_.clear();
+}
+
+void OAuth2AccessTokenManager::Fetcher::InformWaitingRequestsAndDelete() {
+  // Deregisters itself from the manager to prevent more waiting requests to
+  // be added when it calls back the waiting requests.
+  oauth2_access_token_manager_->OnFetchComplete(this);
+  InformWaitingRequests();
+  base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
+}
+
+void OAuth2AccessTokenManager::Fetcher::AddWaitingRequest(
+    base::WeakPtr<OAuth2TokenService::RequestImpl> waiting_request) {
+  waiting_requests_.push_back(waiting_request);
+}
+
+size_t OAuth2AccessTokenManager::Fetcher::GetWaitingRequestCount() const {
+  return waiting_requests_.size();
+}
+
+void OAuth2AccessTokenManager::Fetcher::Cancel() {
+  if (fetcher_)
+    fetcher_->CancelRequest();
+  fetcher_.reset();
+  retry_timer_.Stop();
+  error_ = GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED);
+  InformWaitingRequestsAndDelete();
+}
+
+const OAuth2TokenService::ScopeSet&
+OAuth2AccessTokenManager::Fetcher::GetScopeSet() const {
+  return scopes_;
+}
+
+const std::string& OAuth2AccessTokenManager::Fetcher::GetClientId() const {
+  return client_id_;
+}
+
+const std::string& OAuth2AccessTokenManager::Fetcher::GetAccountId() const {
+  return account_id_;
+}
+
 OAuth2AccessTokenManager::OAuth2AccessTokenManager(
     OAuth2TokenService* token_service,
     OAuth2TokenServiceDelegate* delegate)
@@ -18,7 +317,19 @@
   DCHECK(delegate_);
 }
 
-OAuth2AccessTokenManager::~OAuth2AccessTokenManager() = default;
+OAuth2AccessTokenManager::~OAuth2AccessTokenManager() {
+  // Release all the pending fetchers.
+  pending_fetchers_.clear();
+}
+
+OAuth2TokenServiceDelegate* OAuth2AccessTokenManager::GetDelegate() {
+  return delegate_;
+}
+
+const OAuth2TokenServiceDelegate* OAuth2AccessTokenManager::GetDelegate()
+    const {
+  return delegate_;
+}
 
 void OAuth2AccessTokenManager::AddDiagnosticsObserver(
     AccessTokenDiagnosticsObserver* observer) {
@@ -65,6 +376,29 @@
       GaiaUrls::GetInstance()->oauth2_chrome_client_secret(), scopes, consumer);
 }
 
+void OAuth2AccessTokenManager::FetchOAuth2Token(
+    OAuth2TokenService::RequestImpl* request,
+    const CoreAccountId& account_id,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+    const std::string& client_id,
+    const std::string& client_secret,
+    const OAuth2TokenService::ScopeSet& scopes) {
+  // If there is already a pending fetcher for |scopes| and |account_id|,
+  // simply register this |request| for those results rather than starting
+  // a new fetcher.
+  OAuth2TokenService::RequestParameters request_parameters =
+      OAuth2TokenService::RequestParameters(client_id, account_id, scopes);
+  auto iter = pending_fetchers_.find(request_parameters);
+  if (iter != pending_fetchers_.end()) {
+    iter->second->AddWaitingRequest(request->AsWeakPtr());
+    return;
+  }
+
+  pending_fetchers_[request_parameters] =
+      Fetcher::CreateAndStart(this, account_id, url_loader_factory, client_id,
+                              client_secret, scopes, request->AsWeakPtr());
+}
+
 void OAuth2AccessTokenManager::RegisterTokenResponse(
     const std::string& client_id,
     const CoreAccountId& account_id,
@@ -118,20 +452,46 @@
 }
 
 void OAuth2AccessTokenManager::CancelAllRequests() {
-  std::vector<OAuth2TokenService::Fetcher*> fetchers_to_cancel;
-  for (const auto& pending_fetcher : token_service_->pending_fetchers_)
+  std::vector<Fetcher*> fetchers_to_cancel;
+  for (const auto& pending_fetcher : pending_fetchers_)
     fetchers_to_cancel.push_back(pending_fetcher.second.get());
-  token_service_->CancelFetchers(fetchers_to_cancel);
+  CancelFetchers(fetchers_to_cancel);
 }
 
 void OAuth2AccessTokenManager::CancelRequestsForAccount(
     const CoreAccountId& account_id) {
-  std::vector<OAuth2TokenService::Fetcher*> fetchers_to_cancel;
-  for (const auto& pending_fetcher : token_service_->pending_fetchers_) {
+  std::vector<Fetcher*> fetchers_to_cancel;
+  for (const auto& pending_fetcher : pending_fetchers_) {
     if (pending_fetcher.first.account_id == account_id)
       fetchers_to_cancel.push_back(pending_fetcher.second.get());
   }
-  token_service_->CancelFetchers(fetchers_to_cancel);
+  CancelFetchers(fetchers_to_cancel);
+}
+
+void OAuth2AccessTokenManager::
+    set_max_authorization_token_fetch_retries_for_testing(int max_retries) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  max_fetch_retry_num_ = max_retries;
+}
+
+size_t OAuth2AccessTokenManager::GetNumPendingRequestsForTesting(
+    const std::string& client_id,
+    const CoreAccountId& account_id,
+    const OAuth2TokenService::ScopeSet& scopes) const {
+  auto iter = pending_fetchers_.find(
+      OAuth2TokenService::RequestParameters(client_id, account_id, scopes));
+  return iter == pending_fetchers_.end()
+             ? 0
+             : iter->second->GetWaitingRequestCount();
+}
+
+std::unique_ptr<OAuth2AccessTokenFetcher>
+OAuth2AccessTokenManager::CreateAccessTokenFetcher(
+    const CoreAccountId& account_id,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+    OAuth2AccessTokenConsumer* consumer) {
+  return delegate_->CreateAccessTokenFetcher(account_id, url_loader_factory,
+                                             consumer);
 }
 
 std::unique_ptr<OAuth2TokenService::Request>
@@ -173,6 +533,10 @@
     InformConsumerWithCachedTokenResponse(token_response, request.get(),
                                           request_parameters);
   } else {
+    // TODO(https://crbug.com/967598): Use directly
+    // OAuth2AccessTokenManager::FetchOAuth2Token this fully manages access
+    // tokens independently of OAuth2TokenService. For now, some tests need to
+    // override OAuth2TokenService::FetchOAuth2Token.
     token_service_->FetchOAuth2Token(request.get(), account_id,
                                      url_loader_factory, client_id,
                                      client_secret, scopes);
@@ -216,3 +580,70 @@
   }
   return false;
 }
+
+void OAuth2AccessTokenManager::OnFetchComplete(
+    OAuth2AccessTokenManager::Fetcher* fetcher) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  // Update the auth error state so auth errors are appropriately communicated
+  // to the user.
+  token_service_->UpdateAuthError(fetcher->GetAccountId(), fetcher->error());
+
+  // Note |fetcher| is recorded in |pending_fetcher_| mapped from its
+  // combination of client ID, account ID, and scope set. This is guaranteed as
+  // follows; here a Fetcher is said to be uncompleted if it has not finished
+  // calling back
+  // OAuth2AccessTokenManager::OnFetchComplete().
+  //
+  // (1) All the live Fetchers are created by this manager.
+  //     This is because (1) all the live Fetchers are created by a live
+  //     manager, as all the fetchers created by a manager are destructed in the
+  //     manager's dtor.
+  //
+  // (2) All the uncompleted Fetchers created by this manager are recorded in
+  //     |pending_fetchers_|.
+  //     This is because (1) all the created Fetchers are added to
+  //     |pending_fetchers_| (in method StartRequest()) and (2) method
+  //     OnFetchComplete() is the only place where a Fetcher is erased from
+  //     |pending_fetchers_|. Note no Fetcher is erased in method
+  //     StartRequest().
+  //
+  // (3) Each of the Fetchers recorded in |pending_fetchers_| is mapped from
+  //     its combination of client ID, account ID, and scope set. This is
+  //     guaranteed by Fetcher creation in method StartRequest().
+  //
+  // When this method is called, |fetcher| is alive and uncompleted.
+  // By (1), |fetcher| is created by this manager.
+  // Then by (2), |fetcher| is recorded in |pending_fetchers_|.
+  // Then by (3), |fetcher_| is mapped from its combination of client ID,
+  // account ID, and scope set.
+  OAuth2TokenService::RequestParameters request_param(
+      fetcher->GetClientId(), fetcher->GetAccountId(), fetcher->GetScopeSet());
+
+  const OAuth2AccessTokenConsumer::TokenResponse* entry =
+      GetCachedTokenResponse(request_param);
+  for (const base::WeakPtr<OAuth2TokenService::RequestImpl>& req :
+       fetcher->waiting_requests()) {
+    if (req) {
+      for (auto& observer : diagnostics_observer_list_) {
+        observer.OnFetchAccessTokenComplete(
+            req->GetAccountId(), req->GetConsumerId(), fetcher->GetScopeSet(),
+            fetcher->error(), entry ? entry->expiration_time : base::Time());
+      }
+    }
+  }
+
+  auto iter = pending_fetchers_.find(request_param);
+  DCHECK(iter != pending_fetchers_.end());
+  DCHECK_EQ(fetcher, iter->second.get());
+
+  // The Fetcher deletes itself.
+  iter->second.release();
+  pending_fetchers_.erase(iter);
+}
+
+void OAuth2AccessTokenManager::CancelFetchers(
+    std::vector<Fetcher*> fetchers_to_cancel) {
+  for (Fetcher* pending_fetcher : fetchers_to_cancel)
+    pending_fetcher->Cancel();
+}
diff --git a/google_apis/gaia/oauth2_access_token_manager.h b/google_apis/gaia/oauth2_access_token_manager.h
index dd286c81..4271065 100644
--- a/google_apis/gaia/oauth2_access_token_manager.h
+++ b/google_apis/gaia/oauth2_access_token_manager.h
@@ -12,6 +12,9 @@
 // separated from OAuth2TokenService.
 #include "google_apis/gaia/oauth2_token_service.h"
 
+class OAuth2AccessTokenFetcher;
+class OAuth2TokenServiceDelegate;
+
 // Class that manages requests for OAuth2 access tokens.
 class OAuth2AccessTokenManager {
  public:
@@ -23,6 +26,9 @@
                                     OAuth2TokenServiceDelegate* delegate);
   virtual ~OAuth2AccessTokenManager();
 
+  OAuth2TokenServiceDelegate* GetDelegate();
+  const OAuth2TokenServiceDelegate* GetDelegate() const;
+
   // Add or remove observers of this token manager.
   void AddDiagnosticsObserver(AccessTokenDiagnosticsObserver* observer);
   void RemoveDiagnosticsObserver(AccessTokenDiagnosticsObserver* observer);
@@ -58,6 +64,15 @@
       const OAuth2TokenService::ScopeSet& scopes,
       OAuth2TokenService::Consumer* consumer);
 
+  // Fetches an OAuth token for the specified client/scopes.
+  void FetchOAuth2Token(
+      OAuth2TokenService::RequestImpl* request,
+      const CoreAccountId& account_id,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+      const std::string& client_id,
+      const std::string& client_secret,
+      const OAuth2TokenService::ScopeSet& scopes);
+
   // Add a new entry to the cache.
   void RegisterTokenResponse(
       const std::string& client_id,
@@ -86,13 +101,30 @@
   // Cancels all requests related to a given |account_id|.
   void CancelRequestsForAccount(const CoreAccountId& account_id);
 
+  void set_max_authorization_token_fetch_retries_for_testing(int max_retries);
+
+  // Returns the current number of pending fetchers matching given params.
+  size_t GetNumPendingRequestsForTesting(
+      const std::string& client_id,
+      const CoreAccountId& account_id,
+      const OAuth2TokenService::ScopeSet& scopes) const;
+
  private:
   // TODO(https://crbug.com/967598): Remove this once |token_cache_| management
   // is moved to OAuth2AccessTokenManager.
   friend class OAuth2TokenService;
 
+  class Fetcher;
+  friend class Fetcher;
+
   OAuth2TokenService::TokenCache& token_cache() { return token_cache_; }
 
+  // Create an access token fetcher for the given account id.
+  std::unique_ptr<OAuth2AccessTokenFetcher> CreateAccessTokenFetcher(
+      const CoreAccountId& account_id,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+      OAuth2AccessTokenConsumer* consumer);
+
   // This method does the same as |StartRequestWithContext| except it
   // uses |client_id| and |client_secret| to identify OAuth
   // client app instead of using Chrome's default values.
@@ -116,6 +148,12 @@
       const OAuth2TokenService::RequestParameters& client_scopes,
       const std::string& token_to_remove);
 
+  // Called when |fetcher| finishes fetching.
+  void OnFetchComplete(Fetcher* fetcher);
+
+  // Called when a number of fetchers need to be canceled.
+  void CancelFetchers(std::vector<Fetcher*> fetchers_to_cancel);
+
   // The cache of currently valid tokens.
   OAuth2TokenService::TokenCache token_cache_;
   // List of observers to notify when access token status changes.
@@ -127,6 +165,12 @@
   // TODO(https://crbug.com/967598): Replace it with
   // OAuth2AccessTokenManagerDelegate.
   OAuth2TokenServiceDelegate* delegate_;
+  // A map from fetch parameters to a fetcher that is fetching an OAuth2 access
+  // token using these parameters.
+  std::map<OAuth2TokenService::RequestParameters, std::unique_ptr<Fetcher>>
+      pending_fetchers_;
+  // Maximum number of retries in fetching an OAuth2 access token.
+  static int max_fetch_retry_num_;
 
   SEQUENCE_CHECKER(sequence_checker_);
 
diff --git a/google_apis/gaia/oauth2_token_service.cc b/google_apis/gaia/oauth2_token_service.cc
index 2fa7dee..a790bf2 100644
--- a/google_apis/gaia/oauth2_token_service.cc
+++ b/google_apis/gaia/oauth2_token_service.cc
@@ -13,22 +13,16 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/weak_ptr.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/rand_util.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
-#include "base/timer/timer.h"
 #include "google_apis/gaia/gaia_constants.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "google_apis/gaia/google_service_auth_error.h"
-#include "google_apis/gaia/oauth2_access_token_fetcher_impl.h"
 #include "google_apis/gaia/oauth2_access_token_manager.h"
 #include "google_apis/gaia/oauth2_token_service_delegate.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
-int OAuth2TokenService::max_fetch_retry_num_ = 5;
-
 OAuth2TokenService::RequestParameters::RequestParameters(
     const std::string& client_id,
     const std::string& account_id,
@@ -88,295 +82,6 @@
     consumer_->OnGetTokenFailure(this, error);
 }
 
-// Class that fetches an OAuth2 access token for a given account id and set of
-// scopes.
-//
-// It aims to meet OAuth2TokenService's requirements on token fetching. Retry
-// mechanism is used to handle failures.
-//
-// To use this class, call CreateAndStart() to create and start a Fetcher.
-//
-// The Fetcher will call back the service by calling
-// OAuth2TokenService::OnFetchComplete() when it completes fetching, if it is
-// not destroyed before it completes fetching; if the Fetcher is destroyed
-// before it completes fetching, the service will never be called back. The
-// Fetcher destroys itself after calling back the service when it finishes
-// fetching.
-//
-// Requests that are waiting for the fetching results of this Fetcher can be
-// added to the Fetcher by calling
-// OAuth2TokenService::Fetcher::AddWaitingRequest() before the Fetcher
-// completes fetching.
-//
-// The waiting requests are taken as weak pointers and they can be deleted.
-// They will be called back with the result when either the Fetcher completes
-// fetching or is destroyed, whichever comes first. In the latter case, the
-// waiting requests will be called back with an error.
-//
-// The OAuth2TokenService and the waiting requests will never be called back on
-// the same turn of the message loop as when the fetcher is started, even if an
-// immediate error occurred.
-class OAuth2TokenService::Fetcher : public OAuth2AccessTokenConsumer {
- public:
-  // Creates a Fetcher and starts fetching an OAuth2 access token for
-  // |account_id| and |scopes| in the request context obtained by |getter|.
-  // The given |oauth2_token_service| will be informed when fetching is done.
-  static std::unique_ptr<OAuth2TokenService::Fetcher> CreateAndStart(
-      OAuth2TokenService* oauth2_token_service,
-      const std::string& account_id,
-      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
-      const std::string& client_id,
-      const std::string& client_secret,
-      const ScopeSet& scopes,
-      base::WeakPtr<RequestImpl> waiting_request);
-  ~Fetcher() override;
-
-  // Add a request that is waiting for the result of this Fetcher.
-  void AddWaitingRequest(base::WeakPtr<RequestImpl> waiting_request);
-
-  // Returns count of waiting requests.
-  size_t GetWaitingRequestCount() const;
-
-  const std::vector<base::WeakPtr<RequestImpl> >& waiting_requests() const {
-    return waiting_requests_;
-  }
-
-  void Cancel();
-
-  const ScopeSet& GetScopeSet() const;
-  const std::string& GetClientId() const;
-  const std::string& GetAccountId() const;
-
-  // The error result from this fetcher.
-  const GoogleServiceAuthError& error() const { return error_; }
-
- protected:
-  // OAuth2AccessTokenConsumer
-  void OnGetTokenSuccess(
-      const OAuth2AccessTokenConsumer::TokenResponse& token_response) override;
-  void OnGetTokenFailure(const GoogleServiceAuthError& error) override;
-
- private:
-  Fetcher(OAuth2TokenService* oauth2_token_service,
-          const std::string& account_id,
-          scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
-          const std::string& client_id,
-          const std::string& client_secret,
-          const OAuth2TokenService::ScopeSet& scopes,
-          base::WeakPtr<RequestImpl> waiting_request);
-  void Start();
-  void InformWaitingRequests();
-  void InformWaitingRequestsAndDelete();
-  bool ShouldRetry(const GoogleServiceAuthError& error) const;
-  int64_t ComputeExponentialBackOffMilliseconds(int retry_num);
-
-  // Attempts to retry the fetch if possible.  This is possible if the retry
-  // count has not been exceeded.  Returns true if a retry has been restarted
-  // and false otherwise.
-  bool RetryIfPossible(const GoogleServiceAuthError& error);
-
-  // |oauth2_token_service_| remains valid for the life of this Fetcher, since
-  // this Fetcher is destructed in the dtor of the OAuth2TokenService or is
-  // scheduled for deletion at the end of OnGetTokenFailure/OnGetTokenSuccess
-  // (whichever comes first).
-  OAuth2TokenService* const oauth2_token_service_;
-  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
-  const std::string account_id_;
-  const ScopeSet scopes_;
-  std::vector<base::WeakPtr<RequestImpl> > waiting_requests_;
-
-  int retry_number_;
-  base::OneShotTimer retry_timer_;
-  std::unique_ptr<OAuth2AccessTokenFetcher> fetcher_;
-
-  // Variables that store fetch results.
-  // Initialized to be GoogleServiceAuthError::SERVICE_UNAVAILABLE to handle
-  // destruction.
-  GoogleServiceAuthError error_;
-  OAuth2AccessTokenConsumer::TokenResponse token_response_;
-
-  // OAuth2 client id and secret.
-  std::string client_id_;
-  std::string client_secret_;
-
-  DISALLOW_COPY_AND_ASSIGN(Fetcher);
-};
-
-// static
-std::unique_ptr<OAuth2TokenService::Fetcher>
-OAuth2TokenService::Fetcher::CreateAndStart(
-    OAuth2TokenService* oauth2_token_service,
-    const std::string& account_id,
-    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
-    const std::string& client_id,
-    const std::string& client_secret,
-    const OAuth2TokenService::ScopeSet& scopes,
-    base::WeakPtr<RequestImpl> waiting_request) {
-  std::unique_ptr<OAuth2TokenService::Fetcher> fetcher = base::WrapUnique(
-      new Fetcher(oauth2_token_service, account_id, url_loader_factory,
-                  client_id, client_secret, scopes, waiting_request));
-
-  fetcher->Start();
-  return fetcher;
-}
-
-OAuth2TokenService::Fetcher::Fetcher(
-    OAuth2TokenService* oauth2_token_service,
-    const std::string& account_id,
-    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
-    const std::string& client_id,
-    const std::string& client_secret,
-    const OAuth2TokenService::ScopeSet& scopes,
-    base::WeakPtr<RequestImpl> waiting_request)
-    : oauth2_token_service_(oauth2_token_service),
-      url_loader_factory_(url_loader_factory),
-      account_id_(account_id),
-      scopes_(scopes),
-      retry_number_(0),
-      error_(GoogleServiceAuthError::SERVICE_UNAVAILABLE),
-      client_id_(client_id),
-      client_secret_(client_secret) {
-  DCHECK(oauth2_token_service_);
-  waiting_requests_.push_back(waiting_request);
-}
-
-OAuth2TokenService::Fetcher::~Fetcher() {
-  // Inform the waiting requests if it has not done so.
-  if (waiting_requests_.size())
-    InformWaitingRequests();
-}
-
-void OAuth2TokenService::Fetcher::Start() {
-  fetcher_ = oauth2_token_service_->CreateAccessTokenFetcher(
-      account_id_, url_loader_factory_, this);
-  DCHECK(fetcher_);
-
-  // Stop the timer before starting the fetch, as defense in depth against the
-  // fetcher calling us back synchronously (which might restart the timer).
-  retry_timer_.Stop();
-  fetcher_->Start(client_id_,
-                  client_secret_,
-                  std::vector<std::string>(scopes_.begin(), scopes_.end()));
-}
-
-void OAuth2TokenService::Fetcher::OnGetTokenSuccess(
-    const OAuth2AccessTokenConsumer::TokenResponse& token_response) {
-  fetcher_.reset();
-
-  // Fetch completes.
-  error_ = GoogleServiceAuthError::AuthErrorNone();
-  token_response_ = token_response;
-
-  // Subclasses may override this method to skip caching in some cases, but
-  // we still inform all waiting Consumers of a successful token fetch below.
-  // This is intentional -- some consumers may need the token for cleanup
-  // tasks. https://chromiumcodereview.appspot.com/11312124/
-  oauth2_token_service_->RegisterTokenResponse(client_id_, account_id_, scopes_,
-                                               token_response_);
-  InformWaitingRequestsAndDelete();
-}
-
-void OAuth2TokenService::Fetcher::OnGetTokenFailure(
-    const GoogleServiceAuthError& error) {
-  fetcher_.reset();
-
-  if (ShouldRetry(error) && RetryIfPossible(error))
-    return;
-
-  UMA_HISTOGRAM_ENUMERATION("Signin.OAuth2TokenGetFailure",
-      error.state(), GoogleServiceAuthError::NUM_STATES);
-  error_ = error;
-  InformWaitingRequestsAndDelete();
-}
-
-// Returns an exponential backoff in milliseconds including randomness less than
-// 1000 ms when retrying fetching an OAuth2 access token.
-int64_t OAuth2TokenService::Fetcher::ComputeExponentialBackOffMilliseconds(
-    int retry_num) {
-  DCHECK(retry_num < max_fetch_retry_num_);
-  int exponential_backoff_in_seconds = 1 << retry_num;
-  // Returns a backoff with randomness < 1000ms
-  return (exponential_backoff_in_seconds + base::RandDouble()) * 1000;
-}
-
-bool OAuth2TokenService::Fetcher::RetryIfPossible(
-    const GoogleServiceAuthError& error) {
-  if (retry_number_ < max_fetch_retry_num_) {
-    base::TimeDelta backoff = base::TimeDelta::FromMilliseconds(
-        ComputeExponentialBackOffMilliseconds(retry_number_));
-    ++retry_number_;
-    UMA_HISTOGRAM_ENUMERATION("Signin.OAuth2TokenGetRetry", error.state(),
-                              GoogleServiceAuthError::NUM_STATES);
-    retry_timer_.Stop();
-    retry_timer_.Start(FROM_HERE, backoff, this,
-                       &OAuth2TokenService::Fetcher::Start);
-    return true;
-  }
-
-  return false;
-}
-
-bool OAuth2TokenService::Fetcher::ShouldRetry(
-    const GoogleServiceAuthError& error) const {
-  GoogleServiceAuthError::State error_state = error.state();
-  bool should_retry =
-      error_state == GoogleServiceAuthError::CONNECTION_FAILED ||
-      error_state == GoogleServiceAuthError::REQUEST_CANCELED ||
-      error_state == GoogleServiceAuthError::SERVICE_UNAVAILABLE;
-
-  // Give the delegate a chance to correct the error first.  This is a best
-  // effort only.
-  return should_retry ||
-         oauth2_token_service_->GetDelegate()->FixRequestErrorIfPossible();
-}
-
-void OAuth2TokenService::Fetcher::InformWaitingRequests() {
-  for (const base::WeakPtr<RequestImpl>& request : waiting_requests_) {
-    if (request)
-      request->InformConsumer(error_, token_response_);
-  }
-  waiting_requests_.clear();
-}
-
-void OAuth2TokenService::Fetcher::InformWaitingRequestsAndDelete() {
-  // Deregisters itself from the service to prevent more waiting requests to
-  // be added when it calls back the waiting requests.
-  oauth2_token_service_->OnFetchComplete(this);
-  InformWaitingRequests();
-  base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
-}
-
-void OAuth2TokenService::Fetcher::AddWaitingRequest(
-    base::WeakPtr<OAuth2TokenService::RequestImpl> waiting_request) {
-  waiting_requests_.push_back(waiting_request);
-}
-
-size_t OAuth2TokenService::Fetcher::GetWaitingRequestCount() const {
-  return waiting_requests_.size();
-}
-
-void OAuth2TokenService::Fetcher::Cancel() {
-  if (fetcher_)
-    fetcher_->CancelRequest();
-  fetcher_.reset();
-  retry_timer_.Stop();
-  error_ = GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED);
-  InformWaitingRequestsAndDelete();
-}
-
-const OAuth2TokenService::ScopeSet& OAuth2TokenService::Fetcher::GetScopeSet()
-    const {
-  return scopes_;
-}
-
-const std::string& OAuth2TokenService::Fetcher::GetClientId() const {
-  return client_id_;
-}
-
-const std::string& OAuth2TokenService::Fetcher::GetAccountId() const {
-  return account_id_;
-}
-
 OAuth2TokenService::Request::Request() {
 }
 
@@ -400,8 +105,6 @@
 
 OAuth2TokenService::~OAuth2TokenService() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  // Release all the pending fetchers.
-  pending_fetchers_.clear();
   RemoveObserver(this);
 }
 
@@ -507,30 +210,8 @@
     const std::string& client_id,
     const std::string& client_secret,
     const ScopeSet& scopes) {
-  // If there is already a pending fetcher for |scopes| and |account_id|,
-  // simply register this |request| for those results rather than starting
-  // a new fetcher.
-  RequestParameters request_parameters = RequestParameters(client_id,
-                                                           account_id,
-                                                           scopes);
-  auto iter = pending_fetchers_.find(request_parameters);
-  if (iter != pending_fetchers_.end()) {
-    iter->second->AddWaitingRequest(request->AsWeakPtr());
-    return;
-  }
-
-  pending_fetchers_[request_parameters] =
-      Fetcher::CreateAndStart(this, account_id, url_loader_factory, client_id,
-                              client_secret, scopes, request->AsWeakPtr());
-}
-
-std::unique_ptr<OAuth2AccessTokenFetcher>
-OAuth2TokenService::CreateAccessTokenFetcher(
-    const CoreAccountId& account_id,
-    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
-    OAuth2AccessTokenConsumer* consumer) {
-  return delegate_->CreateAccessTokenFetcher(account_id, url_loader_factory,
-                                             consumer);
+  token_manager_->FetchOAuth2Token(request, account_id, url_loader_factory,
+                                   client_id, client_secret, scopes);
 }
 
 bool OAuth2TokenService::AreAllCredentialsLoaded() const {
@@ -602,71 +283,6 @@
   delegate_->InvalidateAccessToken(account_id, client_id, scopes, access_token);
 }
 
-void OAuth2TokenService::OnFetchComplete(Fetcher* fetcher) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  // Update the auth error state so auth errors are appropriately communicated
-  // to the user.
-  UpdateAuthError(fetcher->GetAccountId(), fetcher->error());
-
-  // Note |fetcher| is recorded in |pending_fetcher_| mapped to its refresh
-  // token and scope set. This is guaranteed as follows; here a Fetcher is said
-  // to be uncompleted if it has not finished calling back
-  // OAuth2TokenService::OnFetchComplete().
-  //
-  // (1) All the live Fetchers are created by this service.
-  //     This is because (1) all the live Fetchers are created by a live
-  //     service, as all the fetchers created by a service are destructed in the
-  //     service's dtor.
-  //
-  // (2) All the uncompleted Fetchers created by this service are recorded in
-  //     |pending_fetchers_|.
-  //     This is because (1) all the created Fetchers are added to
-  //     |pending_fetchers_| (in method StartRequest()) and (2) method
-  //     OnFetchComplete() is the only place where a Fetcher is erased from
-  //     |pending_fetchers_|. Note no Fetcher is erased in method
-  //     StartRequest().
-  //
-  // (3) Each of the Fetchers recorded in |pending_fetchers_| is mapped to its
-  //     refresh token and ScopeSet. This is guaranteed by Fetcher creation in
-  //     method StartRequest().
-  //
-  // When this method is called, |fetcher| is alive and uncompleted.
-  // By (1), |fetcher| is created by this service.
-  // Then by (2), |fetcher| is recorded in |pending_fetchers_|.
-  // Then by (3), |fetcher_| is mapped to its refresh token and ScopeSet.
-  RequestParameters request_param(fetcher->GetClientId(),
-                                  fetcher->GetAccountId(),
-                                  fetcher->GetScopeSet());
-
-  const OAuth2AccessTokenConsumer::TokenResponse* entry =
-      GetCachedTokenResponse(request_param);
-  for (const base::WeakPtr<RequestImpl>& req : fetcher->waiting_requests()) {
-    if (req) {
-      for (auto& observer : token_manager_->diagnostics_observer_list_) {
-        observer.OnFetchAccessTokenComplete(
-            req->GetAccountId(), req->GetConsumerId(), fetcher->GetScopeSet(),
-            fetcher->error(), entry ? entry->expiration_time : base::Time());
-      }
-    }
-  }
-
-  auto iter = pending_fetchers_.find(request_param);
-  DCHECK(iter != pending_fetchers_.end());
-  DCHECK_EQ(fetcher, iter->second.get());
-
-  // The Fetcher deletes itself.
-  iter->second.release();
-  pending_fetchers_.erase(iter);
-}
-
-const OAuth2AccessTokenConsumer::TokenResponse*
-OAuth2TokenService::GetCachedTokenResponse(
-    const RequestParameters& request_parameters) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  return token_manager_->GetCachedTokenResponse(request_parameters);
-}
-
 void OAuth2TokenService::OnRefreshTokensLoaded() {
   all_credentials_loaded_ = true;
 }
@@ -705,24 +321,16 @@
   token_manager_->CancelRequestsForAccount(account_id);
 }
 
-void OAuth2TokenService::CancelFetchers(
-    std::vector<Fetcher*> fetchers_to_cancel) {
-  for (Fetcher* pending_fetcher : fetchers_to_cancel)
-    pending_fetcher->Cancel();
-}
-
 void OAuth2TokenService::set_max_authorization_token_fetch_retries_for_testing(
     int max_retries) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  max_fetch_retry_num_ = max_retries;
+  token_manager_->set_max_authorization_token_fetch_retries_for_testing(
+      max_retries);
 }
 
 size_t OAuth2TokenService::GetNumPendingRequestsForTesting(
     const std::string& client_id,
     const CoreAccountId& account_id,
     const ScopeSet& scopes) const {
-  auto iter = pending_fetchers_.find(
-      OAuth2TokenService::RequestParameters(client_id, account_id, scopes));
-  return iter == pending_fetchers_.end() ?
-             0 : iter->second->GetWaitingRequestCount();
+  return token_manager_->GetNumPendingRequestsForTesting(client_id, account_id,
+                                                         scopes);
 }
diff --git a/google_apis/gaia/oauth2_token_service.h b/google_apis/gaia/oauth2_token_service.h
index 254e76f..bc5301a 100644
--- a/google_apis/gaia/oauth2_token_service.h
+++ b/google_apis/gaia/oauth2_token_service.h
@@ -23,7 +23,6 @@
 #include "google_apis/gaia/core_account_id.h"
 #include "google_apis/gaia/google_service_auth_error.h"
 #include "google_apis/gaia/oauth2_access_token_consumer.h"
-#include "google_apis/gaia/oauth2_access_token_fetcher.h"
 #include "google_apis/gaia/oauth2_access_token_manager_diagnostics_observer.h"
 #include "google_apis/gaia/oauth2_token_service_observer.h"
 
@@ -31,8 +30,6 @@
 class SharedURLLoaderFactory;
 }
 
-class GoogleServiceAuthError;
-class OAuth2AccessTokenFetcher;
 class OAuth2TokenServiceDelegate;
 class OAuth2AccessTokenManager;
 
@@ -219,8 +216,10 @@
   virtual void InvalidateTokenForMultilogin(const CoreAccountId& failed_account,
                                             const std::string& token);
 
+  // Deprecated. It's moved to OAuth2AccessTokenManager.
   void set_max_authorization_token_fetch_retries_for_testing(int max_retries);
   // Returns the current number of pending fetchers matching given params.
+  // Deprecated. It's moved to OAuth2AccessTokenManager.
   size_t GetNumPendingRequestsForTesting(const std::string& client_id,
                                          const CoreAccountId& account_id,
                                          const ScopeSet& scopes) const;
@@ -239,7 +238,6 @@
   // TODO(https://crbug.com/967598): Remove this once OAuth2AccessTokenManager
   // fully manages access tokens independently of OAuth2TokenService.
   friend class OAuth2AccessTokenManager;
-
   // Implements a cancelable |OAuth2TokenService::Request|, which should be
   // operated on the UI thread.
   // TODO(davidroche): move this out of header file.
@@ -304,6 +302,7 @@
 
   // Fetches an OAuth token for the specified client/scopes. Virtual so it can
   // be overridden for tests and for platform-specific behavior.
+  // Deprecated. It's moved to OAuth2AccessTokenManager.
   virtual void FetchOAuth2Token(
       RequestImpl* request,
       const CoreAccountId& account_id,
@@ -312,12 +311,6 @@
       const std::string& client_secret,
       const ScopeSet& scopes);
 
-  // Create an access token fetcher for the given account id.
-  std::unique_ptr<OAuth2AccessTokenFetcher> CreateAccessTokenFetcher(
-      const CoreAccountId& account_id,
-      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
-      OAuth2AccessTokenConsumer* consumer) WARN_UNUSED_RESULT;
-
   // Invalidates the |access_token| issued for |account_id|, |client_id| and
   // |scopes|. Virtual so it can be overriden for tests and for platform-
   // specifc behavior.
@@ -327,8 +320,6 @@
                                          const std::string& access_token);
 
  private:
-  class Fetcher;
-  friend class Fetcher;
   friend class OAuth2TokenServiceDelegate;
 
   // Provide a URLLoaderFactory used for fetching access tokens with the
@@ -342,18 +333,8 @@
   const OAuth2AccessTokenConsumer::TokenResponse* GetCachedTokenResponse(
       const RequestParameters& client_scopes);
 
-  // Called when |fetcher| finishes fetching.
-  void OnFetchComplete(Fetcher* fetcher);
-
-  // Called when a number of fetchers need to be canceled.
-  void CancelFetchers(std::vector<Fetcher*> fetchers_to_cancel);
-
   std::unique_ptr<OAuth2TokenServiceDelegate> delegate_;
 
-  // A map from fetch parameters to a fetcher that is fetching an OAuth2 access
-  // token using these parameters.
-  std::map<RequestParameters, std::unique_ptr<Fetcher>> pending_fetchers_;
-
   // The depth of batch changes.
   int batch_change_depth_;
 
@@ -362,9 +343,6 @@
 
   std::unique_ptr<OAuth2AccessTokenManager> token_manager_;
 
-  // Maximum number of retries in fetching an OAuth2 access token.
-  static int max_fetch_retry_num_;
-
   FRIEND_TEST_ALL_PREFIXES(OAuth2TokenServiceTest, RequestParametersOrderTest);
   FRIEND_TEST_ALL_PREFIXES(OAuth2TokenServiceTest,
                            SameScopesRequestedForDifferentClients);
diff --git a/google_apis/gaia/oauth2_token_service_delegate.h b/google_apis/gaia/oauth2_token_service_delegate.h
index 9b2fec8..1b56e5dc 100644
--- a/google_apis/gaia/oauth2_token_service_delegate.h
+++ b/google_apis/gaia/oauth2_token_service_delegate.h
@@ -22,6 +22,8 @@
 class SharedURLLoaderFactory;
 }
 
+class OAuth2AccessTokenFetcher;
+
 // Abstract base class to fetch and maintain refresh tokens from various
 // entities. Concrete subclasses should implement RefreshTokenIsAvailable and
 // CreateAccessTokenFetcher properly.
diff --git a/infra/config/luci-milo.cfg b/infra/config/luci-milo.cfg
index 3ae5f990..b81138a2 100644
--- a/infra/config/luci-milo.cfg
+++ b/infra/config/luci-milo.cfg
@@ -3294,7 +3294,7 @@
   builders {
     name: "buildbucket/luci.chromium.ci/Linux FYI Experimental Release (Intel HD 630)"
     category: "Linux|Intel"
-    short_name: "rel"
+    short_name: "exp"
   }
   builders {
     name: "buildbucket/luci.chromium.ci/Linux FYI Release (Intel HD 630)"
diff --git a/ios/chrome/browser/open_in/open_in_tab_helper_unittest.mm b/ios/chrome/browser/open_in/open_in_tab_helper_unittest.mm
index 5e0a7484..39f3f38 100644
--- a/ios/chrome/browser/open_in/open_in_tab_helper_unittest.mm
+++ b/ios/chrome/browser/open_in/open_in_tab_helper_unittest.mm
@@ -32,7 +32,7 @@
 // URL of the last opened document.
 @property(nonatomic, assign) GURL lastOpenedDocumentURL;
 // The last suggested file name used for openIn.
-@property(nonatomic, assign) NSString* lastSuggestedFileName;
+@property(nonatomic, copy) NSString* lastSuggestedFileName;
 // True if disableOpenInForWebState was called.
 @property(nonatomic, assign) BOOL openInDisabled;
 // True if destroyOpenInForWebState was called.
@@ -57,15 +57,10 @@
 
 namespace {
 
-// TODO(crbug.com/977314): Theses variables are only used in simulator until
-// tests are fixed.
-#if TARGET_IPHONE_SIMULATOR
 const char kContentDispositionWithFileName[] =
     "attachment; filename=\"suggested_filename.pdf\"";
 const char kPdfContentType[] = "application/pdf";
 const char kInvalidFileNameUrl[] = "https://test.test/";
-#endif
-
 const char kValidFileNameUrl[] = "https://test.test/file_name.pdf";
 const char kContentDispositionWithoutFileName[] =
     "attachment; parameter=parameter_value";
@@ -137,8 +132,6 @@
   EXPECT_TRUE(delegate_.openInDestroyed);
 }
 
-// TODO(crbug.com/977314): Tests fail on iOS devices.
-#if TARGET_IPHONE_SIMULATOR
 // Tests that openIn is enabled for PDF documents and that it uses the file name
 // from the content desposition key in the response headers.
 TEST_F(OpenInTabHelperTest, OpenInForPDFWithFileNameFromContentDesposition) {
@@ -150,6 +143,7 @@
   EXPECT_EQ(url, delegate_.lastOpenedDocumentURL);
   EXPECT_NSEQ(@"suggested_filename.pdf", delegate_.lastSuggestedFileName);
 }
+
 // Tests that openIn is enabled for PDF documents and that it uses the file name
 // from the URL if the content desposition key in the response headers doesn't
 // have file name.
@@ -180,7 +174,6 @@
   EXPECT_NSEQ(base::SysUTF8ToNSString(default_file_name),
               delegate_.lastSuggestedFileName);
 }
-#endif
 
 // Tests that openIn is disabled for non PDF documents.
 TEST_F(OpenInTabHelperTest, OpenInDisabledForNonPDF) {
diff --git a/ios/chrome/browser/ui/settings/BUILD.gn b/ios/chrome/browser/ui/settings/BUILD.gn
index 2f44bc7..0bef28d3 100644
--- a/ios/chrome/browser/ui/settings/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/BUILD.gn
@@ -177,6 +177,7 @@
     "//ios/chrome/common",
     "//ios/chrome/common/favicon",
     "//ios/chrome/common/ui_util",
+    "//ios/chrome/common/ui_util:semantic_colors",
     "//ios/public/provider/chrome/browser",
     "//ios/public/provider/chrome/browser/images",
     "//ios/public/provider/chrome/browser/mailto",
diff --git a/ios/chrome/browser/ui/settings/cells/BUILD.gn b/ios/chrome/browser/ui/settings/cells/BUILD.gn
index c440a845..dcf02b9 100644
--- a/ios/chrome/browser/ui/settings/cells/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/cells/BUILD.gn
@@ -52,6 +52,7 @@
     "//ios/chrome/browser/ui/table_view/cells",
     "//ios/chrome/browser/ui/util",
     "//ios/chrome/common/ui_util",
+    "//ios/chrome/common/ui_util:semantic_colors",
     "//ios/public/provider/chrome/browser",
     "//ios/public/provider/chrome/browser/signin",
     "//ios/third_party/material_roboto_font_loader_ios",
diff --git a/ios/chrome/browser/ui/settings/cells/settings_image_detail_text_cell.mm b/ios/chrome/browser/ui/settings/cells/settings_image_detail_text_cell.mm
index 22e438c..e4e0c9f2 100644
--- a/ios/chrome/browser/ui/settings/cells/settings_image_detail_text_cell.mm
+++ b/ios/chrome/browser/ui/settings/cells/settings_image_detail_text_cell.mm
@@ -7,6 +7,7 @@
 #include "base/logging.h"
 #include "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
+#import "ios/chrome/common/ui_util/UIColor+cr_semantic_colors.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -52,15 +53,14 @@
   _textLabel.numberOfLines = 0;
   _textLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
   _textLabel.adjustsFontForContentSizeCategory = YES;
-  _textLabel.textColor = UIColor.blackColor;
+  _textLabel.textColor = UIColor.cr_labelColor;
 
   _detailTextLabel = [[UILabel alloc] init];
   _detailTextLabel.numberOfLines = 0;
   _detailTextLabel.font =
       [UIFont preferredFontForTextStyle:kTableViewSublabelFontStyle];
   _detailTextLabel.adjustsFontForContentSizeCategory = YES;
-  _detailTextLabel.textColor =
-      UIColorFromRGB(kTableViewSecondaryLabelLightGrayTextColor);
+  _detailTextLabel.textColor = UIColor.cr_secondaryLabelColor;
 }
 
 // Sets constraints on subviews.
diff --git a/ios/chrome/browser/ui/settings/cells/settings_switch_cell.mm b/ios/chrome/browser/ui/settings/cells/settings_switch_cell.mm
index 697ebf8..3fb91cb 100644
--- a/ios/chrome/browser/ui/settings/cells/settings_switch_cell.mm
+++ b/ios/chrome/browser/ui/settings/cells/settings_switch_cell.mm
@@ -7,6 +7,7 @@
 #import "ios/chrome/browser/ui/settings/cells/settings_cells_constants.h"
 #include "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
+#import "ios/chrome/common/ui_util/UIColor+cr_semantic_colors.h"
 #import "ios/chrome/common/ui_util/constraints_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
 #include "ui/base/l10n/l10n_util_mac.h"
@@ -64,7 +65,7 @@
     _textLabel.translatesAutoresizingMaskIntoConstraints = NO;
     _textLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
     _textLabel.adjustsFontForContentSizeCategory = YES;
-    _textLabel.textColor = [UIColor blackColor];
+    _textLabel.textColor = UIColor.cr_labelColor;
     _textLabel.numberOfLines = 0;
     [self.contentView addSubview:_textLabel];
 
@@ -73,8 +74,7 @@
     _detailTextLabel.font =
         [UIFont preferredFontForTextStyle:kTableViewSublabelFontStyle];
     _detailTextLabel.adjustsFontForContentSizeCategory = YES;
-    _detailTextLabel.textColor =
-        UIColorFromRGB(kTableViewSecondaryLabelLightGrayTextColor);
+    _detailTextLabel.textColor = UIColor.cr_secondaryLabelColor;
     _detailTextLabel.numberOfLines = 0;
     [self.contentView addSubview:_detailTextLabel];
 
@@ -166,9 +166,8 @@
 }
 
 + (UIColor*)defaultTextColorForState:(UIControlState)state {
-  return (state & UIControlStateDisabled)
-             ? UIColorFromRGB(kSettingsCellsDetailTextColor)
-             : [UIColor blackColor];
+  return (state & UIControlStateDisabled) ? UIColor.cr_secondaryLabelColor
+                                          : UIColor.cr_labelColor;
 }
 
 - (void)setIconImage:(UIImage*)image {
diff --git a/ios/chrome/browser/ui/settings/settings_root_table_view_controller.mm b/ios/chrome/browser/ui/settings/settings_root_table_view_controller.mm
index 4535dfa..df18314 100644
--- a/ios/chrome/browser/ui/settings/settings_root_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/settings_root_table_view_controller.mm
@@ -113,10 +113,10 @@
 
 - (void)viewDidLoad {
   if (base::FeatureList::IsEnabled(kSettingsRefresh)) {
-    self.styler.tableViewBackgroundColor = UIColor.whiteColor;
+    self.styler.tableViewBackgroundColor = UIColor.cr_systemBackgroundColor;
   } else {
     self.styler.tableViewBackgroundColor =
-        [UIColor groupTableViewBackgroundColor];
+        UIColor.cr_systemGroupedBackgroundColor;
   }
   self.styler.tableViewSectionHeaderBlurEffect = nil;
   [super viewDidLoad];
@@ -125,7 +125,7 @@
   }
   self.styler.cellBackgroundColor =
       UIColor.cr_secondarySystemGroupedBackgroundColor;
-  self.styler.cellTitleColor = [UIColor blackColor];
+  self.styler.cellTitleColor = UIColor.cr_labelColor;
   self.tableView.estimatedSectionHeaderHeight = kEstimatedHeaderFooterHeight;
   self.tableView.estimatedRowHeight = kSettingsCellDefaultHeight;
   self.tableView.estimatedSectionFooterHeight = kEstimatedHeaderFooterHeight;
diff --git a/ios/chrome/browser/ui/settings/settings_table_view_controller.mm b/ios/chrome/browser/ui/settings/settings_table_view_controller.mm
index a431d22..00eb0352 100644
--- a/ios/chrome/browser/ui/settings/settings_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/settings_table_view_controller.mm
@@ -69,6 +69,7 @@
 #include "ios/chrome/browser/ui/ui_feature_flags.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
 #include "ios/chrome/browser/voice/speech_input_locale_config.h"
+#import "ios/chrome/common/ui_util/UIColor+cr_semantic_colors.h"
 #include "ios/chrome/grit/ios_chromium_strings.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/public/provider/chrome/browser/chrome_browser_provider.h"
@@ -723,14 +724,13 @@
         LOG(ERROR) << "Save passwords cell was disabled as the password store"
                       " cannot be created.";
         [detailCell setUserInteractionEnabled:NO];
-        detailCell.textLabel.textColor =
-            UIColorFromRGB(kTableViewSecondaryLabelLightGrayTextColor);
+        detailCell.textLabel.textColor = UIColor.cr_secondaryLabelColor;
         return cell;
       }
     }
 
     [detailCell setUserInteractionEnabled:YES];
-    detailCell.textLabel.textColor = UIColor.blackColor;
+    detailCell.textLabel.textColor = UIColor.cr_labelColor;
   }
 
   switch (itemType) {
diff --git a/ios/chrome/browser/ui/table_view/cells/BUILD.gn b/ios/chrome/browser/ui/table_view/cells/BUILD.gn
index e64a21e..72b232199 100644
--- a/ios/chrome/browser/ui/table_view/cells/BUILD.gn
+++ b/ios/chrome/browser/ui/table_view/cells/BUILD.gn
@@ -58,6 +58,7 @@
     "//ios/chrome/common",
     "//ios/chrome/common/favicon",
     "//ios/chrome/common/ui_util",
+    "//ios/chrome/common/ui_util:semantic_colors",
     "//ios/third_party/material_components_ios:material_components_ios",
     "//net",
     "//ui/base",
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_detail_icon_item.mm b/ios/chrome/browser/ui/table_view/cells/table_view_detail_icon_item.mm
index 567709f..bb83e904 100644
--- a/ios/chrome/browser/ui/table_view/cells/table_view_detail_icon_item.mm
+++ b/ios/chrome/browser/ui/table_view/cells/table_view_detail_icon_item.mm
@@ -10,6 +10,7 @@
 #import "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h"
 #import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
+#import "ios/chrome/common/ui_util/UIColor+cr_semantic_colors.h"
 #import "ios/chrome/common/ui_util/constraints_ui_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -34,7 +35,7 @@
   self = [super initWithType:type];
   if (self) {
     self.cellClass = [TableViewDetailIconCell class];
-    _cellBackgroundColor = [UIColor whiteColor];
+    _cellBackgroundColor = UIColor.cr_secondarySystemGroupedBackgroundColor;
   }
   return self;
 }
@@ -103,8 +104,8 @@
     _textLabel.translatesAutoresizingMaskIntoConstraints = NO;
     _textLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
     _textLabel.adjustsFontForContentSizeCategory = YES;
-    _textLabel.textColor = [UIColor blackColor];
-    _textLabel.backgroundColor = [UIColor clearColor];
+    _textLabel.textColor = UIColor.cr_labelColor;
+    _textLabel.backgroundColor = UIColor.clearColor;
     [contentView addSubview:_textLabel];
 
     _detailTextLabel = [[UILabel alloc] init];
@@ -112,8 +113,8 @@
     _detailTextLabel.font =
         [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
     _detailTextLabel.adjustsFontForContentSizeCategory = YES;
-    _detailTextLabel.textColor = UIColorFromRGB(kSettingsCellsDetailTextColor);
-    _detailTextLabel.backgroundColor = [UIColor clearColor];
+    _detailTextLabel.textColor = UIColor.cr_secondaryLabelColor;
+    _detailTextLabel.backgroundColor = UIColor.clearColor;
     [contentView addSubview:_detailTextLabel];
 
     // Set up the constraints for when the icon is visible and hidden.  One of
diff --git a/ios/chrome/common/ui_util/UIColor+cr_semantic_colors.h b/ios/chrome/common/ui_util/UIColor+cr_semantic_colors.h
index 46c43e5a..544ca9c2a 100644
--- a/ios/chrome/common/ui_util/UIColor+cr_semantic_colors.h
+++ b/ios/chrome/common/ui_util/UIColor+cr_semantic_colors.h
@@ -12,9 +12,18 @@
 // to this file. Custom dynamic colors should go in ColorSets.
 @interface UIColor (CRSemanticColors)
 
+// System Background Color
+@property(class, nonatomic, readonly) UIColor* cr_systemBackgroundColor;
+
+// System Grouped Background Colors
+@property(class, nonatomic, readonly) UIColor* cr_systemGroupedBackgroundColor;
 @property(class, nonatomic, readonly)
     UIColor* cr_secondarySystemGroupedBackgroundColor;
 
+// Label Colors
+@property(class, nonatomic, readonly) UIColor* cr_labelColor;
+@property(class, nonatomic, readonly) UIColor* cr_secondaryLabelColor;
+
 @end
 
 #endif  // IOS_CHROME_COMMON_UI_UTIL_UICOLOR_CR_SEMANTIC_COLORS_H_
diff --git a/ios/chrome/common/ui_util/UIColor+cr_semantic_colors.mm b/ios/chrome/common/ui_util/UIColor+cr_semantic_colors.mm
index 4873198..5d020469 100644
--- a/ios/chrome/common/ui_util/UIColor+cr_semantic_colors.mm
+++ b/ios/chrome/common/ui_util/UIColor+cr_semantic_colors.mm
@@ -10,6 +10,28 @@
 
 @implementation UIColor (CRSemanticColors)
 
+#pragma mark - System Background Colors
+
++ (UIColor*)cr_systemBackgroundColor {
+#if defined(__IPHONE_13_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0)
+  if (@available(iOS 13, *)) {
+    return UIColor.systemBackgroundColor;
+  }
+#endif
+  return UIColor.whiteColor;
+}
+
+#pragma mark - System Grouped Background Colors
+
++ (UIColor*)cr_systemGroupedBackgroundColor {
+#if defined(__IPHONE_13_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0)
+  if (@available(iOS 13, *)) {
+    return UIColor.systemGroupedBackgroundColor;
+  }
+#endif
+  return UIColor.groupTableViewBackgroundColor;
+}
+
 + (UIColor*)cr_secondarySystemGroupedBackgroundColor {
 #if defined(__IPHONE_13_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0)
   if (@available(iOS 13, *)) {
@@ -19,4 +41,28 @@
   return UIColor.whiteColor;
 }
 
+#pragma mark - Label Colors
+
++ (UIColor*)cr_labelColor {
+#if defined(__IPHONE_13_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0)
+  if (@available(iOS 13, *)) {
+    return UIColor.labelColor;
+  }
+#endif
+  return UIColor.blackColor;
+}
+
++ (UIColor*)cr_secondaryLabelColor {
+#if defined(__IPHONE_13_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0)
+  if (@available(iOS 13, *)) {
+    return UIColor.secondaryLabelColor;
+  }
+#endif
+  // This is the value for UIColor.secondaryLabelColor in light mode.
+  return [UIColor colorWithRed:0x3C / (CGFloat)0xFF
+                         green:0x3C / (CGFloat)0xFF
+                          blue:0x43 / (CGFloat)0xFF
+                         alpha:0.6];
+}
+
 @end
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index 4d1d7328..5ab4fcb 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -1432,7 +1432,6 @@
   static dispatch_once_t onceToken;
   dispatch_once(&onceToken, ^{
     handlers = new std::map<std::string, SEL>();
-    (*handlers)["chrome.send"] = @selector(handleChromeSendMessage:context:);
     (*handlers)["window.error"] = @selector(handleWindowErrorMessage:context:);
   });
   DCHECK(handlers);
@@ -1552,41 +1551,6 @@
 // data relevant to the message, and |context| contains contextual information
 // about web view state needed for some handlers.
 
-// Handles 'chrome.send' message.
-- (BOOL)handleChromeSendMessage:(base::DictionaryValue*)message
-                        context:(NSDictionary*)context {
-  // Chrome message are only handled if sent from the main frame.
-  if (![context[kIsMainFrame] boolValue])
-    return NO;
-  if (self.webStateImpl->HasWebUI()) {
-    const GURL currentURL([self currentURL]);
-    if (web::GetWebClient()->IsAppSpecificURL(currentURL)) {
-      std::string messageContent;
-      base::ListValue* arguments = nullptr;
-      if (!message->GetString("message", &messageContent)) {
-        DLOG(WARNING) << "JS message parameter not found: message";
-        return NO;
-      }
-      if (!message->GetList("arguments", &arguments)) {
-        DLOG(WARNING) << "JS message parameter not found: arguments";
-        return NO;
-      }
-      // WebFrame messaging is not supported in WebUI (as window.isSecureContext
-      // is false. Pass nullptr as sender_frame.
-      self.webStateImpl->OnScriptCommandReceived(
-          messageContent, *message, currentURL, context[kUserIsInteractingKey],
-          [context[kIsMainFrame] boolValue], nullptr);
-      self.webStateImpl->ProcessWebUIMessage(currentURL, messageContent,
-                                             *arguments);
-      return YES;
-    }
-  }
-
-  DLOG(WARNING)
-      << "chrome.send message not handled because WebUI was not found.";
-  return NO;
-}
-
 // Handles 'window.error' message.
 - (BOOL)handleWindowErrorMessage:(base::DictionaryValue*)message
                          context:(NSDictionary*)context {
diff --git a/ios/web/web_state/web_state_impl.h b/ios/web/web_state/web_state_impl.h
index 0447bfa..b86978bf5 100644
--- a/ios/web/web_state/web_state_impl.h
+++ b/ios/web/web_state/web_state_impl.h
@@ -128,10 +128,6 @@
   void ClearWebUI();
   // Returns true if there is a WebUI active.
   bool HasWebUI();
-  // Processes a message from a WebUI displayed at the given URL.
-  void ProcessWebUIMessage(const GURL& source_url,
-                           const std::string& message,
-                           const base::ListValue& args);
 
   // Gets the HTTP response headers associated with the current page.
   // NOTE: For a WKWebView-based WebState, these headers are generated via
diff --git a/ios/web/web_state/web_state_impl.mm b/ios/web/web_state/web_state_impl.mm
index 1d03944..5df9a85 100644
--- a/ios/web/web_state/web_state_impl.mm
+++ b/ios/web/web_state/web_state_impl.mm
@@ -311,13 +311,6 @@
   return !!web_ui_;
 }
 
-void WebStateImpl::ProcessWebUIMessage(const GURL& source_url,
-                                       const std::string& message,
-                                       const base::ListValue& args) {
-  if (web_ui_)
-    web_ui_->ProcessWebUIIOSMessage(source_url, message, args);
-}
-
 const base::string16& WebStateImpl::GetTitle() const {
   // TODO(stuartmorgan): Implement the NavigationManager logic necessary to
   // match the WebContents implementation of this method.
diff --git a/ios/web/webui/web_ui_ios_impl.h b/ios/web/webui/web_ui_ios_impl.h
index 7e94d9ac..4a6dc54 100644
--- a/ios/web/webui/web_ui_ios_impl.h
+++ b/ios/web/webui/web_ui_ios_impl.h
@@ -12,10 +12,12 @@
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "base/values.h"
 #include "ios/web/public/webui/web_ui_ios.h"
 
 namespace web {
 class WebStateImpl;
+class WebFrame;
 }
 
 namespace web {
@@ -47,6 +49,12 @@
                                 const base::Value& response) override;
 
  private:
+  bool OnJsMessage(const base::DictionaryValue& message,
+                   const GURL& page_url,
+                   bool has_user_gesture,
+                   bool form_in_main_frame,
+                   web::WebFrame* sender_frame);
+
   // Executes JavaScript asynchronously on the page.
   void ExecuteJavascript(const base::string16& javascript);
 
diff --git a/ios/web/webui/web_ui_ios_impl.mm b/ios/web/webui/web_ui_ios_impl.mm
index 3c09a5fa..93bd38b 100644
--- a/ios/web/webui/web_ui_ios_impl.mm
+++ b/ios/web/webui/web_ui_ios_impl.mm
@@ -10,6 +10,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
+#import "ios/web/public/web_client.h"
 #include "ios/web/public/webui/web_ui_ios_controller.h"
 #include "ios/web/public/webui/web_ui_ios_controller_factory.h"
 #include "ios/web/public/webui/web_ui_ios_message_handler.h"
@@ -21,6 +22,10 @@
 
 using web::WebUIIOSController;
 
+namespace {
+const char kCommandPrefix[] = "webui";
+}
+
 namespace web {
 
 // static
@@ -42,9 +47,13 @@
 
 WebUIIOSImpl::WebUIIOSImpl(WebStateImpl* web_state) : web_state_(web_state) {
   DCHECK(web_state);
+  web_state->AddScriptCommandCallback(
+      base::BindRepeating(&WebUIIOSImpl::OnJsMessage, base::Unretained(this)),
+      kCommandPrefix);
 }
 
 WebUIIOSImpl::~WebUIIOSImpl() {
+  web_state_->RemoveScriptCommandCallback(kCommandPrefix);
   controller_.reset();
 }
 
@@ -94,6 +103,34 @@
   message_callbacks_.insert(std::make_pair(message, callback));
 }
 
+bool WebUIIOSImpl::OnJsMessage(const base::DictionaryValue& message,
+                               const GURL& page_url,
+                               bool has_user_gesture,
+                               bool form_in_main_frame,
+                               web::WebFrame* sender_frame) {
+  // Chrome message are only handled if sent from the main frame.
+  if (!sender_frame->IsMainFrame())
+    return false;
+
+  web::URLVerificationTrustLevel trust_level =
+      web::URLVerificationTrustLevel::kNone;
+  const GURL current_url = web_state_->GetCurrentURL(&trust_level);
+  if (web::GetWebClient()->IsAppSpecificURL(current_url)) {
+    std::string message_content;
+    const base::ListValue* arguments = nullptr;
+    if (!message.GetString("message", &message_content)) {
+      DLOG(WARNING) << "JS message parameter not found: message";
+      return false;
+    }
+    if (!message.GetList("arguments", &arguments)) {
+      DLOG(WARNING) << "JS message parameter not found: arguments";
+      return false;
+    }
+    ProcessWebUIIOSMessage(current_url, message_content, *arguments);
+  }
+  return true;
+}
+
 void WebUIIOSImpl::ProcessWebUIIOSMessage(const GURL& source_url,
                                           const std::string& message,
                                           const base::ListValue& args) {
diff --git a/media/gpu/vaapi/vaapi_jpeg_encode_accelerator.cc b/media/gpu/vaapi/vaapi_jpeg_encode_accelerator.cc
index 4ee6e5c..28be628 100644
--- a/media/gpu/vaapi/vaapi_jpeg_encode_accelerator.cc
+++ b/media/gpu/vaapi/vaapi_jpeg_encode_accelerator.cc
@@ -93,10 +93,13 @@
   base::RepeatingCallback<void(int32_t, size_t)> video_frame_ready_cb_;
   base::RepeatingCallback<void(int32_t, Status)> notify_error_cb_;
 
-  // The current VA surface used for encoding.
+  // The current VA surface ID used for encoding. Only used for Non-DMA-buf use
+  // case.
   VASurfaceID va_surface_id_;
   // The size of the surface associated with |va_surface_id_|.
-  gfx::Size surface_size_;
+  gfx::Size input_size_;
+  // The format used to create VAContext. Only used for DMA-buf use case.
+  uint32_t va_format_;
 
   SEQUENCE_CHECKER(sequence_checker_);
 
@@ -113,7 +116,9 @@
       gpu_memory_buffer_support_(new gpu::GpuMemoryBufferSupport()),
       video_frame_ready_cb_(std::move(video_frame_ready_cb)),
       notify_error_cb_(std::move(notify_error_cb)),
-      va_surface_id_(VA_INVALID_SURFACE) {
+      va_surface_id_(VA_INVALID_SURFACE),
+      input_size_(gfx::Size()),
+      va_format_(0) {
   DETACH_FROM_SEQUENCE(sequence_checker_);
 }
 
@@ -149,6 +154,22 @@
   // once we support other formats.
   DCHECK(num_planes_input == 2);
   gfx::BufferFormat buffer_format = gfx::BufferFormat::YUV_420_BIPLANAR;
+  uint32_t va_format = VaapiWrapper::BufferFormatToVARTFormat(buffer_format);
+  bool context_changed = input_size != input_size_ || va_format != va_format_;
+  if (context_changed) {
+    vaapi_wrapper_->DestroyContext();
+    const bool success = vaapi_wrapper_->CreateContext(va_format, input_size);
+    if (!success) {
+      VLOGF(1) << "Failed to create context";
+      vaapi_wrapper_->DestroyContext();
+      va_format_ = 0;
+      input_size_ = gfx::Size();
+      notify_error_cb_.Run(task_id, PLATFORM_FAILURE);
+      return;
+    }
+    va_format_ = va_format;
+    input_size_ = input_size;
+  }
 
   auto va_surface = vaapi_wrapper_->CreateVASurfaceForPixmap(
       base::WrapRefCounted(new gfx::NativePixmapDmaBuf(
@@ -159,21 +180,11 @@
     notify_error_cb_.Run(task_id, PLATFORM_FAILURE);
     return;
   }
-  va_surface_id_ = va_surface->id();
-  vaapi_wrapper_->DestroyContext();
-
-  const bool success = vaapi_wrapper_->CreateContext(
-      VaapiWrapper::BufferFormatToVARTFormat(buffer_format), input_size);
-  if (!success) {
-    VLOGF(1) << "Failed to create context";
-    notify_error_cb_.Run(task_id, PLATFORM_FAILURE);
-    return;
-  }
 
   // Create output buffer for encoding result.
   size_t max_coded_buffer_size =
       VaapiJpegEncoder::GetMaxCodedBufferSize(input_size);
-  if (max_coded_buffer_size > cached_output_buffer_size_) {
+  if (context_changed || max_coded_buffer_size > cached_output_buffer_size_) {
     vaapi_wrapper_->DestroyVABuffers();
     cached_output_buffer_size_ = 0;
 
@@ -206,7 +217,7 @@
   size_t exif_offset = 0;
 
   if (!jpeg_encoder_->Encode(input_size, exif_buffer_dummy.data(),
-                             exif_buffer_size, quality, va_surface_id_,
+                             exif_buffer_size, quality, va_surface->id(),
                              cached_output_buffer_id_, &exif_offset)) {
     VLOGF(1) << "Encode JPEG failed";
     notify_error_cb_.Run(task_id, PLATFORM_FAILURE);
@@ -246,7 +257,7 @@
   // use its area as the maximum bytes we need to download to avoid buffer
   // overflow.
   if (!vaapi_wrapper_->DownloadFromVABuffer(
-          cached_output_buffer_id_, va_surface_id_,
+          cached_output_buffer_id_, va_surface->id(),
           static_cast<uint8_t*>(output_memory),
           output_gmb_buffer->GetSize().GetArea(), &encoded_size)) {
     VLOGF(1) << "Failed to retrieve output image from VA coded buffer";
@@ -274,11 +285,13 @@
   gfx::Size input_size = request->video_frame->coded_size();
 
   // Recreate VASurface if the video frame's size changed.
-  if (input_size != surface_size_ || va_surface_id_ == VA_INVALID_SURFACE) {
+  bool context_changed =
+      input_size != input_size_ || va_surface_id_ == VA_INVALID_SURFACE;
+  if (context_changed) {
     vaapi_wrapper_->DestroyContextAndSurfaces(
         std::vector<VASurfaceID>({va_surface_id_}));
     va_surface_id_ = VA_INVALID_SURFACE;
-    surface_size_ = gfx::Size();
+    input_size_ = gfx::Size();
 
     std::vector<VASurfaceID> va_surfaces;
     if (!vaapi_wrapper_->CreateContextAndSurfaces(
@@ -288,7 +301,7 @@
       return;
     }
     va_surface_id_ = va_surfaces[0];
-    surface_size_ = input_size;
+    input_size_ = input_size;
   }
 
   if (!vaapi_wrapper_->UploadVideoFrameToSurface(*request->video_frame,
@@ -301,7 +314,7 @@
   // Create output buffer for encoding result.
   size_t max_coded_buffer_size =
       VaapiJpegEncoder::GetMaxCodedBufferSize(input_size);
-  if (max_coded_buffer_size > cached_output_buffer_size_) {
+  if (max_coded_buffer_size > cached_output_buffer_size_ || context_changed) {
     vaapi_wrapper_->DestroyVABuffers();
     cached_output_buffer_size_ = 0;
 
@@ -347,6 +360,7 @@
           request->output_shm->size(), &encoded_size)) {
     VLOGF(1) << "Failed to retrieve output image from VA coded buffer";
     notify_error_cb_.Run(task_id, PLATFORM_FAILURE);
+    return;
   }
 
   // Copy the real exif buffer into preserved space.
diff --git a/services/network/origin_policy/origin_policy_constants.h b/services/network/origin_policy/origin_policy_constants.h
index 1fe98db..c9f4600 100644
--- a/services/network/origin_policy/origin_policy_constants.h
+++ b/services/network/origin_policy/origin_policy_constants.h
@@ -10,6 +10,7 @@
 const char kOriginPolicyDeletePolicy[] = "0";
 const char kOriginPolicyReportTo[] = "report-to";
 const char kOriginPolicyPolicy[] = "policy";
+
 // Maximum policy size (implementation-defined limit in bytes).
 // (Limit copied from network::SimpleURLLoader::kMaxBoundedStringDownloadSize.)
 static const size_t kOriginPolicyMaxPolicySize = 1024 * 1024;
diff --git a/services/network/origin_policy/origin_policy_fetcher.cc b/services/network/origin_policy/origin_policy_fetcher.cc
index ea3e03e..d7fba35 100644
--- a/services/network/origin_policy/origin_policy_fetcher.cc
+++ b/services/network/origin_policy/origin_policy_fetcher.cc
@@ -8,11 +8,8 @@
 #include "base/strings/strcat.h"
 #include "net/base/load_flags.h"
 #include "net/http/http_util.h"
-#include "services/network/origin_policy/origin_policy_constants.h"
 #include "services/network/origin_policy/origin_policy_manager.h"
-#include "services/network/public/cpp/resource_response.h"
 #include "services/network/public/cpp/simple_url_loader.h"
-#include "services/network/public/mojom/url_loader_factory.mojom.h"
 
 namespace network {
 
@@ -89,7 +86,6 @@
     std::vector<std::string>* to_be_removed_headers) {
   if (IsValidRedirect(redirect_info)) {
     must_redirect_ = false;
-    // TODO(andypaicu): should we callback with the original url or the new url?
     fetch_url_ = redirect_info.new_url;
     return;
   }
@@ -147,20 +143,17 @@
 
 void OriginPolicyFetcher::WorkDone(std::unique_ptr<std::string> policy_content,
                                    mojom::OriginPolicyState state) {
-  if (callback_) {
-    auto result = mojom::OriginPolicy::New();
-    result->state = state;
-    if (policy_content) {
-      result->contents = mojom::OriginPolicyContents::New();
-      result->contents->raw_policy = *policy_content;
-    }
-    result->policy_url = fetch_url_;
-
-    std::move(callback_).Run(std::move(result));
+  auto result = mojom::OriginPolicy::New();
+  result->state = state;
+  if (policy_content) {
+    result->contents = mojom::OriginPolicyContents::New();
+    result->contents->raw_policy = *policy_content;
   }
+  result->policy_url = fetch_url_;
 
   // Do not add code after this call as it will destroy this object.
-  owner_policy_manager_->FetcherDone(this);
+  owner_policy_manager_->FetcherDone(this, std::move(result),
+                                     std::move(callback_));
 }
 
 bool OriginPolicyFetcher::IsValidRedirect(
diff --git a/services/network/origin_policy/origin_policy_fetcher.h b/services/network/origin_policy/origin_policy_fetcher.h
index 97ac857..87681a08 100644
--- a/services/network/origin_policy/origin_policy_fetcher.h
+++ b/services/network/origin_policy/origin_policy_fetcher.h
@@ -88,7 +88,7 @@
   mojom::OriginPolicyManager::RetrieveOriginPolicyCallback callback_;
 
   // Will be true if we started a fetch at <origin>/well-known/origin-policy
-  // which will redirect to the latest origin policy.
+  // which must redirect to the latest origin policy.
   bool must_redirect_;
 
   DISALLOW_COPY_AND_ASSIGN(OriginPolicyFetcher);
diff --git a/services/network/origin_policy/origin_policy_fetcher_unittest.cc b/services/network/origin_policy/origin_policy_fetcher_unittest.cc
index 042bfc3..8eed79c0 100644
--- a/services/network/origin_policy/origin_policy_fetcher_unittest.cc
+++ b/services/network/origin_policy/origin_policy_fetcher_unittest.cc
@@ -53,6 +53,13 @@
 
     manager_ = std::make_unique<OriginPolicyManager>(
         network_context_->CreateUrlLoaderFactoryForNetworkService());
+
+    test_server_.RegisterRequestHandler(base::BindRepeating(
+        &OriginPolicyFetcherTest::HandleResponse, base::Unretained(this)));
+
+    EXPECT_TRUE(test_server_.Start());
+
+    test_server_origin_ = url::Origin::Create(test_server_.base_url());
   }
 
   const url::Origin& test_server_origin() const { return test_server_origin_; }
@@ -64,16 +71,6 @@
   }
 
  protected:
-  // testing::Test implementation.
-  void SetUp() override {
-    test_server_.RegisterRequestHandler(base::BindRepeating(
-        &OriginPolicyFetcherTest::HandleResponse, base::Unretained(this)));
-
-    EXPECT_TRUE(test_server_.Start());
-
-    test_server_origin_ = url::Origin::Create(test_server_.base_url());
-  }
-
   const net::test_server::EmbeddedTestServer& test_server() const {
     return test_server_;
   }
diff --git a/services/network/origin_policy/origin_policy_manager.cc b/services/network/origin_policy/origin_policy_manager.cc
index ec19690..17f7662 100644
--- a/services/network/origin_policy/origin_policy_manager.cc
+++ b/services/network/origin_policy/origin_policy_manager.cc
@@ -7,9 +7,18 @@
 #include <memory>
 #include <utility>
 
+#include "base/logging.h"
 #include "base/optional.h"
 #include "net/http/http_util.h"
-#include "services/network/origin_policy/origin_policy_constants.h"
+#include "services/network/origin_policy/origin_policy_fetcher.h"
+
+namespace {
+
+// Marker for (temporarily) exempted origins. The presence of the "?" guarantees
+// that this is not a valid policy as it is not a valid http token.
+const char kExemptedOriginPolicyVersion[] = "exception?";
+
+}  // namespace
 
 namespace network {
 
@@ -28,47 +37,82 @@
     const url::Origin& origin,
     const std::string& header_value,
     RetrieveOriginPolicyCallback callback) {
+  DCHECK(origin.GetURL().is_valid());
+  DCHECK(!origin.opaque());
+
   OriginPolicyHeaderValues header_info =
       GetRequestedPolicyAndReportGroupFromHeaderString(header_value);
-  if (header_info.policy_version.empty()) {
-    if (callback) {
-      auto result = mojom::OriginPolicy::New();
-      result->state = mojom::OriginPolicyState::kCannotLoadPolicy;
-      std::move(callback).Run(std::move(result));
-    }
+
+  auto iter = latest_version_map_.find(origin);
+
+  // Process policy deletion first!
+  if (header_info.policy_version == kOriginPolicyDeletePolicy) {
+    if (iter != latest_version_map_.end())
+      latest_version_map_.erase(iter);
+    InvokeCallbackWithPolicyState(origin,
+                                  mojom::OriginPolicyState::kNoPolicyApplies,
+                                  std::move(callback));
     return;
   }
 
-  // Here we might check the cache and only then start the fetch.
-  StartPolicyFetch(origin, header_info, std::move(callback));
+  // Process policy exceptions.
+  if (iter != latest_version_map_.end() &&
+      iter->second == kExemptedOriginPolicyVersion) {
+    InvokeCallbackWithPolicyState(origin,
+                                  mojom::OriginPolicyState::kNoPolicyApplies,
+                                  std::move(callback));
+    return;
+  }
+
+  // No policy applies to this request or invalid header present.
+  if (header_info.policy_version.empty()) {
+    // If there header has no policy version is present, use cached version, if
+    // there is one. Otherwise, fail.
+    if (iter == latest_version_map_.end()) {
+      InvokeCallbackWithPolicyState(
+          origin,
+          header_value.empty() ? mojom::OriginPolicyState::kNoPolicyApplies
+                               : mojom::OriginPolicyState::kCannotLoadPolicy,
+          std::move(callback));
+      return;
+    }
+    header_info.policy_version = iter->second;
+  } else if (iter == latest_version_map_.end()) {
+    latest_version_map_.emplace(origin, header_info.policy_version);
+  } else {
+    iter->second = header_info.policy_version;
+  }
+
+  origin_policy_fetchers_.emplace(std::make_unique<OriginPolicyFetcher>(
+      this, header_info.policy_version, header_info.report_to, origin,
+      url_loader_factory_.get(), std::move(callback)));
+}
+
+void OriginPolicyManager::AddExceptionFor(const url::Origin& origin) {
+  latest_version_map_[origin] = kExemptedOriginPolicyVersion;
+}
+
+void OriginPolicyManager::FetcherDone(OriginPolicyFetcher* fetcher,
+                                      mojom::OriginPolicyPtr origin_policy,
+                                      RetrieveOriginPolicyCallback callback) {
+  std::move(callback).Run(std::move(origin_policy));
+
+  auto it = origin_policy_fetchers_.find(fetcher);
+  DCHECK(it != origin_policy_fetchers_.end());
+  origin_policy_fetchers_.erase(it);
 }
 
 void OriginPolicyManager::RetrieveDefaultOriginPolicy(
     const url::Origin& origin,
     RetrieveOriginPolicyCallback callback) {
-  // Here we might check the cache and only then start the fetch.
-  StartPolicyFetch(origin, OriginPolicyHeaderValues(), std::move(callback));
+  origin_policy_fetchers_.emplace(std::make_unique<OriginPolicyFetcher>(
+      this, std::string() /* report_to */, origin, url_loader_factory_.get(),
+      std::move(callback)));
 }
 
-void OriginPolicyManager::StartPolicyFetch(
-    const url::Origin& origin,
-    const OriginPolicyHeaderValues& header_info,
-    RetrieveOriginPolicyCallback callback) {
-  if (header_info.policy_version.empty()) {
-    origin_policy_fetchers_.emplace(std::make_unique<OriginPolicyFetcher>(
-        this, header_info.report_to, origin, url_loader_factory_.get(),
-        std::move(callback)));
-  } else {
-    origin_policy_fetchers_.emplace(std::make_unique<OriginPolicyFetcher>(
-        this, header_info.policy_version, header_info.report_to, origin,
-        url_loader_factory_.get(), std::move(callback)));
-  }
-}
-
-void OriginPolicyManager::FetcherDone(OriginPolicyFetcher* fetcher) {
-  auto it = origin_policy_fetchers_.find(fetcher);
-  DCHECK(it != origin_policy_fetchers_.end());
-  origin_policy_fetchers_.erase(it);
+// static
+const char* OriginPolicyManager::GetExemptedVersionForTesting() {
+  return kExemptedOriginPolicyVersion;
 }
 
 // static
@@ -102,4 +146,15 @@
   return OriginPolicyHeaderValues({policy.value(), report_to.value_or("")});
 }
 
+// static
+void OriginPolicyManager::InvokeCallbackWithPolicyState(
+    const url::Origin& origin,
+    mojom::OriginPolicyState state,
+    RetrieveOriginPolicyCallback callback) {
+  mojom::OriginPolicyPtr result = mojom::OriginPolicy::New();
+  result->state = state;
+  result->policy_url = OriginPolicyFetcher::GetDefaultPolicyURL(origin);
+  std::move(callback).Run(std::move(result));
+}
+
 }  // namespace network
diff --git a/services/network/origin_policy/origin_policy_manager.h b/services/network/origin_policy/origin_policy_manager.h
index 7b352ce..950d29d1 100644
--- a/services/network/origin_policy/origin_policy_manager.h
+++ b/services/network/origin_policy/origin_policy_manager.h
@@ -5,6 +5,7 @@
 #ifndef SERVICES_NETWORK_ORIGIN_POLICY_ORIGIN_POLICY_MANAGER_H_
 #define SERVICES_NETWORK_ORIGIN_POLICY_ORIGIN_POLICY_MANAGER_H_
 
+#include <map>
 #include <memory>
 #include <set>
 #include <string>
@@ -13,12 +14,14 @@
 #include "base/containers/unique_ptr_adapters.h"
 #include "base/macros.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
-#include "services/network/origin_policy/origin_policy_fetcher.h"
+#include "services/network/origin_policy/origin_policy_constants.h"
 #include "services/network/public/mojom/origin_policy_manager.mojom.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
 
 namespace network {
 
+class OriginPolicyFetcher;
+
 // The OriginPolicyManager is the entry point for all Origin Policy related
 // API calls. Spec: https://wicg.github.io/origin-policy/
 // A client will likely call AddBinding (or use the NetworkContext function)
@@ -44,14 +47,17 @@
   // coming through the associated pipe will be served by this object.
   void AddBinding(mojom::OriginPolicyManagerRequest request);
 
-  // mojom::OriginPolicy
+  // mojom::OriginPolicyManager
   void RetrieveOriginPolicy(const url::Origin& origin,
                             const std::string& header_value,
                             RetrieveOriginPolicyCallback callback) override;
+  void AddExceptionFor(const url::Origin& origin) override;
 
   // To be called by fetcher when it has finished its work.
   // This removes the fetcher which results in the fetcher being destroyed.
-  void FetcherDone(OriginPolicyFetcher* fetcher);
+  void FetcherDone(OriginPolicyFetcher* fetcher,
+                   mojom::OriginPolicyPtr origin_policy,
+                   RetrieveOriginPolicyCallback callback);
 
   // Retrieves an origin's default origin policy by attempting to fetch it
   // from "<origin>/.well-known/origin-policy".
@@ -69,17 +75,28 @@
     return GetRequestedPolicyAndReportGroupFromHeaderString(header_value);
   }
 
+  // Get the version used for exempted policies. For testing purposes only.
+  static const char* GetExemptedVersionForTesting();
+
  private:
+  using KnownVersionMap = std::map<url::Origin, std::string>;
+
   // Parses a header and returns the result. If a parsed result does not contain
   // a non-empty policy version it means the `header_value` is invalid.
   static OriginPolicyHeaderValues
   GetRequestedPolicyAndReportGroupFromHeaderString(
       const std::string& header_value);
 
-  // Will start a fetch based on the provided origin and info.
-  void StartPolicyFetch(const url::Origin& origin,
-                        const OriginPolicyHeaderValues& header_info,
-                        RetrieveOriginPolicyCallback callback);
+  // Returns an origin policy with the specified state. The contents is empty
+  // and the `policy_url` is the default policy url for the specified origin.
+  static void InvokeCallbackWithPolicyState(
+      const url::Origin& origin,
+      mojom::OriginPolicyState state,
+      RetrieveOriginPolicyCallback callback);
+
+  // In memory cache of current policy version per origin.
+  // TODO(andypaicu): clear this when the disk cache is cleaned.
+  KnownVersionMap latest_version_map_;
 
   // A list of fetchers owned by this object
   std::set<std::unique_ptr<OriginPolicyFetcher>, base::UniquePtrComparator>
diff --git a/services/network/origin_policy/origin_policy_manager_unittest.cc b/services/network/origin_policy/origin_policy_manager_unittest.cc
index 1a04b27..0848a63 100644
--- a/services/network/origin_policy/origin_policy_manager_unittest.cc
+++ b/services/network/origin_policy/origin_policy_manager_unittest.cc
@@ -5,13 +5,16 @@
 #include <memory>
 #include <utility>
 
+#include "base/strings/strcat.h"
 #include "base/test/scoped_task_environment.h"
 #include "net/http/http_status_code.h"
+#include "net/http/http_util.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/embedded_test_server/http_request.h"
 #include "net/test/embedded_test_server/http_response.h"
 #include "services/network/network_context.h"
 #include "services/network/network_service.h"
+#include "services/network/origin_policy/origin_policy_fetcher.h"
 #include "services/network/origin_policy/origin_policy_manager.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -41,9 +44,26 @@
         std::move(context_params));
     manager_ = std::make_unique<OriginPolicyManager>(
         network_context_->CreateUrlLoaderFactoryForNetworkService());
+
+    test_server_.RegisterRequestHandler(base::BindRepeating(
+        &OriginPolicyManagerTest::HandleResponse, base::Unretained(this)));
+
+    EXPECT_TRUE(test_server_.Start());
+
+    test_server_origin_ = url::Origin::Create(test_server_.base_url());
+
+    test_server_2_.RegisterRequestHandler(base::BindRepeating(
+        &OriginPolicyManagerTest::HandleResponse, base::Unretained(this)));
+
+    EXPECT_TRUE(test_server_2_.Start());
+
+    test_server_origin_2_ = url::Origin::Create(test_server_2_.base_url());
   }
 
   const url::Origin& test_server_origin() const { return test_server_origin_; }
+  const url::Origin& test_server_origin_2() const {
+    return test_server_origin_2_;
+  }
 
   OriginPolicyManager* manager() { return manager_.get(); }
 
@@ -52,23 +72,17 @@
   void WaitUntilResponseHandled() { response_run_loop.Run(); }
 
  protected:
-  // testing::Test implementation.
-  void SetUp() override {
-    test_server_.RegisterRequestHandler(base::BindRepeating(
-        &OriginPolicyManagerTest::HandleResponse, base::Unretained(this)));
-
-    EXPECT_TRUE(test_server_.Start());
-
-    test_server_origin_ = url::Origin::Create(test_server_.base_url());
-  }
-
   std::unique_ptr<net::test_server::HttpResponse> HandleResponse(
       const net::test_server::HttpRequest& request) {
     response_run_loop.Quit();
     std::unique_ptr<net::test_server::BasicHttpResponse> response =
         std::make_unique<net::test_server::BasicHttpResponse>();
 
-    if (request.relative_url == "/.well-known/origin-policy/policy-1") {
+    if (request.relative_url == "/.well-known/origin-policy") {
+      response->set_code(net::HTTP_FOUND);
+      response->AddCustomHeader("Location",
+                                "/.well-known/origin-policy/policy-1");
+    } else if (request.relative_url == "/.well-known/origin-policy/policy-1") {
       response->set_code(net::HTTP_OK);
       response->set_content("manifest-1");
     } else if (request.relative_url == "/.well-known/origin-policy/policy-2") {
@@ -99,9 +113,11 @@
   std::unique_ptr<NetworkContext> network_context_;
   mojom::NetworkContextPtr network_context_ptr_;
   std::unique_ptr<OriginPolicyManager> manager_;
-  net::test_server::EmbeddedTestServer test_server_;
-  url::Origin test_server_origin_;
   base::RunLoop response_run_loop;
+  net::test_server::EmbeddedTestServer test_server_;
+  net::test_server::EmbeddedTestServer test_server_2_;
+  url::Origin test_server_origin_;
+  url::Origin test_server_origin_2_;
 
   DISALLOW_COPY_AND_ASSIGN(OriginPolicyManagerTest);
 };
@@ -119,8 +135,10 @@
 }
 
 TEST_F(OriginPolicyManagerTest, ParseHeaders) {
+  const std::string kExemptedOriginPolicyVersion =
+      OriginPolicyManager::GetExemptedVersionForTesting();
   const struct {
-    const char* header;
+    const std::string header;
     const char* expected_policy_version;
     const char* expected_report_to;
   } kTests[] = {
@@ -196,6 +214,13 @@
       {"policy=, policy=p2, report-to=r1", "", ""},
       {"policy=, policy=, report-to=r1", "", ""},
       {"policy=p1, report-to=r1, report-to=r2", "", ""},
+
+      // kExemptedOriginPolicyVersion is not a valid version
+      {base::StrCat({"policy=", kExemptedOriginPolicyVersion}), "", ""},
+      {base::StrCat({"report-to=r, policy=", kExemptedOriginPolicyVersion}), "",
+       ""},
+      {base::StrCat({"policy=", kExemptedOriginPolicyVersion, ", report-to=r"}),
+       "", ""},
   };
   for (const auto& test : kTests) {
     SCOPED_TRACE(test.header);
@@ -204,17 +229,21 @@
     EXPECT_EQ(test.expected_policy_version, result.policy_version);
     EXPECT_EQ(test.expected_report_to, result.report_to);
   }
+
+  EXPECT_FALSE(net::HttpUtil::IsToken(kExemptedOriginPolicyVersion));
 }
 
 // Helper class for starting saving a retrieved policy result
 class TestOriginPolicyManagerResult {
  public:
-  TestOriginPolicyManagerResult() {}
+  TestOriginPolicyManagerResult(OriginPolicyManagerTest* fixture,
+                                OriginPolicyManager* manager = nullptr)
+      : fixture_(fixture), manager_(manager ? manager : fixture->manager()) {}
 
   void RetrieveOriginPolicy(const std::string& header_value,
-                            OriginPolicyManagerTest* fixture) {
-    fixture->manager()->RetrieveOriginPolicy(
-        fixture->test_server_origin(), header_value,
+                            const url::Origin* origin = nullptr) {
+    manager_->RetrieveOriginPolicy(
+        origin ? *origin : fixture_->test_server_origin(), header_value,
         base::BindOnce(&TestOriginPolicyManagerResult::Callback,
                        base::Unretained(this)));
     run_loop_.Run();
@@ -231,6 +260,8 @@
   }
 
   base::RunLoop run_loop_;
+  OriginPolicyManagerTest* fixture_;
+  OriginPolicyManager* manager_;
   mojom::OriginPolicyPtr origin_policy_result_;
 
   DISALLOW_COPY_AND_ASSIGN(TestOriginPolicyManagerResult);
@@ -249,7 +280,7 @@
       {"policy=policy-2, report-to=endpoint", mojom::OriginPolicyState::kLoaded,
        "manifest-2"},
 
-      {"", mojom::OriginPolicyState::kCannotLoadPolicy, ""},
+      {"", mojom::OriginPolicyState::kNoPolicyApplies, ""},
       {"unknown=keyword", mojom::OriginPolicyState::kCannotLoadPolicy, ""},
       {"report_to=endpoint", mojom::OriginPolicyState::kCannotLoadPolicy, ""},
       {"policy=policy/policy-3", mojom::OriginPolicyState::kCannotLoadPolicy,
@@ -266,8 +297,11 @@
   for (const auto& test : kTests) {
     SCOPED_TRACE(test.header);
 
-    TestOriginPolicyManagerResult tester;
-    tester.RetrieveOriginPolicy(test.header, this);
+    OriginPolicyManager manager(
+        network_context()->CreateUrlLoaderFactoryForNetworkService());
+
+    TestOriginPolicyManagerResult tester(this, &manager);
+    tester.RetrieveOriginPolicy(test.header);
     EXPECT_EQ(test.expected_state, tester.origin_policy_result()->state);
     if (test.expected_raw_policy.empty()) {
       EXPECT_FALSE(tester.origin_policy_result()->contents);
@@ -302,4 +336,92 @@
   // the test has passed.
 }
 
+TEST_F(OriginPolicyManagerTest, CacheStatesAfterPolicyFetches) {
+  const struct {
+    std::string header;
+    mojom::OriginPolicyState expected_state;
+    std::string expected_raw_policy;
+    const url::Origin& origin;
+  } kTests[] = {
+      // The order of these tests is important as the cache is not cleared in
+      // between tests and some tests rely on the state left over by previous
+      // tests.
+
+      // Nothing in the cache, no policy applies if header unspecified.
+      {"", mojom::OriginPolicyState::kNoPolicyApplies, "",
+       test_server_origin()},
+
+      // An invalid header and nothing in the cache means an error.
+      {"invalid", mojom::OriginPolicyState::kCannotLoadPolicy, "",
+       test_server_origin()},
+
+      // A valid header results in loaded policy.
+      {"policy=policy-1", mojom::OriginPolicyState::kLoaded, "manifest-1",
+       test_server_origin()},
+
+      // With a valid header, we use that version if header unspecified.
+      {"", mojom::OriginPolicyState::kLoaded, "manifest-1",
+       test_server_origin()},
+
+      // A second valid header results in loaded policy. Changes cached last
+      // version.
+      {"policy=policy-2", mojom::OriginPolicyState::kLoaded, "manifest-2",
+       test_server_origin()},
+
+      // The latest version is correctly uses when header is unspecified.
+      {"", mojom::OriginPolicyState::kLoaded, "manifest-2",
+       test_server_origin()},
+
+      // Same as above for invalid header.
+      {"invalid", mojom::OriginPolicyState::kLoaded, "manifest-2",
+       test_server_origin()},
+
+      // Delete the policy.
+      {base::StrCat({"policy=", kOriginPolicyDeletePolicy}),
+       mojom::OriginPolicyState::kNoPolicyApplies, "", test_server_origin()},
+
+      // We are the back to the initial status quo, no policy applies if header
+      // unspecified.
+      {"", mojom::OriginPolicyState::kNoPolicyApplies, "",
+       test_server_origin()},
+
+      // Load a new policy to have something in the cache.
+      {"policy=policy-1", mojom::OriginPolicyState::kLoaded, "manifest-1",
+       test_server_origin()},
+
+      // Check that the version in the cache is used.
+      {"", mojom::OriginPolicyState::kLoaded, "manifest-1",
+       test_server_origin()},
+
+      // In a different origin, it should not pick up the initial origin's
+      // cached version.
+      {"", mojom::OriginPolicyState::kNoPolicyApplies, "",
+       test_server_origin_2()},
+
+      // Load a new policy to have something in the cache for the second origin.
+      {"policy=policy-2", mojom::OriginPolicyState::kLoaded, "manifest-2",
+       test_server_origin_2()},
+
+      // Check that the version in the cache is used for the second origin.
+      {"", mojom::OriginPolicyState::kLoaded, "manifest-2",
+       test_server_origin_2()},
+
+      // The initial origins cached state is unaffected.
+      {"", mojom::OriginPolicyState::kLoaded, "manifest-1",
+       test_server_origin()},
+  };
+
+  for (const auto& test : kTests) {
+    TestOriginPolicyManagerResult tester(this);
+    tester.RetrieveOriginPolicy(test.header, &test.origin);
+    EXPECT_EQ(test.expected_state, tester.origin_policy_result()->state);
+    if (test.expected_raw_policy.empty()) {
+      EXPECT_FALSE(tester.origin_policy_result()->contents);
+    } else {
+      EXPECT_EQ(test.expected_raw_policy,
+                tester.origin_policy_result()->contents->raw_policy);
+    }
+  }
+}
+
 }  // namespace network
diff --git a/services/network/public/mojom/origin_policy_manager.mojom b/services/network/public/mojom/origin_policy_manager.mojom
index 94e8e6a..5785a8f4 100644
--- a/services/network/public/mojom/origin_policy_manager.mojom
+++ b/services/network/public/mojom/origin_policy_manager.mojom
@@ -81,7 +81,14 @@
 interface OriginPolicyManager {
   // Attempts to retrieve the origin policy for an origin and
   // `Sec-Origin-Policy` HTTP header value. Calls back with the result.
+  // The header_value needs to contain a proper policy version or be empty. An
+  // invalid header_value will result in a returned empty policy with the state
+  // of `kCannotLoadPolicy`.
   // https://wicg.github.io/origin-policy/#origin-policy-header
   RetrieveOriginPolicy(url.mojom.Origin origin, string header_value)
       => (OriginPolicy origin_policy);
+
+  // Adds an exception for the specified origin. This means that no policy will
+  // apply for the specified origin from this point forward.
+  AddExceptionFor(url.mojom.Origin origin);
 };
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index 6ddba42a..15355dc 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -7868,11 +7868,12 @@
           "containment_type": "AUTO",
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.3.3",
-              "os": "Ubuntu",
+              "gpu": "8086:5912-19.0.2",
+              "os": "Ubuntu-19.04",
               "pool": "Chrome-GPU"
             }
-          ]
+          ],
+          "expiration": 21600
         },
         "test": "angle_unittests"
       },
@@ -7890,11 +7891,12 @@
           "containment_type": "AUTO",
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.3.3",
-              "os": "Ubuntu",
+              "gpu": "8086:5912-19.0.2",
+              "os": "Ubuntu-19.04",
               "pool": "Chrome-GPU"
             }
-          ]
+          ],
+          "expiration": 21600
         },
         "test": "gl_tests"
       },
@@ -7912,11 +7914,12 @@
           "containment_type": "AUTO",
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.3.3",
-              "os": "Ubuntu",
+              "gpu": "8086:5912-19.0.2",
+              "os": "Ubuntu-19.04",
               "pool": "Chrome-GPU"
             }
-          ]
+          ],
+          "expiration": 21600
         },
         "test": "gl_unittests"
       },
@@ -7933,11 +7936,12 @@
           "containment_type": "AUTO",
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.3.3",
-              "os": "Ubuntu",
+              "gpu": "8086:5912-19.0.2",
+              "os": "Ubuntu-19.04",
               "pool": "Chrome-GPU"
             }
-          ]
+          ],
+          "expiration": 21600
         },
         "test": "gles2_conform_test"
       },
@@ -7951,11 +7955,12 @@
           "containment_type": "AUTO",
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.3.3",
-              "os": "Ubuntu",
+              "gpu": "8086:5912-19.0.2",
+              "os": "Ubuntu-19.04",
               "pool": "Chrome-GPU"
             }
-          ]
+          ],
+          "expiration": 21600
         },
         "test": "swiftshader_unittests"
       }
@@ -7982,11 +7987,12 @@
           "containment_type": "AUTO",
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.3.3",
-              "os": "Ubuntu",
+              "gpu": "8086:5912-19.0.2",
+              "os": "Ubuntu-19.04",
               "pool": "Chrome-GPU"
             }
           ],
+          "expiration": 21600,
           "idempotent": false
         }
       },
@@ -8011,11 +8017,12 @@
           "containment_type": "AUTO",
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.3.3",
-              "os": "Ubuntu",
+              "gpu": "8086:5912-19.0.2",
+              "os": "Ubuntu-19.04",
               "pool": "Chrome-GPU"
             }
           ],
+          "expiration": 21600,
           "idempotent": false
         }
       },
@@ -8040,11 +8047,12 @@
           "containment_type": "AUTO",
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.3.3",
-              "os": "Ubuntu",
+              "gpu": "8086:5912-19.0.2",
+              "os": "Ubuntu-19.04",
               "pool": "Chrome-GPU"
             }
           ],
+          "expiration": 21600,
           "idempotent": false
         }
       },
@@ -8069,11 +8077,12 @@
           "containment_type": "AUTO",
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.3.3",
-              "os": "Ubuntu",
+              "gpu": "8086:5912-19.0.2",
+              "os": "Ubuntu-19.04",
               "pool": "Chrome-GPU"
             }
           ],
+          "expiration": 21600,
           "idempotent": false
         }
       },
@@ -8102,11 +8111,12 @@
           "containment_type": "AUTO",
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.3.3",
-              "os": "Ubuntu",
+              "gpu": "8086:5912-19.0.2",
+              "os": "Ubuntu-19.04",
               "pool": "Chrome-GPU"
             }
           ],
+          "expiration": 21600,
           "idempotent": false
         }
       },
@@ -8138,11 +8148,12 @@
           "containment_type": "AUTO",
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.3.3",
-              "os": "Ubuntu",
+              "gpu": "8086:5912-19.0.2",
+              "os": "Ubuntu-19.04",
               "pool": "Chrome-GPU"
             }
           ],
+          "expiration": 21600,
           "idempotent": false
         }
       },
@@ -8190,11 +8201,12 @@
           "containment_type": "AUTO",
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.3.3",
-              "os": "Ubuntu",
+              "gpu": "8086:5912-19.0.2",
+              "os": "Ubuntu-19.04",
               "pool": "Chrome-GPU"
             }
           ],
+          "expiration": 21600,
           "idempotent": false,
           "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com"
         }
@@ -8235,11 +8247,12 @@
           "containment_type": "AUTO",
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.3.3",
-              "os": "Ubuntu",
+              "gpu": "8086:5912-19.0.2",
+              "os": "Ubuntu-19.04",
               "pool": "Chrome-GPU"
             }
           ],
+          "expiration": 21600,
           "idempotent": false
         }
       },
@@ -8265,11 +8278,12 @@
           "containment_type": "AUTO",
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.3.3",
-              "os": "Ubuntu",
+              "gpu": "8086:5912-19.0.2",
+              "os": "Ubuntu-19.04",
               "pool": "Chrome-GPU"
             }
           ],
+          "expiration": 21600,
           "idempotent": false
         }
       },
@@ -8294,11 +8308,12 @@
           "containment_type": "AUTO",
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.3.3",
-              "os": "Ubuntu",
+              "gpu": "8086:5912-19.0.2",
+              "os": "Ubuntu-19.04",
               "pool": "Chrome-GPU"
             }
           ],
+          "expiration": 21600,
           "idempotent": false
         }
       },
@@ -8325,11 +8340,12 @@
           "containment_type": "AUTO",
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.3.3",
-              "os": "Ubuntu",
+              "gpu": "8086:5912-19.0.2",
+              "os": "Ubuntu-19.04",
               "pool": "Chrome-GPU"
             }
           ],
+          "expiration": 21600,
           "idempotent": false,
           "shards": 20
         }
@@ -8355,11 +8371,12 @@
           "containment_type": "AUTO",
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.3.3",
-              "os": "Ubuntu",
+              "gpu": "8086:5912-19.0.2",
+              "os": "Ubuntu-19.04",
               "pool": "Chrome-GPU"
             }
           ],
+          "expiration": 21600,
           "idempotent": false,
           "shards": 2
         }
@@ -8385,11 +8402,12 @@
           "containment_type": "AUTO",
           "dimension_sets": [
             {
-              "gpu": "8086:5912-18.3.3",
-              "os": "Ubuntu",
+              "gpu": "8086:5912-19.0.2",
+              "os": "Ubuntu-19.04",
               "pool": "Chrome-GPU"
             }
           ],
+          "expiration": 21600,
           "idempotent": false,
           "shards": 2
         }
diff --git a/testing/buildbot/filters/fuchsia.services_unittests.filter b/testing/buildbot/filters/fuchsia.services_unittests.filter
index b496cdb..1331705 100644
--- a/testing/buildbot/filters/fuchsia.services_unittests.filter
+++ b/testing/buildbot/filters/fuchsia.services_unittests.filter
@@ -23,3 +23,6 @@
 
 # https://crbug.com/925653 - Unexpected address-in-use.
 -TCPBoundSocketTest.ListenError
+
+# https://crbug.com/976319 - Flakily times-out due to virtualization overhead.
+-SimpleURLLoaderTest.OnUploadProgressCallback/*
diff --git a/testing/buildbot/mixins.pyl b/testing/buildbot/mixins.pyl
index 5986eeec..7e372a7 100644
--- a/testing/buildbot/mixins.pyl
+++ b/testing/buildbot/mixins.pyl
@@ -282,8 +282,8 @@
     # Similar to stable, but with a newer Mesa version.
     'swarming': {
       'dimensions': {
-        'gpu': '8086:5912-18.3.3',
-        'os': 'Ubuntu',
+        'gpu': '8086:5912-19.0.2',
+        'os': 'Ubuntu-19.04',
         'pool': 'Chrome-GPU',
       },
     },
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 88acad7a2..013d08f 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -2605,6 +2605,7 @@
         'os_type': 'linux',
         'browser_config': 'release',
         'mixins': [
+          'limited_capacity_bot',
           'linux_intel_hd_630_experimental',
         ],
         'test_suites': {
diff --git a/third_party/blink/public/mojom/BUILD.gn b/third_party/blink/public/mojom/BUILD.gn
index 12570ff..a7c3724 100644
--- a/third_party/blink/public/mojom/BUILD.gn
+++ b/third_party/blink/public/mojom/BUILD.gn
@@ -76,6 +76,7 @@
     "native_file_system/native_file_system_directory_handle.mojom",
     "native_file_system/native_file_system_error.mojom",
     "native_file_system/native_file_system_file_handle.mojom",
+    "native_file_system/native_file_system_file_writer.mojom",
     "native_file_system/native_file_system_manager.mojom",
     "native_file_system/native_file_system_transfer_token.mojom",
     "net/ip_address_space.mojom",
diff --git a/third_party/blink/public/mojom/native_file_system/native_file_system_file_handle.mojom b/third_party/blink/public/mojom/native_file_system/native_file_system_file_handle.mojom
index e08476a0..e7e78ac2 100644
--- a/third_party/blink/public/mojom/native_file_system/native_file_system_file_handle.mojom
+++ b/third_party/blink/public/mojom/native_file_system/native_file_system_file_handle.mojom
@@ -7,6 +7,7 @@
 import "third_party/blink/public/mojom/blob/blob.mojom";
 import "third_party/blink/public/mojom/blob/serialized_blob.mojom";
 import "third_party/blink/public/mojom/native_file_system/native_file_system_error.mojom";
+import "third_party/blink/public/mojom/native_file_system/native_file_system_file_writer.mojom";
 import "third_party/blink/public/mojom/native_file_system/native_file_system_transfer_token.mojom";
 import "third_party/blink/public/mojom/permissions/permission_status.mojom";
 
@@ -24,6 +25,7 @@
   AsBlob() => (NativeFileSystemError result, SerializedBlob? blob);
 
   // Deletes this file.
+  // TODO(oyiptong): Remove this method. It isn't part of the spec anymore.
   Remove() => (NativeFileSystemError result);
 
   // Write data from |data| to the given |position| in the file being written
@@ -31,6 +33,7 @@
   // written.
   // TODO(mek): This might need some way of reporting progress events back to
   // the renderer.
+  // TODO(oyiptong): Refactor into NFSFileWriter.
   Write(uint64 offset, Blob data) => (NativeFileSystemError result,
                                       uint64 bytes_written);
 
@@ -39,14 +42,19 @@
   // written.
   // TODO(mek): This might need some way of reporting progress events back to
   // the renderer.
+  // TODO(oyiptong): Refactor into NFSFileWriter.
   WriteStream(uint64 offset, handle<data_pipe_consumer> stream) =>
       (NativeFileSystemError result, uint64 bytes_written);
 
   // Changes the length of the file to be |length|. If |length| is larger than
   // the current size of the file, the file will be extended, and the extended
   // part is filled with null bytes.
+  // TODO(oyiptong): Refactor into NFSFileWriter.
   Truncate(uint64 length) => (NativeFileSystemError result);
 
+  // Returns a FileWriter object. The FileWriter provides write operations on a file.
+  CreateFileWriter() => (NativeFileSystemError result, NativeFileSystemFileWriter? writer);
+
   // Create a TransferToken for this directory. This token can be used to pass
   // a reference to this directory to other methods, for example to copy or move
   // the file, or when transferring the handle over postMessage.
diff --git a/third_party/blink/public/mojom/native_file_system/native_file_system_file_writer.mojom b/third_party/blink/public/mojom/native_file_system/native_file_system_file_writer.mojom
new file mode 100644
index 0000000..9ade7e5
--- /dev/null
+++ b/third_party/blink/public/mojom/native_file_system/native_file_system_file_writer.mojom
@@ -0,0 +1,18 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module blink.mojom;
+
+import "third_party/blink/public/mojom/native_file_system/native_file_system_error.mojom";
+
+// Represents an object to modify a file.
+interface NativeFileSystemFileWriter {
+  // Closes the file writer. This will materialize the writes operations on the
+  // intended file target in the case of atomic writes.
+  // Close() will close the mojo pipe after completion.
+  // If the mojo pipe closes before Close() is invoked, the write operation is deemed
+  // unsuccessful. Any temporary artifacts will be deleted.
+  // Returns whether the operation succeeded.
+  Close() => (NativeFileSystemError result);
+};
\ No newline at end of file
diff --git a/third_party/blink/public/platform/web_rect.h b/third_party/blink/public/platform/web_rect.h
index 59aeaac..32fe2f7 100644
--- a/third_party/blink/public/platform/web_rect.h
+++ b/third_party/blink/public/platform/web_rect.h
@@ -51,13 +51,13 @@
 
   bool IsEmpty() const { return width <= 0 || height <= 0; }
 
-  WebRect() : x(0), y(0), width(0), height(0) {}
+  constexpr WebRect() : x(0), y(0), width(0), height(0) {}
 
-  WebRect(int x, int y, int width, int height)
+  constexpr WebRect(int x, int y, int width, int height)
       : x(x), y(y), width(width), height(height) {}
 
 #if INSIDE_BLINK
-  WebRect(const IntRect& r)
+  constexpr WebRect(const IntRect& r)
       : x(r.X()), y(r.Y()), width(r.Width()), height(r.Height()) {}
 
   WebRect& operator=(const IntRect& r) {
@@ -68,15 +68,15 @@
     return *this;
   }
 
-  operator IntRect() const { return IntRect(x, y, width, height); }
+  constexpr operator IntRect() const { return IntRect(x, y, width, height); }
 
-  explicit WebRect(const gfx::Rect& r)
+  constexpr explicit WebRect(const gfx::Rect& r)
       : x(r.x()), y(r.y()), width(r.width()), height(r.height()) {}
 
   // Note that this conversion clamps the size to be non-negative.
   explicit operator gfx::Rect() const { return gfx::Rect(x, y, width, height); }
 #else
-  WebRect(const gfx::Rect& r)
+  constexpr WebRect(const gfx::Rect& r)
       : x(r.x()), y(r.y()), width(r.width()), height(r.height()) {}
 
   WebRect& operator=(const gfx::Rect& r) {
@@ -88,7 +88,9 @@
   }
 
   // Note that this conversion clamps the size to be non-negative.
-  operator gfx::Rect() const { return gfx::Rect(x, y, width, height); }
+  constexpr operator gfx::Rect() const {
+    return gfx::Rect(x, y, width, height);
+  }
 #endif
 };
 
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context.cc b/third_party/blink/renderer/core/display_lock/display_lock_context.cc
index 8c278d0..2773b44 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_context.cc
+++ b/third_party/blink/renderer/core/display_lock/display_lock_context.cc
@@ -615,6 +615,12 @@
 }
 
 bool DisplayLockContext::MarkForStyleRecalcIfNeeded() {
+  if (reattach_layout_tree_was_blocked_) {
+    // We previously blocked a layout tree reattachment on |element_|'s
+    // descendants, so we should mark it for layout tree reattachment now.
+    element_->SetForceReattachLayoutTree();
+    reattach_layout_tree_was_blocked_ = false;
+  }
   if (IsElementDirtyForStyleRecalc()) {
     if (blocked_style_traversal_type_ > kStyleUpdateNotRequired) {
       // We blocked a traversal going to the element previously.
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context.h b/third_party/blink/renderer/core/display_lock/display_lock_context.h
index 4d42e58..1303221 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_context.h
+++ b/third_party/blink/renderer/core/display_lock/display_lock_context.h
@@ -164,6 +164,10 @@
         std::max(blocked_style_traversal_type_, type);
   }
 
+  void NotifyReattachLayoutTreeWasBlocked() {
+    reattach_layout_tree_was_blocked_ = true;
+  }
+
   // Inform the display lock that it needs a graphics layer collection when it
   // needs to paint.
   void NotifyNeedsGraphicsLayerCollection() {
@@ -316,6 +320,10 @@
 
   bool is_locked_after_connect_ = false;
   StyleType blocked_style_traversal_type_ = kStyleUpdateNotRequired;
+  // Signifies whether we've blocked a layout tree reattachment on |element_|'s
+  // descendants or not, so that we can mark |element_| for reattachment when
+  // needed.
+  bool reattach_layout_tree_was_blocked_ = false;
 
   bool needs_effective_allowed_touch_action_update_ = false;
   bool needs_prepaint_subtree_walk_ = false;
diff --git a/third_party/blink/renderer/core/dom/container_node.cc b/third_party/blink/renderer/core/dom/container_node.cc
index e815215..9939d396 100644
--- a/third_party/blink/renderer/core/dom/container_node.cc
+++ b/third_party/blink/renderer/core/dom/container_node.cc
@@ -976,6 +976,21 @@
 
 DISABLE_CFI_PERF
 void ContainerNode::AttachLayoutTree(AttachContext& context) {
+  if (IsElementNode() && ToElement(this)->StyleRecalcBlockedByDisplayLock(
+                             DisplayLockContext::kChildren)) {
+    // Since we block style recalc on descendants of this node due to display
+    // locking, none of its descendants should have the NeedsReattachLayoutTree
+    // bit set.
+    DCHECK(!ChildNeedsReattachLayoutTree());
+    // If an element is locked we shouldn't attach the layout tree for its
+    // descendants. We should notify that we blocked a reattach so that we will
+    // correctly attach the descendants when allowed.
+    ToElement(this)
+        ->GetDisplayLockContext()
+        ->NotifyReattachLayoutTreeWasBlocked();
+    Node::AttachLayoutTree(context);
+    return;
+  }
   for (Node* child = firstChild(); child; child = child->nextSibling())
     child->AttachLayoutTree(context);
   Node::AttachLayoutTree(context);
diff --git a/third_party/blink/renderer/core/exported/web_frame_test.cc b/third_party/blink/renderer/core/exported/web_frame_test.cc
index 795fd6c8..a3ab9ca0 100644
--- a/third_party/blink/renderer/core/exported/web_frame_test.cc
+++ b/third_party/blink/renderer/core/exported/web_frame_test.cc
@@ -4080,7 +4080,6 @@
 
   web_view_helper.GetWebView()->EnableFakePageScaleAnimationForTesting(true);
 
-  WebRect edit_box_with_text(200, 200, 250, 20);
   WebRect edit_box_with_no_text(200, 250, 250, 20);
 
   // Test scrolling the focused node
@@ -4203,9 +4202,6 @@
   web_view_helper.GetWebView()->SetPageScaleFactor(2);
   web_view_helper.GetWebView()->SetVisualViewportOffset(WebFloatPoint(100, 50));
 
-  WebRect base_rect;
-  WebRect extent_rect;
-
   WebLocalFrame* main_frame =
       web_view_helper.GetWebView()->MainFrame()->ToWebLocalFrame();
 
@@ -4234,9 +4230,6 @@
   web_view_helper.GetWebView()->SetPageScaleFactor(scale);
   web_view_helper.GetWebView()->SetVisualViewportOffset(visual_offset);
 
-  WebRect base_rect;
-  WebRect extent_rect;
-
   WebRect rect;
   main_frame->FirstRectForCharacterRange(0, 5, rect);
 
diff --git a/third_party/blink/renderer/core/exported/web_plugin_container_test.cc b/third_party/blink/renderer/core/exported/web_plugin_container_test.cc
index 0819a4fd3..1e22b76 100644
--- a/third_party/blink/renderer/core/exported/web_plugin_container_test.cc
+++ b/third_party/blink/renderer/core/exported/web_plugin_container_test.cc
@@ -1421,7 +1421,7 @@
 }
 
 TEST_F(WebPluginContainerTest, TopmostAfterDetachTest) {
-  static WebRect topmost_rect(10, 10, 40, 40);
+  static constexpr WebRect kTopmostRect(10, 10, 40, 40);
 
   // Plugin that checks isRectTopmost in destroy().
   class TopmostPlugin : public FakeWebPlugin {
@@ -1429,11 +1429,11 @@
     explicit TopmostPlugin(const WebPluginParams& params)
         : FakeWebPlugin(params) {}
 
-    bool IsRectTopmost() { return Container()->IsRectTopmost(topmost_rect); }
+    bool IsRectTopmost() { return Container()->IsRectTopmost(kTopmostRect); }
 
     void Destroy() override {
       // In destroy, IsRectTopmost is no longer valid.
-      EXPECT_FALSE(Container()->IsRectTopmost(topmost_rect));
+      EXPECT_FALSE(Container()->IsRectTopmost(kTopmostRect));
       FakeWebPlugin::Destroy();
     }
 
@@ -1454,7 +1454,7 @@
           web_view, WebString::FromUTF8("translated-plugin")));
   plugin_container_impl->SetFrameRect(IntRect(0, 0, 300, 300));
 
-  EXPECT_TRUE(plugin_container_impl->IsRectTopmost(topmost_rect));
+  EXPECT_TRUE(plugin_container_impl->IsRectTopmost(kTopmostRect));
 
   TopmostPlugin* test_plugin =
       static_cast<TopmostPlugin*>(plugin_container_impl->Plugin());
@@ -1463,7 +1463,7 @@
   // Cause the plugin's frame to be detached.
   web_view_helper.Reset();
 
-  EXPECT_FALSE(plugin_container_impl->IsRectTopmost(topmost_rect));
+  EXPECT_FALSE(plugin_container_impl->IsRectTopmost(kTopmostRect));
 }
 
 namespace {
diff --git a/third_party/blink/renderer/core/inspector/devtools_session.cc b/third_party/blink/renderer/core/inspector/devtools_session.cc
index 4c3cc8e5..adffc9b 100644
--- a/third_party/blink/renderer/core/inspector/devtools_session.cc
+++ b/third_party/blink/renderer/core/inspector/devtools_session.cc
@@ -26,6 +26,7 @@
 namespace blink {
 
 namespace {
+using ::inspector_protocol_encoding::span;
 using ::inspector_protocol_encoding::SpanFrom;
 using ::inspector_protocol_encoding::cbor::IsCBORMessage;
 const char kV8StateKey[] = "v8";
@@ -42,10 +43,10 @@
          method == "Emulation.setScriptExecutionDisabled";
 }
 
-std::vector<uint8_t> UnwrapMessage(
-    const mojom::blink::DevToolsMessagePtr& message) {
-  return std::vector<uint8_t>(message->data.data(),
-                              message->data.data() + message->data.size());
+Vector<uint8_t> UnwrapMessage(const mojom::blink::DevToolsMessagePtr& message) {
+  Vector<uint8_t> unwrap_message;
+  unwrap_message.Append(message->data.data(), message->data.size());
+  return unwrap_message;
 }
 
 mojom::blink::DevToolsMessagePtr WrapMessage(
@@ -53,7 +54,7 @@
   auto result = mojom::blink::DevToolsMessage::New();
 
   if (message.json.IsEmpty()) {
-    result->data = std::move(message.binary);
+    result->data = message.binary.ReleaseVector();
   } else {
     WTF::StringUTF8Adaptor adaptor(message.json);
     result->data =
@@ -68,8 +69,7 @@
   const auto& string = buffer->string();
   DCHECK(string.is8Bit());
   // TODO: add StringBuffer::takeBytes().
-  message.binary = std::vector<uint8_t>(string.characters8(),
-                                        string.characters8() + string.length());
+  message.binary = WebVector<uint8_t>(string.characters8(), string.length());
   return message;
 }
 
@@ -136,7 +136,7 @@
       session_state_(std::move(reattach_session_state)),
       v8_session_state_(kV8StateKey),
       v8_session_state_cbor_(&v8_session_state_,
-                             /*default_value=*/std::vector<uint8_t>()) {
+                             /*default_value=*/{}) {
   io_session_ =
       new IOSession(agent_->io_task_runner_, agent_->inspector_task_runner_,
                     WrapCrossThreadWeakPersistent(this), std::move(io_request));
@@ -161,7 +161,7 @@
 
 void DevToolsSession::ConnectToV8(v8_inspector::V8Inspector* inspector,
                                   int context_group_id) {
-  const std::vector<uint8_t>& cbor = v8_session_state_cbor_.Get();
+  const auto& cbor = v8_session_state_cbor_.Get();
   v8_session_ =
       inspector->connect(context_group_id, this,
                          v8_inspector::StringView(cbor.data(), cbor.size()));
@@ -208,8 +208,8 @@
 
 void DevToolsSession::DispatchProtocolCommandImpl(int call_id,
                                                   const String& method,
-                                                  std::vector<uint8_t> data) {
-  DCHECK(IsCBORMessage(SpanFrom(data)));
+                                                  Vector<uint8_t> data) {
+  DCHECK(IsCBORMessage(span<uint8_t>(data.data(), data.size())));
 
   // IOSession does not provide ordering guarantees relative to
   // Session, so a command may come to IOSession after Session is detached,
diff --git a/third_party/blink/renderer/core/inspector/devtools_session.h b/third_party/blink/renderer/core/inspector/devtools_session.h
index e554d87..fbb4043 100644
--- a/third_party/blink/renderer/core/inspector/devtools_session.h
+++ b/third_party/blink/renderer/core/inspector/devtools_session.h
@@ -61,7 +61,7 @@
       mojom::blink::DevToolsMessagePtr message) override;
   void DispatchProtocolCommandImpl(int call_id,
                                    const String& method,
-                                   std::vector<uint8_t> message);
+                                   Vector<uint8_t> message);
 
   // protocol::FrontendChannel implementation.
   void sendProtocolResponse(
diff --git a/third_party/blink/renderer/core/inspector/inspect_tools.cc b/third_party/blink/renderer/core/inspector/inspect_tools.cc
index 9ce7f0ab..287de15 100644
--- a/third_party/blink/renderer/core/inspector/inspect_tools.cc
+++ b/third_party/blink/renderer/core/inspector/inspect_tools.cc
@@ -344,8 +344,8 @@
 
 // NearbyDistanceTool ----------------------------------------------------------
 
-std::string NearbyDistanceTool::GetDataResourceName() {
-  return std::string("inspect_tool_distances.html");
+String NearbyDistanceTool::GetDataResourceName() {
+  return String("inspect_tool_distances.html");
 }
 
 bool NearbyDistanceTool::HandleMouseDown(const WebMouseEvent& event,
@@ -414,8 +414,8 @@
   overlay_->EvaluateInOverlay("drawViewSize", "");
 }
 
-std::string ShowViewSizeTool::GetDataResourceName() {
-  return std::string("inspect_tool_viewport_size.html");
+String ShowViewSizeTool::GetDataResourceName() {
+  return String("inspect_tool_viewport_size.html");
 }
 
 bool ShowViewSizeTool::ForwardEventsToOverlay() {
@@ -431,8 +431,8 @@
   client.SetCursorOverridden(true);
 }
 
-std::string ScreenshotTool::GetDataResourceName() {
-  return std::string("inspect_tool_screenshot.html");
+String ScreenshotTool::GetDataResourceName() {
+  return String("inspect_tool_screenshot.html");
 }
 
 void ScreenshotTool::Dispatch(const String& message) {
@@ -501,8 +501,8 @@
 
 // PausedInDebuggerTool --------------------------------------------------------
 
-std::string PausedInDebuggerTool::GetDataResourceName() {
-  return std::string("inspect_tool_paused.html");
+String PausedInDebuggerTool::GetDataResourceName() {
+  return String("inspect_tool_paused.html");
 }
 
 void PausedInDebuggerTool::Draw(float scale) {
diff --git a/third_party/blink/renderer/core/inspector/inspect_tools.h b/third_party/blink/renderer/core/inspector/inspect_tools.h
index 755bca3..da47234f 100644
--- a/third_party/blink/renderer/core/inspector/inspect_tools.h
+++ b/third_party/blink/renderer/core/inspector/inspect_tools.h
@@ -95,7 +95,7 @@
   NearbyDistanceTool() = default;
 
  private:
-  std::string GetDataResourceName() override;
+  String GetDataResourceName() override;
   bool HandleMouseDown(const WebMouseEvent& event,
                        bool* swallow_next_mouse_up) override;
   bool HandleMouseMove(const WebMouseEvent& event) override;
@@ -115,7 +115,7 @@
 
  private:
   bool ForwardEventsToOverlay() override;
-  std::string GetDataResourceName() override;
+  String GetDataResourceName() override;
   void Draw(float scale) override;
   DISALLOW_COPY_AND_ASSIGN(ShowViewSizeTool);
 };
@@ -127,7 +127,7 @@
   ScreenshotTool() = default;
 
  private:
-  std::string GetDataResourceName() override;
+  String GetDataResourceName() override;
   void DoInit() override;
   void Dispatch(const String& message) override;
 
@@ -143,7 +143,7 @@
       : v8_session_(v8_session), message_(message) {}
 
  private:
-  std::string GetDataResourceName() override;
+  String GetDataResourceName() override;
   void Draw(float scale) override;
   void Dispatch(const String& message) override;
   v8_inspector::V8InspectorSession* v8_session_;
diff --git a/third_party/blink/renderer/core/inspector/inspector_memory_agent.cc b/third_party/blink/renderer/core/inspector/inspector_memory_agent.cc
index 29aa97fd..4b4d763 100644
--- a/third_party/blink/renderer/core/inspector/inspector_memory_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_memory_agent.cc
@@ -131,18 +131,17 @@
   base::ModuleCache module_cache;
   auto samples = std::make_unique<
       protocol::Array<protocol::Memory::SamplingProfileNode>>();
-  std::vector<base::SamplingHeapProfiler::Sample> raw_samples =
-      base::SamplingHeapProfiler::Get()->GetSamples(id);
+  auto raw_samples = base::SamplingHeapProfiler::Get()->GetSamples(id);
 
   for (auto& it : raw_samples) {
     for (const void* frame : it.stack) {
       uintptr_t address = reinterpret_cast<uintptr_t>(frame);
       module_cache.GetModuleForAddress(address);  // Populates module_cache.
     }
-    std::vector<std::string> source_stack = Symbolize(it.stack);
+    Vector<String> source_stack = Symbolize(it.stack);
     auto stack = std::make_unique<protocol::Array<protocol::String>>();
-    for (const std::string& frame : source_stack)
-      stack->emplace_back(frame.c_str());
+    for (const auto& frame : source_stack)
+      stack->emplace_back(frame);
     samples->emplace_back(protocol::Memory::SamplingProfileNode::create()
                               .setSize(it.size)
                               .setTotal(it.total)
@@ -183,42 +182,48 @@
       .build();
 }
 
-std::vector<std::string> InspectorMemoryAgent::Symbolize(
-    const std::vector<void*>& addresses) {
+Vector<String> InspectorMemoryAgent::Symbolize(
+    const WebVector<void*>& addresses) {
 #if defined(OS_LINUX)
   // TODO(alph): Move symbolization to the client.
-  std::vector<void*> addresses_to_symbolize;
-  for (void* address : addresses) {
+  Vector<void*> addresses_to_symbolize;
+  for (size_t i = 0; i < addresses.size(); i++) {
+    void* address = addresses[i];
     if (!symbols_cache_.Contains(address))
       addresses_to_symbolize.push_back(address);
   }
 
-  std::string text = base::debug::StackTrace(addresses_to_symbolize.data(),
-                                             addresses_to_symbolize.size())
-                         .ToString();
+  String text(base::debug::StackTrace(addresses_to_symbolize.data(),
+                                      addresses_to_symbolize.size())
+                  .ToString()
+                  .c_str());
   // Populate cache with new entries.
   size_t next_pos;
   for (size_t pos = 0, i = 0;; pos = next_pos + 1, ++i) {
     next_pos = text.find('\n', pos);
-    if (next_pos == std::string::npos)
+    if (next_pos == kNotFound)
       break;
-    std::string line = text.substr(pos, next_pos - pos);
-    size_t space_pos = line.rfind(' ');
-    std::string name =
-        line.substr(space_pos == std::string::npos ? 0 : space_pos + 1);
+    String line = text.Substring(pos, next_pos - pos);
+    size_t space_pos = line.ReverseFind(' ');
+    String name = line.Substring(space_pos == kNotFound ? 0 : space_pos + 1);
     symbols_cache_.insert(addresses_to_symbolize[i], name);
   }
 #endif
 
-  std::vector<std::string> result;
+  Vector<String> result;
   for (void* address : addresses) {
     char buffer[20];
     std::snprintf(buffer, sizeof(buffer), "0x%" PRIxPTR,
                   reinterpret_cast<uintptr_t>(address));
-    if (symbols_cache_.Contains(address))
-      result.push_back(std::string(buffer) + " " + symbols_cache_.at(address));
-    else
+    if (symbols_cache_.Contains(address)) {
+      StringBuilder builder;
+      builder.Append(buffer);
+      builder.Append(" ");
+      builder.Append(symbols_cache_.at(address));
+      result.push_back(builder.ToString());
+    } else {
       result.push_back(buffer);
+    }
   }
   return result;
 }
diff --git a/third_party/blink/renderer/core/inspector/inspector_memory_agent.h b/third_party/blink/renderer/core/inspector/inspector_memory_agent.h
index 7431c4f..264b9ca1 100644
--- a/third_party/blink/renderer/core/inspector/inspector_memory_agent.h
+++ b/third_party/blink/renderer/core/inspector/inspector_memory_agent.h
@@ -70,13 +70,13 @@
       std::unique_ptr<protocol::Memory::SamplingProfile>*) override;
 
  private:
-  std::vector<std::string> Symbolize(const std::vector<void*>& addresses);
+  Vector<String> Symbolize(const WebVector<void*>& addresses);
   std::unique_ptr<protocol::Memory::SamplingProfile> GetSamplingProfileById(
       uint32_t id);
 
   Member<InspectedFrames> frames_;
   uint32_t profile_id_ = 0;
-  HashMap<void*, std::string> symbols_cache_;
+  HashMap<void*, String> symbols_cache_;
 
   InspectorAgentState::Integer sampling_profile_interval_;
   DISALLOW_COPY_AND_ASSIGN(InspectorMemoryAgent);
diff --git a/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc b/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc
index c8ed469..ba4ae345 100644
--- a/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc
@@ -31,7 +31,6 @@
 #include <algorithm>
 #include <memory>
 #include <utility>
-#include <vector>
 
 #include "base/auto_reset.h"
 #include "build/build_config.h"
@@ -114,8 +113,8 @@
   DoInit();
 }
 
-std::string InspectTool::GetDataResourceName() {
-  return std::string("inspect_tool_highlight.html");
+String InspectTool::GetDataResourceName() {
+  return String("inspect_tool_highlight.html");
 }
 
 bool InspectTool::HandleInputEvent(LocalFrameView* frame_view,
@@ -409,7 +408,7 @@
   resize_timer_.Stop();
   resize_timer_active_ = false;
   frame_overlay_.reset();
-  frame_resource_name_ = std::string();
+  frame_resource_name_ = String();
   PickTheRightTool();
   SetNeedsUnbufferedInput(false);
   return Response::OK();
@@ -740,9 +739,9 @@
       return OverlayMainFrame()->GetEventHandler().HandleMouseMoveEvent(
           mouse_event,
           TransformWebMouseEventVector(frame_impl_->GetFrameView(),
-                                       std::vector<const WebInputEvent*>()),
+                                       WebVector<const WebInputEvent*>()),
           TransformWebMouseEventVector(frame_impl_->GetFrameView(),
-                                       std::vector<const WebInputEvent*>()));
+                                       WebVector<const WebInputEvent*>()));
     }
     if (mouse_event.GetType() == WebInputEvent::kMouseDown) {
       return OverlayMainFrame()->GetEventHandler().HandleMousePressEvent(
@@ -898,8 +897,8 @@
   data->Append("<script>", static_cast<size_t>(8));
   data->Append(Platform::Current()->GetDataResource("inspect_tool_common.js"));
   data->Append("</script>", static_cast<size_t>(9));
-  data->Append(
-      Platform::Current()->GetDataResource(frame_resource_name_.c_str()));
+  data->Append(Platform::Current()->GetDataResource(
+      frame_resource_name_.Utf8().c_str()));
 
   frame->ForceSynchronousDocumentInstall("text/html", data);
 
diff --git a/third_party/blink/renderer/core/inspector/inspector_overlay_agent.h b/third_party/blink/renderer/core/inspector/inspector_overlay_agent.h
index 54c54e4..fb989f3 100644
--- a/third_party/blink/renderer/core/inspector/inspector_overlay_agent.h
+++ b/third_party/blink/renderer/core/inspector/inspector_overlay_agent.h
@@ -76,7 +76,7 @@
  public:
   virtual ~InspectTool() = default;
   void Init(InspectorOverlayAgent* overlay, OverlayFrontend* frontend);
-  virtual std::string GetDataResourceName();
+  virtual String GetDataResourceName();
   virtual bool HandleInputEvent(LocalFrameView* frame_view,
                                 const WebInputEvent& input_event,
                                 bool* swallow_next_mouse_up);
@@ -215,7 +215,7 @@
   Member<WebLocalFrameImpl> frame_impl_;
   Member<InspectedFrames> inspected_frames_;
   Member<Page> overlay_page_;
-  std::string frame_resource_name_;
+  String frame_resource_name_;
   Member<InspectorOverlayChromeClient> overlay_chrome_client_;
   Member<InspectorOverlayHost> overlay_host_;
   bool resize_timer_active_;
diff --git a/third_party/blink/renderer/core/inspector/inspector_page_agent.cc b/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
index 628c4c3a..6553a17b 100644
--- a/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
@@ -539,8 +539,8 @@
     const String& source,
     Maybe<String> world_name,
     String* identifier) {
-  std::vector<WTF::String> keys = scripts_to_evaluate_on_load_.Keys();
-  auto result = std::max_element(
+  Vector<WTF::String> keys = scripts_to_evaluate_on_load_.Keys();
+  auto* result = std::max_element(
       keys.begin(), keys.end(), [](const WTF::String& a, const WTF::String& b) {
         return Decimal::FromString(a) < Decimal::FromString(b);
       });
@@ -847,7 +847,7 @@
 void InspectorPageAgent::DidClearDocumentOfWindowObject(LocalFrame* frame) {
   if (!GetFrontend())
     return;
-  std::vector<WTF::String> keys = scripts_to_evaluate_on_load_.Keys();
+  Vector<WTF::String> keys = scripts_to_evaluate_on_load_.Keys();
   std::sort(keys.begin(), keys.end(),
             [](const WTF::String& a, const WTF::String& b) {
               return Decimal::FromString(a) < Decimal::FromString(b);
diff --git a/third_party/blink/renderer/core/inspector/inspector_session_state.cc b/third_party/blink/renderer/core/inspector/inspector_session_state.cc
index 4c906ae3..206ad872 100644
--- a/third_party/blink/renderer/core/inspector/inspector_session_state.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_session_state.cc
@@ -36,11 +36,11 @@
 }
 
 void InspectorSessionState::EnqueueUpdate(const WTF::String& key,
-                                          const std::vector<uint8_t>* value) {
+                                          const WebVector<uint8_t>* value) {
   base::Optional<WTF::Vector<uint8_t>> updated_value;
   if (value) {
     WTF::Vector<uint8_t> payload;
-    payload.Append(value->data(), value->size());
+    payload.AppendRange(value->begin(), value->end());
     updated_value = std::move(payload);
   }
   updates_->entries.Set(key, std::move(updated_value));
@@ -56,8 +56,8 @@
 // Encoding / Decoding routines.
 //
 /*static*/
-void InspectorAgentState::Serialize(bool v, std::vector<uint8_t>* out) {
-  out->push_back(v ? EncodeTrue() : EncodeFalse());
+void InspectorAgentState::Serialize(bool v, WebVector<uint8_t>* out) {
+  out->emplace_back(v ? EncodeTrue() : EncodeFalse());
 }
 
 /*static*/
@@ -75,8 +75,10 @@
 }
 
 /*static*/
-void InspectorAgentState::Serialize(int32_t v, std::vector<uint8_t>* out) {
-  ::inspector_protocol_encoding::cbor::EncodeInt32(v, out);
+void InspectorAgentState::Serialize(int32_t v, WebVector<uint8_t>* out) {
+  auto encode = out->ReleaseVector();
+  ::inspector_protocol_encoding::cbor::EncodeInt32(v, &encode);
+  *out = std::move(encode);
 }
 
 /*static*/
@@ -90,8 +92,10 @@
 }
 
 /*static*/
-void InspectorAgentState::Serialize(double v, std::vector<uint8_t>* out) {
-  ::inspector_protocol_encoding::cbor::EncodeDouble(v, out);
+void InspectorAgentState::Serialize(double v, WebVector<uint8_t>* out) {
+  auto encode = out->ReleaseVector();
+  ::inspector_protocol_encoding::cbor::EncodeDouble(v, &encode);
+  *out = std::move(encode);
 }
 
 /*static*/
@@ -106,17 +110,19 @@
 
 /*static*/
 void InspectorAgentState::Serialize(const WTF::String& v,
-                                    std::vector<uint8_t>* out) {
+                                    WebVector<uint8_t>* out) {
+  auto encode = out->ReleaseVector();
   if (v.Is8Bit()) {
     auto span8 = v.Span8();
-    EncodeFromLatin1(span<uint8_t>(span8.data(), span8.size()), out);
+    EncodeFromLatin1(span<uint8_t>(span8.data(), span8.size()), &encode);
   } else {
     auto span16 = v.Span16();
     EncodeFromUTF16(
         span<uint16_t>(reinterpret_cast<const uint16_t*>(span16.data()),
                        span16.size()),
-        out);
+        &encode);
   }
+  *out = std::move(encode);
 }
 
 /*static*/
@@ -139,11 +145,11 @@
 
 /*static*/
 void InspectorAgentState::Serialize(const std::vector<uint8_t>& v,
-                                    std::vector<uint8_t>* out) {
+                                    WebVector<uint8_t>* out) {
   // We could CBOR encode this, but since we never look at the contents
   // anyway (except for decoding just below), we just cheat and use the
   // blob directly.
-  out->insert(out->end(), v.begin(), v.end());
+  out->Assign(v.data(), v.size());
 }
 
 /*static*/
diff --git a/third_party/blink/renderer/core/inspector/inspector_session_state.h b/third_party/blink/renderer/core/inspector/inspector_session_state.h
index bc63d697..74611e911 100644
--- a/third_party/blink/renderer/core/inspector/inspector_session_state.h
+++ b/third_party/blink/renderer/core/inspector/inspector_session_state.h
@@ -7,8 +7,8 @@
 
 #include <memory>
 #include <type_traits>
-#include <vector>
 #include "third_party/blink/public/mojom/devtools/devtools_agent.mojom-blink.h"
+#include "third_party/blink/public/platform/web_vector.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "third_party/inspector_protocol/encoding/encoding.h"
@@ -30,7 +30,7 @@
   // that are sent back to the browser.
   // A null string for |value| indicates a deletion.
   // TODO(johannes): Lower cost of repeated updates.
-  void EnqueueUpdate(const WTF::String& key, const std::vector<uint8_t>* value);
+  void EnqueueUpdate(const WTF::String& key, const WebVector<uint8_t>* value);
 
   // Yields and consumes the field updates that have thus far accumulated.
   // These updates are sent back to DevToolsSession on the browser side.
@@ -50,20 +50,19 @@
   // these is to be able to call overloaded methods from the template
   // implementations below; they just delegate to protocol::Value parsing
   // and serialization.
-  static void Serialize(bool v, std::vector<uint8_t>* out);
+  static void Serialize(bool v, WebVector<uint8_t>* out);
   static bool Deserialize(::inspector_protocol_encoding::span<uint8_t> in,
                           bool* v);
-  static void Serialize(int32_t v, std::vector<uint8_t>* out);
+  static void Serialize(int32_t v, WebVector<uint8_t>* out);
   static bool Deserialize(::inspector_protocol_encoding::span<uint8_t> in,
                           int32_t* v);
-  static void Serialize(double v, std::vector<uint8_t>* out);
+  static void Serialize(double v, WebVector<uint8_t>* out);
   static bool Deserialize(::inspector_protocol_encoding::span<uint8_t> in,
                           double* v);
-  static void Serialize(const WTF::String& v, std::vector<uint8_t>* out);
+  static void Serialize(const WTF::String& v, WebVector<uint8_t>* out);
   static bool Deserialize(::inspector_protocol_encoding::span<uint8_t> in,
                           WTF::String* v);
-  static void Serialize(const std::vector<uint8_t>& v,
-                        std::vector<uint8_t>* out);
+  static void Serialize(const std::vector<uint8_t>& v, WebVector<uint8_t>* out);
   static bool Deserialize(::inspector_protocol_encoding::span<uint8_t> in,
                           std::vector<uint8_t>* v);
 
@@ -128,7 +127,7 @@
         return;
       }
       value_ = value;
-      std::vector<uint8_t> encoded_value;
+      WebVector<uint8_t> encoded_value;
       Serialize(value, &encoded_value);
       session_state_->EnqueueUpdate(prefix_key_, &encoded_value);
     }
@@ -180,10 +179,10 @@
 
     // Enumerates the keys for which values are stored in this field.
     // The order of the keys is undefined.
-    std::vector<WTF::String> Keys() const {
+    Vector<WTF::String> Keys() const {
       // TODO(johannes): It'd be nice to avoid copying; unfortunately
       // it didn't seem easy to return map_.Keys().
-      std::vector<WTF::String> keys;
+      Vector<WTF::String> keys;
       for (const WTF::String& s : map_.Keys())
         keys.push_back(s);
       return keys;
@@ -210,7 +209,7 @@
       if (it != map_.end() && it->value == value)
         return;
       map_.Set(key, value);
-      std::vector<uint8_t> encoded_value;
+      WebVector<uint8_t> encoded_value;
       Serialize(value, &encoded_value);
       session_state_->EnqueueUpdate(prefix_key_ + key, &encoded_value);
     }
@@ -287,7 +286,7 @@
 
  private:
   const WTF::String domain_name_;
-  std::vector<Field*> fields_;
+  Vector<Field*> fields_;
 };
 }  // namespace blink
 
diff --git a/third_party/blink/renderer/core/inspector/inspector_session_state_test.cc b/third_party/blink/renderer/core/inspector/inspector_session_state_test.cc
index dcb657f1..9b632b8 100644
--- a/third_party/blink/renderer/core/inspector/inspector_session_state_test.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_session_state_test.cc
@@ -55,7 +55,7 @@
         multiplier_(&agent_state_, /*default_value=*/1.0),
         counter_(&agent_state_, /*default_value=*/1),
         message_(&agent_state_, /*default_value=*/WTF::String()),
-        bytes_(&agent_state_, /*default_value=*/std::vector<uint8_t>()) {}
+        bytes_(&agent_state_, /*default_value=*/{}) {}
 
   InspectorAgentState agent_state_;
   InspectorAgentState::Boolean enabled_;
@@ -230,7 +230,7 @@
   // Show that the keys for the field values are prefixed with the domain name
   // passed to AgentState so that the stored values won't collide.
   DevToolsSessionStatePtr cookie = dev_tools_session.CloneCookie();
-  std::vector<WTF::String> keys;
+  Vector<WTF::String> keys;
   for (const WTF::String& k : cookie->entries.Keys())
     keys.push_back(k);
 
diff --git a/third_party/blink/renderer/core/inspector/protocol_unittest.cc b/third_party/blink/renderer/core/inspector/protocol_unittest.cc
index 376c836..017e00a 100644
--- a/third_party/blink/renderer/core/inspector/protocol_unittest.cc
+++ b/third_party/blink/renderer/core/inspector/protocol_unittest.cc
@@ -4,7 +4,6 @@
 
 #include "third_party/blink/renderer/core/inspector/v8_inspector_string.h"
 
-#include <vector>
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace blink {
@@ -16,9 +15,9 @@
   bool success = false;
   Binary decoded = Binary::fromBase64("", &success);
   EXPECT_TRUE(success);
-  EXPECT_EQ(
-      std::vector<uint8_t>(),
-      std::vector<uint8_t>(decoded.data(), decoded.data() + decoded.size()));
+  Vector<uint8_t> decoded_bytes;
+  decoded_bytes.Append(decoded.data(), decoded.size());
+  EXPECT_EQ(Vector<uint8_t>(), decoded_bytes);
 }
 
 TEST(ProtocolStringTest, AllBytesBase64Roundtrip) {
diff --git a/third_party/blink/renderer/core/inspector/v8_inspector_string.cc b/third_party/blink/renderer/core/inspector/v8_inspector_string.cc
index 9eed0c2..e2cf5e1 100644
--- a/third_party/blink/renderer/core/inspector/v8_inspector_string.cc
+++ b/third_party/blink/renderer/core/inspector/v8_inspector_string.cc
@@ -66,7 +66,7 @@
 }
 
 // static
-ProtocolMessage StringUtil::binaryToMessage(std::vector<uint8_t> message) {
+ProtocolMessage StringUtil::binaryToMessage(WebVector<uint8_t> message) {
   ProtocolMessage result;
   result.binary = std::move(message);
   return result;
diff --git a/third_party/blink/renderer/core/inspector/v8_inspector_string.h b/third_party/blink/renderer/core/inspector/v8_inspector_string.h
index 7490a45..6853f45d 100644
--- a/third_party/blink/renderer/core/inspector/v8_inspector_string.h
+++ b/third_party/blink/renderer/core/inspector/v8_inspector_string.h
@@ -6,8 +6,8 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_V8_INSPECTOR_STRING_H_
 
 #include <memory>
-#include <vector>
 
+#include "third_party/blink/public/platform/web_vector.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/shared_buffer.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
@@ -41,7 +41,7 @@
 
 struct ProtocolMessage {
   String json;
-  std::vector<uint8_t> binary;
+  WebVector<uint8_t> binary;
 };
 
 class CORE_EXPORT StringUtil {
@@ -84,7 +84,7 @@
   }
   static std::unique_ptr<protocol::Value> parseJSON(const String&);
   static ProtocolMessage jsonToMessage(const String& message);
-  static ProtocolMessage binaryToMessage(std::vector<uint8_t> message);
+  static ProtocolMessage binaryToMessage(WebVector<uint8_t> message);
 
   static String fromUTF8(const uint8_t* data, size_t length) {
     return String::FromUTF8(reinterpret_cast<const char*>(data), length);
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
index e07113d8..f6990c1 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
@@ -465,6 +465,7 @@
   NGStaticPosition static_position(descendant.static_position);
   static_position.offset -= container_info.physical_container_offset;
 
+  // Need a constraint space to resolve offsets.
   NGConstraintSpace descendant_constraint_space =
       NGConstraintSpaceBuilder(container_writing_mode, descendant_writing_mode,
                                /* is_new_fc */ true)
@@ -482,6 +483,14 @@
   base::Optional<MinMaxSize> min_max_size;
   scoped_refptr<const NGLayoutResult> layout_result = nullptr;
 
+  // In order to calculate the offsets, we may need to know the size.
+
+  // In some cases we will need the fragment size in order to calculate the
+  // offset. We may have to lay out to get the fragment size. For block
+  // fragmentation, we *need* to know the block-offset before layout. In other
+  // words, in that case, we may have to lay out, calculate the offset, and
+  // then lay out again at the correct block-offset.
+
   bool is_replaced = node.IsReplaced();
   bool should_be_considered_as_replaced = node.ShouldBeConsideredAsReplaced();
 
@@ -526,11 +535,77 @@
     block_estimate = fragment.BlockSize();
   }
 
+  // Calculate the offsets.
+
   ComputeFullAbsoluteWithChildBlockSize(
       descendant_constraint_space, descendant_style, border_padding,
       static_position, block_estimate, replaced_size, container_writing_mode,
       container_style.Direction(), &node_position);
 
+  NGBoxStrut inset = node_position.inset.ConvertToLogical(
+      container_writing_mode, default_containing_block_.style->Direction());
+
+  // |inset| is relative to the container's padding-box. Convert this to being
+  // relative to the default container's border-box.
+  LogicalOffset offset = container_info.container_offset;
+  offset.inline_offset += inset.inline_start;
+  offset.block_offset += inset.block_start;
+
+  if (!only_layout) {
+    // Special case: oof css container is a split inline.
+    // When css container spans multiple anonymous blocks, its dimensions can
+    // only be computed by a block that is an ancestor of all fragments
+    // generated by css container. That block is parent of anonymous containing
+    // block.
+    // That is why instead of OOF being placed by its anonymous container,
+    // they get placed by anonymous container's parent.
+    // This is different from all other OOF blocks, and requires special
+    // handling in several places in the OOF code.
+    // There is an exception to special case: if anonymous block is Legacy, we
+    // cannot do the fancy multiple anonymous block traversal, and we handle it
+    // like regular blocks.
+    //
+    // Detailed example:
+    //
+    // If Layout tree looks like this:
+    // LayoutNGBlockFlow#container
+    //   LayoutNGBlockFlow (anonymous#1)
+    //     LayoutInline#1 (relative)
+    //   LayoutNGBlockFlow (anonymous#2 relative)
+    //     LayoutNGBlockFlow#oof (positioned)
+    //   LayoutNGBlockFlow (anonymous#3)
+    //     LayoutInline#3 (continuation)
+    //
+    // The containing block geometry is defined by split inlines,
+    // LayoutInline#1, LayoutInline#3.
+    // Css container anonymous#2 does not have information needed
+    // to compute containing block geometry.
+    // Therefore, #oof cannot be placed by anonymous#2. NG handles this case
+    // by placing #oof in parent of anonymous (#container).
+    //
+    // But, PaintPropertyTreeBuilder expects #oof.Location() to be wrt css
+    // container, #anonymous2. This is why the code below adjusts the legacy
+    // offset from being wrt #container to being wrt #anonymous2.
+    const LayoutObject* container = node.GetLayoutBox()->Container();
+    if (container->IsAnonymousBlock()) {
+      LogicalOffset container_offset =
+          container_builder_->GetChildOffset(container);
+      offset -= container_offset;
+    } else if (container->IsLayoutInline() &&
+               container->ContainingBlock()->IsAnonymousBlock()) {
+      // Location of OOF with inline container, and anonymous containing block
+      // is wrt container.
+      LogicalOffset container_offset =
+          container_builder_->GetChildOffset(container->ContainingBlock());
+      offset -= container_offset;
+    }
+  }
+
+  // We have calculated the offsets, and if we need to lay out, we can do so at
+  // the correct block-start offset now.
+
+  // TODO(mstensho): Actually pass the block-start offset to layout.
+
   // Skip this step if we produced a fragment when estimating the block-size.
   if (!layout_result) {
     block_estimate =
@@ -551,78 +626,18 @@
            ->IsDisplayFlexibleOrGridBox())
     node.GetLayoutBox()->SetMargin(node_position.margins);
 
-  NGBoxStrut inset = node_position.inset.ConvertToLogical(
-      container_writing_mode, default_containing_block_.style->Direction());
-
-  // |inset| is relative to the container's padding-box. Convert this to being
-  // relative to the default container's border-box.
-  LogicalOffset offset = container_info.container_offset;
-  offset.inline_offset += inset.inline_start;
-  offset.block_offset += inset.block_start;
-
+  // Adjusting the offset for a dialog after layout is fine, since we cannot
+  // have dialogs needing alignment inside block fragmentation.
   base::Optional<LayoutUnit> y = ComputeAbsoluteDialogYPosition(
       *node.GetLayoutBox(), layout_result->PhysicalFragment().Size().height);
   if (y.has_value()) {
+    DCHECK(!container_space_.HasBlockFragmentation());
     if (IsHorizontalWritingMode(container_writing_mode))
       offset.block_offset = *y;
     else
       offset.inline_offset = *y;
   }
 
-  if (only_layout) {
-    layout_result->GetMutableForOutOfFlow().SetOutOfFlowPositionedOffset(
-        offset);
-    return layout_result;
-  }
-
-  // Special case: oof css container is a split inline.
-  // When css container spans multiple anonymous blocks, its dimensions
-  // can only be computed by a block that is an ancestor of all fragments
-  // generated by css container. That block is parent of anonymous containing
-  // block.
-  // That is why instead of OOF being placed by its anonymous container,
-  // they get placed by anonymous container's parent.
-  // This is different from all other OOF blocks, and requires special
-  // handling in several places in the OOF code.
-  // There is an exception to special case: if anonymous block is Legacy,
-  // we cannot do the fancy multiple anonymous block traversal, and we handle
-  // it like regular blocks.
-  //
-  // Detailed example:
-  //
-  // If Layout tree looks like this:
-  // LayoutNGBlockFlow#container
-  //   LayoutNGBlockFlow (anonymous#1)
-  //     LayoutInline#1 (relative)
-  //   LayoutNGBlockFlow (anonymous#2 relative)
-  //     LayoutNGBlockFlow#oof (positioned)
-  //   LayoutNGBlockFlow (anonymous#3)
-  //     LayoutInline#3 (continuation)
-  //
-  // The containing block geometry is defined by split inlines,
-  // LayoutInline#1, LayoutInline#3.
-  // Css container anonymous#2 does not have information needed
-  // to compute containing block geometry.
-  // Therefore, #oof cannot be placed by anonymous#2. NG handles this case
-  // by placing #oof in parent of anonymous (#container).
-  //
-  // But, PaintPropertyTreeBuilder expects #oof.Location() to be wrt
-  // css container, #anonymous2. This is why the code below adjusts
-  // the legacy offset from being wrt #container to being wrt #anonymous2.
-  const LayoutObject* container = node.GetLayoutBox()->Container();
-  if (container->IsAnonymousBlock()) {
-    LogicalOffset container_offset =
-        container_builder_->GetChildOffset(container);
-    offset -= container_offset;
-  } else if (container->IsLayoutInline() &&
-             container->ContainingBlock()->IsAnonymousBlock()) {
-    // Location of OOF with inline container, and anonymous containing block
-    // is wrt container.
-    LogicalOffset container_offset =
-        container_builder_->GetChildOffset(container->ContainingBlock());
-    offset -= container_offset;
-  }
-
   layout_result->GetMutableForOutOfFlow().SetOutOfFlowPositionedOffset(offset);
   return layout_result;
 }
diff --git a/third_party/blink/renderer/core/script/resources/layered_api/elements/switch/index.mjs b/third_party/blink/renderer/core/script/resources/layered_api/elements/switch/index.mjs
index 8d91110..7a75560 100644
--- a/third_party/blink/renderer/core/script/resources/layered_api/elements/switch/index.mjs
+++ b/third_party/blink/renderer/core/script/resources/layered_api/elements/switch/index.mjs
@@ -10,17 +10,53 @@
 const STATE_ATTR = 'on';
 
 // Private property symbols
-// TODO(tkent): Use a private field.
+// TODO(tkent): Use private fields.
 const _internals = Symbol();
+const _track = Symbol();
+const _rippleElement = Symbol();
 
 export class StdSwitchElement extends HTMLElement {
+  // TODO(tkent): The following should be |static fooBar = value;|
+  // after enabling babel-eslint.
   static get formAssociated() {
     return true;
   }
+  static get observedAttributes() {
+    return [STATE_ATTR];
+  }
 
   constructor() {
     super();
     this[_internals] = this.attachInternals();
+    this._initializeDOM();
+  }
+
+  attributeChangedCallback(attrName, oldValue, newValue) {
+    if (attrName == STATE_ATTR) {
+      this[_track].value = newValue !== null;
+    }
+  }
+
+  // TODO(tkent): Make this private.
+  _initializeDOM() {
+    let factory = this.ownerDocument;
+    let root = this.attachShadow({mode: 'closed'});
+    let container = factory.createElement('span');
+    container.classList.add('container');
+    root.appendChild(container);
+
+    this[_track] = new SwitchTrack(factory);
+    container.appendChild(this[_track].element);
+    this[_track].value = this.on;
+
+    let thumbElement = container.appendChild(factory.createElement('span'));
+    thumbElement.classList.add('thumb');
+
+    this[_rippleElement] = thumbElement.appendChild(factory.createElement('span'));
+    this[_rippleElement].classList.add('ripple');
+
+    // TODO(tkent): Add stylesheets for std-switch too.
+    root.adoptedStyleSheets = [this[_track].styleSheet];
   }
 }
 
@@ -39,3 +75,6 @@
 });
 
 customElements.define('std-switch', StdSwitchElement);
+delete StdSwitchElement.formAssociated;
+delete StdSwitchElement.observedAttributes;
+delete StdSwitchElement.prototype.attributeChangedCallback;
diff --git a/third_party/blink/renderer/core/script/resources/layered_api/elements/switch/track.mjs b/third_party/blink/renderer/core/script/resources/layered_api/elements/switch/track.mjs
index 0a160a2..a74454e 100644
--- a/third_party/blink/renderer/core/script/resources/layered_api/elements/switch/track.mjs
+++ b/third_party/blink/renderer/core/script/resources/layered_api/elements/switch/track.mjs
@@ -104,9 +104,9 @@
    */
   _addSlot() {
     if (this[_value]) {
-      this[_trackElement].appendChild(this[_slotElement]);
-    } else {
       this[_fillElement].appendChild(this[_slotElement]);
+    } else {
+      this[_trackElement].appendChild(this[_slotElement]);
     }
   }
 }
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h
index 75901b0..e4f7886 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h
+++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h
@@ -193,7 +193,6 @@
   void HandleAriaExpandedChangeWithCleanLayout(Node*);
   void HandleAriaSelectedChangedWithCleanLayout(Node*);
 
-  bool AccessibilityEnabled();
   bool InlineTextBoxAccessibilityEnabled();
 
   void RemoveAXID(AXObject*);
diff --git a/third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.cc b/third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.cc
index 417c841..a0a03b9 100644
--- a/third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.cc
+++ b/third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.h"
 
 #include "third_party/blink/public/mojom/native_file_system/native_file_system_error.mojom-blink.h"
+#include "third_party/blink/public/mojom/native_file_system/native_file_system_file_writer.mojom-blink.h"
 #include "third_party/blink/public/mojom/native_file_system/native_file_system_transfer_token.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
@@ -30,7 +31,19 @@
   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
   ScriptPromise result = resolver->Promise();
 
-  resolver->Resolve(MakeGarbageCollected<NativeFileSystemWriter>(this));
+  mojo_ptr_->CreateFileWriter(WTF::Bind(
+      [](ScriptPromiseResolver* resolver, NativeFileSystemFileHandle* handle,
+         mojom::blink::NativeFileSystemErrorPtr result,
+         mojom::blink::NativeFileSystemFileWriterPtr writer) {
+        if (result->error_code == base::File::FILE_OK) {
+          resolver->Resolve(MakeGarbageCollected<NativeFileSystemWriter>(
+              handle, std::move(writer)));
+        } else {
+          resolver->Reject(file_error::CreateDOMException(result->error_code));
+        }
+      },
+      WrapPersistent(resolver), WrapPersistent(this)));
+
   return result;
 }
 
diff --git a/third_party/blink/renderer/modules/native_file_system/native_file_system_writer.cc b/third_party/blink/renderer/modules/native_file_system/native_file_system_writer.cc
index 3bbc7ab..89d4d67 100644
--- a/third_party/blink/renderer/modules/native_file_system/native_file_system_writer.cc
+++ b/third_party/blink/renderer/modules/native_file_system/native_file_system_writer.cc
@@ -24,9 +24,12 @@
 
 namespace blink {
 
-NativeFileSystemWriter::NativeFileSystemWriter(NativeFileSystemFileHandle* file)
-    : file_(file) {
+NativeFileSystemWriter::NativeFileSystemWriter(
+    NativeFileSystemFileHandle* file,
+    mojom::blink::NativeFileSystemFileWriterPtr mojo_ptr)
+    : mojo_ptr_(std::move(mojo_ptr)), file_(file) {
   DCHECK(file_);
+  DCHECK(mojo_ptr_);
 }
 
 ScriptPromise NativeFileSystemWriter::write(
@@ -213,13 +216,18 @@
 }
 
 ScriptPromise NativeFileSystemWriter::close(ScriptState* script_state) {
-  if (!file_) {
+  if (!file_ || pending_operation_) {
     return ScriptPromise::RejectWithDOMException(
         script_state, MakeGarbageCollected<DOMException>(
                           DOMExceptionCode::kInvalidStateError));
   }
-  file_ = nullptr;
-  return ScriptPromise::CastUndefined(script_state);
+  pending_operation_ =
+      MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+  ScriptPromise result = pending_operation_->Promise();
+  mojo_ptr_->Close(
+      WTF::Bind(&NativeFileSystemWriter::CloseComplete, WrapPersistent(this)));
+
+  return result;
 }
 
 void NativeFileSystemWriter::Trace(Visitor* visitor) {
@@ -254,4 +262,17 @@
   pending_operation_ = nullptr;
 }
 
+void NativeFileSystemWriter::CloseComplete(
+    mojom::blink::NativeFileSystemErrorPtr result) {
+  DCHECK(pending_operation_);
+  if (result->error_code == base::File::FILE_OK) {
+    pending_operation_->Resolve();
+  } else {
+    pending_operation_->Reject(
+        file_error::CreateDOMException(result->error_code));
+  }
+  file_ = nullptr;
+  pending_operation_ = nullptr;
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/native_file_system/native_file_system_writer.h b/third_party/blink/renderer/modules/native_file_system/native_file_system_writer.h
index 2dfa99b..70d2601 100644
--- a/third_party/blink/renderer/modules/native_file_system/native_file_system_writer.h
+++ b/third_party/blink/renderer/modules/native_file_system/native_file_system_writer.h
@@ -6,6 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_WRITER_H_
 
 #include "third_party/blink/public/mojom/native_file_system/native_file_system_error.mojom-blink.h"
+#include "third_party/blink/public/mojom/native_file_system/native_file_system_file_writer.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/array_buffer_or_array_buffer_view_or_blob_or_usv_string.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 
@@ -24,7 +25,8 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  explicit NativeFileSystemWriter(NativeFileSystemFileHandle*);
+  explicit NativeFileSystemWriter(NativeFileSystemFileHandle*,
+                                  mojom::blink::NativeFileSystemFileWriterPtr);
 
   ScriptPromise write(ScriptState*,
                       uint64_t position,
@@ -47,7 +49,9 @@
   void WriteComplete(mojom::blink::NativeFileSystemErrorPtr result,
                      uint64_t bytes_written);
   void TruncateComplete(mojom::blink::NativeFileSystemErrorPtr result);
+  void CloseComplete(mojom::blink::NativeFileSystemErrorPtr result);
 
+  mojom::blink::NativeFileSystemFileWriterPtr mojo_ptr_;
   Member<NativeFileSystemFileHandle> file_;
 
   Member<ScriptPromiseResolver> pending_operation_;
diff --git a/third_party/blink/renderer/modules/permissions/permissions.cc b/third_party/blink/renderer/modules/permissions/permissions.cc
index d200c02..ef94bd7 100644
--- a/third_party/blink/renderer/modules/permissions/permissions.cc
+++ b/third_party/blink/renderer/modules/permissions/permissions.cc
@@ -26,7 +26,6 @@
 #include "third_party/blink/renderer/modules/permissions/permission_status.h"
 #include "third_party/blink/renderer/modules/permissions/permission_utils.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
-#include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 #include "third_party/blink/renderer/platform/wtf/wtf_size_t.h"
@@ -177,45 +176,6 @@
   return nullptr;
 }
 
-base::Optional<SchedulingPolicy::Feature> PermissionToSchedulingFeature(
-    PermissionName permission) {
-  switch (permission) {
-    case PermissionName::GEOLOCATION:
-      return SchedulingPolicy::Feature::kRequestedGeolocationPermission;
-    case PermissionName::NOTIFICATIONS:
-      return SchedulingPolicy::Feature::kRequestedNotificationsPermission;
-    case PermissionName::MIDI:
-      return SchedulingPolicy::Feature::kRequestedMIDIPermission;
-    case PermissionName::AUDIO_CAPTURE:
-      return SchedulingPolicy::Feature::kRequestedAudioCapturePermission;
-    case PermissionName::VIDEO_CAPTURE:
-      return SchedulingPolicy::Feature::kRequestedVideoCapturePermission;
-    case PermissionName::SENSORS:
-      return SchedulingPolicy::Feature::kRequestedSensorsPermission;
-    case PermissionName::BACKGROUND_SYNC:
-    case PermissionName::BACKGROUND_FETCH:
-    case PermissionName::PERIODIC_BACKGROUND_SYNC:
-      return SchedulingPolicy::Feature::kRequestedBackgroundWorkPermission;
-    default:
-      return base::nullopt;
-  }
-}
-
-void NotifySchedulerAboutPermissionRequest(ExecutionContext* context,
-                                           PermissionName permission) {
-  if (!context)
-    return;
-
-  base::Optional<SchedulingPolicy::Feature> feature =
-      PermissionToSchedulingFeature(permission);
-
-  if (!feature)
-    return;
-
-  context->GetScheduler()->RegisterStickyFeature(
-      feature.value(), {SchedulingPolicy::RecordMetricsForBackForwardCache()});
-}
-
 }  // anonymous namespace
 
 ScriptPromise Permissions::query(ScriptState* script_state,
@@ -252,8 +212,6 @@
 
   ExecutionContext* context = ExecutionContext::From(script_state);
 
-  NotifySchedulerAboutPermissionRequest(context, descriptor->name);
-
   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
   ScriptPromise promise = resolver->Promise();
 
@@ -310,8 +268,6 @@
     if (exception_state.HadException())
       return ScriptPromise();
 
-    NotifySchedulerAboutPermissionRequest(context, descriptor->name);
-
     // Only append permissions types that are not already present in the vector.
     wtf_size_t internal_index = kNotFound;
     for (wtf_size_t j = 0; j < internal_permissions.size(); ++j) {
diff --git a/third_party/blink/renderer/platform/heap/BUILD.gn b/third_party/blink/renderer/platform/heap/BUILD.gn
index a9b68c0..910928f 100644
--- a/third_party/blink/renderer/platform/heap/BUILD.gn
+++ b/third_party/blink/renderer/platform/heap/BUILD.gn
@@ -46,6 +46,7 @@
     "heap_stats_collector.cc",
     "heap_stats_collector.h",
     "heap_traits.h",
+    "marking_verifier.cc",
     "marking_verifier.h",
     "marking_visitor.cc",
     "marking_visitor.h",
diff --git a/third_party/blink/renderer/platform/heap/heap.cc b/third_party/blink/renderer/platform/heap/heap.cc
index 3f00ddb..7763233 100644
--- a/third_party/blink/renderer/platform/heap/heap.cc
+++ b/third_party/blink/renderer/platform/heap/heap.cc
@@ -365,7 +365,7 @@
 
 void ThreadHeap::ResetAllocationPointForTesting() {
   for (int i = 0; i < BlinkGC::kNumberOfArenas; ++i)
-    arenas_[i]->ResetAllocationPointForTesting();
+    arenas_[i]->ResetAllocationPoint();
 }
 
 BasePage* ThreadHeap::LookupPageForAddress(Address address) {
diff --git a/third_party/blink/renderer/platform/heap/heap_page.cc b/third_party/blink/renderer/platform/heap/heap_page.cc
index 56d46af..819655f0 100644
--- a/third_party/blink/renderer/platform/heap/heap_page.cc
+++ b/third_party/blink/renderer/platform/heap/heap_page.cc
@@ -572,17 +572,24 @@
 #endif  // DCHECK_IS_ON()
 }
 
-void NormalPageArena::VerifyMarking() {
+void BaseArena::VerifyMarking() {
 #if DCHECK_IS_ON()
   // We cannot rely on other marking phases to clear the allocation area as
   // for incremental marking the application is running between steps and
-  // might set up a new area.
-  SetAllocationPoint(nullptr, 0);
+  // might set up a new area. For large object arenas this is a no-op.
+  ResetAllocationPoint();
+
   DCHECK(swept_unfinalized_pages_.IsEmpty());
   DCHECK(swept_unfinalized_empty_pages_.IsEmpty());
-  // There may be objects on swept_pages_ as pre-finalizers may allocate.
+  // There may be objects on |swept_pages_| as pre-finalizers may allocate.
+  // These objects may point to other object on |swept_pages_| or marked objects
+  // on |unswept_pages_| but may never point to a dead (unmarked) object in
+  // |unswept_pages_|.
+  for (BasePage* page : swept_pages_) {
+    page->VerifyMarking();
+  }
   for (BasePage* page : unswept_pages_) {
-    static_cast<NormalPage*>(page)->VerifyMarking();
+    page->VerifyMarking();
   }
 #endif  // DCHECK_IS_ON()
 }
@@ -1673,6 +1680,11 @@
   }
 }
 
+void LargeObjectPage::VerifyMarking() {
+  MarkingVerifier verifier(Arena()->GetThreadState());
+  verifier.VerifyObject(ObjectHeader());
+}
+
 Address ObjectStartBitmap::FindHeader(
     Address address_maybe_pointing_to_the_middle_of_object) {
   size_t object_offset =
diff --git a/third_party/blink/renderer/platform/heap/heap_page.h b/third_party/blink/renderer/platform/heap/heap_page.h
index cb8f094..954472f 100644
--- a/third_party/blink/renderer/platform/heap/heap_page.h
+++ b/third_party/blink/renderer/platform/heap/heap_page.h
@@ -762,7 +762,7 @@
 
   bool IsLargeObjectPage() override { return true; }
 
-  void VerifyMarking() override {}
+  void VerifyMarking() override;
 
 #if defined(ADDRESS_SANITIZER)
   void PoisonUnmarkedObjects() override;
@@ -835,9 +835,11 @@
 
   Address AllocateLargeObject(size_t allocation_size, size_t gc_info_index);
 
+  // Resets the allocation point if it exists for an arena.
+  virtual void ResetAllocationPoint() {}
+
+  void VerifyMarking();
   virtual void VerifyObjectStartBitmap() {}
-  virtual void VerifyMarking() {}
-  virtual void ResetAllocationPointForTesting() {}
 
  protected:
   bool SweepingCompleted() const { return unswept_pages_.IsEmpty(); }
@@ -908,11 +910,9 @@
 
   void SweepAndCompact();
 
+  void ResetAllocationPoint() override { SetAllocationPoint(nullptr, 0); }
+
   void VerifyObjectStartBitmap() override;
-  void VerifyMarking() override;
-  void ResetAllocationPointForTesting() override {
-    SetAllocationPoint(nullptr, 0);
-  }
 
   Address CurrentAllocationPoint() const { return current_allocation_point_; }
 
@@ -964,6 +964,7 @@
   LargeObjectArena(ThreadState*, int index);
   Address AllocateLargeObjectPage(size_t, size_t gc_info_index);
   void FreeLargeObjectPage(LargeObjectPage*);
+
 #if DCHECK_IS_ON()
   bool IsConsistentForGC() override { return true; }
 #endif
diff --git a/third_party/blink/renderer/platform/heap/marking_verifier.cc b/third_party/blink/renderer/platform/heap/marking_verifier.cc
new file mode 100644
index 0000000..9b2098c1
--- /dev/null
+++ b/third_party/blink/renderer/platform/heap/marking_verifier.cc
@@ -0,0 +1,101 @@
+// 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/platform/heap/marking_verifier.h"
+
+#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
+#include "third_party/blink/renderer/platform/heap/heap_page.h"
+
+namespace blink {
+
+void MarkingVerifier::VerifyObject(HeapObjectHeader* header) {
+  // Verify only non-free marked objects.
+  if (header->IsFree() || !header->IsMarked())
+    return;
+
+  const GCInfo* info =
+      GCInfoTable::Get().GCInfoFromIndex(header->GcInfoIndex());
+  const bool can_verify =
+      !info->has_v_table || blink::VTableInitialized(header->Payload());
+  if (can_verify) {
+    CHECK(header->IsValid());
+    parent_ = header;
+    info->trace(this, header->Payload());
+  }
+}
+
+void MarkingVerifier::Visit(void* object, TraceDescriptor desc) {
+  VerifyChild(object, desc.base_object_payload);
+}
+
+void MarkingVerifier::VisitWeak(void* object,
+                                void** object_slot,
+                                TraceDescriptor desc,
+                                WeakCallback callback) {
+  // Weak objects should have been cleared at this point. As a consequence, all
+  // objects found through weak references have to point to live objects at this
+  // point.
+  VerifyChild(object, desc.base_object_payload);
+}
+
+void MarkingVerifier::VisitBackingStoreStrongly(const char*,
+                                                void* object,
+                                                void**,
+                                                TraceDescriptor desc) {
+  if (!object)
+    return;
+
+  // Contents of backing stores are verified through page iteration. The
+  // verification here only makes sure that the backing itself is properly
+  // marked.
+  VerifyChild(object, desc.base_object_payload);
+}
+
+void MarkingVerifier::VisitBackingStoreWeakly(const char*,
+                                              void* object,
+                                              void**,
+                                              TraceDescriptor desc,
+                                              WeakCallback,
+                                              void*) {
+  if (!object)
+    return;
+
+  // Contents of weak backing stores are found themselves through page
+  // iteration and are treated strongly that way, similar to how they are
+  // treated strongly when found through stack scanning. The verification
+  // here only makes sure that the backing itself is properly marked. Weak
+  // backing stores found through
+  VerifyChild(object, desc.base_object_payload);
+}
+
+void MarkingVerifier::VerifyChild(void* object, void* base_object_payload) {
+  CHECK(object);
+  // Verification may check objects that are currently under construction and
+  // would require vtable access to figure out their headers. A nullptr in
+  // |base_object_payload| indicates that a mixin object is in construction
+  // and the vtable cannot be used to get to the object header.
+  const HeapObjectHeader* const child_header =
+      (base_object_payload) ? HeapObjectHeader::FromPayload(base_object_payload)
+                            : HeapObjectHeader::FromInnerAddress(object);
+  // These checks ensure that any children reachable from marked parents are
+  // also marked. If you hit these checks then marking is in an inconsistent
+  // state meaning that there are unmarked objects reachable from marked
+  // ones.
+  CHECK(child_header);
+  if (!child_header->IsMarked()) {
+    // Pre-finalizers may allocate. In that case the newly allocated objects
+    // reside on a page that is not scheduled for sweeping.
+    if (PageFromObject(child_header->Payload())->HasBeenSwept())
+      return;
+
+    LOG(FATAL) << "MarkingVerifier: Encountered unmarked object. " << std::endl
+               << std::endl
+               << "Hint (use v8_enable_raw_heap_snapshots for better naming): "
+               << std::endl
+               << parent_->Name() << std::endl
+               << "\\-> " << child_header->Name() << std::endl;
+  }
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/platform/heap/marking_verifier.h b/third_party/blink/renderer/platform/heap/marking_verifier.h
index 5775e19..fba209ce 100644
--- a/third_party/blink/renderer/platform/heap/marking_verifier.h
+++ b/third_party/blink/renderer/platform/heap/marking_verifier.h
@@ -5,8 +5,6 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MARKING_VERIFIER_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_MARKING_VERIFIER_H_
 
-#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
-#include "third_party/blink/renderer/platform/heap/heap_page.h"
 #include "third_party/blink/renderer/platform/heap/visitor.h"
 
 namespace blink {
@@ -15,46 +13,29 @@
 class MarkingVerifier final : public Visitor {
  public:
   explicit MarkingVerifier(ThreadState* state) : Visitor(state) {}
-  ~MarkingVerifier() override {}
+  ~MarkingVerifier() override = default;
 
-  void VerifyObject(HeapObjectHeader* header) {
-    // Verify only non-free marked objects.
-    if (header->IsFree() || !header->IsMarked())
-      return;
+  void VerifyObject(HeapObjectHeader* header);
 
-    const GCInfo* info =
-        GCInfoTable::Get().GCInfoFromIndex(header->GcInfoIndex());
-    const bool can_verify =
-        !info->has_v_table || blink::VTableInitialized(header->Payload());
-    if (can_verify) {
-      CHECK(header->IsValid());
-      parent_ = header;
-      info->trace(this, header->Payload());
-    }
-  }
-
-  void Visit(void* object, TraceDescriptor desc) final {
-    VerifyChild(object, desc.base_object_payload);
-  }
-
+  void Visit(void* object, TraceDescriptor desc) final;
   void VisitWeak(void* object,
                  void** object_slot,
                  TraceDescriptor desc,
-                 WeakCallback callback) final {
-    VerifyChild(object, desc.base_object_payload);
-  }
+                 WeakCallback callback) final;
 
-  // Unused overrides.
   void VisitBackingStoreStrongly(const char*,
                                  void*,
                                  void**,
-                                 TraceDescriptor) final {}
+                                 TraceDescriptor) final;
+
   void VisitBackingStoreWeakly(const char*,
                                void*,
                                void**,
                                TraceDescriptor,
                                WeakCallback,
-                               void*) final {}
+                               void*) final;
+
+  // Unused overrides.
   void VisitBackingStoreOnly(const char*, void*, void**) final {}
   void RegisterBackingStoreCallback(void**, MovingObjectCallback, void*) final {
   }
@@ -62,36 +43,7 @@
   void Visit(const TraceWrapperV8Reference<v8::Value>&) final {}
 
  private:
-  void VerifyChild(void* object, void* base_object_payload) {
-    CHECK(object);
-    // Verification may check objects that are currently under construction and
-    // would require vtable access to figure out their headers. A nullptr in
-    // |base_object_payload| indicates that a mixin object is in construction
-    // and the vtable cannot be used to get to the object header.
-    const HeapObjectHeader* const child_header =
-        (base_object_payload)
-            ? HeapObjectHeader::FromPayload(base_object_payload)
-            : HeapObjectHeader::FromInnerAddress(object);
-    // These checks ensure that any children reachable from marked parents are
-    // also marked. If you hit these checks then marking is in an inconsistent
-    // state meaning that there are unmarked objects reachable from marked
-    // ones.
-    CHECK(child_header);
-    if (!child_header->IsMarked()) {
-      // Pre-finalizers may allocate. In that case the newly allocated objects
-      // reside on a page that is not scheduled for sweeping.
-      if (PageFromObject(child_header->Payload())->HasBeenSwept())
-        return;
-
-      LOG(FATAL)
-          << "MarkingVerifier: Encountered unmarked object. " << std::endl
-          << std::endl
-          << "Hint (use v8_enable_raw_heap_snapshots for better naming): "
-          << std::endl
-          << parent_->Name() << std::endl
-          << "\\-> " << child_header->Name() << std::endl;
-    }
-  }
+  void VerifyChild(void* object, void* base_object_payload);
 
   HeapObjectHeader* parent_ = nullptr;
 };
diff --git a/third_party/blink/renderer/platform/heap/marking_verifier_test.cc b/third_party/blink/renderer/platform/heap/marking_verifier_test.cc
index 497c3f9..49ba752 100644
--- a/third_party/blink/renderer/platform/heap/marking_verifier_test.cc
+++ b/third_party/blink/renderer/platform/heap/marking_verifier_test.cc
@@ -18,17 +18,37 @@
   USING_PRE_FINALIZER(ResurrectingPreFinalizer, Dispose);
 
  public:
-  enum TestType { kMember, kWeakMember };
+  enum TestType {
+    kMember,
+    kWeakMember,
+    kHeapVectorMember,
+    kHeapHashSetMember,
+    kHeapHashSetWeakMember
+  };
 
   class GlobalStorage : public GarbageCollected<GlobalStorage> {
    public:
+    GlobalStorage() {
+      // Reserve storage upfront to avoid allocations during pre-finalizer
+      // insertion.
+      vector_member.ReserveCapacity(32);
+      hash_set_member.ReserveCapacityForSize(32);
+      hash_set_weak_member.ReserveCapacityForSize(32);
+    }
+
     void Trace(Visitor* visitor) {
       visitor->Trace(strong);
       visitor->Trace(weak);
+      visitor->Trace(vector_member);
+      visitor->Trace(hash_set_member);
+      visitor->Trace(hash_set_weak_member);
     }
 
     Member<LinkedObject> strong;
     WeakMember<LinkedObject> weak;
+    HeapVector<Member<LinkedObject>> vector_member;
+    HeapHashSet<Member<LinkedObject>> hash_set_member;
+    HeapHashSet<WeakMember<LinkedObject>> hash_set_weak_member;
   };
 
   ResurrectingPreFinalizer(TestType test_type,
@@ -52,6 +72,15 @@
       case TestType::kWeakMember:
         storage_->weak = object_that_dies_;
         break;
+      case TestType::kHeapVectorMember:
+        storage_->vector_member.push_back(object_that_dies_);
+        break;
+      case TestType::kHeapHashSetMember:
+        storage_->hash_set_member.insert(object_that_dies_);
+        break;
+      case TestType::kHeapHashSetWeakMember:
+        storage_->hash_set_weak_member.insert(object_that_dies_);
+        break;
     }
   }
 
@@ -88,4 +117,43 @@
                             "MarkingVerifier: Encountered unmarked object.");
 }
 
+TEST(MarkingVerifierDeathTest, DiesOnResurrectedHeapVectorMember) {
+  if (!ThreadState::Current()->VerifyMarkingEnabled())
+    return;
+
+  Persistent<ResurrectingPreFinalizer::GlobalStorage> storage(
+      MakeGarbageCollected<ResurrectingPreFinalizer::GlobalStorage>());
+  MakeGarbageCollected<ResurrectingPreFinalizer>(
+      ResurrectingPreFinalizer::kHeapVectorMember, storage.Get(),
+      MakeGarbageCollected<LinkedObject>());
+  ASSERT_DEATH_IF_SUPPORTED(PreciselyCollectGarbage(),
+                            "MarkingVerifier: Encountered unmarked object.");
+}
+
+TEST(MarkingVerifierDeathTest, DiesOnResurrectedHeapHashSetMember) {
+  if (!ThreadState::Current()->VerifyMarkingEnabled())
+    return;
+
+  Persistent<ResurrectingPreFinalizer::GlobalStorage> storage(
+      MakeGarbageCollected<ResurrectingPreFinalizer::GlobalStorage>());
+  MakeGarbageCollected<ResurrectingPreFinalizer>(
+      ResurrectingPreFinalizer::kHeapHashSetMember, storage.Get(),
+      MakeGarbageCollected<LinkedObject>());
+  ASSERT_DEATH_IF_SUPPORTED(PreciselyCollectGarbage(),
+                            "MarkingVerifier: Encountered unmarked object.");
+}
+
+TEST(MarkingVerifierDeathTest, DiesOnResurrectedHeapHashSetWeakMember) {
+  if (!ThreadState::Current()->VerifyMarkingEnabled())
+    return;
+
+  Persistent<ResurrectingPreFinalizer::GlobalStorage> storage(
+      MakeGarbageCollected<ResurrectingPreFinalizer::GlobalStorage>());
+  MakeGarbageCollected<ResurrectingPreFinalizer>(
+      ResurrectingPreFinalizer::kHeapHashSetWeakMember, storage.Get(),
+      MakeGarbageCollected<LinkedObject>());
+  ASSERT_DEATH_IF_SUPPORTED(PreciselyCollectGarbage(),
+                            "MarkingVerifier: Encountered unmarked object.");
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/heap/unified_heap_controller.cc b/third_party/blink/renderer/platform/heap/unified_heap_controller.cc
index b791793..8a70547 100644
--- a/third_party/blink/renderer/platform/heap/unified_heap_controller.cc
+++ b/third_party/blink/renderer/platform/heap/unified_heap_controller.cc
@@ -27,11 +27,13 @@
 
 UnifiedHeapController::UnifiedHeapController(ThreadState* thread_state)
     : thread_state_(thread_state) {
-  thread_state->Heap().stats_collector()->RegisterObserver(this);
+  if (RuntimeEnabledFeatures::HeapUnifiedGCSchedulingEnabled())
+    thread_state->Heap().stats_collector()->RegisterObserver(this);
 }
 
 UnifiedHeapController::~UnifiedHeapController() {
-  thread_state_->Heap().stats_collector()->UnregisterObserver(this);
+  if (RuntimeEnabledFeatures::HeapUnifiedGCSchedulingEnabled())
+    thread_state_->Heap().stats_collector()->UnregisterObserver(this);
 }
 
 void UnifiedHeapController::TracePrologue(
@@ -92,11 +94,13 @@
                                               BlinkGC::kLazySweeping);
   }
 
-  ThreadHeapStatsCollector* const stats_collector =
-      thread_state_->Heap().stats_collector();
-  summary->allocated_size =
-      static_cast<size_t>(stats_collector->marked_bytes());
-  summary->time = stats_collector->marking_time_so_far().InMillisecondsF();
+  if (RuntimeEnabledFeatures::HeapUnifiedGCSchedulingEnabled()) {
+    ThreadHeapStatsCollector* const stats_collector =
+        thread_state_->Heap().stats_collector();
+    summary->allocated_size =
+        static_cast<size_t>(stats_collector->marked_bytes());
+    summary->time = stats_collector->marking_time_so_far().InMillisecondsF();
+  }
   buffered_allocated_size_ = 0;
 
   if (!thread_state_->IsSweepingInProgress()) {
@@ -181,6 +185,7 @@
 }
 
 void UnifiedHeapController::ReportBufferedAllocatedSizeIfPossible() {
+  DCHECK(RuntimeEnabledFeatures::HeapUnifiedGCSchedulingEnabled());
   // Reported from a recursive sweeping call.
   if (thread_state()->IsSweepingInProgress() &&
       thread_state()->SweepForbidden()) {
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index a9e2ac29..6aa5944 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1477,7 +1477,7 @@
     },
     {
       name: "StreamsNative",
-      status: "experimental",
+      status: "test",
     },
     {
       name: "TextFragmentIdentifiers",
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 7741420..6b77f63e 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -3214,6 +3214,7 @@
 crbug.com/968164 external/wpt/css/css-ui/webkit-appearance-menulist-button-001.html [ Failure ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 [ Mac10.11 ] external/wpt/shape-detection/detection-HTMLVideoElement-invalid-state.html [ Timeout ]
 crbug.com/626703 [ Mac10.12 ] external/wpt/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSourceToScriptProcessorTest.html [ Timeout ]
 crbug.com/626703 [ Mac10.12 ] external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-mode.html [ Timeout ]
 crbug.com/626703 [ Mac10.12 ] external/wpt/html/semantics/embedded-content/media-elements/ready-states/autoplay-hidden.optional.html [ Timeout ]
@@ -5811,7 +5812,6 @@
 
 # Sheriff 2019-02-27
 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 ]
 
 
 # Sheriff 2019-02-28
@@ -6044,6 +6044,9 @@
 # Workaround for bug; should be removed soon.
 crbug.com/959693 external/wpt/trusted-types/WorkerGlobalScope-importScripts.https.html [ Timeout ]
 
+# Allow failure until its appearance gets stable.
+crbug.com/972476 std-switch/switch-appearance.html [ Failure ]
+
 # Sheriff 2019-05-20
 crbug.com/963739 [ Fuchsia ] synthetic_gestures/smooth-scroll-tiny-delta.html [ Pass Timeout ]
 crbug.com/964239 external/wpt/css/css-scroll-snap/scroll-margin.html [ Pass Failure ]
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 abec1732..0d22592 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
@@ -41983,6 +41983,18 @@
      {}
     ]
    ],
+   "css/css-flexbox/flex-aspect-ratio-img-column-005.html": [
+    [
+     "css/css-flexbox/flex-aspect-ratio-img-column-005.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-flexbox/flex-aspect-ratio-img-row-001.html": [
     [
      "css/css-flexbox/flex-aspect-ratio-img-row-001.html",
@@ -54857,6 +54869,18 @@
      {}
     ]
    ],
+   "css/css-multicol/composited-under-clip-under-multicol.html": [
+    [
+     "css/css-multicol/composited-under-clip-under-multicol.html",
+     [
+      [
+       "/css/css-multicol/composited-under-clip-under-multicol-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-multicol/float-and-block.html": [
     [
      "css/css-multicol/float-and-block.html",
@@ -130259,9 +130283,6 @@
    "css/css-easing/META.yml": [
     []
    ],
-   "css/css-easing/cubic-bezier-timing-functions-output-expected.txt": [
-    []
-   ],
    "css/css-easing/step-timing-functions-syntax-expected.txt": [
     []
    ],
@@ -137231,6 +137252,9 @@
    "css/css-multicol/OWNERS": [
     []
    ],
+   "css/css-multicol/composited-under-clip-under-multicol-ref.html": [
+    []
+   ],
    "css/css-multicol/float-with-line-after-spanner-ref.html": [
     []
    ],
@@ -171641,9 +171665,6 @@
    "web-animations/animation-model/keyframe-effects/effect-value-replaced-animations-expected.txt": [
     []
    ],
-   "web-animations/animation-model/keyframe-effects/effect-value-transformed-distance-expected.txt": [
-    []
-   ],
    "web-animations/interfaces/Animatable/animate-expected.txt": [
     []
    ],
@@ -203821,6 +203842,12 @@
      {}
     ]
    ],
+   "css/css-sizing/min-max-content-orthogonal-flow-crash-001.html": [
+    [
+     "css/css-sizing/min-max-content-orthogonal-flow-crash-001.html",
+     {}
+    ]
+   ],
    "css/css-sizing/parsing/box-sizing-computed.html": [
     [
      "css/css-sizing/parsing/box-sizing-computed.html",
@@ -245345,13 +245372,17 @@
    "kv-storage/cause-errors-via-idb.https.html": [
     [
      "kv-storage/cause-errors-via-idb.https.html",
-     {}
+     {
+      "timeout": "long"
+     }
     ]
    ],
    "kv-storage/entries.https.html": [
     [
      "kv-storage/entries.https.html",
-     {}
+     {
+      "timeout": "long"
+     }
     ]
    ],
    "kv-storage/key-types.https.html": [
@@ -245365,13 +245396,17 @@
    "kv-storage/keys-values-entries.https.html": [
     [
      "kv-storage/keys-values-entries.https.html",
-     {}
+     {
+      "timeout": "long"
+     }
     ]
    ],
    "kv-storage/keys.https.html": [
     [
      "kv-storage/keys.https.html",
-     {}
+     {
+      "timeout": "long"
+     }
     ]
    ],
    "kv-storage/non-secure-context-dynamic-import.html": [
@@ -245395,19 +245430,25 @@
    "kv-storage/storage-smoke-test.https.html": [
     [
      "kv-storage/storage-smoke-test.https.html",
-     {}
+     {
+      "timeout": "long"
+     }
     ]
    ],
    "kv-storage/undefined-value.https.html": [
     [
      "kv-storage/undefined-value.https.html",
-     {}
+     {
+      "timeout": "long"
+     }
     ]
    ],
    "kv-storage/values.https.html": [
     [
      "kv-storage/values.https.html",
-     {}
+     {
+      "timeout": "long"
+     }
     ]
    ],
    "largest-contentful-paint/observe-image.html": [
@@ -275502,6 +275543,12 @@
      {}
     ]
    ],
+   "shape-detection/detection-HTMLVideoElement-invalid-state.html": [
+    [
+     "shape-detection/detection-HTMLVideoElement-invalid-state.html",
+     {}
+    ]
+   ],
    "shape-detection/detection-HTMLVideoElement.html": [
     [
      "shape-detection/detection-HTMLVideoElement.html",
@@ -344853,10 +344900,6 @@
    "2c412b40f0f1b6059099682bc5c787310e8d2991",
    "support"
   ],
-  "css/css-easing/cubic-bezier-timing-functions-output-expected.txt": [
-   "b022577ffc139ed60d27fa47e36cbc30a1ed6174",
-   "support"
-  ],
   "css/css-easing/cubic-bezier-timing-functions-output.html": [
    "168f4cd907ec93d84bafcd11b00a7c78878569c8",
    "testharness"
@@ -345281,6 +345324,10 @@
    "5ae39e11fe0454f3e70302dcb2591d9855adaaf6",
    "reftest"
   ],
+  "css/css-flexbox/flex-aspect-ratio-img-column-005.html": [
+   "0bd7ef8b23fb19d100d27431ba093a0dee182f34",
+   "reftest"
+  ],
   "css/css-flexbox/flex-aspect-ratio-img-row-001.html": [
    "14fabf760ca4293abf5af9e618b2e2ed627be2b2",
    "reftest"
@@ -361489,6 +361536,14 @@
    "8a6bd957911251bdb952e35e69297d3ed86696cc",
    "reftest"
   ],
+  "css/css-multicol/composited-under-clip-under-multicol-ref.html": [
+   "ebd2d860cec74ba0d535637934aca8dadf90571d",
+   "support"
+  ],
+  "css/css-multicol/composited-under-clip-under-multicol.html": [
+   "a47ed89a2e0eb11624bfb5c96d547f632f9c27e7",
+   "reftest"
+  ],
   "css/css-multicol/extremely-tall-multicol-with-extremely-tall-child-crash.html": [
    "6e40afe54c9ce9aa50765f778d74640454dcc1ce",
    "testharness"
@@ -367873,6 +367928,10 @@
    "bce0a18be6f66e57cad2e2e90694a6f53dab71c7",
    "reftest"
   ],
+  "css/css-sizing/min-max-content-orthogonal-flow-crash-001.html": [
+   "d2617f8aa2d1c966e394abb1d1617c012ea4648e",
+   "testharness"
+  ],
   "css/css-sizing/orthogonal-writing-mode-float-in-inline.html": [
    "fa95069dbf0083b0dc7095d2bb3acf20a6ccf898",
    "reftest"
@@ -435374,7 +435433,7 @@
    "support"
   ],
   "interfaces/mediasession.idl": [
-   "95210c0bca3e06a8c1b418ea48d0c0c2e6b1caba",
+   "565eab7b02715ee2b20e06992292a136bfc5bf22",
    "support"
   ],
   "interfaces/mediastream-recording.idl": [
@@ -435614,7 +435673,7 @@
    "support"
   ],
   "interfaces/webrtc.idl": [
-   "b18d4ac2b46e2b9924820ab227d21b78a86fa349",
+   "c7bb45d012aa56ed1b77957f461f62a24f7b080e",
    "support"
   ],
   "interfaces/webusb.idl": [
@@ -435974,11 +436033,11 @@
    "testharness"
   ],
   "kv-storage/cause-errors-via-idb.https.html": [
-   "d77e56621e037b71fa6ae9bfb3e80a0ab85677fc",
+   "1a7294d093f482b1c2c30840684c8b6a74bc5a0c",
    "testharness"
   ],
   "kv-storage/entries.https.html": [
-   "0d1ab849a709bc8361bca88de34aa91c1ee3e23b",
+   "397525de2499caa7912059ffa9a407ba7bb52c1f",
    "testharness"
   ],
   "kv-storage/helpers/class-assert.js": [
@@ -435998,11 +436057,11 @@
    "testharness"
   ],
   "kv-storage/keys-values-entries.https.html": [
-   "b26323809bb3d33551ee9630bcf841fa0246262b",
+   "2a9cabef5f10b01d7ac04101c39490a3130bb27f",
    "testharness"
   ],
   "kv-storage/keys.https.html": [
-   "a6be29725bf3274f6b5bb92b370962507a29b692",
+   "19a397c4eeba41b2770d8187e60796faa5044bc4",
    "testharness"
   ],
   "kv-storage/non-secure-context-dynamic-import.html": [
@@ -436018,15 +436077,15 @@
    "testharness"
   ],
   "kv-storage/storage-smoke-test.https.html": [
-   "da48dc7cf13cb31fd5f5a3b4b7fa086100197bd9",
+   "31dac972d984f4301f54f2948eb4e2c7d6481c25",
    "testharness"
   ],
   "kv-storage/undefined-value.https.html": [
-   "4cb483a3d982ab150fb28c6aee3a1398c273e82c",
+   "d87641e95b8f55a0f7c3d724f620f17943537c96",
    "testharness"
   ],
   "kv-storage/values.https.html": [
-   "64756bf195fc3319d9dd21abad4c5d86fa266cfe",
+   "d04ded37eaeec714ceb1b2604c1030fc88a33ffd",
    "testharness"
   ],
   "largest-contentful-paint/observe-image.html": [
@@ -440850,7 +440909,7 @@
    "testharness"
   ],
   "native-file-system/FileSystemWriter.tentative.window.js": [
-   "bc5cfd104b6a2645a5321e0f9d38e990b6533969",
+   "f2c2fc82866b83953e2783f8dc56ceaa0803b097",
    "testharness"
   ],
   "native-file-system/NativeFileSystemWritableFileStream.tentative.window.js": [
@@ -449470,7 +449529,7 @@
    "testharness"
   ],
   "portals/portal-activate-data.html": [
-   "6010fe663aa673a9c6b83a08b608e3524ebb66c7",
+   "057ecbf6e01b03f32e81fa9dc7f23dfb125a2645",
    "testharness"
   ],
   "portals/portal-activate-event-constructor.html": [
@@ -464765,6 +464824,10 @@
    "979efabdcb07cfdc0190383026a24e144dea1747",
    "testharness"
   ],
+  "shape-detection/detection-HTMLVideoElement-invalid-state.html": [
+   "e777c96e4a1737968d60f390bf97d5f4c971e95d",
+   "testharness"
+  ],
   "shape-detection/detection-HTMLVideoElement.html": [
    "7b3736d02e9b6b0769a18354b054e5c3ce268773",
    "testharness"
@@ -464818,7 +464881,7 @@
    "support"
   ],
   "shape-detection/shapedetection-cross-origin.sub.html": [
-   "c9d86430356de470bca7a8dfef8596e9159164ad",
+   "f45369266973ee771c648d01b6e4a48ce1282959",
    "testharness"
   ],
   "shape-detection/shapedetection-empty-input.html": [
@@ -472622,7 +472685,7 @@
    "support"
   ],
   "tools/webdriver/webdriver/client.py": [
-   "52ebc95e84aaea1536d15a7325e2ea62b7f2914c",
+   "1ce49069cfdc128f4ea0e6584bd13bac4d50774a",
    "support"
   ],
   "tools/webdriver/webdriver/error.py": [
@@ -475289,10 +475352,6 @@
    "d40a01fdd2a8c13649383d9cc1a8483ce84be902",
    "testharness"
   ],
-  "web-animations/animation-model/keyframe-effects/effect-value-transformed-distance-expected.txt": [
-   "d9a6c37685ddb3aa2ceb4561f4b452d9acf227e3",
-   "support"
-  ],
   "web-animations/animation-model/keyframe-effects/effect-value-transformed-distance.html": [
    "a33d6d4f24676356b59b6b431968d8486df50615",
    "testharness"
@@ -478598,7 +478657,7 @@
    "support"
   ],
   "webrtc-identity/RTCPeerConnection-peerIdentity.https.html": [
-   "518d57777aa79cd2c74ac1820f3538c4afb2732b",
+   "f372e37a9a693ccf35597f47273d139f7f6b74a0",
    "testharness"
   ],
   "webrtc-identity/identity-helper.sub.js": [
@@ -478934,7 +478993,7 @@
    "testharness"
   ],
   "webrtc/RTCPeerConnection-ontrack.https.html": [
-   "10210129acd598fd959124fbe51462de8a1cdb0b",
+   "99f30c264b3648d52fda6bb50de980bcbe84be3c",
    "testharness"
   ],
   "webrtc/RTCPeerConnection-remote-track-mute.https.html": [
diff --git a/third_party/blink/web_tests/external/wpt/kv-storage/cause-errors-via-idb.https.html b/third_party/blink/web_tests/external/wpt/kv-storage/cause-errors-via-idb.https.html
index d77e566..1a7294d0 100644
--- a/third_party/blink/web_tests/external/wpt/kv-storage/cause-errors-via-idb.https.html
+++ b/third_party/blink/web_tests/external/wpt/kv-storage/cause-errors-via-idb.https.html
@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
 <title>KV Storage: causing errors by directly manipulating the IDB</title>
+<meta name="timeout" content="long">
 
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/kv-storage/entries.https.html b/third_party/blink/web_tests/external/wpt/kv-storage/entries.https.html
index 0d1ab84..397525de 100644
--- a/third_party/blink/web_tests/external/wpt/kv-storage/entries.https.html
+++ b/third_party/blink/web_tests/external/wpt/kv-storage/entries.https.html
@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
 <title>KV Storage: entries() trickier tests</title>
+<meta name="timeout" content="long">
 
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/kv-storage/keys-values-entries.https.html b/third_party/blink/web_tests/external/wpt/kv-storage/keys-values-entries.https.html
index b263238..2a9cabe 100644
--- a/third_party/blink/web_tests/external/wpt/kv-storage/keys-values-entries.https.html
+++ b/third_party/blink/web_tests/external/wpt/kv-storage/keys-values-entries.https.html
@@ -1,6 +1,8 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
 <title>KV Storage: keys()/values()/entries()</title>
+<meta name="timeout" content="long">
+
 <!--
   This file contains tests that are easy to generalize over all three methods.
   See sibling files for more complicated tests which are not worth generalizing.
diff --git a/third_party/blink/web_tests/external/wpt/kv-storage/keys.https.html b/third_party/blink/web_tests/external/wpt/kv-storage/keys.https.html
index a6be2972..19a397c4 100644
--- a/third_party/blink/web_tests/external/wpt/kv-storage/keys.https.html
+++ b/third_party/blink/web_tests/external/wpt/kv-storage/keys.https.html
@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
 <title>KV Storage: keys() trickier tests</title>
+<meta name="timeout" content="long">
 
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/kv-storage/storage-smoke-test.https.html b/third_party/blink/web_tests/external/wpt/kv-storage/storage-smoke-test.https.html
index da48dc7..31dac97 100644
--- a/third_party/blink/web_tests/external/wpt/kv-storage/storage-smoke-test.https.html
+++ b/third_party/blink/web_tests/external/wpt/kv-storage/storage-smoke-test.https.html
@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
 <title>KV storage: storage export smoke test</title>
+<meta name="timeout" content="long">
 
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/kv-storage/undefined-value.https.html b/third_party/blink/web_tests/external/wpt/kv-storage/undefined-value.https.html
index 4cb483a..d87641e9 100644
--- a/third_party/blink/web_tests/external/wpt/kv-storage/undefined-value.https.html
+++ b/third_party/blink/web_tests/external/wpt/kv-storage/undefined-value.https.html
@@ -1,6 +1,8 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
 <title>KV Storage: undefined values</title>
+<meta name="timeout" content="long">
+
 <!-- https://github.com/wicg/kv-storage/commit/5bf31109f37d1371f619ea33d0e2391f10e8b8f5 -->
 
 <script src="/resources/testharness.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/kv-storage/values.https.html b/third_party/blink/web_tests/external/wpt/kv-storage/values.https.html
index 64756bf1..d04ded37 100644
--- a/third_party/blink/web_tests/external/wpt/kv-storage/values.https.html
+++ b/third_party/blink/web_tests/external/wpt/kv-storage/values.https.html
@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
 <title>KV Storage: values() trickier tests</title>
+<meta name="timeout" content="long">
 
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/native-file-system/FileSystemWriter.tentative.window.js b/third_party/blink/web_tests/external/wpt/native-file-system/FileSystemWriter.tentative.window.js
index bc5cfd1..f2c2fc8 100644
--- a/third_party/blink/web_tests/external/wpt/native-file-system/FileSystemWriter.tentative.window.js
+++ b/third_party/blink/web_tests/external/wpt/native-file-system/FileSystemWriter.tentative.window.js
@@ -7,6 +7,7 @@
     const writer = await handle.createWriter();
 
     await writer.write(0, new Blob([]));
+    await writer.close();
 
     assert_equals(await getFileContents(handle), '');
     assert_equals(await getFileSize(handle), 0);
@@ -17,6 +18,7 @@
     const writer = await handle.createWriter();
 
     await writer.write(0, new Blob(['1234567890']));
+    await writer.close();
 
     assert_equals(await getFileContents(handle), '1234567890');
     assert_equals(await getFileSize(handle), 10);
@@ -28,6 +30,7 @@
 
     await writer.write(0, new Blob(['1234567890']));
     await writer.write(4, new Blob(['abc']));
+    await writer.close();
 
     assert_equals(await getFileContents(handle), '1234abc890');
     assert_equals(await getFileSize(handle), 10);
@@ -38,6 +41,7 @@
     const writer = await handle.createWriter();
 
     await promise_rejects(t, 'InvalidStateError', writer.write(4, new Blob(['abc'])));
+    await writer.close();
 
     assert_equals(await getFileContents(handle), '');
     assert_equals(await getFileSize(handle), 0);
@@ -48,6 +52,7 @@
   const writer = await handle.createWriter();
 
   await writer.write(0, '');
+  await writer.close();
   assert_equals(await getFileContents(handle), '');
   assert_equals(await getFileSize(handle), 0);
 }, 'write() with an empty string to an empty file');
@@ -57,6 +62,7 @@
   const writer = await handle.createWriter();
 
   await writer.write(0, 'foo🤘');
+  await writer.close();
   assert_equals(await getFileContents(handle), 'foo🤘');
   assert_equals(await getFileSize(handle), 7);
 }, 'write() with a valid utf-8 string');
@@ -66,6 +72,7 @@
   const writer = await handle.createWriter();
 
   await writer.write(0, 'foo\n');
+  await writer.close();
   assert_equals(await getFileContents(handle), 'foo\n');
   assert_equals(await getFileSize(handle), 4);
 }, 'write() with a string with unix line ending preserved');
@@ -75,6 +82,7 @@
   const writer = await handle.createWriter();
 
   await writer.write(0, 'foo\r\n');
+  await writer.close();
   assert_equals(await getFileContents(handle), 'foo\r\n');
   assert_equals(await getFileSize(handle), 5);
 }, 'write() with a string with windows line ending preserved');
@@ -85,6 +93,7 @@
 
   let buf = new ArrayBuffer(0);
   await writer.write(0, buf);
+  await writer.close();
   assert_equals(await getFileContents(handle), '');
   assert_equals(await getFileSize(handle), 0);
 }, 'write() with an empty array buffer to an empty file');
@@ -99,6 +108,7 @@
   intView[1] = 0x6f;
   intView[2] = 0x6f;
   await writer.write(0, buf);
+  await writer.close();
   assert_equals(await getFileContents(handle), 'foo');
   assert_equals(await getFileSize(handle), 3);
 }, 'write() with a valid typed array buffer');
@@ -109,6 +119,7 @@
 
     await writer.write(0, new Blob(['1234567890']));
     await writer.truncate(5);
+    await writer.close();
 
     assert_equals(await getFileContents(handle), '12345');
     assert_equals(await getFileSize(handle), 5);
@@ -120,6 +131,7 @@
 
     await writer.write(0, new Blob(['abc']));
     await writer.truncate(5);
+    await writer.close();
 
     assert_equals(await getFileContents(handle), 'abc\0\0');
     assert_equals(await getFileSize(handle), 5);
diff --git a/third_party/blink/web_tests/external/wpt/shape-detection/detection-HTMLVideoElement-invalid-state.html b/third_party/blink/web_tests/external/wpt/shape-detection/detection-HTMLVideoElement-invalid-state.html
new file mode 100644
index 0000000..e777c96e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/shape-detection/detection-HTMLVideoElement-invalid-state.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+const videoElementTests =
+    [
+      {
+        createDetector: () => { return new FaceDetector(); },
+        name: "Face - detect(HTMLVideoElement)",
+      },
+      {
+        createDetector: () => { return new BarcodeDetector(); },
+        name: "Barcode - detect(HTMLVideoElement)",
+      }
+    ];
+
+for (let videoElementTest of videoElementTests) {
+
+  // Detector's detect() rejects on a HAVE_NOTHING HTMLVideoElement.
+  promise_test(async t => {
+    const video = document.createElement("video");
+    video.src = "";
+    const videoWatcher = new EventWatcher(t, video, ["play", "error"]);
+    video.load();
+    await videoWatcher.wait_for("error");
+    assert_equals(video.readyState, video.HAVE_NOTHING);
+
+    const detector = videoElementTest.createDetector();
+    await promise_rejects(t, 'InvalidStateError', detector.detect(video));
+  }, `${videoElementTest.name} - HAVE_NOTHING`);
+
+  // Detector's detect() rejects on a HAVE_METADATA HTMLVideoElement.
+  promise_test(async t => {
+    const video = document.createElement("video");
+    video.src = "/media/white.webm";
+    video.loop = true;
+    video.autoplay = true;
+    const videoWatcher = new EventWatcher(t, video, ["loadedmetadata", "error"]);
+    video.load();
+    await videoWatcher.wait_for("loadedmetadata");
+    assert_equals(video.readyState, video.HAVE_METADATA);
+
+    const detector = videoElementTest.createDetector();
+    await promise_rejects(t, 'InvalidStateError', detector.detect(video));
+  }, `${videoElementTest.name} - HAVE_METADATA`);
+
+}
+
+</script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/shape-detection/shapedetection-cross-origin.sub.html b/third_party/blink/web_tests/external/wpt/shape-detection/shapedetection-cross-origin.sub.html
index c9d86430..f4536926 100644
--- a/third_party/blink/web_tests/external/wpt/shape-detection/shapedetection-cross-origin.sub.html
+++ b/third_party/blink/web_tests/external/wpt/shape-detection/shapedetection-cross-origin.sub.html
@@ -30,9 +30,9 @@
     img.src = IMAGE_URL;
     await imgWatcher.wait_for("load");
     const detector = crossOriginTest.createDetector();
-    promise_rejects(t, "SecurityError", detector.detect(img));
-  }, crossOriginTest.detectorType
-  + " should reject cross-origin HTMLImageElements with a SecurityError.");
+    await promise_rejects(t, "SecurityError", detector.detect(img));
+  }, `${crossOriginTest.detectorType} should reject cross-origin \
+HTMLImageElements with a SecurityError.`);
 
   // Verifies that Detector rejects a cross-origin ImageBitmap.
   promise_test(async t => {
@@ -42,9 +42,9 @@
     await imgWatcher.wait_for("load");
     const imgBitmap = await createImageBitmap(img);
     const detector = crossOriginTest.createDetector();
-    promise_rejects(t, "SecurityError", detector.detect(imgBitmap));
-  }, crossOriginTest.detectorType
-  + " should reject cross-origin ImageBitmaps with a SecurityError.");
+    await promise_rejects(t, "SecurityError", detector.detect(imgBitmap));
+  }, `${crossOriginTest.detectorType} should reject cross-origin \
+ImageBitmaps with a SecurityError.`);
 
   // Verifies that Detector rejects a cross-origin HTMLVideoElement.
   promise_test(async t => {
@@ -53,9 +53,22 @@
     video.src = VIDEO_URL;
     await videoWatcher.wait_for("loadeddata");
     const detector = crossOriginTest.createDetector();
-    promise_rejects(t, "SecurityError", detector.detect(video));
-  }, crossOriginTest.detectorType
-  + " should reject cross-origin HTMLVideoElements with a SecurityError.");
+    await promise_rejects(t, "SecurityError", detector.detect(video));
+  }, `${crossOriginTest.detectorType} should reject cross-origin \
+HTMLVideoElements with a SecurityError.`);
+
+  // Verifies that Detector rejects a cross-origin HTMLCanvasElement.
+  promise_test(async t => {
+    const img = new Image();
+    const imgWatcher = new EventWatcher(t, img, ["load", "error"]);
+    img.src = IMAGE_URL;
+    await imgWatcher.wait_for("load");
+    const canvas = document.createElement("canvas");
+    canvas.getContext("2d").drawImage(img, 0, 0);
+    const detector = crossOriginTest.createDetector();
+    await promise_rejects(t, "SecurityError", detector.detect(canvas));
+  }, `${crossOriginTest.detectorType} should reject cross-origin \
+HTMLCanvasElement with a SecurityError.`);
 
 }
 
diff --git a/third_party/blink/web_tests/external/wpt/tools/webdriver/webdriver/client.py b/third_party/blink/web_tests/external/wpt/tools/webdriver/webdriver/client.py
index 52ebc95..1ce4906 100644
--- a/third_party/blink/web_tests/external/wpt/tools/webdriver/webdriver/client.py
+++ b/third_party/blink/web_tests/external/wpt/tools/webdriver/webdriver/client.py
@@ -413,7 +413,7 @@
         if self.session_id is not None:
             return
 
-        body = {}
+        body = {"capabilities": {}}
 
         if self.requested_capabilities is not None:
             body["capabilities"] = self.requested_capabilities
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-identity/RTCPeerConnection-peerIdentity.https-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc-identity/RTCPeerConnection-peerIdentity.https-expected.txt
index 36044e3b..2fa5f9b 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc-identity/RTCPeerConnection-peerIdentity.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webrtc-identity/RTCPeerConnection-peerIdentity.https-expected.txt
@@ -1,6 +1,6 @@
 This is a testharness.js-based test.
 FAIL setRemoteDescription() on offer with a=identity should establish peerIdentity promise_test: Unhandled rejection with value: object "TypeError: pc1.setIdentityProvider is not a function"
-FAIL setRemoteDescription() on offer with a=identity that resolve to value different from target peer identity should reject with InvalidModificationError promise_test: Unhandled rejection with value: object "TypeError: pc1.setIdentityProvider is not a function"
+FAIL setRemoteDescription() on offer with a=identity that resolve to value different from target peer identity should reject with OperationError promise_test: Unhandled rejection with value: object "TypeError: pc1.setIdentityProvider is not a function"
 FAIL setRemoteDescription() with peerIdentity set and with IdP proxy that return validationAssertion with mismatch contents should reject with OperationError pc1.setIdentityProvider is not a function
 FAIL setRemoteDescription() and peerIdentity should reject with OperationError if IdP return validated identity that is different from its own domain pc1.setIdentityProvider is not a function
 FAIL When IdP throws error and pc has target peer identity, setRemoteDescription() and peerIdentity rejected with RTCError('idp-execution-error') pc1.setIdentityProvider is not a function
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-identity/RTCPeerConnection-peerIdentity.https.html b/third_party/blink/web_tests/external/wpt/webrtc-identity/RTCPeerConnection-peerIdentity.https.html
index 518d5777..f372e37a 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc-identity/RTCPeerConnection-peerIdentity.https.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc-identity/RTCPeerConnection-peerIdentity.https.html
@@ -78,15 +78,6 @@
       `Expect validated identity from mock-idp.js to be same as specified in usernameHint`);
   }, 'setRemoteDescription() on offer with a=identity should establish peerIdentity');
 
-  /*
-    If the peerIdentity configuration is applied to the RTCPeerConnection, this
-    establishes a target peer identity of the provided value. Alternatively, if the
-    RTCPeerConnection has previously authenticated the identity of the peer (that
-    is, the peerIdentity promise is resolved), then this also establishes a
-    target peer identity.
-
-    The target peer identity cannot be changed once set.
-  */
   promise_test(async t => {
     const port = window.location.port;
     const [idpDomain] = getIdpDomains();
@@ -112,16 +103,11 @@
 
     const offer = await pc1.createOffer();
 
-    try {
-      await pc2.setRemoteDescription(offer);
-      assert_true(false, "Previous line (sRD) should have thrown!");
-    } catch (e) {
-      assert_equals(e.name, 'InvalidModificationError');
-    }
-
-    assert_true(pc2.signalingState, 'closed',
-      'Expect peer connection to be closed after mismatch peer identity');
-  }, 'setRemoteDescription() on offer with a=identity that resolve to value different from target peer identity should reject with InvalidModificationError');
+    await promise_rejects(t, 'OperationError',
+      pc2.setRemoteDescription(offer));
+    await promise_rejects(t, 'OperationError',
+      pc2.peerIdentity);
+  }, 'setRemoteDescription() on offer with a=identity that resolve to value different from target peer identity should reject with OperationError');
 
   /*
     9.4.  Verifying Identity Assertions
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-ontrack.https.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-ontrack.https.html
index 1021012..99f30c26 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-ontrack.https.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-ontrack.https.html
@@ -95,7 +95,7 @@
 
   // tests that ontrack is called and parses the msid information from the SDP and creates
   // the streams with matching identifiers.
-  async_test(t => {
+  promise_test(async t => {
     const pc = new RTCPeerConnection();
 
     t.add_cleanup(() => pc.close());
@@ -123,34 +123,28 @@
 a=ssrc:1001 cname:some
 `;
 
-    pc.ontrack = t.step_func(trackEvent => {
-      const { streams, track, transceiver } = trackEvent;
+    const trackEventPromise = addEventListenerPromise(t, pc, 'track');
+    await pc.setRemoteDescription({ type: 'offer', sdp });
+    const trackEvent = await trackEventPromise;
+    const { streams, track, transceiver } = trackEvent;
 
-      assert_equals(streams.length, 1,
-        'the track belongs to one MediaStream');
+    assert_equals(streams.length, 1,
+      'the track belongs to one MediaStream');
 
-      const [stream] = streams;
-      assert_equals(stream.id, 'stream1',
-        'Expect stream.id to be the same as specified in the a=msid line');
+    const [stream] = streams;
+    assert_equals(stream.id, 'stream1',
+      'Expect stream.id to be the same as specified in the a=msid line');
 
-      assert_equals(track.kind, 'audio',
-        'Expect track.kind to be audio');
+    assert_equals(track.kind, 'audio',
+      'Expect track.kind to be audio');
 
-      validateTrackEvent(trackEvent);
+    validateTrackEvent(trackEvent);
 
-      assert_equals(transceiver.direction, 'recvonly',
-        'Expect transceiver.direction to be reverse of sendonly (recvonly)');
-
-      t.done();
-    });
-
-    pc.setRemoteDescription({ type: 'offer', sdp })
-    .catch(t.step_func(err => {
-      assert_unreached('Error ' + err.name + ': ' + err.message);
-    }));
+    assert_equals(transceiver.direction, 'recvonly',
+      'Expect transceiver.direction to be reverse of sendonly (recvonly)');
   }, 'setRemoteDescription should trigger ontrack event when the MSID of the stream is is parsed.');
 
-  async_test(t => {
+  promise_test(async t => {
     const pc = new RTCPeerConnection();
 
     t.add_cleanup(() => pc.close());
@@ -179,101 +173,61 @@
 
     pc.ontrack = t.unreached_func('ontrack event should not fire for track with recvonly direction');
 
-    pc.setRemoteDescription({ type: 'offer', sdp })
-    .catch(t.step_func(err => {
-      assert_unreached('Error ' + err.name + ': ' + err.message);
-    }))
-    .then(t.step_func(() => {
-      t.step_timeout(t.step_func_done(), 100);
-    }));
+    await pc.setRemoteDescription({ type: 'offer', sdp });
+    await new Promise(resolve => t.step_timeout(resolve, 100));
   }, 'setRemoteDescription() with m= line of recvonly direction should not trigger track event');
 
-  async_test(t => {
+  promise_test(async t => {
     const pc1 = new RTCPeerConnection();
     t.add_cleanup(() => pc1.close());
     const pc2 = new RTCPeerConnection();
 
     t.add_cleanup(() => pc2.close());
 
-    pc2.ontrack = t.step_func(trackEvent => {
-      const { track } = trackEvent;
+    const [track, mediaStream] = await getTrackFromUserMedia('audio');
+    pc1.addTrack(track, mediaStream);
+    const trackEventPromise = addEventListenerPromise(t, pc2, 'track');
+    await pc2.setRemoteDescription(await pc1.createOffer());
+    const trackEvent = await trackEventPromise;
 
-      assert_equals(track.kind, 'audio',
-        'Expect track.kind to be audio');
+    assert_equals(trackEvent.track.kind, 'audio',
+      'Expect track.kind to be audio');
 
-      validateTrackEvent(trackEvent);
-
-      t.done();
-    });
-
-    return getTrackFromUserMedia('audio')
-    .then(([track, mediaStream]) => {
-      pc1.addTrack(track, mediaStream);
-
-      return pc1.createOffer()
-      .then(offer => pc2.setRemoteDescription(offer));
-    })
-    .catch(t.step_func(err => {
-      assert_unreached('Error ' + err.name + ': ' + err.message);
-    }));
+    validateTrackEvent(trackEvent);
   }, 'addTrack() should cause remote connection to fire ontrack when setRemoteDescription()');
 
-  async_test(t => {
+  promise_test(async t => {
     const pc1 = new RTCPeerConnection();
     t.add_cleanup(() => pc1.close());
     const pc2 = new RTCPeerConnection();
 
     t.add_cleanup(() => pc2.close());
 
-    pc2.ontrack = t.step_func(trackEvent => {
-      const { track } = trackEvent;
-
-      assert_equals(track.kind, 'video',
-        'Expect track.kind to be video');
-
-      validateTrackEvent(trackEvent);
-
-      t.done();
-    });
-
     pc1.addTransceiver('video');
 
-    return pc1.createOffer()
-    .then(offer => pc2.setRemoteDescription(offer))
-    .catch(t.step_func(err => {
-      assert_unreached('Error ' + err.name + ': ' + err.message);
-    }));
+    const trackEventPromise = addEventListenerPromise(t, pc2, 'track');
+    await pc2.setRemoteDescription(await pc1.createOffer());
+    const trackEvent = await trackEventPromise;
+    const { track } = trackEvent;
+
+    assert_equals(track.kind, 'video',
+      'Expect track.kind to be video');
+
+    validateTrackEvent(trackEvent);
   }, `addTransceiver('video') should cause remote connection to fire ontrack when setRemoteDescription()`);
 
-  async_test(t => {
+  promise_test(async t => {
     const pc1 = new RTCPeerConnection();
     t.add_cleanup(() => pc1.close());
     const pc2 = new RTCPeerConnection();
 
     t.add_cleanup(() => pc2.close());
 
-    pc2.ontrack = t.step_func(trackEvent => {
-      const { track } = trackEvent;
-
-      assert_equals(track.kind, 'video',
-        'Expect track.kind to be video');
-
-      validateTrackEvent(trackEvent);
-
-      t.done();
-    });
-
     pc1.addTransceiver('audio', { direction: 'inactive' });
     pc2.ontrack = t.unreached_func('ontrack event should not fire for track with inactive direction');
 
-    return pc1.createOffer()
-    .then(offer => pc2.setRemoteDescription(offer))
-    .catch(t.step_func(err => {
-      assert_unreached('Error ' + err.name + ': ' + err.message);
-    }))
-    .then(t.step_func(() => {
-      t.step_timeout(t.step_func_done(), 100);
-    }));
+    await pc2.setRemoteDescription(await pc1.createOffer());
+    await new Promise(resolve => t.step_timeout(resolve, 100));
   }, `addTransceiver() with inactive direction should not cause remote connection to fire ontrack when setRemoteDescription()`);
 
 </script>
diff --git a/third_party/blink/web_tests/fast/forms/validation-bubble-appearance-wrap.html b/third_party/blink/web_tests/fast/forms/validation-bubble-appearance-wrap.html
index 550b930..4605e134 100644
--- a/third_party/blink/web_tests/fast/forms/validation-bubble-appearance-wrap.html
+++ b/third_party/blink/web_tests/fast/forms/validation-bubble-appearance-wrap.html
@@ -1,6 +1,9 @@
 <!DOCTYPE html>
+<script src="../../resources/run-after-layout-and-paint.js"></script>
 <p>Check if text in a validation bubble is wrapped within the bubble.</p>
 <input type="email" value="emailaddressemailaddressemailaddressemailaddressemailaddressemailaddressemailaddressemailaddressemailaddressemailaddressemailaddressemailaddressemailaddressemailaddress">
 <script>
-document.querySelector('input').reportValidity();
+runAfterLayoutAndPaint(() => {
+  document.querySelector('input').reportValidity();
+}, true);
 </script>
diff --git a/third_party/blink/web_tests/http/tests/shapedetection/shapedetection-cross-origin.html b/third_party/blink/web_tests/http/tests/shapedetection/shapedetection-cross-origin.html
index 16956f79..593b06d1 100644
--- a/third_party/blink/web_tests/http/tests/shapedetection/shapedetection-cross-origin.html
+++ b/third_party/blink/web_tests/http/tests/shapedetection/shapedetection-cross-origin.html
@@ -7,74 +7,51 @@
 const IMAGE_URL = "http://localhost:8080/security/resources/abe.png";
 const VIDEO_URL = "http://localhost:8080/external/wpt/media/white.webm";
 
-// Returns a Promise that is resolve()d if detect() is rejected. Needs an input
-// |element| (e.g. an HTMLImageElement or HTMLVideoElement) and a |url| to load.
-function detectTextOnElementAndExpectError(element, url) {
-  return new Promise(function(resolve, reject) {
-    var tryTextDetection = function() {
-      var textDetector = new TextDetector();
-      textDetector.detect(element)
-          .then(textDetectionResult => {
-            reject("Promise should have been rejected.");
-          })
-          .catch(error => {
-            resolve(error);
-          });
-    };
-    element.onload = tryTextDetection;
-    element.onerror = tryTextDetection;
-    element.src = url;
-  });
-}
-
-function detectTextOnImageBitmapAndExpectError(imageUrl) {
-  return new Promise(function(resolve, reject) {
-    var image = new Image();
-    image.onload = function() {
-      createImageBitmap(image)
-          .then(imageBitmap => {
-            var textDetector = new TextDetector();
-            return textDetector.detect(imageBitmap);
-          })
-          .then(textDetectionResult => {
-            reject("Promise should have been rejected.");
-          })
-          .catch(error => {
-            resolve(error);
-          });
-    };
-    image.onerror = () => {};  // Explicitly ignore expected error events.
-    image.src = imageUrl;
-  });
-}
-
 // Verifies that TextDetector rejects a cross-origin HTMLImageElement.
-promise_test(function(t) {
-  var image = new Image();
-  return detectTextOnElementAndExpectError(image, IMAGE_URL)
-      .then(error => {
-        assert_equals(error.name, "SecurityError");
-      });
+promise_test(async t => {
+  const img = new Image();
+  const imgWatcher = new EventWatcher(t, img, ["load", "error"]);
+  img.src = IMAGE_URL;
+  await imgWatcher.wait_for("load");
+  const detector = new TextDetector();
+  await promise_rejects(t, "SecurityError", detector.detect(img));
 },
 "TextDetector should reject cross-origin HTMLImageElements with a SecurityError.");
 
 // Verifies that TextDetector rejects a cross-origin ImageBitmap.
-promise_test(function(t) {
-  return detectTextOnImageBitmapAndExpectError(IMAGE_URL)
-      .then(error => {
-        assert_equals(error.name, "SecurityError");
-      });
+promise_test(async t => {
+  const img = new Image();
+  const imgWatcher = new EventWatcher(t, img, ["load", "error"]);
+  img.src = IMAGE_URL;
+  await imgWatcher.wait_for("load");
+  const imgBitmap = await createImageBitmap(img);
+  const detector = new TextDetector();
+  await promise_rejects(t, "SecurityError", detector.detect(imgBitmap));
 },
 "TextDetector should reject cross-origin ImageBitmaps with a SecurityError.");
 
 // Verifies that TextDetector rejects a cross-origin HTMLVideoElement.
-promise_test(function(t) {
-  var video = document.createElement('video');
-  return detectTextOnElementAndExpectError(video, VIDEO_URL)
-      .then(error => {
-        assert_equals(error.name, "SecurityError");
-      });
+promise_test(async t => {
+  const video = document.createElement('video');
+  const videoWatcher = new EventWatcher(t, video, ["load", "error"]);
+  video.src = VIDEO_URL;
+  await videoWatcher.wait_for("error");
+  const detector = new TextDetector();
+  await promise_rejects(t, "SecurityError", detector.detect(video));
 },
 "TextDetector should reject cross-origin HTMLVideoElements with a SecurityError.");
 
+// Verifies that TextDetector rejects a cross-origin HTMLCanvasElement.
+promise_test(async t => {
+  const img = new Image();
+  const imgWatcher = new EventWatcher(t, img, ["load", "error"]);
+  img.src = IMAGE_URL;
+  await imgWatcher.wait_for("load");
+  const canvas = document.createElement("canvas");
+  canvas.getContext("2d").drawImage(img, 0, 0);
+  const detector = new TextDetector();
+  await promise_rejects(t, "SecurityError", detector.detect(canvas));
+},
+"TextDetector should reject cross-origin HTMLCanvasElements with a SecurityError.");
+
 </script>
diff --git a/third_party/blink/web_tests/platform/mac/std-switch/switch-appearance-expected.png b/third_party/blink/web_tests/platform/mac/std-switch/switch-appearance-expected.png
new file mode 100644
index 0000000..beb04ee
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/std-switch/switch-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/std-switch/switch-appearance-expected.png b/third_party/blink/web_tests/platform/win/std-switch/switch-appearance-expected.png
new file mode 100644
index 0000000..beb04ee
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/std-switch/switch-appearance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/shapedetection/detection-HTMLVideoElement-invalid-state.html b/third_party/blink/web_tests/shapedetection/detection-HTMLVideoElement-invalid-state.html
new file mode 100644
index 0000000..115e685f
--- /dev/null
+++ b/third_party/blink/web_tests/shapedetection/detection-HTMLVideoElement-invalid-state.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script>
+
+// Detector's detect() rejects on a HAVE_NOTHING HTMLVideoElement.
+promise_test(async t => {
+  const video = document.createElement("video");
+  video.src = "";
+  const videoWatcher = new EventWatcher(t, video, ["play", "error"]);
+  video.load();
+  await videoWatcher.wait_for("error");
+  assert_equals(video.readyState, video.HAVE_NOTHING);
+  const detector = new TextDetector();
+  await promise_rejects(t, 'InvalidStateError', detector.detect(video));
+}, "Text - detect(HTMLVideoElement) - HAVE_NOTHING");
+
+// Detector's detect() rejects on a HAVE_METADATA HTMLVideoElement.
+promise_test(async t => {
+  const video = document.createElement("video");
+  video.src = "../external/wpt/media/white.webm";
+  video.loop = true;
+  video.autoplay = true;
+  const videoWatcher = new EventWatcher(t, video, ["loadedmetadata", "error"]);
+  video.load();
+  await videoWatcher.wait_for("loadedmetadata");
+  assert_equals(video.readyState, video.HAVE_METADATA);
+  const detector = new TextDetector();
+  await promise_rejects(t, 'InvalidStateError', detector.detect(video));
+}, "Text - detect(HTMLVideoElement) - HAVE_METADATA");
+
+</script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/std-switch/switch-appearance.html b/third_party/blink/web_tests/std-switch/switch-appearance.html
new file mode 100644
index 0000000..5bae2f41
--- /dev/null
+++ b/third_party/blink/web_tests/std-switch/switch-appearance.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<body>
+<script type="module" async>
+import 'std:elements/switch';
+
+
+</script>
+
+<div><std-switch></std-switch></div>
+<div><std-switch>off</std-switch></div>
+<div><std-switch on></std-switch></div>
+<div><std-switch on>on</std-switch></div>
+
+</body>
diff --git a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-ontrack.https-expected.txt b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-ontrack.https-expected.txt
index 0539a14..4ae360ff 100644
--- a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-ontrack.https-expected.txt
+++ b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-ontrack.https-expected.txt
@@ -2,7 +2,7 @@
 FAIL setRemoteDescription should trigger ontrack event when the MSID of the stream is is parsed. assert_true: Expect trackEvent.transceiver to be defined and is instance of RTCRtpTransceiver expected true got false
 PASS setRemoteDescription() with m= line of recvonly direction should not trigger track event
 FAIL addTrack() should cause remote connection to fire ontrack when setRemoteDescription() assert_true: Expect trackEvent.transceiver to be defined and is instance of RTCRtpTransceiver expected true got false
-FAIL addTransceiver('video') should cause remote connection to fire ontrack when setRemoteDescription() Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'.
-FAIL addTransceiver() with inactive direction should not cause remote connection to fire ontrack when setRemoteDescription() Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'.
+FAIL addTransceiver('video') should cause remote connection to fire ontrack when setRemoteDescription() promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'."
+FAIL addTransceiver() with inactive direction should not cause remote connection to fire ontrack when setRemoteDescription() promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'."
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/wpt_internal/std-switch/tentative/form-associated-basic.js b/third_party/blink/web_tests/wpt_internal/std-switch/tentative/form-associated-basic.js
index 988a71f..b4cbccb 100644
--- a/third_party/blink/web_tests/wpt_internal/std-switch/tentative/form-associated-basic.js
+++ b/third_party/blink/web_tests/wpt_internal/std-switch/tentative/form-associated-basic.js
@@ -12,6 +12,22 @@
 
 function formAssociatedTests(tag, reflectionDict) {
   test(() => {
+    // TODO(tkent): Move the following checks to idlharness.js?
+    let interface = document.createElement(tag).constructor;
+    assert_not_own_property(interface, 'disabledFeatures');
+    assert_not_own_property(interface, 'formAssociated');
+    assert_not_own_property(interface, 'observedAttributes');
+    assert_not_own_property(interface.prototype, 'adoptedCallback');
+    assert_not_own_property(interface.prototype, 'attributeChangedCallback');
+    assert_not_own_property(interface.prototype, 'connectedCallback');
+    assert_not_own_property(interface.prototype, 'disconnectedCallback');
+    assert_not_own_property(interface.prototype, 'formAssociatedCallback');
+    assert_not_own_property(interface.prototype, 'formDisabledCallback');
+    assert_not_own_property(interface.prototype, 'formResetCallback');
+    assert_not_own_property(interface.prototype, 'formStateRestoreCallback');
+  }, `Interface for ${tag} should not have custom-element-like properties`);
+
+  test(() => {
     let control = document.createElement(tag);
     assert_equals(control.type, tag);
   }, `${tag} supports type property`);
diff --git a/third_party/freetype/README.chromium b/third_party/freetype/README.chromium
index ce78c96d..974ef53 100644
--- a/third_party/freetype/README.chromium
+++ b/third_party/freetype/README.chromium
@@ -1,7 +1,7 @@
 Name: FreeType
 URL: http://www.freetype.org/
-Version: VER-2-10-0-71-ga41e560b2
-Revision: a41e560b213d72f36c37b7b25960839de7d29fd0
+Version: VER-2-10-0-72-g81445c034
+Revision: 81445c034aca36040b6311dc71a2cbed9548b262
 License: Custom license "inspired by the BSD, Artistic, and IJG (Independent
          JPEG Group) licenses"
 License File: src/docs/FTL.TXT
diff --git a/tools/android/customtabs_benchmark/java/src/org/chromium/customtabs/test/MainActivity.java b/tools/android/customtabs_benchmark/java/src/org/chromium/customtabs/test/MainActivity.java
index 4bb10e3..c529a24 100644
--- a/tools/android/customtabs_benchmark/java/src/org/chromium/customtabs/test/MainActivity.java
+++ b/tools/android/customtabs_benchmark/java/src/org/chromium/customtabs/test/MainActivity.java
@@ -45,6 +45,7 @@
  */
 public class MainActivity extends Activity implements View.OnClickListener {
     static final String TAG = "CUSTOMTABSBENCH";
+    static final String TAGCSV = "CUSTOMTABSBENCHCSV";
     private static final String MEMORY_TAG = "CUSTOMTABSMEMORY";
     private static final String DEFAULT_URL = "https://www.android.com";
     private static final String DEFAULT_PACKAGE = "com.google.android.apps.chrome";
@@ -108,14 +109,14 @@
     private void setUpUi() {
         setContentView(R.layout.main);
 
-        mUrlEditText = (EditText) findViewById(R.id.url_text);
-        mChromeRadioButton = (RadioButton) findViewById(R.id.radio_chrome);
-        mWebViewRadioButton = (RadioButton) findViewById(R.id.radio_webview);
-        mWarmupCheckbox = (CheckBox) findViewById(R.id.warmup_checkbox);
-        mParallelUrlCheckBox = (CheckBox) findViewById(R.id.parallel_url_checkbox);
-        mParallelUrlEditText = (EditText) findViewById(R.id.parallel_url_text);
+        mUrlEditText = findViewById(R.id.url_text);
+        mChromeRadioButton = findViewById(R.id.radio_chrome);
+        mWebViewRadioButton = findViewById(R.id.radio_webview);
+        mWarmupCheckbox = findViewById(R.id.warmup_checkbox);
+        mParallelUrlCheckBox = findViewById(R.id.parallel_url_checkbox);
+        mParallelUrlEditText = findViewById(R.id.parallel_url_text);
 
-        Button goButton = (Button) findViewById(R.id.go_button);
+        Button goButton = findViewById(R.id.go_button);
 
         mUrlEditText.setOnClickListener(this);
         mChromeRadioButton.setOnClickListener(this);
@@ -386,12 +387,12 @@
                     + mSpeculationMode + "," + mDelayToMayLaunchUrl + "," + mDelayToLaunchUrl + ","
                     + mIntentSentMs + "," + mPageLoadStartedMs + "," + mPageLoadFinishedMs + ","
                     + mFirstContentfulPaintMs;
-            Log.w(TAG, logLine);
+            Log.w(TAGCSV, logLine);
             logMemory(mPackageName, "AfterMetrics");
             MainActivity.this.finish();
         }
 
-        /** Same as {@link logMetricsAndFinish()} with a set delay in ms. */
+        /** Same as {@link #logMetricsAndFinish()} with a set delay in ms. */
         public void logMetricsAndFinishDelayed(int delayMs) {
             mHandler.postDelayed(new Runnable() {
                 @Override
@@ -406,8 +407,8 @@
      * Sums all the memory usage of a package, and returns (PSS, Private Dirty).
      *
      * Only works for packages where a service is exported by each process, which is the case for
-     * Chrome. Also, doesn't work on O and above, as {@link ActivityManager.getRunningServices} is
-     * restricted.
+     * Chrome. Also, doesn't work on O and above, as
+     * {@link ActivityManager#getRunningServices(int)}} is restricted.
      *
      * @param context Application context
      * @param packageName the package to query
@@ -457,7 +458,7 @@
         params.putBoolean("ignoreFragments", true);
         params.putBoolean("prerender", true);
 
-        int speculationModeValue = 0;
+        int speculationModeValue;
         switch (speculationMode) {
             case "disabled":
                 speculationModeValue = NO_SPECULATION;
diff --git a/tools/android/customtabs_benchmark/scripts/customtabs_benchmark.py b/tools/android/customtabs_benchmark/scripts/customtabs_benchmark.py
index b5a3afe..d9a161fe 100755
--- a/tools/android/customtabs_benchmark/scripts/customtabs_benchmark.py
+++ b/tools/android/customtabs_benchmark/scripts/customtabs_benchmark.py
@@ -90,7 +90,7 @@
                 'delay_to_may_launch_url': delay_to_may_launch_url,
                 'delay_to_launch_url': delay_to_launch_url,
                 'timeout': timeout_s})
-    result_line_re = re.compile(r'CUSTOMTABSBENCH.*: (.*)')
+    result_line_re = re.compile(r'CUSTOMTABSBENCHCSV.*: (.*)')
     logcat_monitor = device.GetLogcatMonitor(clear=True)
     logcat_monitor.Start()
     device.ForceStop(_CHROME_PACKAGE)
diff --git a/tools/clang/scripts/build.py b/tools/clang/scripts/build.py
index 23b7610a..f2ffbb4 100755
--- a/tools/clang/scripts/build.py
+++ b/tools/clang/scripts/build.py
@@ -370,7 +370,12 @@
   if args.skip_build:
     return 0
 
-  cc, cxx = None, None
+  # The variable "lld" is only used on Windows because only there does setting
+  # CMAKE_LINKER have an effect: On Windows, the linker is called directly,
+  # while elsewhere it's called through the compiler driver, and we pass
+  # -fuse-ld=lld there to make the compiler driver call the linker (by setting
+  # LLVM_ENABLE_LLD).
+  cc, cxx, lld = None, None, None
 
   cflags = []
   cxxflags = []
@@ -430,9 +435,7 @@
     if args.pgo:
       # Need libclang_rt.profile
       projects += ';compiler-rt'
-    if (sys.platform.startswith('linux') and args.pgo) or args.lto_lld:
-      # Old gnu ld doesn't handle libclang_rt.profile well.
-      # TODO(crbug.com/958852): Always use lld for later stages.
+    if sys.platform != 'darwin' or args.lto_lld:
       projects += ';lld'
     if sys.platform == 'darwin':
       # Need libc++ and compiler-rt for the bootstrap compiler on mac.
@@ -469,6 +472,7 @@
           ])
     if cc is not None:  bootstrap_args.append('-DCMAKE_C_COMPILER=' + cc)
     if cxx is not None: bootstrap_args.append('-DCMAKE_CXX_COMPILER=' + cxx)
+    if lld is not None: bootstrap_args.append('-DCMAKE_LINKER=' + lld)
     RunCommand(['cmake'] + bootstrap_args + [os.path.join(LLVM_DIR, 'llvm')],
                msvc_arch='x64')
     RunCommand(['ninja'], msvc_arch='x64')
@@ -481,13 +485,17 @@
     if sys.platform == 'win32':
       cc = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'clang-cl.exe')
       cxx = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'clang-cl.exe')
+      lld = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'lld-link.exe')
       # CMake has a hard time with backslashes in compiler paths:
       # https://stackoverflow.com/questions/13050827
       cc = cc.replace('\\', '/')
       cxx = cxx.replace('\\', '/')
+      lld = lld.replace('\\', '/')
     else:
       cc = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'clang')
       cxx = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'clang++')
+    if sys.platform.startswith('linux'):
+      base_cmake_args.append('-DLLVM_ENABLE_LLD=ON')
 
     print('Bootstrap compiler installed.')
 
@@ -507,16 +515,13 @@
         '-DLLVM_ENABLE_PROJECTS=' + projects,
         '-DCMAKE_C_FLAGS=' + ' '.join(cflags),
         '-DCMAKE_CXX_FLAGS=' + ' '.join(cxxflags),
-        # Build with the bootstrap compiler.
-        '-DCMAKE_C_COMPILER=' + cc,
-        '-DCMAKE_CXX_COMPILER=' + cxx,
         # Build with instrumentation.
         '-DLLVM_BUILD_INSTRUMENTED=IR',
         ]
-
-    if sys.platform.startswith('linux'):
-      # Ubuntu 16's ld doesn't generate __start__ section, so link with lld.
-      instrument_args.append('-DLLVM_ENABLE_LLD=ON')
+    # Build with the bootstrap compiler.
+    if cc is not None:  instrument_args.append('-DCMAKE_C_COMPILER=' + cc)
+    if cxx is not None: instrument_args.append('-DCMAKE_CXX_COMPILER=' + cxx)
+    if lld is not None: instrument_args.append('-DCMAKE_LINKER=' + lld)
 
     RunCommand(['cmake'] + instrument_args + [os.path.join(LLVM_DIR, 'llvm')],
                msvc_arch='x64')
@@ -557,8 +562,6 @@
                                        '*.profraw')), msvc_arch='x64')
     print('Profile generated.')
 
-
-
   compiler_rt_args = [
     "-DCOMPILER_RT_BUILD_CRT=OFF",
     "-DCOMPILER_RT_BUILD_LIBFUZZER=ON",
@@ -638,6 +641,8 @@
     threads_enabled_cmake_args.append('-DCMAKE_C_COMPILER=' + cc)
   if cxx is not None:
     threads_enabled_cmake_args.append('-DCMAKE_CXX_COMPILER=' + cxx)
+  if lld is not None:
+    threads_enabled_cmake_args.append('-DCMAKE_LINKER=' + lld)
 
   if args.lto_lld:
     # Build lld with LTO. That speeds up the linker by ~10%.
@@ -653,7 +658,7 @@
         '-DCMAKE_AR=' + ar,
         '-DCMAKE_RANLIB=' + ranlib,
         '-DLLVM_ENABLE_LTO=thin',
-        '-DLLVM_USE_LINKER=lld']
+        ]
 
   RunCommand(['cmake'] + threads_enabled_cmake_args +
              [os.path.join(LLVM_DIR, 'llvm')],
@@ -666,6 +671,7 @@
   chrome_tools = list(set(default_tools + args.extra_tools))
   if cc is not None:  base_cmake_args.append('-DCMAKE_C_COMPILER=' + cc)
   if cxx is not None: base_cmake_args.append('-DCMAKE_CXX_COMPILER=' + cxx)
+  if lld is not None: base_cmake_args.append('-DCMAKE_LINKER=' + lld)
   cmake_args = base_cmake_args + compiler_rt_args + [
       '-DLLVM_ENABLE_THREADS=OFF',
       '-DCMAKE_C_FLAGS=' + ' '.join(cflags),
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py
index 8aa83b1..0d207dc 100755
--- a/tools/clang/scripts/update.py
+++ b/tools/clang/scripts/update.py
@@ -39,7 +39,7 @@
 # Reverting problematic clang rolls is safe, though.
 CLANG_REVISION = 'd874c057bc2361da5157553e1e2178f43c3ade1a'
 CLANG_SVN_REVISION = '363790'
-CLANG_SUB_REVISION = 2
+CLANG_SUB_REVISION = 3
 
 PACKAGE_VERSION = '%s-%s-%s' % (CLANG_SVN_REVISION, CLANG_REVISION[:8],
                                 CLANG_SUB_REVISION)
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index acd243f..ef1fd13 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -59826,6 +59826,7 @@
   <int value="8" label="InstallManagerDestroyed"/>
   <int value="9" label="WindowOpened"/>
   <int value="10" label="NotValidManifestForWebApp"/>
+  <int value="11" label="IntentToPlayStore"/>
 </enum>
 
 <enum name="WebAppInstallSource">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index d14c8832..1103684 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -1860,7 +1860,7 @@
 </histogram>
 
 <histogram name="Android.Download.InfoBar.CloseButtonClicked"
-    enum="DownloadInfoBarState" expires_after="M77">
+    enum="DownloadInfoBarState" expires_after="M85">
   <owner>shaktisahu@chromium.org</owner>
   <summary>
     Records the state of the download infobar when the user taps on the
@@ -2149,6 +2149,9 @@
 
 <histogram name="Android.DownloadManager.ShowStorageInfo" enum="BooleanVisible"
     expires_after="M77">
+  <obsolete>
+    Deprecated 06/2016 with code removal of download home V1 to follow.
+  </obsolete>
   <owner>shaktisahu@chromium.org</owner>
   <owner>clank-downloads@google.com</owner>
   <summary>
@@ -29706,7 +29709,9 @@
 </histogram>
 
 <histogram name="Download.HttpResponseCode" enum="HttpResponseCode"
-    expires_after="M77">
+    expires_after="never">
+<!-- expires-never: Used to monitor download system health. -->
+
   <owner>xingliu@chromium.org</owner>
   <summary>The count of HTTP Response codes for download requests.</summary>
 </histogram>
@@ -30376,8 +30381,9 @@
   </summary>
 </histogram>
 
-<histogram name="Download.Service.Files.Cleanup.Attempts" units="attempts"
-    expires_after="M77">
+<histogram name="Download.Service.Files.Cleanup.Attempts" units="attempts">
+<!-- expires-never: Used for monitoring background download system stability. -->
+
   <owner>shaktisahu@chromium.org</owner>
   <summary>
     The number of times download service tried to delete the download file
@@ -30499,7 +30505,9 @@
 </histogram>
 
 <histogram name="Download.Service.OnUploadDataReceived.PauseReason"
-    enum="Download.Service.PauseReason" expires_after="M77">
+    enum="Download.Service.PauseReason">
+<!-- expires-never: Used for detecting anomalies in background download service. -->
+
   <owner>shaktisahu@chromium.org</owner>
   <summary>
     The reason for suspending a download right after the upload data is received
@@ -30509,7 +30517,9 @@
 </histogram>
 
 <histogram name="Download.Service.PauseReason"
-    enum="Download.Service.PauseReason" expires_after="M77">
+    enum="Download.Service.PauseReason">
+<!-- expires-never: Used for detecting anomalies in background download service. -->
+
   <owner>shaktisahu@chromium.org</owner>
   <summary>
     The reason for pausing an in-progress download. Every pause will result in
@@ -37531,7 +37541,7 @@
 </histogram>
 
 <histogram name="Extensions.AppTabLaunchType" enum="ExtensionLaunchType"
-    expires_after="M77">
+    expires_after="M90">
   <owner>benwells@chromium.org</owner>
   <owner>tapted@chromium.org</owner>
   <summary>
@@ -37693,6 +37703,9 @@
 
 <histogram name="Extensions.BookmarkApp.GetAppForCurrentURLDuration" units="ms"
     expires_after="M77">
+  <obsolete>
+    Removed 2019/05 as PWA link capturing has been removed.
+  </obsolete>
   <owner>mgiuca@chromium.org</owner>
   <owner>ortuno@chromium.org</owner>
   <summary>
@@ -37702,6 +37715,9 @@
 
 <histogram name="Extensions.BookmarkApp.GetAppForWindowDuration" units="ms"
     expires_after="M77">
+  <obsolete>
+    Removed 2019/05 as PWA link capturing has been removed.
+  </obsolete>
   <owner>mgiuca@chromium.org</owner>
   <owner>ortuno@chromium.org</owner>
   <summary>
@@ -37712,6 +37728,9 @@
 
 <histogram name="Extensions.BookmarkApp.GetTargetAppDuration" units="ms"
     expires_after="M77">
+  <obsolete>
+    Removed 2019/05 as PWA link capturing has been removed.
+  </obsolete>
   <owner>mgiuca@chromium.org</owner>
   <owner>ortuno@chromium.org</owner>
   <summary>
@@ -37747,6 +37766,9 @@
 
 <histogram name="Extensions.BookmarkApp.NavigationResult"
     enum="BookmarkAppNavigationResult" expires_after="M77">
+  <obsolete>
+    Removed 2019/05 as PWA link capturing has been removed.
+  </obsolete>
   <owner>mgiuca@chromium.org</owner>
   <owner>ortuno@chromium.org</owner>
   <summary>
@@ -37757,6 +37779,9 @@
 
 <histogram name="Extensions.BookmarkApp.TimeBetweenOpenAppAndLastNavigation"
     units="ms">
+  <obsolete>
+    Removed 2019/05 as PWA link capturing has been removed.
+  </obsolete>
   <owner>mgiuca@chromium.org</owner>
   <owner>ortuno@chromium.org</owner>
   <summary>
@@ -37767,7 +37792,7 @@
 </histogram>
 
 <histogram name="Extensions.BookmarkAppLaunchContainer"
-    enum="AppLaunchContainer" expires_after="M77">
+    enum="AppLaunchContainer" expires_after="M90">
   <owner>benwells@chromium.org</owner>
   <summary>Records the container used for a bookmark app launch.</summary>
 </histogram>
@@ -98353,6 +98378,9 @@
 
 <histogram name="Plugin.EnabledStatusMigrationDone" enum="Boolean"
     expires_after="M77">
+  <obsolete>
+    Deprecated as of 06/2019 (M77).
+  </obsolete>
   <owner>pastarmovj@chromium.org</owner>
   <owner>tommycli@chromium.org</owner>
   <summary>Tracks whether plugins that were disabled were migrated.</summary>
diff --git a/ui/file_manager/file_manager/foreground/css/drive_welcome.css b/ui/file_manager/file_manager/foreground/css/drive_welcome.css
index 0fd1317..25a29fcd 100644
--- a/ui/file_manager/file_manager/foreground/css/drive_welcome.css
+++ b/ui/file_manager/file_manager/foreground/css/drive_welcome.css
@@ -80,10 +80,6 @@
   font-size: 16px;
 }
 
-.drive-welcome.header .drive-welcome-dismiss {
-  display: none;
-}
-
 .drive-welcome.header .drive-welcome-links {
   z-index: 1;
 }
@@ -193,10 +189,6 @@
   margin-bottom: 24px;
 }
 
-.drive-welcome.page .drive-welcome-dismiss {
-  margin-left: 20px;
-}
-
 .drive-welcome.page .drive-welcome-links {
   display: flex;
   flex-direction: row;
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 59bb9e3..144541e 100644
--- a/ui/file_manager/file_manager/foreground/css/file_manager.css
+++ b/ui/file_manager/file_manager/foreground/css/file_manager.css
@@ -1152,6 +1152,7 @@
   background: -webkit-image-set(
       url(../images/files/ui/close_button_white.png) 1x,
       url(../images/files/ui/2x/close_button_white.png) 2x) no-repeat center;
+  border: 0;
   cursor: pointer;
   display: inline-block;
   height: 40px;
diff --git a/ui/file_manager/file_manager/foreground/elements/files_xf_elements.css b/ui/file_manager/file_manager/foreground/elements/files_xf_elements.css
index f62fcc221..f392a20 100644
--- a/ui/file_manager/file_manager/foreground/elements/files_xf_elements.css
+++ b/ui/file_manager/file_manager/foreground/elements/files_xf_elements.css
@@ -7,13 +7,19 @@
     max-width: 400px;
 }
 
+.feedback-panels {
+    align-items: flex-end;
+    display: flex;
+    flex-direction: column;
+}
+
 .xf-panel-item {
     align-items: center;
     background-color: #FFF;
     display: flex;
     flex-direction: row;
-    height: 68px;
     max-width: 400px;
+    min-height: 68px;
 }
 
 .xf-button {
@@ -51,6 +57,10 @@
     width: 24px;
 }
 
+.xf-vertical-padder-8 {
+    height: 8px;
+}
+
 xf-circular-progress {
     padding: 16px;
 }
diff --git a/ui/file_manager/file_manager/foreground/elements/xf_button.js b/ui/file_manager/file_manager/foreground/elements/xf_button.js
index d4818d7..841dc260 100644
--- a/ui/file_manager/file_manager/foreground/elements/xf_button.js
+++ b/ui/file_manager/file_manager/foreground/elements/xf_button.js
@@ -69,11 +69,11 @@
               }
 
               :host([data-category='expand']) {
-                  animation: setexpand 1s forwards;
+                  animation: setexpand 150ms forwards;
               }
 
               :host([data-category='collapse']) {
-                  animation: setcollapse 1s forwards;
+                  animation: setcollapse 150ms forwards;
               }
             </style>
             <button>
diff --git a/ui/file_manager/file_manager/foreground/elements/xf_display_panel.js b/ui/file_manager/file_manager/foreground/elements/xf_display_panel.js
index 219d52ac..580beff 100644
--- a/ui/file_manager/file_manager/foreground/elements/xf_display_panel.js
+++ b/ui/file_manager/file_manager/foreground/elements/xf_display_panel.js
@@ -18,6 +18,9 @@
     /** @private {?Element} */
     this.panels_ = this.shadowRoot.querySelector('#panels');
 
+    /** @private {!function(!Event)} */
+    this.listener_;
+
     /**
      * True if the panel is not visible.
      * @type {boolean}
@@ -74,9 +77,62 @@
                 background-color: rgba(60, 64, 67, 0.15);
                 height: 1px;
               }
+              /* Limit to 3 visible progress panels before scroll */
               #panels {
-                  max-height: 204px;
-                  overflow-y: auto;
+                  max-height: calc(92px * 3);
+              }
+              xf-panel-item:not(:only-child) {
+                --multi-progress-height: 92px;
+              }
+              @keyframes setcollapse {
+                0% {
+                  max-height: 0;
+                  max-width: 0;
+                  opacity: 0;
+                }
+                75% {
+                  max-height: calc(92px * 3);;
+                  max-width: 400px;
+                  opacity: 0;
+                }
+                100% {
+                  max-height: calc(92px * 3);;
+                  max-width: 400px;
+                  opacity: 1;
+                }
+              }
+
+              @keyframes setexpand {
+                0% {
+                  max-height: calc(92px * 3);;
+                  max-width: 400px;
+                  opacity: 1;
+                }
+                25% {
+                  max-height: calc(92px * 3);;
+                  max-width: 400px;
+                  opacity: 0;
+                }
+                100% {
+                  max-height: 0;
+                  max-width: 0;
+                  opacity: 0;
+                }
+              }
+              .expanded {
+                animation: setcollapse 200ms forwards;
+              }
+              .collapsed {
+                animation: setexpand 200ms forwards;
+              }
+              .expanding {
+                overflow: hidden;
+              }
+              .expandfinished {
+                overflow-y: auto;
+              }
+              xf-panel-item:not(:only-child) {
+                --multi-progress-height: 92px;
               }
             </style>
             <div id="container">
@@ -87,6 +143,27 @@
   }
 
   /**
+   * Re-enable scrollbar visibility after expand/contract animation.
+   * @param {!Event} event
+   */
+  panelExpandFinished(event) {
+    this.classList.remove('expanding');
+    this.classList.add('expandfinished');
+    this.removeEventListener('animationend', this.listener_);
+  }
+
+  /**
+   * Hides the active panel items at end of collapse animation.
+   * @param {!Event} event
+   */
+  panelCollapseFinished(event) {
+    this.hidden = true;
+    this.classList.remove('expanding');
+    this.classList.add('expandfinished');
+    this.removeEventListener('animationend', this.listener_);
+  }
+
+  /**
    * Event handler to toggle the visible state of panel items.
    * @private
    */
@@ -100,11 +177,17 @@
       expandButton.setAttribute('data-category', 'collapse');
       panel.panels_.hidden = false;
       panel.separator_.hidden = false;
+      panel.panels_.listener_ = panel.panelExpandFinished;
+      panel.panels_.addEventListener('animationend', panel.panelExpandFinished);
+      panel.panels_.setAttribute('class', 'expanded expanding');
     } else {
       panel.collapsed_ = true;
       expandButton.setAttribute('data-category', 'expand');
-      panel.panels_.hidden = true;
       panel.separator_.hidden = true;
+      panel.panels_.listener_ = panel.panelCollapseFinished;
+      panel.panels_.addEventListener(
+          'animationend', panel.panelCollapseFinished);
+      panel.panels_.setAttribute('class', 'collapsed expanding');
     }
   }
 
@@ -145,6 +228,9 @@
         button.removeEventListener('click', this.toggleSummary);
       }
       summaryPanel.remove();
+      this.panels_.hidden = false;
+      this.separator_.hidden = true;
+      this.panels_.classList.remove('collapsed');
       return;
     }
     // Show summary panel if there are more than 1 progress panels.
diff --git a/ui/file_manager/file_manager/foreground/elements/xf_panel_item.js b/ui/file_manager/file_manager/foreground/elements/xf_panel_item.js
index 57c6c9e7..5ab026c 100644
--- a/ui/file_manager/file_manager/foreground/elements/xf_panel_item.js
+++ b/ui/file_manager/file_manager/foreground/elements/xf_panel_item.js
@@ -41,23 +41,28 @@
   static get template_() {
     return `<link rel='stylesheet'
               href='foreground/elements/files_xf_elements.css'>
-                <div class='xf-panel-item'>
-                    <xf-circular-progress id='indicator'>
-                    </xf-circular-progress>
-                    <div class='xf-panel-text'>
-                        <span class='xf-panel-label-text'>
-                                Placeholder text
-                        </span>
-                        <br/>
-                    </div>
-                    <div class='xf-padder-24'></div>
-                    <xf-button id='secondary-action' tabindex='-1'>
-                    </xf-button>
-                    <div id='button-gap' class='xf-padder-4'></div>
-                    <xf-button id='primary-action' tabindex='-1'>
-                    </xf-button>
-                    <div class='xf-padder-16'></div>
-                </div>`;
+            <style>
+              :host([panel-type='0']) .xf-panel-item {
+                height: var(--multi-progress-height);
+              }
+            </style>
+            <div class='xf-panel-item'>
+                <xf-circular-progress id='indicator'>
+                </xf-circular-progress>
+                <div class='xf-panel-text'>
+                    <span class='xf-panel-label-text'>
+                            Placeholder text
+                    </span>
+                    <br/>
+                </div>
+                <div class='xf-padder-24'></div>
+                <xf-button id='secondary-action' tabindex='-1'>
+                </xf-button>
+                <div id='button-gap' class='xf-padder-4'></div>
+                <xf-button id='primary-action' tabindex='-1'>
+                </xf-button>
+                <div class='xf-padder-16'></div>
+            </div>`;
   }
 
   /**
diff --git a/ui/file_manager/file_manager/foreground/js/quick_view_controller.js b/ui/file_manager/file_manager/foreground/js/quick_view_controller.js
index 1adb9d42..e52046f2 100644
--- a/ui/file_manager/file_manager/foreground/js/quick_view_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/quick_view_controller.js
@@ -296,12 +296,14 @@
     const item = items[0];
     const typeInfo = FileType.getType(entry);
     const type = typeInfo.type;
+    const locationInfo = this.volumeManager_.getLocationInfo(entry);
+    const label = util.getEntryLabel(locationInfo, entry);
 
     /** @type {!QuickViewParams} */
     const params = {
       type: type,
       subtype: typeInfo.subtype,
-      filePath: entry.name,
+      filePath: label,
       hasTask: tasks.length > 0,
     };
 
diff --git a/ui/file_manager/file_manager/foreground/js/ui/banners.js b/ui/file_manager/file_manager/foreground/js/ui/banners.js
index eeaa760..bbac776 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/banners.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/banners.js
@@ -64,7 +64,6 @@
     this.volumeManager_ = volumeManager;
     this.document_ = assert(document);
     this.showWelcome_ = showWelcome;
-    this.driveEnabled_ = false;
 
     /** @private {boolean} */
     this.previousDirWasOnDrive_ = false;
@@ -214,7 +213,10 @@
       util.createChild(wrapper, 'banner-people');
     }
 
-    const close = util.createChild(wrapper, 'banner-close');
+    const close = util.createChild(wrapper, 'banner-close', 'button');
+    close.setAttribute('aria-label', str('DRIVE_WELCOME_DISMISS'));
+    close.id = 'welcome-dismiss';
+    close.tabIndex = 22;
     close.addEventListener('click', this.closeWelcomeBanner_.bind(this));
 
     const message = util.createChild(wrapper, 'drive-welcome-message');
@@ -234,11 +236,6 @@
     more.id = 'drive-welcome-link';
     more.target = '_blank';
 
-    const dismiss = util.createChild(links, 'plain-link');
-    dismiss.classList.add('drive-welcome-dismiss');
-    dismiss.textContent = str('DRIVE_WELCOME_DISMISS');
-    dismiss.addEventListener('click', this.closeWelcomeBanner_.bind(this));
-
     this.previousDirWasOnDrive_ = false;
   }
 
@@ -298,17 +295,19 @@
       link.appendChild(button);
       box.appendChild(link);
 
-      const close = this.document_.createElement('div');
+      const close = this.document_.createElement('button');
+      close.setAttribute('aria-label', str('DRIVE_WELCOME_DISMISS'));
+      close.id = 'welcome-dismiss';
       close.className = 'banner-close';
       box.appendChild(close);
-      close.addEventListener('click', ((total) => {
-                                        const values = {};
-                                        values[DRIVE_WARNING_DISMISSED_KEY] =
-                                            total;
-                                        chrome.storage.local.set(values);
-                                        box.hidden = true;
-                                        this.requestRelayout_(100);
-                                      }).bind(null, opt_sizeStats.totalSize));
+      const totalSize = opt_sizeStats.totalSize;
+      close.addEventListener('click', () => {
+        const values = {};
+        values[DRIVE_WARNING_DISMISSED_KEY] = totalSize;
+        chrome.storage.local.set(values);
+        box.hidden = true;
+        this.requestRelayout_(100);
+      });
     }
 
     if (box.hidden != !show) {
@@ -604,9 +603,10 @@
         e.preventDefault();
       });
 
-      const close = this.document_.createElement('div');
+      const close = this.document_.createElement('button');
       close.className = 'banner-close';
-      close.tabIndex = 0;
+      close.setAttribute('aria-label', str('DRIVE_WELCOME_DISMISS'));
+      close.id = 'welcome-dismiss';
       box.appendChild(close);
       close.addEventListener('click', () => {
         const values = {};
diff --git a/ui/file_manager/file_manager/main.html b/ui/file_manager/file_manager/main.html
index 53fb04a6..2775f53 100644
--- a/ui/file_manager/file_manager/main.html
+++ b/ui/file_manager/file_manager/main.html
@@ -562,6 +562,7 @@
     <div class="feedback-panels">
       <xf-display-panel id="completed-panel">
       </xf-display-panel>
+      <div class="xf-vertical-padder-8"></div>
       <xf-display-panel id="progress-panel">
       </xf-display-panel>
     </div>
diff --git a/ui/file_manager/file_manager/manifest.json b/ui/file_manager/file_manager/manifest.json
index 207ad4e..73a01ff 100644
--- a/ui/file_manager/file_manager/manifest.json
+++ b/ui/file_manager/file_manager/manifest.json
@@ -135,8 +135,6 @@
   // enough that anything is passed to web_accessible_resources. If there is
   // at least any file, then all files are allowed. http://crbug.com/179127.
   "web_accessible_resources": [
-    "foreground/elements/files_format_dialog.html",
-    "foreground/elements/files_format_dialog.js",
     "foreground/elements/files_icon_button.html",
     "foreground/elements/files_icon_button.js",
     "foreground/elements/files_ripple.html",
diff --git a/ui/file_manager/integration_tests/file_manager/tab_index.js b/ui/file_manager/integration_tests/file_manager/tab_index.js
index 736e9cac..af285c9 100644
--- a/ui/file_manager/integration_tests/file_manager/tab_index.js
+++ b/ui/file_manager/integration_tests/file_manager/tab_index.js
@@ -59,6 +59,8 @@
   chrome.test.assertTrue(
       await remoteCall.checkNextTabFocus(appId, 'drive-welcome-link'));
   chrome.test.assertTrue(
+      await remoteCall.checkNextTabFocus(appId, 'welcome-dismiss'));
+  chrome.test.assertTrue(
       await remoteCall.checkNextTabFocus(appId, 'file-list'));
 };
 
@@ -163,6 +165,8 @@
   chrome.test.assertTrue(
       await remoteCall.checkNextTabFocus(appId, 'drive-welcome-link'));
   chrome.test.assertTrue(
+      await remoteCall.checkNextTabFocus(appId, 'welcome-dismiss'));
+  chrome.test.assertTrue(
       await remoteCall.checkNextTabFocus(appId, 'file-list'));
 };
 
diff --git a/ui/gfx/image/canvas_image_source.cc b/ui/gfx/image/canvas_image_source.cc
index f0768ed..a5c8177 100644
--- a/ui/gfx/image/canvas_image_source.cc
+++ b/ui/gfx/image/canvas_image_source.cc
@@ -21,8 +21,7 @@
  public:
   PaddedImageSource(const ImageSkia& image, const Insets& insets)
       : CanvasImageSource(Size(image.width() + insets.width(),
-                               image.height() + insets.height()),
-                          false),
+                               image.height() + insets.height())),
         image_(image),
         insets_(insets) {}
 
@@ -49,8 +48,7 @@
   return MakeImageSkia<PaddedImageSource>(image, insets);
 }
 
-CanvasImageSource::CanvasImageSource(const Size& size, bool is_opaque)
-    : size_(size), is_opaque_(is_opaque) {}
+CanvasImageSource::CanvasImageSource(const Size& size) : size_(size) {}
 
 ImageSkiaRep CanvasImageSource::GetImageForScale(float scale) {
   scoped_refptr<cc::DisplayItemList> display_item_list =
diff --git a/ui/gfx/image/canvas_image_source.h b/ui/gfx/image/canvas_image_source.h
index bde35a0..e95b3aea 100644
--- a/ui/gfx/image/canvas_image_source.h
+++ b/ui/gfx/image/canvas_image_source.h
@@ -38,7 +38,7 @@
   // edges as specified by |insets|.
   static ImageSkia CreatePadded(const ImageSkia& image, const Insets& insets);
 
-  CanvasImageSource(const Size& size, bool is_opaque);
+  explicit CanvasImageSource(const Size& size);
   ~CanvasImageSource() override {}
 
   // Called when a new image needs to be drawn for a scale factor.
@@ -52,7 +52,6 @@
 
  protected:
   const Size size_;
-  const bool is_opaque_;
   DISALLOW_COPY_AND_ASSIGN(CanvasImageSource);
 };
 
diff --git a/ui/gfx/image/image_skia_operations.cc b/ui/gfx/image/image_skia_operations.cc
index bb5fa62..a190ece 100644
--- a/ui/gfx/image/image_skia_operations.cc
+++ b/ui/gfx/image/image_skia_operations.cc
@@ -132,12 +132,8 @@
 
 class SuperimposedImageSource : public gfx::CanvasImageSource {
  public:
-  SuperimposedImageSource(const ImageSkia& first,
-                          const ImageSkia& second)
-      : gfx::CanvasImageSource(first.size(), false /* is opaque */),
-        first_(first),
-        second_(second) {
-  }
+  SuperimposedImageSource(const ImageSkia& first, const ImageSkia& second)
+      : gfx::CanvasImageSource(first.size()), first_(first), second_(second) {}
 
   ~SuperimposedImageSource() override {}
 
@@ -400,7 +396,7 @@
  public:
   HorizontalShadowSource(const std::vector<ShadowValue>& shadows,
                          bool fades_down)
-      : CanvasImageSource(Size(1, GetHeightForShadows(shadows)), false),
+      : CanvasImageSource(Size(1, GetHeightForShadows(shadows))),
         shadows_(shadows),
         fades_down_(fades_down) {}
   ~HorizontalShadowSource() override {}
@@ -458,9 +454,7 @@
 class IconWithBadgeSource : public gfx::CanvasImageSource {
  public:
   IconWithBadgeSource(const ImageSkia& icon, const ImageSkia& badge)
-      : gfx::CanvasImageSource(icon.size(), false /* is opaque */),
-        icon_(icon),
-        badge_(badge) {}
+      : gfx::CanvasImageSource(icon.size()), icon_(icon), badge_(badge) {}
 
   ~IconWithBadgeSource() override {}
 
diff --git a/ui/gfx/paint_vector_icon.cc b/ui/gfx/paint_vector_icon.cc
index d6b4b83..7de3547 100644
--- a/ui/gfx/paint_vector_icon.cc
+++ b/ui/gfx/paint_vector_icon.cc
@@ -481,11 +481,10 @@
 class VectorIconSource : public CanvasImageSource {
  public:
   explicit VectorIconSource(const IconDescription& data)
-      : CanvasImageSource(Size(data.dip_size, data.dip_size), false),
-        data_(data) {}
+      : CanvasImageSource(Size(data.dip_size, data.dip_size)), data_(data) {}
 
   VectorIconSource(const std::string& definition, int dip_size, SkColor color)
-      : CanvasImageSource(Size(dip_size, dip_size), false),
+      : CanvasImageSource(Size(dip_size, dip_size)),
         data_(kNoneIcon, dip_size, color, base::TimeDelta(), kNoneIcon),
         path_(PathFromSource(definition)) {}
 
diff --git a/ui/gfx/shadow_util.cc b/ui/gfx/shadow_util.cc
index 10fc06b..a2f35f0 100644
--- a/ui/gfx/shadow_util.cc
+++ b/ui/gfx/shadow_util.cc
@@ -28,7 +28,7 @@
  public:
   ShadowNineboxSource(const std::vector<ShadowValue>& shadows,
                       float corner_radius)
-      : CanvasImageSource(CalculateSize(shadows, corner_radius), false),
+      : CanvasImageSource(CalculateSize(shadows, corner_radius)),
         shadows_(shadows),
         corner_radius_(corner_radius) {
     DCHECK(!shadows.empty());
diff --git a/ui/views/bubble/bubble_frame_view.cc b/ui/views/bubble/bubble_frame_view.cc
index 908bf7dd..ee06e57 100644
--- a/ui/views/bubble/bubble_frame_view.cc
+++ b/ui/views/bubble/bubble_frame_view.cc
@@ -456,7 +456,7 @@
   DCHECK(!footnote_container_);
   int radius = bubble_border_ ? bubble_border_->corner_radius() : 0;
   footnote_container_ = AddChildView(std::make_unique<FootnoteContainerView>(
-      footnote_margins_, view.release(), radius));
+      footnote_margins_, std::move(view), radius));
 }
 
 void BubbleFrameView::SetCornerRadius(int radius) {
diff --git a/ui/views/bubble/footnote_container_view.cc b/ui/views/bubble/footnote_container_view.cc
index 5fec2842..b4ab1985 100644
--- a/ui/views/bubble/footnote_container_view.cc
+++ b/ui/views/bubble/footnote_container_view.cc
@@ -49,7 +49,7 @@
 }  // namespace
 
 FootnoteContainerView::FootnoteContainerView(const gfx::Insets& margins,
-                                             View* child_view,
+                                             std::unique_ptr<View> child_view,
                                              float corner_radius) {
   SetLayoutManager(
       std::make_unique<BoxLayout>(BoxLayout::kVertical, margins, 0));
@@ -58,8 +58,8 @@
                                    GetNativeTheme()->SystemDarkModeEnabled()
                                        ? gfx::kGoogleGrey900
                                        : gfx::kGoogleGrey200));
-  AddChildView(child_view);
-  SetVisible(child_view->GetVisible());
+  auto* child_view_ptr = AddChildView(std::move(child_view));
+  SetVisible(child_view_ptr->GetVisible());
 }
 
 FootnoteContainerView::~FootnoteContainerView() = default;
diff --git a/ui/views/bubble/footnote_container_view.h b/ui/views/bubble/footnote_container_view.h
index 40b4c1f..d5d75e93 100644
--- a/ui/views/bubble/footnote_container_view.h
+++ b/ui/views/bubble/footnote_container_view.h
@@ -16,7 +16,7 @@
   METADATA_HEADER(FootnoteContainerView);
 
   FootnoteContainerView(const gfx::Insets& margins,
-                        View* child_view,
+                        std::unique_ptr<View> child_view,
                         float corner_radius);
   ~FootnoteContainerView() override;
 
diff --git a/ui/webui/resources/js/ios/web_ui.js b/ui/webui/resources/js/ios/web_ui.js
index 6377b83..ba821ab7 100644
--- a/ui/webui/resources/js/ios/web_ui.js
+++ b/ui/webui/resources/js/ios/web_ui.js
@@ -12,6 +12,9 @@
  * @param {Array=} args optional.
  */
 window['chrome']['send'] = function(message, args) {
-  __gCrWeb.message.invokeOnHost(
-      {'command': 'chrome.send', 'message': message, 'arguments': args || []});
+  __gCrWeb.message.invokeOnHost({
+    'command': 'webui.chromeSend',
+    'message': message,
+    'arguments': args || []
+  });
 };