diff --git a/AUTHORS b/AUTHORS
index 58e1693..44353195 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1035,6 +1035,7 @@
 Youngsoo Choi <kenshin.choi@samsung.com>
 Youngsun Suh <zard17@gmail.com>
 Yuhong Sha <yuhong.sha@samsung.com>
+Yuki Tsuchiya <Yuki.Tsuchiya@sony.com>
 Yumikiyo Osanai <yumios.art@gmail.com>
 Yunchao He <yunchao.he@intel.com>
 Yupei Lin <yplam@yplam.com>
diff --git a/DEPS b/DEPS
index 7645272..3bafa880 100644
--- a/DEPS
+++ b/DEPS
@@ -181,11 +181,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': 'cedab522227a909f57b270081af6130133b2c70b',
+  'skia_revision': 'd59053987a27c74333073e03fdd5e8f4d4fe2f16',
   # 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': '4cde67a85fd4c29f78551e5aebca1fc8912876e8',
+  'v8_revision': '4a1aaa1a60702682d492fc55b679c7186436e528',
   # 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.
@@ -193,7 +193,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '7f8b6e3fabbd579065944112095ffb69a869316b',
+  'angle_revision': '1eb0ddb4d0c3cf9c85fa4d61d2badf34de58a9e7',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # 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 PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'c3e55aa23f888aaf9334a3fd35c1f49a3179869c',
+  'pdfium_revision': 'a216865467ddf9430fe1207adcd71c2d5318e3bc',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -252,7 +252,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': '564dcf4c071b93382616e9421610aa2ac655a833',
+  'devtools_frontend_revision': '10a4521109796588698cf71e38f0012630bf3415',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -296,7 +296,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'spv_tools_revision': '323a81fc5e30e43a04e5e22af4cba98ca2a161e6',
+  'spv_tools_revision': 'ab7ac60f14ae66006bed5c989a2cfd4c4881704c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -316,7 +316,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'quiche_revision': '57425e34e9f55afe23a1158b59eafc12677f9494',
+  'quiche_revision': 'dfabdfb6884bf8ccd92c6f818aa8764a84f5a984',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ios_webkit
   # and whatever else without interference from each other.
@@ -554,7 +554,7 @@
   },
 
   'src/ios/third_party/material_roboto_font_loader_ios/src': {
-      'url': Var('chromium_git') + '/external/github.com/material-foundation/material-roboto-font-loader-ios.git' + '@' + '4aa51e906e5671c71d24e991f1f10d782a58409f',
+      'url': Var('chromium_git') + '/external/github.com/material-foundation/material-roboto-font-loader-ios.git' + '@' + 'bc63eabbbd1e14cee0779b05827e08db2e413553',
       'condition': 'checkout_ios',
   },
 
@@ -904,7 +904,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'd339e36642df06f0e26f9a5143ce044bf9376b72',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '6a5aa6680ce4da1be7d3a825b33a6f0fe92537d9',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -1501,7 +1501,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'ec18cc3262922e7dcdbe70243c6f40606f979144',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '06df1e1c4655a1048bfeb30e090ab52005f1e841',
+    Var('webrtc_git') + '/src.git' + '@' + '402379f1f35ca472ce1905413c3e0e3a19bc5f9d',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1571,7 +1571,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@6b41dac7d03098e0482bf9cafa84c60683d20372',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@52524c03db2fd246604943d2100578ce18905ae6',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/java/src/org/chromium/android_webview/common/crash/AwCrashReporterClient.java b/android_webview/java/src/org/chromium/android_webview/common/crash/AwCrashReporterClient.java
index b9ddd31d..f513ef2 100644
--- a/android_webview/java/src/org/chromium/android_webview/common/crash/AwCrashReporterClient.java
+++ b/android_webview/java/src/org/chromium/android_webview/common/crash/AwCrashReporterClient.java
@@ -14,6 +14,11 @@
  */
 @JNINamespace("android_webview")
 public class AwCrashReporterClient {
+    // The filename prefix used by GMS proguarding, which we use to recognise
+    // otherwise colliding proguarded class names as belonging to dynamite
+    // modules.
+    private static final String DYNAMITE_PREFIX = ":com.google.android.gms";
+
     /**
      * Determine if a Throwable should be reported to the crash reporting mechanism.
      *
@@ -31,10 +36,15 @@
     public static boolean stackTraceContainsWebViewCode(Throwable t) {
         ClassLoader webViewClassLoader = AwCrashReporterClient.class.getClassLoader();
         for (StackTraceElement frame : t.getStackTrace()) {
+            if (frame.getClassName().startsWith("android.webkit.")) {
+                return true;
+            }
+            if (frame.getFileName().startsWith(DYNAMITE_PREFIX)) {
+                continue;
+            }
             try {
                 Class frameClass = webViewClassLoader.loadClass(frame.getClassName());
-                if (frameClass.getClassLoader() == webViewClassLoader
-                        || frameClass.getPackage().getName().equals("android.webkit")) {
+                if (frameClass.getClassLoader() == webViewClassLoader) {
                     return true;
                 }
             } catch (ClassNotFoundException e) {
diff --git a/android_webview/nonembedded/BUILD.gn b/android_webview/nonembedded/BUILD.gn
index 3b9f820..0df90258 100644
--- a/android_webview/nonembedded/BUILD.gn
+++ b/android_webview/nonembedded/BUILD.gn
@@ -127,6 +127,7 @@
 android_resources("monochrome_devui_launcher_icon_resources") {
   resource_dirs = []
   android_manifest = "java/MonochromeDeveloperUiLauncherManifest.xml"
+  deps = [ ":icon_resources" ]
   custom_package = "org.chromium.android_webview.devui.icon"
 }
 
diff --git a/android_webview/nonembedded/java/MonochromeDeveloperUiLauncherManifest.xml b/android_webview/nonembedded/java/MonochromeDeveloperUiLauncherManifest.xml
index 6d473ffad..814d7a3 100644
--- a/android_webview/nonembedded/java/MonochromeDeveloperUiLauncherManifest.xml
+++ b/android_webview/nonembedded/java/MonochromeDeveloperUiLauncherManifest.xml
@@ -14,6 +14,7 @@
         <activity-alias android:name="org.chromium.android_webview.devui.MonochromeLauncherActivity"
                   android:targetActivity="org.chromium.android_webview.devui.MainActivity"
                   android:label="WebView DevTools"
+                  android:icon="@drawable/icon_webview"
                   android:exported="true"
                   android:enabled="false">
             <intent-filter>
diff --git a/android_webview/nonembedded/java/src/org/chromium/android_webview/devui/util/WebViewPackageHelper.java b/android_webview/nonembedded/java/src/org/chromium/android_webview/devui/util/WebViewPackageHelper.java
index 3ce3852..75376d8 100644
--- a/android_webview/nonembedded/java/src/org/chromium/android_webview/devui/util/WebViewPackageHelper.java
+++ b/android_webview/nonembedded/java/src/org/chromium/android_webview/devui/util/WebViewPackageHelper.java
@@ -120,6 +120,18 @@
         }
     }
 
+    /**
+     * Check if the given context is a WebView package and if it's currently selected as system's
+     * WebView implementation.
+     *
+     * @param context the {@link Context} to check its package.
+     */
+    public static boolean isCurrentSystemWebViewImplementation(Context context) {
+        PackageInfo systemWebViewPackage = getCurrentWebViewPackage(context);
+        if (systemWebViewPackage == null) return false;
+        return context.getPackageName().equals(systemWebViewPackage.packageName);
+    }
+
     // Do not instantiate this class.
     private WebViewPackageHelper() {}
 }
diff --git a/android_webview/nonembedded/java/src/org/chromium/android_webview/nonembedded/WebViewApkApplication.java b/android_webview/nonembedded/java/src/org/chromium/android_webview/nonembedded/WebViewApkApplication.java
index 19e8243..3e598d2 100644
--- a/android_webview/nonembedded/java/src/org/chromium/android_webview/nonembedded/WebViewApkApplication.java
+++ b/android_webview/nonembedded/java/src/org/chromium/android_webview/nonembedded/WebViewApkApplication.java
@@ -5,16 +5,21 @@
 package org.chromium.android_webview.nonembedded;
 
 import android.app.Application;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.pm.PackageManager;
 
 import org.chromium.android_webview.AwLocaleConfig;
 import org.chromium.android_webview.common.CommandLineUtil;
+import org.chromium.android_webview.devui.util.WebViewPackageHelper;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.PathUtils;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.annotations.NativeMethods;
 import org.chromium.base.library_loader.LibraryLoader;
 import org.chromium.base.library_loader.LibraryProcessType;
+import org.chromium.base.task.PostTask;
+import org.chromium.base.task.TaskTraits;
 import org.chromium.components.embedder_support.application.FontPreloadingWorkaround;
 import org.chromium.ui.base.ResourceBundle;
 
@@ -70,6 +75,40 @@
     }
 
     /**
+     * Post a non-blocking, low priority background task that shows a launcher icon for WebView
+     * DevTools if this Monochrome package is the current selected WebView provider for the system
+     * otherwise it hides that icon. This works only for Monochrome and shouldn't be used for other
+     * WebView providers. Other WebView Providers (Standalone and Trichrome) will always have
+     * launcher icons whether they are the current selected providers or not.
+     *
+     * Should be guarded by process type checks and should only be called if it's a webview process
+     * or a browser process.
+     */
+    public static void postDeveloperUiLauncherIconTask() {
+        PostTask.postTask(TaskTraits.BEST_EFFORT, () -> {
+            Context context = ContextUtils.getApplicationContext();
+            try {
+                ComponentName devToolsLauncherActivity = new ComponentName(
+                        context, "org.chromium.android_webview.devui.MonochromeLauncherActivity");
+                if (WebViewPackageHelper.isCurrentSystemWebViewImplementation(context)) {
+                    // Enable the component to show the launcher icon.
+                    context.getPackageManager().setComponentEnabledSetting(devToolsLauncherActivity,
+                            PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+                            PackageManager.DONT_KILL_APP);
+                } else {
+                    // Disable the component to hide the launcher icon.
+                    context.getPackageManager().setComponentEnabledSetting(devToolsLauncherActivity,
+                            PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
+                            PackageManager.DONT_KILL_APP);
+                }
+            } catch (IllegalArgumentException e) {
+                // If MonochromeLauncherActivity doesn't exist, Dynamically showing/hiding DevTools
+                // launcher icon is not enabled in this package; e.g when it is a stable channel.
+            }
+        });
+    }
+
+    /**
      * Performs minimal native library initialization required when running as a stand-alone APK.
      * @return True if the library was loaded, false if running as webview stub.
      */
diff --git a/android_webview/variables.gni b/android_webview/variables.gni
index 20d0cfb..e9910f34 100644
--- a/android_webview/variables.gni
+++ b/android_webview/variables.gni
@@ -7,7 +7,8 @@
 
 declare_args() {
   # Show a launcher icon to open WebView developer UI, enabled by default for dev and canary
-  # channels. The icon for Monochrome is always hidden by default (https://crbug.com/1026062)
+  # channels. The icon for Monochrome is shown dynamically at runtime if Monochrome is the current
+  # selected system WebView implementation or hidden otherwise.
   # TODO(https://crbug.com/1002589): add beta channel when approved
   webview_devui_show_icon =
       android_channel == "canary" || android_channel == "dev"
diff --git a/ash/login/ui/parent_access_view.cc b/ash/login/ui/parent_access_view.cc
index 220fcd1..c8cb2561 100644
--- a/ash/login/ui/parent_access_view.cc
+++ b/ash/login/ui/parent_access_view.cc
@@ -52,6 +52,7 @@
 #include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/controls/textfield/textfield_controller.h"
 #include "ui/views/layout/box_layout.h"
+#include "ui/views/vector_icons.h"
 
 namespace ash {
 
@@ -67,8 +68,11 @@
 constexpr int kParentAccessViewHeightDp = 340;
 constexpr int kParentAccessViewTabletModeHeightDp = 580;
 constexpr int kParentAccessViewRoundedCornerRadiusDp = 8;
-constexpr int kParentAccessViewVerticalInsetDp = 24;
-constexpr int kParentAccessViewHorizontalInsetDp = 36;
+constexpr int kParentAccessViewVerticalInsetDp = 8;
+// Inset for all elements except the back button.
+constexpr int kParentAccessViewMainHorizontalInsetDp = 36;
+// Minimum inset (= back button inset).
+constexpr int kParentAccessViewHorizontalInsetDp = 8;
 
 constexpr int kLockIconSizeDp = 24;
 
@@ -78,7 +82,7 @@
 constexpr int kAccessCodeToPinKeyboardDistanceDp = 5;
 constexpr int kPinKeyboardToFooterDistanceDp = 57;
 constexpr int kPinKeyboardToFooterTabletModeDistanceDp = 17;
-constexpr int kSubmitButtonBottomMarginDp = 8;
+constexpr int kSubmitButtonBottomMarginDp = 28;
 
 constexpr int kTitleFontSizeDeltaDp = 3;
 constexpr int kDescriptionFontSizeDeltaDp = -1;
@@ -90,7 +94,9 @@
 constexpr int kAccessCodeBetweenInputFieldsGapDp = 4;
 
 constexpr int kArrowButtonSizeDp = 48;
-constexpr int kArrowSizeDp = 20;
+
+constexpr int kCrossSizeDp = 20;
+constexpr int kBackButtonSizeDp = 36;
 
 constexpr int kAlpha70Percent = 178;
 constexpr int kAlpha74Percent = 189;
@@ -600,25 +606,29 @@
   layer()->SetBackgroundBlur(ShelfConfig::Get()->shelf_blur_radius());
 
   const int child_view_width =
-      kParentAccessViewWidthDp - 2 * kParentAccessViewHorizontalInsetDp;
+      kParentAccessViewWidthDp - 2 * kParentAccessViewMainHorizontalInsetDp;
 
-  // Header view contains back button that is aligned to its start.
+  // Header view contains back button that is aligned to its end.
   auto header_layout = std::make_unique<views::BoxLayout>(
       views::BoxLayout::Orientation::kHorizontal, gfx::Insets(), 0);
   header_layout->set_main_axis_alignment(
-      views::BoxLayout::MainAxisAlignment::kStart);
+      views::BoxLayout::MainAxisAlignment::kEnd);
   auto* header = new NonAccessibleView();
-  header->SetPreferredSize(gfx::Size(child_view_width, 0));
+  header->SetPreferredSize(
+      gfx::Size(child_view_width + 2 * (kParentAccessViewMainHorizontalInsetDp -
+                                        kParentAccessViewHorizontalInsetDp),
+                0));
   header->SetLayoutManager(std::move(header_layout));
   AddChildView(header);
 
   back_button_ = new LoginButton(this);
-  back_button_->SetPreferredSize(gfx::Size(kArrowSizeDp, kArrowSizeDp));
+  back_button_->SetPreferredSize(
+      gfx::Size(kBackButtonSizeDp, kBackButtonSizeDp));
   back_button_->SetBackground(
       views::CreateSolidBackground(SK_ColorTRANSPARENT));
-  back_button_->SetImage(views::Button::STATE_NORMAL,
-                         gfx::CreateVectorIcon(kLockScreenArrowBackIcon,
-                                               kArrowSizeDp, SK_ColorWHITE));
+  back_button_->SetImage(
+      views::Button::STATE_NORMAL,
+      gfx::CreateVectorIcon(views::kIcCloseIcon, kCrossSizeDp, SK_ColorWHITE));
   back_button_->SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER);
   back_button_->SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
   back_button_->SetAccessibleName(
diff --git a/ash/public/cpp/app_list/app_list_types.h b/ash/public/cpp/app_list/app_list_types.h
index fc45947..b80200a6f 100644
--- a/ash/public/cpp/app_list/app_list_types.h
+++ b/ash/public/cpp/app_list/app_list_types.h
@@ -145,6 +145,8 @@
   kArcAppShortcut,         // ARC++ app shortcuts.
   kZeroStateFile,          // Zero state local file results.
   kDriveQuickAccess,       // Drive QuickAccess results.
+  kFileChip,               // Local file results in suggestion chips.
+  kDriveQuickAccessChip,   // Drive file results in suggestion chips.
   // Add new values here.
 };
 
diff --git a/ash/system/accessibility/autoclick_menu_bubble_controller.cc b/ash/system/accessibility/autoclick_menu_bubble_controller.cc
index d0424c0..076ca5c8 100644
--- a/ash/system/accessibility/autoclick_menu_bubble_controller.cc
+++ b/ash/system/accessibility/autoclick_menu_bubble_controller.cc
@@ -4,6 +4,7 @@
 
 #include "ash/system/accessibility/autoclick_menu_bubble_controller.h"
 
+#include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shell.h"
@@ -224,16 +225,15 @@
   init_params.max_width = kAutoclickMenuWidth;
   init_params.corner_radius = kUnifiedTrayCornerRadius;
   init_params.has_shadow = false;
-  init_params.translucent = true;
   bubble_view_ = new AutoclickMenuBubbleView(init_params);
 
   menu_view_ = new AutoclickMenuView(type, position);
+  menu_view_->SetBackground(UnifiedSystemTrayView::CreateBackground());
   menu_view_->SetBorder(
       views::CreateEmptyBorder(kUnifiedTopShortcutSpacing, 0, 0, 0));
   bubble_view_->AddChildView(menu_view_);
-
-  menu_view_->SetPaintToLayer();
-  menu_view_->layer()->SetFillsBoundsOpaquely(false);
+  bubble_view_->set_color(SK_ColorTRANSPARENT);
+  bubble_view_->layer()->SetFillsBoundsOpaquely(false);
 
   bubble_widget_ = views::BubbleDialogDelegateView::CreateBubble(bubble_view_);
   TrayBackgroundView::InitializeBubbleAnimations(bubble_widget_);
@@ -242,6 +242,11 @@
       CollisionDetectionUtils::RelativePriority::kAutomaticClicksMenu);
   bubble_view_->InitializeAndShowBubble();
 
+  if (features::IsBackgroundBlurEnabled()) {
+    bubble_widget_->client_view()->layer()->SetBackgroundBlur(
+        kUnifiedMenuBackgroundBlur);
+  }
+
   SetPosition(position);
 }
 
diff --git a/ash/system/accessibility/autoclick_scroll_bubble_controller.cc b/ash/system/accessibility/autoclick_scroll_bubble_controller.cc
index 983255d..2dcc4d51 100644
--- a/ash/system/accessibility/autoclick_scroll_bubble_controller.cc
+++ b/ash/system/accessibility/autoclick_scroll_bubble_controller.cc
@@ -4,6 +4,7 @@
 
 #include "ash/system/accessibility/autoclick_scroll_bubble_controller.h"
 
+#include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shell.h"
@@ -199,16 +200,16 @@
   init_params.max_height = kAutoclickScrollMenuSizeDips;
   init_params.corner_radius = kUnifiedTrayCornerRadius;
   init_params.has_shadow = false;
-  init_params.translucent = true;
   bubble_view_ = new AutoclickScrollBubbleView(init_params);
   bubble_view_->SetArrow(alignment);
 
   scroll_view_ = new AutoclickScrollView();
+  scroll_view_->SetBackground(UnifiedSystemTrayView::CreateBackground());
   scroll_view_->SetBorder(
       views::CreateEmptyBorder(kUnifiedTopShortcutSpacing, 0, 0, 0));
   bubble_view_->AddChildView(scroll_view_);
-  scroll_view_->SetPaintToLayer();
-  scroll_view_->layer()->SetFillsBoundsOpaquely(false);
+  bubble_view_->set_color(SK_ColorTRANSPARENT);
+  bubble_view_->layer()->SetFillsBoundsOpaquely(false);
 
   bubble_widget_ = views::BubbleDialogDelegateView::CreateBubble(bubble_view_);
   TrayBackgroundView::InitializeBubbleAnimations(bubble_widget_);
@@ -216,6 +217,11 @@
       bubble_widget_->GetNativeWindow(),
       CollisionDetectionUtils::RelativePriority::kAutomaticClicksScrollMenu);
   bubble_view_->InitializeAndShowBubble();
+
+  if (features::IsBackgroundBlurEnabled()) {
+    bubble_widget_->client_view()->layer()->SetBackgroundBlur(
+        kUnifiedMenuBackgroundBlur);
+  }
 }
 
 void AutoclickScrollBubbleController::CloseBubble() {
diff --git a/ash/system/machine_learning/user_settings_event.proto b/ash/system/machine_learning/user_settings_event.proto
index 6d06029e..20d1550 100644
--- a/ash/system/machine_learning/user_settings_event.proto
+++ b/ash/system/machine_learning/user_settings_event.proto
@@ -102,9 +102,9 @@
     // Whether the user has connected to a cellular network in the current
     // session.
     optional bool used_cellular_in_session = 17;
-    // Whether there are previously paired bluetooth devices available for
-    // connection.
-    optional bool has_available_bluetooth_devices = 18;
+    // Whether or not the current bluetooth device was already paired. Only
+    // populated upon connection to a bluetooth device.
+    optional bool is_paired_bluetooth_device = 18;
     // Whether the user has set up a night light schedule.
     optional bool has_night_light_schedule = 19;
     // True if it is after sunset and before sunrise in the local time.
diff --git a/ash/system/machine_learning/user_settings_event_logger.cc b/ash/system/machine_learning/user_settings_event_logger.cc
index 0bb5fa5..52fa030 100644
--- a/ash/system/machine_learning/user_settings_event_logger.cc
+++ b/ash/system/machine_learning/user_settings_event_logger.cc
@@ -62,11 +62,29 @@
     // We are not interested in other types of networks.
     return;
   }
-
   event->set_setting_type(UserSettingsEvent::Event::QUICK_SETTINGS);
-  // Convert the setting state to an int. Some settings have multiple states, so
-  // all setting states are stored as ints.
-  event->set_current_value(1);
+
+  PopulateSharedFeatures(&settings_event);
+  SendToUkm(settings_event);
+}
+
+void UserSettingsEventLogger::LogBluetoothUkmEvent(
+    const BluetoothAddress& device_address) {
+  UserSettingsEvent settings_event;
+  auto* const event = settings_event.mutable_event();
+
+  event->set_setting_id(UserSettingsEvent::Event::BLUETOOTH);
+  event->set_setting_type(UserSettingsEvent::Event::QUICK_SETTINGS);
+
+  const auto& devices =
+      Shell::Get()->tray_bluetooth_helper()->GetAvailableBluetoothDevices();
+  for (const auto& device : devices) {
+    if (device->address == device_address) {
+      settings_event.mutable_features()->set_is_paired_bluetooth_device(
+          device->is_paired);
+      break;
+    }
+  }
 
   PopulateSharedFeatures(&settings_event);
   SendToUkm(settings_event);
diff --git a/ash/system/machine_learning/user_settings_event_logger.h b/ash/system/machine_learning/user_settings_event_logger.h
index 148fbf8..a78312d 100644
--- a/ash/system/machine_learning/user_settings_event_logger.h
+++ b/ash/system/machine_learning/user_settings_event_logger.h
@@ -5,6 +5,7 @@
 #ifndef ASH_SYSTEM_MACHINE_LEARNING_USER_SETTINGS_EVENT_LOGGER_H_
 #define ASH_SYSTEM_MACHINE_LEARNING_USER_SETTINGS_EVENT_LOGGER_H_
 
+#include "ash/system/bluetooth/tray_bluetooth_helper.h"
 #include "ash/system/machine_learning/user_settings_event.pb.h"
 #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom-forward.h"
 
@@ -27,6 +28,9 @@
   // Logs an event to UKM that the user has connected to the given network.
   void LogNetworkUkmEvent(
       const chromeos::network_config::mojom::NetworkStateProperties& network);
+  // Logs an event to UKM that the user has connected to the given bluetooth
+  // device.
+  void LogBluetoothUkmEvent(const BluetoothAddress& device_address);
 
  private:
   UserSettingsEventLogger();
diff --git a/ash/system/tray/tray_bubble_view.cc b/ash/system/tray/tray_bubble_view.cc
index 4152a6f..2bbfa72 100644
--- a/ash/system/tray/tray_bubble_view.cc
+++ b/ash/system/tray/tray_bubble_view.cc
@@ -8,8 +8,6 @@
 #include <numeric>
 
 #include "ash/public/cpp/ash_features.h"
-#include "ash/system/tray/tray_constants.h"
-#include "ash/system/unified/unified_system_tray_view.h"
 #include "base/macros.h"
 #include "base/numerics/ranges.h"
 #include "third_party/skia/include/core/SkCanvas.h"
@@ -240,22 +238,7 @@
   set_notify_enter_exit_on_child(true);
   set_close_on_deactivate(init_params.close_on_deactivate);
   set_margins(gfx::Insets());
-
-  if (init_params.translucent) {
-    // The following code will not work with bubble's shadow.
-    DCHECK(!init_params.has_shadow);
-    SetPaintToLayer(ui::LAYER_SOLID_COLOR);
-
-    layer()->SetRoundedCornerRadius(
-        gfx::RoundedCornersF{kUnifiedTrayCornerRadius});
-    layer()->SetColor(UnifiedSystemTrayView::GetBackgroundColor());
-    layer()->SetFillsBoundsOpaquely(false);
-    layer()->SetIsFastRoundedCorner(true);
-    if (features::IsBackgroundBlurEnabled()) {
-      layer()->SetBackgroundBlur(kUnifiedMenuBackgroundBlur);
-      layer()->SetName("trayBubble");
-    }
-  }
+  SetPaintToLayer();
 
   auto layout = std::make_unique<BottomAlignedBoxLayout>(this);
   layout->SetDefaultFlex(1);
@@ -284,6 +267,10 @@
 }
 
 void TrayBubbleView::InitializeAndShowBubble() {
+  int radius = bubble_border_->corner_radius();
+  layer()->parent()->SetRoundedCornerRadius({radius, radius, radius, radius});
+  layer()->parent()->SetIsFastRoundedCorner(true);
+
   GetWidget()->Show();
   UpdateBubble();
 
@@ -393,12 +380,6 @@
   BubbleDialogDelegateView::OnWidgetActivationChanged(widget, active);
 }
 
-ui::LayerType TrayBubbleView::GetLayerType() const {
-  if (params_.translucent)
-    return ui::LAYER_NOT_DRAWN;
-  return ui::LAYER_TEXTURED;
-}
-
 NonClientFrameView* TrayBubbleView::CreateNonClientFrameView(Widget* widget) {
   BubbleFrameView* frame = static_cast<BubbleFrameView*>(
       BubbleDialogDelegateView::CreateNonClientFrameView(widget));
@@ -485,6 +466,14 @@
   SizeToContents();
 }
 
+void TrayBubbleView::ViewHierarchyChanged(
+    const views::ViewHierarchyChangedDetails& details) {
+  if (details.is_add && details.child == this) {
+    details.parent->SetPaintToLayer();
+    details.parent->layer()->SetMasksToBounds(true);
+  }
+}
+
 void TrayBubbleView::SetBubbleBorderInsets(gfx::Insets insets) {
   bubble_border_->set_insets(insets);
 }
diff --git a/ash/system/tray/tray_bubble_view.h b/ash/system/tray/tray_bubble_view.h
index 1bd77b5..45e1caf2 100644
--- a/ash/system/tray/tray_bubble_view.h
+++ b/ash/system/tray/tray_bubble_view.h
@@ -95,8 +95,6 @@
     base::Optional<int> corner_radius;
     base::Optional<gfx::Insets> insets;
     bool has_shadow = true;
-    // Use half opaque widget instead of fully opaque.
-    bool translucent = false;
   };
 
   explicit TrayBubbleView(const InitParams& init_params);
@@ -166,7 +164,6 @@
                                 views::Widget* bubble_widget) const override;
   void OnWidgetClosing(views::Widget* widget) override;
   void OnWidgetActivationChanged(views::Widget* widget, bool active) override;
-  ui::LayerType GetLayerType() const override;
 
   // Overridden from views::View.
   gfx::Size CalculatePreferredSize() const override;
@@ -185,6 +182,8 @@
 
   // Overridden from views::View.
   void ChildPreferredSizeChanged(View* child) override;
+  void ViewHierarchyChanged(
+      const views::ViewHierarchyChangedDetails& details) override;
 
   // Changes the insets from the bubble border. These were initially set using
   // the InitParams.insets, but may need to be reset programmatically.
diff --git a/ash/system/unified/page_indicator_view.cc b/ash/system/unified/page_indicator_view.cc
index 9ba8232a..98acd58 100644
--- a/ash/system/unified/page_indicator_view.cc
+++ b/ash/system/unified/page_indicator_view.cc
@@ -169,11 +169,11 @@
       expanded_amount_(initially_expanded ? 1 : 0),
       buttons_container_(new views::View) {
   SetVisible(initially_expanded);
+  SetPaintToLayer();
+  layer()->SetFillsBoundsOpaquely(false);
 
   buttons_container_->SetLayoutManager(std::make_unique<views::BoxLayout>(
       views::BoxLayout::Orientation::kHorizontal, gfx::Insets()));
-  buttons_container_->SetPaintToLayer();
-  buttons_container_->layer()->SetFillsBoundsOpaquely(false);
 
   AddChildView(buttons_container_);
 
@@ -209,11 +209,9 @@
   DCHECK(0.0 <= expanded_amount && expanded_amount <= 1.0);
   SetVisible(expanded_amount > 0.0);
   expanded_amount_ = expanded_amount;
+  InvalidateLayout();
   // TODO(amehfooz): Confirm animation curve with UX.
-  buttons_container_->layer()->SetOpacity(
-      std::max(0., 6 * expanded_amount_ - 5.));
-  if (CalculatePreferredSize() != size())
-    InvalidateLayout();
+  layer()->SetOpacity(std::max(0., 6 * expanded_amount_ - 5.));
 }
 
 int PageIndicatorView::GetExpandedHeight() {
diff --git a/ash/system/unified/unified_slider_bubble_controller.cc b/ash/system/unified/unified_slider_bubble_controller.cc
index be0593b..b3df4fc4 100644
--- a/ash/system/unified/unified_slider_bubble_controller.cc
+++ b/ash/system/unified/unified_slider_bubble_controller.cc
@@ -4,6 +4,7 @@
 
 #include "ash/system/unified/unified_slider_bubble_controller.h"
 
+#include "ash/public/cpp/ash_features.h"
 #include "ash/root_window_controller.h"
 #include "ash/session/session_controller_impl.h"
 #include "ash/shelf/shelf.h"
@@ -34,6 +35,7 @@
 }
 
 void ConfigureSliderViewStyle(views::View* slider_view) {
+  slider_view->SetBackground(UnifiedSystemTrayView::CreateBackground());
   slider_view->SetBorder(views::CreateEmptyBorder(kUnifiedSliderBubblePadding));
 }
 
@@ -169,19 +171,25 @@
   init_params.insets = GetTrayBubbleInsets();
   init_params.corner_radius = kUnifiedTrayCornerRadius;
   init_params.has_shadow = false;
-  init_params.translucent = true;
 
   bubble_view_ = new TrayBubbleView(init_params);
   UnifiedSliderView* slider_view =
       static_cast<UnifiedSliderView*>(slider_controller_->CreateView());
   ConfigureSliderViewStyle(slider_view);
   bubble_view_->AddChildView(slider_view);
+  bubble_view_->set_color(SK_ColorTRANSPARENT);
+  bubble_view_->layer()->SetFillsBoundsOpaquely(false);
 
   bubble_widget_ = views::BubbleDialogDelegateView::CreateBubble(bubble_view_);
 
   TrayBackgroundView::InitializeBubbleAnimations(bubble_widget_);
   bubble_view_->InitializeAndShowBubble();
 
+  if (features::IsBackgroundBlurEnabled()) {
+    bubble_widget_->client_view()->layer()->SetBackgroundBlur(
+        kUnifiedMenuBackgroundBlur);
+  }
+
   // Notify value change accessibility event because the popup is triggered by
   // changing value using an accessor key like VolUp.
   slider_view->slider()->NotifyAccessibilityEvent(
diff --git a/ash/system/unified/unified_slider_view.cc b/ash/system/unified/unified_slider_view.cc
index 1466b1ef..635b575 100644
--- a/ash/system/unified/unified_slider_view.cc
+++ b/ash/system/unified/unified_slider_view.cc
@@ -148,9 +148,6 @@
   layout->SetFlexForView(slider_, 1);
   layout->set_cross_axis_alignment(
       views::BoxLayout::CrossAxisAlignment::kCenter);
-
-  SetPaintToLayer();
-  layer()->SetFillsBoundsOpaquely(false);
 }
 
 void UnifiedSliderView::SetSliderValue(float value, bool by_user) {
diff --git a/ash/system/unified/unified_system_tray_bubble.cc b/ash/system/unified/unified_system_tray_bubble.cc
index 630c02f..573db0ae 100644
--- a/ash/system/unified/unified_system_tray_bubble.cc
+++ b/ash/system/unified/unified_system_tray_bubble.cc
@@ -92,7 +92,6 @@
   init_params.has_shadow = false;
   init_params.show_by_click = show_by_click;
   init_params.close_on_deactivate = false;
-  init_params.translucent = true;
 
   bubble_view_ = new TrayBubbleView(init_params);
 
@@ -105,12 +104,20 @@
   controller_->ResetToCollapsedIfRequired();
   bubble_view_->AddChildView(new ContainerView(unified_view_));
 
+  bubble_view_->set_color(SK_ColorTRANSPARENT);
+  bubble_view_->layer()->SetFillsBoundsOpaquely(false);
+
   bubble_widget_ = views::BubbleDialogDelegateView::CreateBubble(bubble_view_);
   bubble_widget_->AddObserver(this);
 
   TrayBackgroundView::InitializeBubbleAnimations(bubble_widget_);
   bubble_view_->InitializeAndShowBubble();
 
+  if (features::IsBackgroundBlurEnabled()) {
+    bubble_widget_->client_view()->layer()->SetBackgroundBlur(
+        kUnifiedMenuBackgroundBlur);
+  }
+
   tray->tray_event_filter()->AddBubble(this);
   tray->shelf()->AddObserver(this);
   Shell::Get()->tablet_mode_controller()->AddObserver(this);
@@ -227,7 +234,7 @@
 
   if (!unified_view_->IsTransformEnabled()) {
     unified_view_->SetTransform(gfx::Transform());
-    OnAnimationFinished();
+    DestroyBlurLayerForAnimation();
     SetFrameVisible(true);
     return;
   }
@@ -244,9 +251,13 @@
   transform.Translate(0, y_offset);
   unified_view_->SetTransform(transform);
 
-  gfx::Rect blur_bounds = bubble_view_->bounds();
-  blur_bounds.Inset(gfx::Insets(y_offset, 0, 0, 0));
-  bubble_view_->layer()->SetClipRect(blur_bounds);
+  CreateBlurLayerForAnimation();
+
+  if (blur_layer_) {
+    gfx::Rect blur_bounds = bubble_widget_->client_view()->layer()->bounds();
+    blur_bounds.Inset(gfx::Insets(y_offset, 0, 0, 0));
+    blur_layer_->layer()->SetBounds(blur_bounds);
+  }
 }
 
 TrayBackgroundView* UnifiedSystemTrayBubble::GetTray() const {
@@ -374,8 +385,44 @@
     tray_->message_center_bubble()->UpdatePosition();
 }
 
-void UnifiedSystemTrayBubble::OnAnimationFinished() {
-  bubble_widget_->GetNativeWindow()->layer()->SetClipRect(gfx::Rect());
+void UnifiedSystemTrayBubble::CreateBlurLayerForAnimation() {
+  if (!features::IsBackgroundBlurEnabled())
+    return;
+
+  if (blur_layer_)
+    return;
+
+  DCHECK(bubble_widget_);
+
+  bubble_widget_->client_view()->layer()->SetBackgroundBlur(0);
+
+  blur_layer_ = std::make_unique<ui::LayerOwner>(
+      std::make_unique<ui::Layer>(ui::LAYER_SOLID_COLOR));
+  blur_layer_->layer()->SetColor(SK_ColorTRANSPARENT);
+  blur_layer_->layer()->SetRoundedCornerRadius(
+      {kUnifiedTrayCornerRadius, kUnifiedTrayCornerRadius,
+       kUnifiedTrayCornerRadius, kUnifiedTrayCornerRadius});
+  blur_layer_->layer()->SetFillsBoundsOpaquely(false);
+
+  bubble_widget_->GetLayer()->Add(blur_layer_->layer());
+  bubble_widget_->GetLayer()->StackAtBottom(blur_layer_->layer());
+
+  blur_layer_->layer()->SetBounds(
+      bubble_widget_->client_view()->layer()->bounds());
+  blur_layer_->layer()->SetBackgroundBlur(kUnifiedMenuBackgroundBlur);
+}
+
+void UnifiedSystemTrayBubble::DestroyBlurLayerForAnimation() {
+  if (!features::IsBackgroundBlurEnabled())
+    return;
+
+  if (!blur_layer_)
+    return;
+
+  blur_layer_.reset();
+
+  bubble_widget_->client_view()->layer()->SetBackgroundBlur(
+      kUnifiedMenuBackgroundBlur);
 }
 
 void UnifiedSystemTrayBubble::SetFrameVisible(bool visible) {
diff --git a/ash/system/unified/unified_system_tray_bubble.h b/ash/system/unified/unified_system_tray_bubble.h
index 4e0b301..a75a77c 100644
--- a/ash/system/unified/unified_system_tray_bubble.h
+++ b/ash/system/unified/unified_system_tray_bubble.h
@@ -19,6 +19,10 @@
 #include "ui/views/widget/widget_observer.h"
 #include "ui/wm/public/activation_change_observer.h"
 
+namespace ui {
+class LayerOwner;
+}  // namespace ui
+
 namespace views {
 class Widget;
 }  // namespace views
@@ -142,8 +146,9 @@
 
   void UpdateBubbleBounds();
 
-  // Called when the tray animation is finished.
-  void OnAnimationFinished();
+  // Create / destroy background blur layer that is used during animation.
+  void CreateBlurLayerForAnimation();
+  void DestroyBlurLayerForAnimation();
 
   // Set visibility of bubble frame border. Used for disabling the border during
   // animation.
@@ -170,6 +175,9 @@
   // click (|show_by_click| in ctor is false), it is not set.
   base::Optional<base::TimeTicks> time_shown_by_click_;
 
+  // Background blur layer that is used during animation.
+  std::unique_ptr<ui::LayerOwner> blur_layer_;
+
   TrayBubbleView* bubble_view_ = nullptr;
   UnifiedSystemTrayView* unified_view_ = nullptr;
 
diff --git a/ash/system/unified/unified_system_tray_view.cc b/ash/system/unified/unified_system_tray_view.cc
index bca424fb..d71535f 100644
--- a/ash/system/unified/unified_system_tray_view.cc
+++ b/ash/system/unified/unified_system_tray_view.cc
@@ -96,6 +96,8 @@
   SystemTrayContainer() {
     SetLayoutManager(std::make_unique<views::BoxLayout>(
         views::BoxLayout::Orientation::kVertical));
+    SetBackground(UnifiedSystemTrayView::CreateBackground());
+
     if (!features::IsUnifiedMessageCenterRefactorEnabled())
       SetBorder(std::make_unique<TopCornerBorder>());
   }
@@ -116,6 +118,8 @@
 class DetailedViewContainer : public views::View {
  public:
   DetailedViewContainer() {
+    SetBackground(UnifiedSystemTrayView::CreateBackground());
+
     if (!features::IsUnifiedMessageCenterRefactorEnabled())
       SetBorder(std::make_unique<TopCornerBorder>());
   }
@@ -308,11 +312,9 @@
   auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>(
       views::BoxLayout::Orientation::kVertical));
 
-  auto add_layered_child = [](views::View* parent, views::View* child) {
-    parent->AddChildView(child);
-    child->SetPaintToLayer();
-    child->layer()->SetFillsBoundsOpaquely(false);
-  };
+  SetBackground(CreateBackground());
+  SetPaintToLayer();
+  layer()->SetFillsBoundsOpaquely(false);
 
   SessionControllerImpl* session_controller =
       Shell::Get()->session_controller();
@@ -320,7 +322,7 @@
   if (!features::IsUnifiedMessageCenterRefactorEnabled()) {
     message_center_view_ = new UnifiedMessageCenterView(
         this, controller->model(), nullptr /* message_center_bubble */);
-    add_layered_child(this, message_center_view_);
+    AddChildView(message_center_view_);
     layout->SetFlexForView(message_center_view_, 1);
   }
 
@@ -328,15 +330,15 @@
       session_controller->GetUserSession(0) &&
       session_controller->IsScreenLocked() &&
       !AshMessageCenterLockScreenController::IsEnabled());
-  add_layered_child(this, notification_hidden_view_);
+  AddChildView(notification_hidden_view_);
 
   AddChildView(system_tray_container_);
 
-  add_layered_child(system_tray_container_, top_shortcuts_view_);
+  system_tray_container_->AddChildView(top_shortcuts_view_);
   system_tray_container_->AddChildView(feature_pods_container_);
   system_tray_container_->AddChildView(page_indicator_view_);
   system_tray_container_->AddChildView(sliders_container_);
-  add_layered_child(system_tray_container_, system_info_view_);
+  system_tray_container_->AddChildView(system_info_view_);
 
   if (features::IsManagedDeviceUIRedesignEnabled()) {
     managed_device_view_ = new UnifiedManagedDeviceView();
@@ -344,7 +346,7 @@
   }
 
   detailed_view_container_->SetVisible(false);
-  add_layered_child(this, detailed_view_container_);
+  AddChildView(detailed_view_container_);
 
   // UnifiedSystemTrayView::FocusSearch makes focus traversal start from
   // |system_tray_container_|, but we have to complete the cycle by setting
diff --git a/base/allocator/partition_allocator/oom.h b/base/allocator/partition_allocator/oom.h
index 8d3fe08..c3a2d1b 100644
--- a/base/allocator/partition_allocator/oom.h
+++ b/base/allocator/partition_allocator/oom.h
@@ -17,23 +17,20 @@
 namespace {
 // The crash is generated in a NOINLINE function so that we can classify the
 // crash as an OOM solely by analyzing the stack trace.
-NOINLINE void OnNoMemory() {
+NOINLINE void OnNoMemory(size_t size) {
   base::internal::RunPartitionAllocOomCallback();
-#if defined(OS_WIN)
-  ::RaiseException(base::win::kOomExceptionCode, EXCEPTION_NONCONTINUABLE, 0,
-                   nullptr);
-#endif
+  base::internal::OnNoMemoryInternal(size);
   IMMEDIATE_CRASH();
 }
 }  // namespace
 
-// OOM_CRASH() - Specialization of IMMEDIATE_CRASH which will raise a custom
+// OOM_CRASH(size) - Specialization of IMMEDIATE_CRASH which will raise a custom
 // exception on Windows to signal this is OOM and not a normal assert.
-// OOM_CRASH() is called by users of PageAllocator (including PartitionAlloc) to
-// signify an allocation failure from the platform.
-#define OOM_CRASH() \
-  do {              \
-    OnNoMemory();   \
+// OOM_CRASH(size) is called by users of PageAllocator (including
+// PartitionAlloc) to signify an allocation failure from the platform.
+#define OOM_CRASH(size) \
+  do {                  \
+    OnNoMemory(size);   \
   } while (0)
 
 #endif  // BASE_ALLOCATOR_PARTITION_ALLOCATOR_OOM_H_
diff --git a/base/allocator/partition_allocator/page_allocator_internals_win.h b/base/allocator/partition_allocator/page_allocator_internals_win.h
index 23f7a43..60a3472f 100644
--- a/base/allocator/partition_allocator/page_allocator_internals_win.h
+++ b/base/allocator/partition_allocator/page_allocator_internals_win.h
@@ -91,7 +91,7 @@
                       GetAccessFlags(accessibility))) {
       int32_t error = GetLastError();
       if (error == ERROR_COMMITMENT_LIMIT)
-        OOM_CRASH();
+        OOM_CRASH(length);
       // We check `GetLastError` for `ERROR_SUCCESS` here so that in a crash
       // report we get the error number.
       CHECK_EQ(ERROR_SUCCESS, error);
diff --git a/base/allocator/partition_allocator/partition_alloc.cc b/base/allocator/partition_allocator/partition_alloc.cc
index 5923b7e..ca7a352 100644
--- a/base/allocator/partition_allocator/partition_alloc.cc
+++ b/base/allocator/partition_allocator/partition_alloc.cc
@@ -62,7 +62,7 @@
 }
 static bool g_initialized = false;
 
-void (*internal::PartitionRootBase::gOomHandlingFunction)() = nullptr;
+OomFunction internal::PartitionRootBase::g_oom_handling_function = nullptr;
 std::atomic<bool> PartitionAllocHooks::hooks_enabled_(false);
 subtle::SpinLock PartitionAllocHooks::set_hooks_lock_;
 std::atomic<PartitionAllocHooks::AllocationObserverHook*>
@@ -187,9 +187,9 @@
   root->inverted_self = ~reinterpret_cast<uintptr_t>(root);
 }
 
-void PartitionAllocGlobalInit(void (*oom_handling_function)()) {
-  DCHECK(oom_handling_function);
-  internal::PartitionRootBase::gOomHandlingFunction = oom_handling_function;
+void PartitionAllocGlobalInit(OomFunction on_out_of_memory) {
+  DCHECK(on_out_of_memory);
+  internal::PartitionRootBase::g_oom_handling_function = on_out_of_memory;
 }
 
 void PartitionRoot::Init(size_t bucket_count, size_t maximum_allocation) {
@@ -370,7 +370,7 @@
   if (new_size > kGenericMaxDirectMapped) {
     if (flags & PartitionAllocReturnNull)
       return nullptr;
-    internal::PartitionExcessiveAllocationSize();
+    internal::PartitionExcessiveAllocationSize(new_size);
   }
 
   const bool hooks_enabled = PartitionAllocHooks::AreHooksEnabled();
@@ -425,7 +425,7 @@
   if (!ret) {
     if (flags & PartitionAllocReturnNull)
       return nullptr;
-    internal::PartitionExcessiveAllocationSize();
+    internal::PartitionExcessiveAllocationSize(new_size);
   }
 
   size_t copy_size = actual_old_size;
diff --git a/base/allocator/partition_allocator/partition_alloc.h b/base/allocator/partition_allocator/partition_alloc.h
index fa73d8c..3ceadda 100644
--- a/base/allocator/partition_allocator/partition_alloc.h
+++ b/base/allocator/partition_allocator/partition_alloc.h
@@ -220,7 +220,7 @@
                                          const PartitionBucketMemoryStats*) = 0;
 };
 
-BASE_EXPORT void PartitionAllocGlobalInit(void (*oom_handling_function)());
+BASE_EXPORT void PartitionAllocGlobalInit(OomFunction on_out_of_memory);
 
 // PartitionAlloc supports setting hooks to observe allocations/frees as they
 // occur as well as 'override' hooks that allow overriding those operations.
diff --git a/base/allocator/partition_allocator/partition_bucket.cc b/base/allocator/partition_allocator/partition_bucket.cc
index c2879e46..2bf7672 100644
--- a/base/allocator/partition_allocator/partition_bucket.cc
+++ b/base/allocator/partition_allocator/partition_bucket.cc
@@ -185,7 +185,7 @@
 }
 
 NOINLINE void PartitionBucket::OnFull() {
-  OOM_CRASH();
+  OOM_CRASH(0);
 }
 
 ALWAYS_INLINE void* PartitionBucket::AllocNewSlotSpan(
@@ -478,7 +478,7 @@
     if (size > kGenericMaxDirectMapped) {
       if (return_null)
         return nullptr;
-      PartitionExcessiveAllocationSize();
+      PartitionExcessiveAllocationSize(size);
     }
     new_page = PartitionDirectMap(root, flags, size);
 #if !defined(OS_MACOSX)
@@ -538,7 +538,7 @@
     DCHECK(active_pages_head == PartitionPage::get_sentinel_page());
     if (return_null)
       return nullptr;
-    root->OutOfMemory();
+    root->OutOfMemory(size);
   }
 
   // TODO(ajwong): Is there a way to avoid the reading of bucket here?
diff --git a/base/allocator/partition_allocator/partition_oom.cc b/base/allocator/partition_allocator/partition_oom.cc
index 5e1cf79..e23705f 100644
--- a/base/allocator/partition_allocator/partition_oom.cc
+++ b/base/allocator/partition_allocator/partition_oom.cc
@@ -10,13 +10,13 @@
 namespace base {
 namespace internal {
 
-void NOINLINE PartitionExcessiveAllocationSize() {
-  OOM_CRASH();
+void NOINLINE PartitionExcessiveAllocationSize(size_t size) {
+  OOM_CRASH(size);
 }
 
 #if !defined(ARCH_CPU_64_BITS)
-NOINLINE void PartitionOutOfMemoryWithLotsOfUncommitedPages() {
-  OOM_CRASH();
+NOINLINE void PartitionOutOfMemoryWithLotsOfUncommitedPages(size_t size) {
+  OOM_CRASH(size);
 }
 #endif
 
diff --git a/base/allocator/partition_allocator/partition_oom.h b/base/allocator/partition_allocator/partition_oom.h
index da8fc15a..2c5e0d3 100644
--- a/base/allocator/partition_allocator/partition_oom.h
+++ b/base/allocator/partition_allocator/partition_oom.h
@@ -8,16 +8,18 @@
 #ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_OOM_H_
 #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_OOM_H_
 
+#include <stddef.h>
+
 #include "base/compiler_specific.h"
 #include "build/build_config.h"
 
 namespace base {
 namespace internal {
 
-NOINLINE void PartitionExcessiveAllocationSize();
+NOINLINE void PartitionExcessiveAllocationSize(size_t size);
 
 #if !defined(ARCH_CPU_64_BITS)
-NOINLINE void PartitionOutOfMemoryWithLotsOfUncommitedPages();
+NOINLINE void PartitionOutOfMemoryWithLotsOfUncommitedPages(size_t size);
 #endif
 
 }  // namespace internal
diff --git a/base/allocator/partition_allocator/partition_root_base.cc b/base/allocator/partition_allocator/partition_root_base.cc
index 91b998f..6e1442f 100644
--- a/base/allocator/partition_allocator/partition_root_base.cc
+++ b/base/allocator/partition_allocator/partition_root_base.cc
@@ -12,19 +12,19 @@
 namespace base {
 namespace internal {
 
-NOINLINE void PartitionRootBase::OutOfMemory() {
+NOINLINE void PartitionRootBase::OutOfMemory(size_t size) {
 #if !defined(ARCH_CPU_64_BITS)
   // Check whether this OOM is due to a lot of super pages that are allocated
   // but not committed, probably due to http://crbug.com/421387.
   if (total_size_of_super_pages + total_size_of_direct_mapped_pages -
           total_size_of_committed_pages >
       kReasonableSizeOfUnusedPages) {
-    PartitionOutOfMemoryWithLotsOfUncommitedPages();
+    PartitionOutOfMemoryWithLotsOfUncommitedPages(size);
   }
 #endif
-  if (PartitionRootBase::gOomHandlingFunction)
-    (*PartitionRootBase::gOomHandlingFunction)();
-  OOM_CRASH();
+  if (PartitionRootBase::g_oom_handling_function)
+    (*PartitionRootBase::g_oom_handling_function)(size);
+  OOM_CRASH(size);
 }
 
 void PartitionRootBase::DecommitEmptyPages() {
diff --git a/base/allocator/partition_allocator/partition_root_base.h b/base/allocator/partition_allocator/partition_root_base.h
index a3f9175..42c1d8d 100644
--- a/base/allocator/partition_allocator/partition_root_base.h
+++ b/base/allocator/partition_allocator/partition_root_base.h
@@ -14,6 +14,9 @@
 #include "build/build_config.h"
 
 namespace base {
+
+typedef void (*OomFunction)(size_t);
+
 namespace internal {
 
 struct PartitionPage;
@@ -73,9 +76,9 @@
   ALWAYS_INLINE static bool IsValidPage(PartitionPage* page);
   ALWAYS_INLINE static PartitionRootBase* FromPage(PartitionPage* page);
 
-  // gOomHandlingFunction is invoked when PartitionAlloc hits OutOfMemory.
-  static void (*gOomHandlingFunction)();
-  NOINLINE void OutOfMemory();
+  // g_oom_handling_function is invoked when PartitionAlloc hits OutOfMemory.
+  static OomFunction g_oom_handling_function;
+  NOINLINE void OutOfMemory(size_t size);
 
   ALWAYS_INLINE void IncreaseCommittedPages(size_t len);
   ALWAYS_INLINE void DecreaseCommittedPages(size_t len);
diff --git a/base/process/memory.cc b/base/process/memory.cc
index 3034d00..bd46ab1 100644
--- a/base/process/memory.cc
+++ b/base/process/memory.cc
@@ -3,6 +3,11 @@
 // found in the LICENSE file.
 
 #include "base/process/memory.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif  // defined(OS_WIN)
+
 #include "base/debug/alias.h"
 #include "base/logging.h"
 #include "base/partition_alloc_buildflags.h"
@@ -13,6 +18,29 @@
 
 namespace base {
 
+namespace internal {
+
+void OnNoMemoryInternal(size_t size) {
+#if defined(OS_WIN)
+  // Kill the process. This is important for security since most of code
+  // does not check the result of memory allocation.
+  // https://msdn.microsoft.com/en-us/library/het71c37.aspx
+  // Pass the size of the failed request in an exception argument.
+  ULONG_PTR exception_args[] = {size};
+  ::RaiseException(base::win::kOomExceptionCode, EXCEPTION_NONCONTINUABLE,
+                   base::size(exception_args), exception_args);
+
+  // Safety check, make sure process exits here.
+  _exit(win::kOomExceptionCode);
+#else
+  size_t tmp_size = size;
+  base::debug::Alias(&tmp_size);
+  LOG(FATAL) << "Out of memory. size=" << tmp_size;
+#endif  // defined(OS_WIN)
+}
+
+}  // namespace internal
+
 // Defined in memory_win.cc for Windows.
 #if !defined(OS_WIN)
 
@@ -21,9 +49,7 @@
 // Breakpad server classifies base::`anonymous namespace'::OnNoMemory as
 // out-of-memory crash.
 NOINLINE void OnNoMemory(size_t size) {
-  size_t tmp_size = size;
-  base::debug::Alias(&tmp_size);
-  LOG(FATAL) << "Out of memory. size=" << tmp_size;
+  internal::OnNoMemoryInternal(size);
 }
 
 }  // namespace
diff --git a/base/process/memory.h b/base/process/memory.h
index 3fb2caa1..ddbb9d9 100644
--- a/base/process/memory.h
+++ b/base/process/memory.h
@@ -60,6 +60,14 @@
 }  // namespace win
 #endif
 
+namespace internal {
+
+// Handles out of memory, with the failed allocation |size|, or 0 when it is not
+// known.
+BASE_EXPORT void OnNoMemoryInternal(size_t size);
+
+}  // namespace internal
+
 // Special allocator functions for callers that want to check for OOM.
 // These will not abort if the allocation fails even if
 // EnableTerminationOnOutOfMemory has been called.
diff --git a/base/process/memory_win.cc b/base/process/memory_win.cc
index f66089c..2d1ae42 100644
--- a/base/process/memory_win.cc
+++ b/base/process/memory_win.cc
@@ -40,30 +40,18 @@
 
 namespace {
 
-#pragma warning(push)
-#pragma warning(disable: 4702)  // Unreachable code after the _exit.
-
-[[noreturn]] NOINLINE int OnNoMemory(size_t size) {
-  // Kill the process. This is important for security since most of code
-  // does not check the result of memory allocation.
-  // https://msdn.microsoft.com/en-us/library/het71c37.aspx
-  // Pass the size of the failed request in an exception argument.
-  ULONG_PTR exception_args[] = {size};
-  ::RaiseException(win::kOomExceptionCode, EXCEPTION_NONCONTINUABLE,
-                   base::size(exception_args), exception_args);
-
-  // Safety check, make sure process exits here.
-  _exit(win::kOomExceptionCode);
-}
-
-#pragma warning(pop)
-
 // Return a non-0 value to retry the allocation.
 int ReleaseReservationOrTerminate(size_t size) {
   constexpr int kRetryAllocation = 1;
   if (internal::ReleaseAddressSpaceReservation())
     return kRetryAllocation;
-  OnNoMemory(size);
+  internal::OnNoMemoryInternal(size);
+  return 0;
+}
+
+NOINLINE int OnNoMemory(size_t size) {
+  internal::OnNoMemoryInternal(size);
+  return 0;
 }
 
 }  // namespace
diff --git a/build/android/pylib/local/emulator/avd.py b/build/android/pylib/local/emulator/avd.py
index e82b7c08..7972cb5 100644
--- a/build/android/pylib/local/emulator/avd.py
+++ b/build/android/pylib/local/emulator/avd.py
@@ -241,6 +241,7 @@
                  or _DEFAULT_SCREEN_DENSITY)
 
       config_ini_contents = {
+          'disk.dataPartition.size': '4G',
           'hw.lcd.density': density,
           'hw.lcd.height': height,
           'hw.lcd.width': width,
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 1455a9f..91c7b3d3 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -1552,13 +1552,6 @@
           "-Wno-deprecated-copy",
         ]
 
-        if (is_win) {
-          cflags += [
-            # TODO(https://crbug.com/1002945): Clean up, enable.
-            "-Wno-sizeof-array-div",
-          ]
-        }
-
         cflags_c += [
           # TODO(https://crbug.com/995993): Clean up and enable.
           "-Wno-implicit-fallthrough",
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 2c9ab12..14d8a008 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-8890671759613905216
\ No newline at end of file
+8890986310162385184
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index e30a0bd..db53a042 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-8890671760545878432
\ No newline at end of file
+8891823802666694096
\ No newline at end of file
diff --git a/chrome/VERSION b/chrome/VERSION
index 9c3b653..b068947 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=81
 MINOR=0
-BUILD=4035
+BUILD=4036
 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
index 6363dadc..ede7042 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
@@ -180,7 +180,7 @@
         return FeatureUtilities.isCommandLineOnNonRootedEnabled();
     }
 
-    private static boolean isBrowserProcess() {
+    protected static boolean isBrowserProcess() {
         return !ContextUtils.getProcessName().contains(":");
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/MonochromeApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/MonochromeApplication.java
index c4801e3d..47df55f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/MonochromeApplication.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/MonochromeApplication.java
@@ -9,6 +9,8 @@
 import com.android.webview.chromium.MonochromeLibraryPreloader;
 
 import org.chromium.android_webview.nonembedded.WebViewApkApplication;
+import org.chromium.base.ActivityState;
+import org.chromium.base.ApplicationStatus;
 import org.chromium.base.library_loader.LibraryLoader;
 import org.chromium.base.library_loader.LibraryProcessType;
 import org.chromium.content_public.browser.ChildProcessCreationParams;
@@ -45,6 +47,31 @@
     }
 
     @Override
+    public void onCreate() {
+        super.onCreate();
+        // TODO(https://crbug.com/1002589): remove beta channel check when approved
+        if (!ChromeVersionInfo.isStableBuild() && !ChromeVersionInfo.isBetaBuild()) {
+            // Performing Monochrome WebView DevTools Launcher icon showing/hiding logic in onCreate
+            // rather than in attachBaseContext() because it depends on application context being
+            // initiatied.
+            if (isWebViewProcess()) {
+                // Whenever a monochrome webview process is launched (WebView service or developer
+                // UI), post a background task to show/hide the DevTools icon.
+                WebViewApkApplication.postDeveloperUiLauncherIconTask();
+            } else if (isBrowserProcess()) {
+                // Frequently check current system webview provider and show/hide the icon
+                // accordingly by listening to Monochrome browser Activities status (whenever a
+                // browser activity comes to the foreground).
+                ApplicationStatus.registerStateListenerForAllActivities((activity, state) -> {
+                    if (state == ActivityState.RESUMED) {
+                        WebViewApkApplication.postDeveloperUiLauncherIconTask();
+                    }
+                });
+            }
+        }
+    }
+
+    @Override
     protected boolean isWebViewProcess() {
         return WebViewApkApplication.isWebViewProcess();
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java
index 7c8c0dad..ce24bd9b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java
@@ -1388,7 +1388,7 @@
         if (quickActionShown) {
             RecordHistogram.recordEnumeratedHistogram(
                     "Search.ContextualSearchQuickActions.Category", quickActionCategory,
-                    QuickActionResolve.NUM_ENTRIES);
+                    QuickActionCategory.BOUNDARY);
         }
     }
 
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index de647b6..6125b89 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -3591,6 +3591,9 @@
   <message name="IDS_CROSTINI_INSTALLER_DISK_SIZE_MESSAGE" desc="Text shown in the Crostini installer dialog describing how and why to choose the initial size of the Crostini disk">
     Disk space to reserve for Crostini (you can change this later).
   </message>
+  <message name="IDS_CROSTINI_INSTALLER_USERNAME_MESSAGE" desc="Text shown in the Crostini installer dialog prompting the user to pick their username">
+    Select a username
+  </message>
   <message name="IDS_CROSTINI_UNINSTALLER_TITLE" desc="Title of the Crostini uninstaller, a dialog for uninstalling Linux, the associated VM and Linux files.">
     Delete Linux (Beta)
   </message>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 134f644..8d70be87 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -3559,6 +3559,8 @@
       "sharing/sharing_notification_handler.h",
       "sharing/sharing_ui_controller.cc",
       "sharing/sharing_ui_controller.h",
+      "sharing/webrtc/ice_config_fetcher.cc",
+      "sharing/webrtc/ice_config_fetcher.h",
       "signin/signin_promo.cc",
       "signin/signin_promo.h",
       "signin/signin_ui_util.cc",
@@ -3713,6 +3715,7 @@
       "//chrome/services/app_service/public/cpp:icon_loader",
       "//chrome/services/app_service/public/cpp:intents",
       "//chrome/services/app_service/public/cpp:preferred_apps",
+      "//chrome/services/sharing/public/mojom",
       "//components/feedback",
       "//components/image_fetcher/core",
       "//components/keep_alive_registry",
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index 1513ddb1..0085b65 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -21,6 +21,7 @@
   "+chrome/services/file_util/public",
   "+chrome/services/media_gallery_util/public",
   "+chrome/services/printing/public",
+  "+chrome/services/sharing/public",
   "+chrome/services/removable_storage_writer/public",
   "+chrome/services/util_win/public",
   "+chromeos",
diff --git a/chrome/browser/browsing_data/cookies_tree_model.h b/chrome/browser/browsing_data/cookies_tree_model.h
index ec4b3538..b7b6e7f9 100644
--- a/chrome/browser/browsing_data/cookies_tree_model.h
+++ b/chrome/browser/browsing_data/cookies_tree_model.h
@@ -18,7 +18,6 @@
 #include "extensions/buildflags/buildflags.h"
 #include "ui/base/models/tree_node_model.h"
 
-class BrowsingDataCookieHelper;
 class CookiesTreeModel;
 class CookieTreeAppCacheNode;
 class CookieTreeAppCachesNode;
@@ -357,7 +356,6 @@
   void PopulateFlashLSOInfo(LocalDataContainer* container);
   void PopulateMediaLicenseInfo(LocalDataContainer* container);
 
-  BrowsingDataCookieHelper* GetCookieHelper(const std::string& app_id);
   LocalDataContainer* data_container() {
     return data_container_.get();
   }
@@ -374,9 +372,6 @@
  private:
   enum CookieIconIndex { COOKIE = 0, DATABASE = 1 };
 
-  // Reset the counters for batches.
-  void ResetBatches();
-
   // Record that one batch has been delivered.
   void RecordBatchSeen();
 
diff --git a/chrome/browser/browsing_data/counters/site_data_counting_helper.cc b/chrome/browser/browsing_data/counters/site_data_counting_helper.cc
index f1f7140b..7d5a211 100644
--- a/chrome/browser/browsing_data/counters/site_data_counting_helper.cc
+++ b/chrome/browser/browsing_data/counters/site_data_counting_helper.cc
@@ -196,19 +196,6 @@
   Done(origins);
 }
 
-void SiteDataCountingHelper::GetSessionStorageUsageInfoCallback(
-    const scoped_refptr<storage::SpecialStoragePolicy>& policy,
-    const std::vector<content::SessionStorageUsageInfo>& infos) {
-  std::vector<GURL> origins;
-  for (const auto& info : infos) {
-    // Session storage doesn't know about creation time.
-    if (!policy || !policy->IsStorageProtected(info.origin)) {
-      origins.push_back(info.origin);
-    }
-  }
-  Done(origins);
-}
-
 void SiteDataCountingHelper::SitesWithFlashDataCallback(
     const std::vector<std::string>& sites) {
   std::vector<GURL> origins;
diff --git a/chrome/browser/browsing_data/counters/site_data_counting_helper.h b/chrome/browser/browsing_data/counters/site_data_counting_helper.h
index 82e8c45..414bce5 100644
--- a/chrome/browser/browsing_data/counters/site_data_counting_helper.h
+++ b/chrome/browser/browsing_data/counters/site_data_counting_helper.h
@@ -21,7 +21,6 @@
 class HostContentSettingsMap;
 
 namespace content {
-struct SessionStorageUsageInfo;
 struct StorageUsageInfo;
 }
 
@@ -49,10 +48,6 @@
   void GetOriginsFromHostContentSettignsMap(HostContentSettingsMap* hcsm,
                                             ContentSettingsType type);
   void GetCookiesCallback(const net::CookieList& cookies);
-  void GetSessionStorageUsageInfoCallback(
-      const scoped_refptr<storage::SpecialStoragePolicy>&
-          special_storage_policy,
-      const std::vector<content::SessionStorageUsageInfo>& infos);
   void GetLocalStorageUsageInfoCallback(
       const scoped_refptr<storage::SpecialStoragePolicy>&
           special_storage_policy,
diff --git a/chrome/browser/browsing_data/counters/sync_aware_counter_browsertest.cc b/chrome/browser/browsing_data/counters/sync_aware_counter_browsertest.cc
index cff119e..6e0cace 100644
--- a/chrome/browser/browsing_data/counters/sync_aware_counter_browsertest.cc
+++ b/chrome/browser/browsing_data/counters/sync_aware_counter_browsertest.cc
@@ -278,7 +278,7 @@
   sync_service->GetUserSettings()->SetSelectedTypes(/*sync_everything=*/false,
                                                     only_passwords);
   sync_blocker.reset();
-  EXPECT_FALSE(counter.HasTrackedTasks());
+  EXPECT_FALSE(counter.HasTrackedTasksForTesting());
   EXPECT_FALSE(CountingFinishedSinceLastAsked());
 
   // Same in this case.
@@ -289,7 +289,7 @@
   sync_service->GetUserSettings()->SetSelectedTypes(
       /*sync_everything=*/false, autofill_and_passwords);
   sync_blocker.reset();
-  EXPECT_FALSE(counter.HasTrackedTasks());
+  EXPECT_FALSE(counter.HasTrackedTasksForTesting());
   EXPECT_FALSE(CountingFinishedSinceLastAsked());
 
   // We start syncing history deletion again. This restarts the counter.
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 78ed2d9..754e542 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -62,6 +62,7 @@
 #include "chrome/browser/font_family_cache.h"
 #include "chrome/browser/gpu/chrome_browser_main_extra_parts_gpu.h"
 #include "chrome/browser/hid/chrome_hid_delegate.h"
+#include "chrome/browser/interstitials/enterprise_util.h"
 #include "chrome/browser/lifetime/browser_shutdown.h"
 #include "chrome/browser/lookalikes/lookalike_url_navigation_throttle.h"
 #include "chrome/browser/media/router/media_router_feature.h"
@@ -3925,6 +3926,10 @@
   throttles.push_back(std::make_unique<PolicyBlacklistNavigationThrottle>(
       handle, handle->GetWebContents()->GetBrowserContext()));
 
+  // Before setting up SSL error detection, configure SSLErrorHandler to invoke
+  // the relevant extension API whenever an SSL interstitial is shown.
+  SSLErrorHandler::SetClientCallbackOnInterstitialsShown(
+      base::BindRepeating(&MaybeTriggerSecurityInterstitialShownEvent));
   throttles.push_back(std::make_unique<SSLErrorNavigationThrottle>(
       handle,
       std::make_unique<CertificateReportingServiceCertReporter>(web_contents),
diff --git a/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_manager.cc b/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_manager.cc
index 668ccb1..a2c4f07 100644
--- a/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_manager.cc
+++ b/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_manager.cc
@@ -86,11 +86,11 @@
   }
 }
 
-void ArcKioskAppManager::UpdateNameAndIcon(const std::string& app_id,
+void ArcKioskAppManager::UpdateNameAndIcon(const AccountId& account_id,
                                            const std::string& name,
                                            const gfx::ImageSkia& icon) {
   for (auto& app : apps_) {
-    if (app->app_id() == app_id) {
+    if (app->account_id() == account_id) {
       app->SetCache(name, icon);
       return;
     }
diff --git a/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_manager.h b/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_manager.h
index 16e033c..daf7e4a2 100644
--- a/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_manager.h
+++ b/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_manager.h
@@ -42,7 +42,7 @@
   // KioskAppManagerBase:
   void GetApps(std::vector<App>* apps) const override;
 
-  void UpdateNameAndIcon(const std::string& app_id,
+  void UpdateNameAndIcon(const AccountId& account_id,
                          const std::string& name,
                          const gfx::ImageSkia& icon);
 
diff --git a/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_service.cc b/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_service.cc
index d865b04..519b09d 100644
--- a/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_service.cc
+++ b/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_service.cc
@@ -128,8 +128,10 @@
     app_icon_.release();
     return;
   }
-  app_manager_->UpdateNameAndIcon(app_id_, app_info_->name,
+  AccountId account_id = multi_user_util::GetAccountIdFromProfile(profile_);
+  app_manager_->UpdateNameAndIcon(account_id, app_info_->name,
                                   app_icon_->image_skia());
+  delegate_->OnAppDataUpdated();
 }
 
 void ArcKioskAppService::OnArcSessionRestarting() {
@@ -217,6 +219,7 @@
           << (pending_policy_app_installs_.count(app_info_->package_name)
                   ? "non-compliant"
                   : "compliant");
+  RequestNameAndIconUpdate();
   if (app_info_ && app_info_->ready && !maintenance_session_running_ &&
       compliance_report_received_ &&
       pending_policy_app_installs_.count(app_info_->package_name) == 0) {
@@ -229,7 +232,6 @@
     VLOG(2) << "Kiosk app should be closed";
     arc::CloseTask(task_id_);
   }
-  RequestNameAndIconUpdate();
 }
 
 std::string ArcKioskAppService::GetAppId() {
diff --git a/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_service.h b/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_service.h
index 505c394..f36f982 100644
--- a/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_service.h
+++ b/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_service.h
@@ -45,6 +45,7 @@
   class Delegate {
    public:
     Delegate() = default;
+    virtual void OnAppDataUpdated() = 0;
     virtual void OnAppStarted() = 0;
     virtual void OnAppWindowLaunched() = 0;
 
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.cc b/chrome/browser/chromeos/crostini/crostini_manager.cc
index dc1bf23..e932a77 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager.cc
+++ b/chrome/browser/chromeos/crostini/crostini_manager.cc
@@ -292,25 +292,25 @@
     }
 
     // Allow concierge to choose an appropriate disk image size.
-    int64_t disk_size_available = options_.disk_size.value_or(0);
+    int64_t disk_size_bytes = options_.disk_size_bytes.value_or(0);
     // If we have an already existing disk, CreateDiskImage will just return its
     // path so we can pass it to StartTerminaVm.
     StartStage(mojom::InstallerState::kCreateDiskImage);
     crostini_manager_->CreateDiskImage(
         base::FilePath(vm_name_),
         vm_tools::concierge::StorageLocation::STORAGE_CRYPTOHOME_ROOT,
-        disk_size_available,
+        disk_size_bytes,
         base::BindOnce(&CrostiniRestarter::CreateDiskImageFinished, this,
-                       disk_size_available));
+                       disk_size_bytes));
   }
 
-  void CreateDiskImageFinished(int64_t disk_size_available,
+  void CreateDiskImageFinished(int64_t disk_size_bytes,
                                bool success,
                                vm_tools::concierge::DiskImageStatus status,
                                const base::FilePath& result_path) {
     DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
     for (auto& observer : observer_list_) {
-      observer.OnDiskImageCreated(success, status, disk_size_available);
+      observer.OnDiskImageCreated(success, status, disk_size_bytes);
     }
     if (ReturnEarlyIfAborted()) {
       return;
@@ -645,11 +645,35 @@
   }
 }
 
+namespace {
+
+ContainerOsVersion VersionFromOsRelease(
+    const vm_tools::cicerone::OsRelease& os_release) {
+  if (os_release.id() == "debian") {
+    if (os_release.version_id() == "9") {
+      return ContainerOsVersion::kDebianStretch;
+    } else if (os_release.version_id() == "10") {
+      return ContainerOsVersion::kDebianBuster;
+    } else {
+      return ContainerOsVersion::kDebianOther;
+    }
+  }
+  return ContainerOsVersion::kOtherOs;
+}
+
+}  // namespace
+
 void CrostiniManager::SetContainerOsRelease(
     std::string vm_name,
     std::string container_name,
     const vm_tools::cicerone::OsRelease& os_release) {
   ContainerId container_id(vm_name, container_name);
+  ContainerOsVersion version = VersionFromOsRelease(os_release);
+  // Store the os release version in prefs. We can use this value to decide if
+  // an upgrade can be offered.
+  UpdateContainerPref(profile_, container_id, prefs::kContainerOsVersionKey,
+                      base::Value(static_cast<int>(version)));
+
   VLOG(1) << container_id;
   VLOG(1) << "os_release.pretty_name " << os_release.pretty_name();
   VLOG(1) << "os_release.name " << os_release.name();
@@ -657,23 +681,7 @@
   VLOG(1) << "os_release.version_id " << os_release.version_id();
   VLOG(1) << "os_release.id " << os_release.id();
   container_os_releases_.emplace(std::move(container_id), os_release);
-  EmitContainerVersionMetric(os_release);
-}
 
-void CrostiniManager::EmitContainerVersionMetric(
-    const vm_tools::cicerone::OsRelease& os_release) {
-  ContainerOsVersion version;
-  if (os_release.id() == "debian") {
-    if (os_release.version_id() == "9") {
-      version = ContainerOsVersion::kDebianStretch;
-    } else if (os_release.version_id() == "10") {
-      version = ContainerOsVersion::kDebianBuster;
-    } else {
-      version = ContainerOsVersion::kDebianOther;
-    }
-  } else {
-    version = ContainerOsVersion::kOtherOs;
-  }
   base::UmaHistogramEnumeration("Crostini.ContainerOsVersion", version);
 }
 
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.h b/chrome/browser/chromeos/crostini/crostini_manager.h
index 67a29a4..bd70179 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager.h
+++ b/chrome/browser/chromeos/crostini/crostini_manager.h
@@ -147,7 +147,7 @@
     virtual void OnConciergeStarted(bool success) {}
     virtual void OnDiskImageCreated(bool success,
                                     vm_tools::concierge::DiskImageStatus status,
-                                    int64_t disk_size_available) {}
+                                    int64_t disk_size_bytes) {}
     virtual void OnVmStarted(bool success) {}
     virtual void OnContainerDownloading(int32_t download_percent) {}
     virtual void OnContainerCreated(CrostiniResult result) {}
@@ -158,9 +158,9 @@
   };
 
   struct RestartOptions {
-    // This normally will not have effect on existing container.
+    // These two options only affect new containers.
     base::Optional<std::string> container_username;
-    base::Optional<int64_t> disk_size;
+    base::Optional<int64_t> disk_size_bytes;
 
     RestartOptions();
     ~RestartOptions();
@@ -781,10 +781,6 @@
 
   void OnVmStoppedCleanup(const std::string& vm_name);
 
-  // Emits a UMA recording the OS version.
-  void EmitContainerVersionMetric(
-      const vm_tools::cicerone::OsRelease& os_release);
-
   // Configure the container so that it can sideload apps into Arc++.
   void ConfigureForArcSideload();
 
diff --git a/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc b/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
index 9b3018e..a5608d169 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
+++ b/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
@@ -1145,6 +1145,14 @@
             stored_os_release->SerializeAsString());
   histogram_tester.ExpectUniqueSample("Crostini.ContainerOsVersion",
                                       ContainerOsVersion::kDebianBuster, 1);
+
+  // The data for this container should also be stored in prefs.
+  const base::Value* os_release_pref_value =
+      GetContainerPrefValue(profile(), ContainerId(kVmName, kContainerName),
+                            prefs::kContainerOsVersionKey);
+  EXPECT_NE(os_release_pref_value, nullptr);
+  EXPECT_EQ(os_release_pref_value->GetInt(),
+            static_cast<int>(ContainerOsVersion::kDebianBuster));
 }
 
 TEST_F(CrostiniManagerRestartTest, RestartThenUninstall) {
diff --git a/chrome/browser/chromeos/crostini/crostini_pref_names.cc b/chrome/browser/chromeos/crostini/crostini_pref_names.cc
index 96829fb..0679bb1 100644
--- a/chrome/browser/chromeos/crostini/crostini_pref_names.cc
+++ b/chrome/browser/chromeos/crostini/crostini_pref_names.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "base/values.h"
+#include "chrome/browser/chromeos/crostini/crostini_simple_types.h"
 #include "chrome/browser/chromeos/crostini/crostini_util.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_registry_simple.h"
@@ -28,6 +29,7 @@
 const char kCrostiniTerminalSettings[] = "crostini.terminal_settings";
 const char kVmKey[] = "vm_name";
 const char kContainerKey[] = "container_name";
+const char kContainerOsVersionKey[] = "container_os_version";
 
 // A boolean preference representing a user level enterprise policy to enable
 // Crostini use.
diff --git a/chrome/browser/chromeos/crostini/crostini_pref_names.h b/chrome/browser/chromeos/crostini/crostini_pref_names.h
index 3d65549..07555ed 100644
--- a/chrome/browser/chromeos/crostini/crostini_pref_names.h
+++ b/chrome/browser/chromeos/crostini/crostini_pref_names.h
@@ -18,6 +18,7 @@
 extern const char kCrostiniTerminalSettings[];
 extern const char kVmKey[];
 extern const char kContainerKey[];
+extern const char kContainerOsVersionKey[];
 
 extern const char kUserCrostiniAllowedByPolicy[];
 extern const char kUserCrostiniExportImportUIAllowedByPolicy[];
diff --git a/chrome/browser/chromeos/crostini/crostini_simple_types.h b/chrome/browser/chromeos/crostini/crostini_simple_types.h
index 63fbd2f..fd90021 100644
--- a/chrome/browser/chromeos/crostini/crostini_simple_types.h
+++ b/chrome/browser/chromeos/crostini/crostini_simple_types.h
@@ -188,7 +188,7 @@
 }  // namespace crostini
 
 enum class ContainerOsVersion {
-  kUnkown = 0,
+  kUnknown = 0,
   kDebianStretch = 1,
   kDebianBuster = 2,
   kDebianOther = 3,
diff --git a/chrome/browser/chromeos/crostini/crostini_util.cc b/chrome/browser/chromeos/crostini/crostini_util.cc
index 5730b6d..81955a8 100644
--- a/chrome/browser/chromeos/crostini/crostini_util.cc
+++ b/chrome/browser/chromeos/crostini/crostini_util.cc
@@ -503,22 +503,36 @@
   base::Value new_container(base::Value::Type::DICTIONARY);
   new_container.SetKey(prefs::kVmKey, base::Value(vm_name));
   new_container.SetKey(prefs::kContainerKey, base::Value(container_name));
+  new_container.SetIntKey(prefs::kContainerOsVersionKey,
+                          static_cast<int>(ContainerOsVersion::kUnknown));
 
   ListPrefUpdate updater(pref_service, crostini::prefs::kCrostiniContainers);
   updater->Append(std::move(new_container));
 }
 
+namespace {
+
+bool MatchContainerDict(const base::Value& dict,
+                        const ContainerId& container_id) {
+  const std::string* vm_name = dict.FindStringKey(prefs::kVmKey);
+  const std::string* container_name = dict.FindStringKey(prefs::kContainerKey);
+  return (vm_name && *vm_name == container_id.vm_name) &&
+         (container_name && *container_name == container_id.container_name);
+}
+
+}  // namespace
+
 void RemoveLxdContainerFromPrefs(Profile* profile,
                                  std::string vm_name,
                                  std::string container_name) {
   auto* pref_service = profile->GetPrefs();
   ListPrefUpdate updater(pref_service, crostini::prefs::kCrostiniContainers);
-  updater->EraseListIter(std::find_if(
-      updater->GetList().begin(), updater->GetList().end(),
-      [&](const auto& dict) {
-        return *dict.FindStringKey(prefs::kVmKey) == vm_name &&
-               *dict.FindStringKey(prefs::kContainerKey) == container_name;
-      }));
+  ContainerId container_id(vm_name, container_name);
+  updater->EraseListIter(
+      std::find_if(updater->GetList().begin(), updater->GetList().end(),
+                   [&](const auto& dict) {
+                     return MatchContainerDict(dict, container_id);
+                   }));
 
   CrostiniRegistryServiceFactory::GetForProfile(profile)->ClearApplicationList(
       vm_name, container_name);
@@ -526,6 +540,37 @@
       vm_name, container_name);
 }
 
+const base::Value* GetContainerPrefValue(Profile* profile,
+                                         const ContainerId& container_id,
+                                         const std::string& key) {
+  const base::ListValue* containers =
+      profile->GetPrefs()->GetList(crostini::prefs::kCrostiniContainers);
+  if (!containers) {
+    return nullptr;
+  }
+  auto it = std::find_if(
+      containers->begin(), containers->end(),
+      [&](const auto& dict) { return MatchContainerDict(dict, container_id); });
+  if (it == containers->end()) {
+    return nullptr;
+  }
+  return it->FindKey(key);
+}
+
+void UpdateContainerPref(Profile* profile,
+                         const ContainerId& container_id,
+                         const std::string& key,
+                         base::Value value) {
+  ListPrefUpdate updater(profile->GetPrefs(),
+                         crostini::prefs::kCrostiniContainers);
+  auto it = std::find_if(
+      updater->GetList().begin(), updater->GetList().end(),
+      [&](const auto& dict) { return MatchContainerDict(dict, container_id); });
+  if (it != updater->GetList().end()) {
+    it->SetKey(key, std::move(value));
+  }
+}
+
 base::string16 GetTimeRemainingMessage(base::TimeTicks start, int percent) {
   // Only estimate once we've spent at least 3 seconds OR gotten 10% of the way
   // through.
diff --git a/chrome/browser/chromeos/crostini/crostini_util.h b/chrome/browser/chromeos/crostini/crostini_util.h
index 6eab876..9a21f706 100644
--- a/chrome/browser/chromeos/crostini/crostini_util.h
+++ b/chrome/browser/chromeos/crostini/crostini_util.h
@@ -12,6 +12,7 @@
 #include "base/callback.h"
 #include "base/files/file_path.h"
 #include "base/optional.h"
+#include "base/values.h"
 #include "storage/browser/file_system/file_system_url.h"
 #include "ui/base/resource/scale_factor.h"
 
@@ -213,6 +214,17 @@
 std::vector<int64_t> GetTicksForDiskSize(int64_t min_size,
                                          int64_t available_space);
 
+// Returns a pref value stored for a specific container.
+const base::Value* GetContainerPrefValue(Profile* profile,
+                                         const ContainerId& container_id,
+                                         const std::string& key);
+
+// Sets a pref value for a specific container.
+void UpdateContainerPref(Profile* profile,
+                         const ContainerId& container_id,
+                         const std::string& key,
+                         base::Value value);
+
 }  // namespace crostini
 
 #endif  // CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_UTIL_H_
diff --git a/chrome/browser/chromeos/file_manager/path_util.cc b/chrome/browser/chromeos/file_manager/path_util.cc
index e6ed1d6..3753a742 100644
--- a/chrome/browser/chromeos/file_manager/path_util.cc
+++ b/chrome/browser/chromeos/file_manager/path_util.cc
@@ -375,7 +375,7 @@
   bool force_external = false;
   // Force external URL for DriveFS and Crostini.
   drive::DriveIntegrationService* integration_service =
-      drive::DriveIntegrationServiceFactory::FindForProfile(primary_profile);
+      drive::util::GetIntegrationServiceByProfile(primary_profile);
   if ((integration_service &&
        integration_service->GetMountPointPath().AppendRelativePath(
            path, &relative_path)) ||
diff --git a/chrome/browser/chromeos/file_manager/path_util_unittest.cc b/chrome/browser/chromeos/file_manager/path_util_unittest.cc
index 6216690..510f221 100644
--- a/chrome/browser/chromeos/file_manager/path_util_unittest.cc
+++ b/chrome/browser/chromeos/file_manager/path_util_unittest.cc
@@ -531,6 +531,8 @@
     ASSERT_TRUE(profile_manager_->CreateTestingProfile("user2@gmail.com"));
     primary_profile->GetPrefs()->SetString(drive::prefs::kDriveFsProfileSalt,
                                            "a");
+    primary_profile->GetPrefs()->SetBoolean(
+        drive::prefs::kDriveFsPinnedMigrated, true);
 
     // Set up an Arc service manager with a fake file system.
     arc_service_manager_ = std::make_unique<arc::ArcServiceManager>();
@@ -550,10 +552,7 @@
     drive::DriveIntegrationService* integration_service =
         drive::DriveIntegrationServiceFactory::GetForProfile(primary_profile);
     drive_mount_point_ = integration_service->GetMountPointPath();
-    mount_points->RegisterFileSystem(
-        drive_mount_point_.BaseName().AsUTF8Unsafe(),
-        storage::kFileSystemTypeNativeLocal, storage::FileSystemMountOption(),
-        drive_mount_point_);
+    integration_service->OnMounted(drive_mount_point_);
 
     // Add a crostini mount point for the primary profile.
     crostini_mount_point_ = GetCrostiniMountDirectory(primary_profile);
diff --git a/chrome/browser/chromeos/fileapi/recent_arc_media_source.cc b/chrome/browser/chromeos/fileapi/recent_arc_media_source.cc
index 6e371b5e..0adbd4e6 100644
--- a/chrome/browser/chromeos/fileapi/recent_arc_media_source.cc
+++ b/chrome/browser/chromeos/fileapi/recent_arc_media_source.cc
@@ -36,8 +36,11 @@
 
 const char kMediaDocumentsProviderAuthority[] =
     "com.android.providers.media.documents";
+constexpr char kMediaDocumentsProviderImagesRoot[] = "images_root";
+constexpr char kMediaDocumentsProviderVideosRoot[] = "videos_root";
 const char* kMediaDocumentsProviderRootIds[] = {
-    "images_root", "videos_root",
+    kMediaDocumentsProviderImagesRoot,
+    kMediaDocumentsProviderVideosRoot,
 };
 
 base::FilePath GetRelativeMountPath(const std::string& root_id) {
@@ -89,6 +92,7 @@
 
   storage::FileSystemURL BuildDocumentsProviderUrl(
       const base::FilePath& path) const;
+  bool MatchesFileType(FileType file_type) const;
 
   // Set in the constructor.
   const std::string root_id_;
@@ -143,6 +147,13 @@
     return;
   }
 
+  if (!MatchesFileType(params_.value().file_type())) {
+    // Return immediately without results when this root's id does not match the
+    // requested file type.
+    OnComplete();
+    return;
+  }
+
   runner->GetRecentDocuments(kMediaDocumentsProviderAuthority, root_id_,
                              base::Bind(&MediaRoot::OnGetRecentDocuments,
                                         weak_ptr_factory_.GetWeakPtr()));
@@ -277,6 +288,20 @@
       relative_mount_path_.Append(path));
 }
 
+bool RecentArcMediaSource::MediaRoot::MatchesFileType(
+    FileType file_type) const {
+  switch (file_type) {
+    case FileType::kAll:
+      return true;
+    case FileType::kImage:
+      return root_id_ == kMediaDocumentsProviderImagesRoot;
+    case FileType::kVideo:
+      return root_id_ == kMediaDocumentsProviderVideosRoot;
+    default:
+      return false;
+  }
+}
+
 RecentArcMediaSource::RecentArcMediaSource(Profile* profile)
     : profile_(profile) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
diff --git a/chrome/browser/chromeos/fileapi/recent_arc_media_source_unittest.cc b/chrome/browser/chromeos/fileapi/recent_arc_media_source_unittest.cc
index 3e2eebaf..085ec1c 100644
--- a/chrome/browser/chromeos/fileapi/recent_arc_media_source_unittest.cc
+++ b/chrome/browser/chromeos/fileapi/recent_arc_media_source_unittest.cc
@@ -30,7 +30,9 @@
 
 const char kMediaDocumentsProviderAuthority[] =
     "com.android.providers.media.documents";
+const char kAudioRootId[] = "audio_root";
 const char kImagesRootId[] = "images_root";
+const char kVideosRootId[] = "videos_root";
 
 std::unique_ptr<KeyedService> CreateFileSystemOperationRunnerForTesting(
     content::BrowserContext* context) {
@@ -88,7 +90,7 @@
 
  protected:
   void AddDocumentsToFakeFileSystemInstance() {
-    auto root_doc =
+    auto images_root_doc =
         MakeDocument(kImagesRootId, "", "", arc::kAndroidDirectoryMimeType,
                      base::Time::FromJavaTime(1));
     auto cat_doc = MakeDocument("cat", kImagesRootId, "cat.png", "image/png",
@@ -99,14 +101,38 @@
                                 base::Time::FromJavaTime(4));
     auto elk_doc = MakeDocument("elk", kImagesRootId, "elk.tiff", "image/tiff",
                                 base::Time::FromJavaTime(5));
-    fake_file_system_.AddDocument(root_doc);
+    auto audio_root_doc =
+        MakeDocument(kAudioRootId, "", "", arc::kAndroidDirectoryMimeType,
+                     base::Time::FromJavaTime(1));
+    auto god_doc = MakeDocument("god", kAudioRootId, "god.mp3", "audio/mp3",
+                                base::Time::FromJavaTime(6));
+    auto videos_root_doc =
+        MakeDocument(kVideosRootId, "", "", arc::kAndroidDirectoryMimeType,
+                     base::Time::FromJavaTime(1));
+    auto hot_doc = MakeDocument("hot", kVideosRootId, "hot.mp4", "video/mp4",
+                                base::Time::FromJavaTime(7));
+    auto ink_doc = MakeDocument("ink", kVideosRootId, "ink.webm", "video/webm",
+                                base::Time::FromJavaTime(8));
+
+    fake_file_system_.AddDocument(images_root_doc);
     fake_file_system_.AddDocument(cat_doc);
     fake_file_system_.AddDocument(dog_doc);
     fake_file_system_.AddDocument(fox_doc);
-    fake_file_system_.AddRecentDocument(kImagesRootId, root_doc);
+    fake_file_system_.AddDocument(audio_root_doc);
+    fake_file_system_.AddDocument(god_doc);
+    fake_file_system_.AddDocument(videos_root_doc);
+    fake_file_system_.AddDocument(hot_doc);
+    fake_file_system_.AddDocument(ink_doc);
+
+    fake_file_system_.AddRecentDocument(kImagesRootId, images_root_doc);
     fake_file_system_.AddRecentDocument(kImagesRootId, cat_doc);
     fake_file_system_.AddRecentDocument(kImagesRootId, dog_doc);
     fake_file_system_.AddRecentDocument(kImagesRootId, elk_doc);
+    fake_file_system_.AddRecentDocument(kAudioRootId, audio_root_doc);
+    fake_file_system_.AddRecentDocument(kAudioRootId, god_doc);
+    fake_file_system_.AddRecentDocument(kVideosRootId, videos_root_doc);
+    fake_file_system_.AddRecentDocument(kVideosRootId, hot_doc);
+    fake_file_system_.AddRecentDocument(kVideosRootId, ink_doc);
   }
 
   void EnableFakeFileSystemInstance() {
@@ -116,7 +142,8 @@
         arc_service_manager_->arc_bridge_service()->file_system());
   }
 
-  std::vector<RecentFile> GetRecentFiles() {
+  std::vector<RecentFile> GetRecentFiles(
+      RecentSource::FileType file_type = RecentSource::FileType::kAll) {
     std::vector<RecentFile> files;
 
     base::RunLoop run_loop;
@@ -124,7 +151,7 @@
     source_->GetRecentFiles(RecentSource::Params(
         nullptr /* file_system_context */, GURL() /* origin */,
         1 /* max_files: ignored */, base::Time() /* cutoff_time: ignored */,
-        RecentSource::FileType::kAll /* file_type: ignored */,
+        file_type /* file_type */,
         base::BindOnce(
             [](base::RunLoop* run_loop, std::vector<RecentFile>* out_files,
                std::vector<RecentFile> files) {
@@ -158,7 +185,7 @@
 
   std::vector<RecentFile> files = GetRecentFiles();
 
-  ASSERT_EQ(2u, files.size());
+  ASSERT_EQ(4u, files.size());
   EXPECT_EQ(arc::GetDocumentsProviderMountPath(kMediaDocumentsProviderAuthority,
                                                kImagesRootId)
                 .Append("cat.png"),
@@ -169,6 +196,16 @@
                 .Append("dog.jpg"),
             files[1].url().path());
   EXPECT_EQ(base::Time::FromJavaTime(3), files[1].last_modified());
+  EXPECT_EQ(arc::GetDocumentsProviderMountPath(kMediaDocumentsProviderAuthority,
+                                               kVideosRootId)
+                .Append("hot.mp4"),
+            files[2].url().path());
+  EXPECT_EQ(base::Time::FromJavaTime(7), files[2].last_modified());
+  EXPECT_EQ(arc::GetDocumentsProviderMountPath(kMediaDocumentsProviderAuthority,
+                                               kVideosRootId)
+                .Append("ink.webm"),
+            files[3].url().path());
+  EXPECT_EQ(base::Time::FromJavaTime(8), files[3].last_modified());
 }
 
 TEST_F(RecentArcMediaSourceTest, ArcNotAvailable) {
@@ -186,6 +223,54 @@
   EXPECT_EQ(0u, files.size());
 }
 
+TEST_F(RecentArcMediaSourceTest, GetAudioFiles) {
+  EnableFakeFileSystemInstance();
+
+  std::vector<RecentFile> files =
+      GetRecentFiles(RecentSource::FileType::kAudio);
+  // Query for recently-modified audio files should be ignored, since
+  // MediaDocumentsProvider doesn't support queryRecentDocuments for audio.
+  ASSERT_EQ(0u, files.size());
+}
+
+TEST_F(RecentArcMediaSourceTest, GetImageFiles) {
+  EnableFakeFileSystemInstance();
+
+  std::vector<RecentFile> files =
+      GetRecentFiles(RecentSource::FileType::kImage);
+
+  ASSERT_EQ(2u, files.size());
+  EXPECT_EQ(arc::GetDocumentsProviderMountPath(kMediaDocumentsProviderAuthority,
+                                               kImagesRootId)
+                .Append("cat.png"),
+            files[0].url().path());
+  EXPECT_EQ(base::Time::FromJavaTime(2), files[0].last_modified());
+  EXPECT_EQ(arc::GetDocumentsProviderMountPath(kMediaDocumentsProviderAuthority,
+                                               kImagesRootId)
+                .Append("dog.jpg"),
+            files[1].url().path());
+  EXPECT_EQ(base::Time::FromJavaTime(3), files[1].last_modified());
+}
+
+TEST_F(RecentArcMediaSourceTest, GetVideoFiles) {
+  EnableFakeFileSystemInstance();
+
+  std::vector<RecentFile> files =
+      GetRecentFiles(RecentSource::FileType::kVideo);
+
+  ASSERT_EQ(2u, files.size());
+  EXPECT_EQ(arc::GetDocumentsProviderMountPath(kMediaDocumentsProviderAuthority,
+                                               kVideosRootId)
+                .Append("hot.mp4"),
+            files[0].url().path());
+  EXPECT_EQ(base::Time::FromJavaTime(7), files[0].last_modified());
+  EXPECT_EQ(arc::GetDocumentsProviderMountPath(kMediaDocumentsProviderAuthority,
+                                               kVideosRootId)
+                .Append("ink.webm"),
+            files[1].url().path());
+  EXPECT_EQ(base::Time::FromJavaTime(8), files[1].last_modified());
+}
+
 TEST_F(RecentArcMediaSourceTest, UmaStats) {
   EnableFakeFileSystemInstance();
 
diff --git a/chrome/browser/chromeos/login/arc_kiosk_controller.cc b/chrome/browser/chromeos/login/arc_kiosk_controller.cc
index 8bee0c6..5f49a92c 100644
--- a/chrome/browser/chromeos/login/arc_kiosk_controller.cc
+++ b/chrome/browser/chromeos/login/arc_kiosk_controller.cc
@@ -18,7 +18,6 @@
 #include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/webui/chromeos/login/arc_kiosk_splash_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
 #include "chromeos/login/auth/user_context.h"
@@ -34,7 +33,7 @@
 ArcKioskController::ArcKioskController(LoginDisplayHost* host, OobeUI* oobe_ui)
     : host_(host),
       arc_kiosk_splash_screen_view_(
-          oobe_ui->GetView<ArcKioskSplashScreenHandler>()) {}
+          oobe_ui->GetView<AppLaunchSplashScreenHandler>()) {}
 
 ArcKioskController::~ArcKioskController() {
   if (arc_kiosk_splash_screen_view_)
@@ -44,6 +43,8 @@
 void ArcKioskController::StartArcKiosk(const AccountId& account_id) {
   DVLOG(1) << "Starting ARC Kiosk for account: " << account_id.GetUserEmail();
 
+  account_id_ = account_id;
+
   host_->GetLoginDisplay()->SetUIEnabled(true);
 
   arc_kiosk_splash_screen_view_->SetDelegate(this);
@@ -56,7 +57,7 @@
   login_performer_->LoginAsArcKioskAccount(account_id);
 }
 
-void ArcKioskController::OnCancelArcKioskLaunch() {
+void ArcKioskController::OnCancelAppLaunch() {
   if (ArcKioskAppManager::Get()->GetDisableBailoutShortcut())
     return;
 
@@ -140,18 +141,35 @@
   // a profile load, so invalidate the delegate now.
   UserSessionManager::GetInstance()->DelegateDeleted(this);
   ArcKioskAppService::Get(profile_)->SetDelegate(this);
+
+  // This is needed to trigger input method extensions being loaded.
+  profile->InitChromeOSPreferences();
+
+  // Reset virtual keyboard to use IME engines in app profile early.
+  ChromeKeyboardControllerClient::Get()->RebuildKeyboardIfEnabled();
+
   if (arc_kiosk_splash_screen_view_) {
-    arc_kiosk_splash_screen_view_->UpdateArcKioskState(
-        ArcKioskSplashScreenView::ArcKioskState::WAITING_APP_LAUNCH);
+    // In ARC kiosk mode, installing means waiting for app be registered.
+    arc_kiosk_splash_screen_view_->UpdateAppLaunchState(
+        AppLaunchSplashScreenView::AppLaunchState::
+            APP_LAUNCH_STATE_INSTALLING_APPLICATION);
   }
 }
 
+void ArcKioskController::OnAppDataUpdated() {
+  // Invokes Show() to update the app title and icon.
+  arc_kiosk_splash_screen_view_->Show();
+}
+
 void ArcKioskController::OnAppStarted() {
   DVLOG(1) << "ARC Kiosk launch succeeded, wait for app window.";
 
   if (arc_kiosk_splash_screen_view_) {
-    arc_kiosk_splash_screen_view_->UpdateArcKioskState(
-        ArcKioskSplashScreenView::ArcKioskState::WAITING_APP_WINDOW);
+    arc_kiosk_splash_screen_view_->UpdateAppLaunchState(
+        AppLaunchSplashScreenView::AppLaunchState::
+            APP_LAUNCH_STATE_WAITING_APP_WINDOW);
+    // Invokes Show() to update the app title and icon.
+    arc_kiosk_splash_screen_view_->Show();
   }
 }
 
@@ -165,4 +183,13 @@
   CloseSplashScreen();
 }
 
+KioskAppManagerBase::App ArcKioskController::GetAppData() {
+  DCHECK(account_id_.is_valid());
+  const ArcKioskAppData* arc_app =
+      ArcKioskAppManager::Get()->GetAppByAccountId(account_id_);
+  DCHECK(arc_app);
+  KioskAppManagerBase::App app(*arc_app);
+  return app;
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/arc_kiosk_controller.h b/chrome/browser/chromeos/login/arc_kiosk_controller.h
index 2fc67dd..ed4c2bdd 100644
--- a/chrome/browser/chromeos/login/arc_kiosk_controller.h
+++ b/chrome/browser/chromeos/login/arc_kiosk_controller.h
@@ -8,7 +8,9 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_service.h"
+#include "chrome/browser/chromeos/app_mode/kiosk_app_manager_base.h"
 #include "chrome/browser/chromeos/login/session/user_session_manager.h"
+#include "chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h"
 #include "chromeos/login/auth/login_performer.h"
 
 class AccountId;
@@ -20,7 +22,6 @@
 
 namespace chromeos {
 
-class ArcKioskSplashScreenView;
 class LoginDisplayHost;
 class OobeUI;
 class UserContext;
@@ -30,7 +31,8 @@
 // updating the splash screen UI.
 class ArcKioskController : public LoginPerformer::Delegate,
                            public UserSessionManagerDelegate,
-                           public ArcKioskAppService::Delegate {
+                           public ArcKioskAppService::Delegate,
+                           public AppLaunchSplashScreenView::Delegate {
  public:
   ArcKioskController(LoginDisplayHost* host, OobeUI* oobe_ui);
 
@@ -39,11 +41,6 @@
   // Starts ARC kiosk splash screen.
   void StartArcKiosk(const AccountId& account_id);
 
-  // Invoked when the launch bailout shortcut key is pressed.
-  void OnCancelArcKioskLaunch();
-  // Invoked when the splash screen view gets being deleted.
-  void OnDeletingSplashScreenView();
-
  private:
   void CleanUp();
   void CloseSplashScreen();
@@ -61,13 +58,22 @@
   void OnProfilePrepared(Profile* profile, bool browser_launched) override;
 
   // ArcKioskAppService::Delegate implementation:
+  void OnAppDataUpdated() override;
   void OnAppStarted() override;
   void OnAppWindowLaunched() override;
 
+  // AppLaunchSplashScreenView::Delegate implementation:
+  KioskAppManagerBase::App GetAppData() override;
+  void OnCancelAppLaunch() override;
+  void OnDeletingSplashScreenView() override;
+
+  // Accound id of the app we are currently running.
+  AccountId account_id_;
+
   // LoginDisplayHost owns itself.
   LoginDisplayHost* const host_;
   // Owned by OobeUI.
-  ArcKioskSplashScreenView* arc_kiosk_splash_screen_view_;
+  AppLaunchSplashScreenView* arc_kiosk_splash_screen_view_;
   // Not owning here.
   Profile* profile_ = nullptr;
 
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_common.cc b/chrome/browser/chromeos/login/ui/login_display_host_common.cc
index 28d9e84..4d68c66 100644
--- a/chrome/browser/chromeos/login/ui/login_display_host_common.cc
+++ b/chrome/browser/chromeos/login/ui/login_display_host_common.cc
@@ -172,7 +172,7 @@
       std::make_unique<ArcKioskController>(this, GetOobeUI());
   arc_kiosk_controller_->StartArcKiosk(account_id);
 
-  OnStartArcKiosk();
+  OnStartAppLaunch();
 }
 
 void LoginDisplayHostCommon::StartWebKiosk(const AccountId& account_id) {
@@ -200,7 +200,7 @@
     // shown by the DeviceDisablingManager.
     return;
   }
-  OnStartWebKiosk();
+  OnStartAppLaunch();
 
   web_kiosk_controller_ =
       std::make_unique<WebKioskController>(this, GetOobeUI());
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_common.h b/chrome/browser/chromeos/login/ui/login_display_host_common.h
index 7222914..e3e1dca 100644
--- a/chrome/browser/chromeos/login/ui/login_display_host_common.h
+++ b/chrome/browser/chromeos/login/ui/login_display_host_common.h
@@ -70,8 +70,6 @@
  protected:
   virtual void OnStartSignInScreen(const LoginScreenContext& context) = 0;
   virtual void OnStartAppLaunch() = 0;
-  virtual void OnStartArcKiosk() = 0;
-  virtual void OnStartWebKiosk() = 0;
   virtual void OnBrowserCreated() = 0;
   virtual void OnStartUserAdding() = 0;
   virtual void OnFinalize() = 0;
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_mojo.cc b/chrome/browser/chromeos/login/ui/login_display_host_mojo.cc
index 05d269d..cec0aae 100644
--- a/chrome/browser/chromeos/login/ui/login_display_host_mojo.cc
+++ b/chrome/browser/chromeos/login/ui/login_display_host_mojo.cc
@@ -250,14 +250,6 @@
   ShowFullScreen();
 }
 
-void LoginDisplayHostMojo::OnStartArcKiosk() {
-  ShowFullScreen();
-}
-
-void LoginDisplayHostMojo::OnStartWebKiosk() {
-  ShowFullScreen();
-}
-
 void LoginDisplayHostMojo::OnBrowserCreated() {
   NOTIMPLEMENTED();
 }
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_mojo.h b/chrome/browser/chromeos/login/ui/login_display_host_mojo.h
index 75e737a..d3257e4 100644
--- a/chrome/browser/chromeos/login/ui/login_display_host_mojo.h
+++ b/chrome/browser/chromeos/login/ui/login_display_host_mojo.h
@@ -82,8 +82,6 @@
   void OnStartSignInScreen(const LoginScreenContext& context) override;
   void OnPreferencesChanged() override;
   void OnStartAppLaunch() override;
-  void OnStartArcKiosk() override;
-  void OnStartWebKiosk() override;
   void OnBrowserCreated() override;
   void ShowGaiaDialog(bool can_close,
                       const AccountId& prefilled_account) override;
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_webui.cc b/chrome/browser/chromeos/login/ui/login_display_host_webui.cc
index b8cee0bb..c9e25914 100644
--- a/chrome/browser/chromeos/login/ui/login_display_host_webui.cc
+++ b/chrome/browser/chromeos/login/ui/login_display_host_webui.cc
@@ -127,9 +127,6 @@
 // URL which corresponds to the app launch splash WebUI.
 const char kAppLaunchSplashURL[] = "chrome://oobe/app-launch-splash";
 
-// URL which corresponds to the ARC kiosk splash WebUI.
-const char kArcKioskSplashURL[] = "chrome://oobe/arc-kiosk-splash";
-
 // Duration of sign-in transition animation.
 const int kLoginFadeoutTransitionDurationMs = 700;
 
@@ -653,24 +650,6 @@
   login_view_->set_should_emit_login_prompt_visible(false);
 }
 
-void LoginDisplayHostWebUI::OnStartArcKiosk() {
-  finalize_animation_type_ = ANIMATION_FADE_OUT;
-  if (!login_window_) {
-    LoadURL(GURL(kArcKioskSplashURL));
-  }
-
-  login_view_->set_should_emit_login_prompt_visible(false);
-}
-
-void LoginDisplayHostWebUI::OnStartWebKiosk() {
-  finalize_animation_type_ = ANIMATION_FADE_OUT;
-  if (!login_window_) {
-    LoadURL(GURL(kAppLaunchSplashURL));
-  }
-
-  login_view_->set_should_emit_login_prompt_visible(false);
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // LoginDisplayHostWebUI, public
 
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_webui.h b/chrome/browser/chromeos/login/ui/login_display_host_webui.h
index 74d6bc4..25b42284 100644
--- a/chrome/browser/chromeos/login/ui/login_display_host_webui.h
+++ b/chrome/browser/chromeos/login/ui/login_display_host_webui.h
@@ -79,8 +79,6 @@
   void OnStartSignInScreen(const LoginScreenContext& context) override;
   void OnPreferencesChanged() override;
   void OnStartAppLaunch() override;
-  void OnStartArcKiosk() override;
-  void OnStartWebKiosk() override;
   void OnBrowserCreated() override;
   void ShowGaiaDialog(bool can_close,
                       const AccountId& prefilled_account) override;
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index f5e7175c..7b8825d 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -97,7 +97,6 @@
 #include "chrome/browser/ui/ash/login_screen_client.h"
 #include "chrome/browser/ui/webui/chromeos/login/app_downloading_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h"
-#include "chrome/browser/ui/webui/chromeos/login/arc_kiosk_splash_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/auto_enrollment_check_screen_handler.h"
@@ -197,7 +196,6 @@
 };
 
 const chromeos::StaticOobeScreenId kScreensWithHiddenStatusArea[] = {
-    chromeos::ArcKioskSplashScreenView::kScreenId,
     chromeos::EnableAdbSideloadingScreenView::kScreenId,
     chromeos::EnableDebuggingScreenView::kScreenId,
     chromeos::KioskAutolaunchScreenView::kScreenId,
@@ -718,10 +716,6 @@
   SetCurrentScreen(screen);
 }
 
-void WizardController::ShowArcKioskSplashScreen() {
-  SetCurrentScreen(GetScreen(ArcKioskSplashScreenView::kScreenId));
-}
-
 void WizardController::ShowHIDDetectionScreen() {
   SetCurrentScreen(GetScreen(HIDDetectionView::kScreenId));
 }
@@ -1508,8 +1502,6 @@
     ShowAutoEnrollmentCheckScreen();
   } else if (screen == AppLaunchSplashScreenView::kScreenId) {
     AutoLaunchKioskApp();
-  } else if (screen == ArcKioskSplashScreenView::kScreenId) {
-    ShowArcKioskSplashScreen();
   } else if (screen == HIDDetectionView::kScreenId) {
     ShowHIDDetectionScreen();
   } else if (screen == DeviceDisabledScreenView::kScreenId) {
diff --git a/chrome/browser/chromeos/login/wizard_controller.h b/chrome/browser/chromeos/login/wizard_controller.h
index a774ab42..6111064 100644
--- a/chrome/browser/chromeos/login/wizard_controller.h
+++ b/chrome/browser/chromeos/login/wizard_controller.h
@@ -185,7 +185,6 @@
   void ShowAppDownloadingScreen();
   void ShowWrongHWIDScreen();
   void ShowAutoEnrollmentCheckScreen();
-  void ShowArcKioskSplashScreen();
   void ShowHIDDetectionScreen();
   void ShowDeviceDisabledScreen();
   void ShowEncryptionMigrationScreen();
diff --git a/chrome/browser/chromeos/plugin_vm/plugin_vm_installer.cc b/chrome/browser/chromeos/plugin_vm/plugin_vm_installer.cc
index 71ea084..288781e 100644
--- a/chrome/browser/chromeos/plugin_vm/plugin_vm_installer.cc
+++ b/chrome/browser/chromeos/plugin_vm/plugin_vm_installer.cc
@@ -69,7 +69,13 @@
     return;
   }
 
-  StartDlcDownload();
+  // If there's an existing VM, we can complete without running the install
+  // flow.
+  PluginVmManager::GetForProfile(profile_)->UpdateVmState(
+      base::BindOnce(&PluginVmInstaller::OnUpdateVmState,
+                     weak_ptr_factory_.GetWeakPtr()),
+      base::BindOnce(&PluginVmInstaller::StartDlcDownload,
+                     weak_ptr_factory_.GetWeakPtr()));
 }
 
 void PluginVmInstaller::Cancel() {
@@ -90,6 +96,18 @@
   }
 }
 
+void PluginVmInstaller::OnUpdateVmState(bool default_vm_exists) {
+  if (default_vm_exists) {
+    if (observer_)
+      observer_->OnVmExists();
+    profile_->GetPrefs()->SetBoolean(plugin_vm::prefs::kPluginVmImageExists,
+                                     true);
+    state_ = State::CONFIGURED;
+    return;
+  }
+  StartDlcDownload();
+}
+
 void PluginVmInstaller::StartDlcDownload() {
   state_ = State::DOWNLOADING_DLC;
   dlc_download_start_tick_ = base::TimeTicks::Now();
diff --git a/chrome/browser/chromeos/plugin_vm/plugin_vm_installer.h b/chrome/browser/chromeos/plugin_vm/plugin_vm_installer.h
index 517195d..9ec2d96 100644
--- a/chrome/browser/chromeos/plugin_vm/plugin_vm_installer.h
+++ b/chrome/browser/chromeos/plugin_vm/plugin_vm_installer.h
@@ -66,6 +66,10 @@
   class Observer {
    public:
     virtual ~Observer() = default;
+
+    // If a VM already exists, we call this and abort the installation process.
+    virtual void OnVmExists() = 0;
+
     virtual void OnDlcDownloadProgressUpdated(double progress,
                                               base::TimeDelta elapsed_time) = 0;
     virtual void OnDlcDownloadCompleted() = 0;
@@ -129,6 +133,7 @@
   std::string GetCurrentDownloadGuidForTesting();
 
  private:
+  void OnUpdateVmState(bool default_vm_exists);
   void StartDlcDownload();
   void StartDownload();
   void StartImport();
diff --git a/chrome/browser/chromeos/plugin_vm/plugin_vm_installer_unittest.cc b/chrome/browser/chromeos/plugin_vm/plugin_vm_installer_unittest.cc
index 4be03e8..bc90637c 100644
--- a/chrome/browser/chromeos/plugin_vm/plugin_vm_installer_unittest.cc
+++ b/chrome/browser/chromeos/plugin_vm/plugin_vm_installer_unittest.cc
@@ -29,6 +29,7 @@
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/dlcservice/fake_dlcservice_client.h"
 #include "chromeos/dbus/fake_concierge_client.h"
+#include "chromeos/dbus/fake_vm_plugin_dispatcher_client.h"
 #include "components/account_id/account_id.h"
 #include "components/download/public/background_service/test/test_download_service.h"
 #include "components/drive/service/dummy_drive_service.h"
@@ -70,6 +71,7 @@
 
 class MockObserver : public PluginVmInstaller::Observer {
  public:
+  MOCK_METHOD0(OnVmExists, void());
   MOCK_METHOD2(OnDlcDownloadProgressUpdated,
                void(double progress, base::TimeDelta elapsed_time));
   MOCK_METHOD0(OnDlcDownloadCompleted, void());
@@ -380,6 +382,19 @@
   DISALLOW_COPY_AND_ASSIGN(PluginVmInstallerDriveTest);
 };
 
+TEST_F(PluginVmInstallerDownloadServiceTest, VmExists) {
+  vm_tools::plugin_dispatcher::ListVmResponse list_vms_response;
+  list_vms_response.add_vm_info()->set_state(
+      vm_tools::plugin_dispatcher::VmState::VM_STATE_STOPPED);
+  static_cast<chromeos::FakeVmPluginDispatcherClient*>(
+      chromeos::DBusThreadManager::Get()->GetVmPluginDispatcherClient())
+      ->set_list_vms_response(list_vms_response);
+
+  EXPECT_CALL(*observer_, OnVmExists());
+  EXPECT_CALL(*observer_, OnDlcDownloadCompleted()).Times(0);
+  StartAndRunToCompletion();
+}
+
 TEST_F(PluginVmInstallerDownloadServiceTest, DownloadPluginVmImageParamsTest) {
   SetupConciergeForSuccessfulDiskImageImport(fake_concierge_client_);
 
diff --git a/chrome/browser/chromeos/plugin_vm/plugin_vm_metrics_util.h b/chrome/browser/chromeos/plugin_vm/plugin_vm_metrics_util.h
index ca8aaa9..4540354 100644
--- a/chrome/browser/chromeos/plugin_vm/plugin_vm_metrics_util.h
+++ b/chrome/browser/chromeos/plugin_vm/plugin_vm_metrics_util.h
@@ -44,7 +44,9 @@
   kErrorDownloadingPluginVmDlc = 6,
   kUserCancelledDownloadingPluginVmDlc = 7,
 
-  kMaxValue = kUserCancelledDownloadingPluginVmDlc,
+  kVmAlreadyExists = 8,
+
+  kMaxValue = kVmAlreadyExists,
 };
 
 enum class PluginVmDlcUseResult {
diff --git a/chrome/browser/chromeos/smb_client/discovery/host_locator.h b/chrome/browser/chromeos/smb_client/discovery/host_locator.h
index f99a375..2f6ec13 100644
--- a/chrome/browser/chromeos/smb_client/discovery/host_locator.h
+++ b/chrome/browser/chromeos/smb_client/discovery/host_locator.h
@@ -9,12 +9,13 @@
 #include <string>
 
 #include "base/callback.h"
+#include "net/base/ip_address.h"
 
 namespace chromeos {
 namespace smb_client {
 
 using Hostname = std::string;
-using Address = std::string;
+using Address = net::IPAddress;
 using HostMap = std::map<Hostname, Address>;
 
 // |success| will be false if an error occurred when finding hosts. |success|
diff --git a/chrome/browser/chromeos/smb_client/discovery/in_memory_host_locator_unittest.cc b/chrome/browser/chromeos/smb_client/discovery/in_memory_host_locator_unittest.cc
index 3c9ca8ae..c6ec7dd8 100644
--- a/chrome/browser/chromeos/smb_client/discovery/in_memory_host_locator_unittest.cc
+++ b/chrome/browser/chromeos/smb_client/discovery/in_memory_host_locator_unittest.cc
@@ -55,21 +55,21 @@
 
 TEST_F(InMemoryHostLocatorTest, AddHostShouldNotBeEqual) {
   HostMap incorrect_map;
-  incorrect_map["host1"] = "1.2.3.4";
+  incorrect_map["host1"] = {1, 2, 3, 4};
 
   // Add a different host entry using AddHost().
-  locator_.AddHost("host2", "5.6.7.8");
+  locator_.AddHost("host2", {5, 6, 7, 8});
 
   ExpectHostMapNotEqual(incorrect_map);
 }
 
 TEST_F(InMemoryHostLocatorTest, AddHostsShouldNotBeEqual) {
   HostMap incorrect_map;
-  incorrect_map["host2"] = "6.7.8.9";
+  incorrect_map["host2"] = {6, 7, 8, 9};
 
   // Add a different host entry using AddHosts().
   HostMap host_map;
-  host_map["host1"] = "1.2.3.4";
+  host_map["host1"] = {1, 2, 3, 4};
   locator_.AddHosts(host_map);
 
   ExpectHostMapNotEqual(incorrect_map);
@@ -80,35 +80,35 @@
 }
 
 TEST_F(InMemoryHostLocatorTest, ShouldFindOneHost) {
-  locator_.AddHost("host1", "1.2.3.4");
+  locator_.AddHost("host1", {1, 2, 3, 4});
 
   HostMap expected;
-  expected["host1"] = "1.2.3.4";
+  expected["host1"] = {1, 2, 3, 4};
   ExpectHostMapEqual(expected);
 }
 
 TEST_F(InMemoryHostLocatorTest, ShouldFindMultipleHosts) {
   HostMap host_map;
-  host_map["host1"] = "1.2.3.4";
-  host_map["host2"] = "3.4.5.6";
+  host_map["host1"] = {1, 2, 3, 4};
+  host_map["host2"] = {3, 4, 5, 6};
   locator_.AddHosts(host_map);
 
   ExpectHostMapEqual(host_map);
 }
 
 TEST_F(InMemoryHostLocatorTest, ShouldOverwriteHostWithSameName) {
-  locator_.AddHost("host1", "1.2.3.4");
-  locator_.AddHost("host1", "5.6.7.8");
+  locator_.AddHost("host1", {1, 2, 3, 4});
+  locator_.AddHost("host1", {5, 6, 7, 8});
 
   HostMap expected;
-  expected["host1"] = "5.6.7.8";
+  expected["host1"] = {5, 6, 7, 8};
   ExpectHostMapEqual(expected);
 }
 
 TEST_F(InMemoryHostLocatorTest, ShouldRemoveHost) {
   HostMap host_map;
-  host_map["host1"] = "1.2.3.4";
-  host_map["host2"] = "3.4.5.6";
+  host_map["host1"] = {1, 2, 3, 4};
+  host_map["host2"] = {3, 4, 5, 6};
   locator_.AddHosts(host_map);
 
   ExpectHostMapEqual(host_map);
@@ -119,39 +119,39 @@
 
   // The locator should only return the host that was not removed.
   HostMap expected;
-  expected["host1"] = "1.2.3.4";
+  expected["host1"] = {1, 2, 3, 4};
   ExpectHostMapEqual(expected);
 }
 
 TEST_F(InMemoryHostLocatorTest, AddHostsShouldKeepPreviousHosts) {
-  locator_.AddHost("host1", "1.2.3.4");
+  locator_.AddHost("host1", {1, 2, 3, 4});
 
   HostMap host_map;
-  host_map["host2"] = "5.6.7.8";
+  host_map["host2"] = {5, 6, 7, 8};
   locator_.AddHosts(host_map);
 
   HostMap expected;
-  expected["host1"] = "1.2.3.4";
-  expected["host2"] = "5.6.7.8";
+  expected["host1"] = {1, 2, 3, 4};
+  expected["host2"] = {5, 6, 7, 8};
   ExpectHostMapEqual(expected);
 }
 
 TEST_F(InMemoryHostLocatorTest, AddHostsShouldKeepPreviousHostsAndOverwrite) {
-  locator_.AddHost("host1", "1.2.3.4");
-  locator_.AddHost("host2", "5.6.7.8");
+  locator_.AddHost("host1", {1, 2, 3, 4});
+  locator_.AddHost("host2", {5, 6, 7, 8});
 
   // Add a host with same hostname but different address, along with a new host.
   HostMap host_map;
-  host_map["host2"] = "15.16.17.18";
-  host_map["host3"] = "25.26.27.28";
+  host_map["host2"] = {15, 16, 17, 18};
+  host_map["host3"] = {25, 26, 27, 28};
   locator_.AddHosts(host_map);
 
   // The host with the same name should be overwritten, and the new host
   // should be added.
   HostMap expected;
-  expected["host1"] = "1.2.3.4";
-  expected["host2"] = "15.16.17.18";
-  expected["host3"] = "25.26.27.28";
+  expected["host1"] = {1, 2, 3, 4};
+  expected["host2"] = {15, 16, 17, 18};
+  expected["host3"] = {25, 26, 27, 28};
   ExpectHostMapEqual(expected);
 }
 
diff --git a/chrome/browser/chromeos/smb_client/discovery/mdns_host_locator.cc b/chrome/browser/chromeos/smb_client/discovery/mdns_host_locator.cc
index 9913bd3..3c59133d 100644
--- a/chrome/browser/chromeos/smb_client/discovery/mdns_host_locator.cc
+++ b/chrome/browser/chromeos/smb_client/discovery/mdns_host_locator.cc
@@ -310,7 +310,7 @@
     const net::ARecordRdata* ip = record->rdata<net::ARecordRdata>();
     DCHECK(ip);
 
-    results_[RemoveLocal(raw_hostname)] = ip->address().ToString();
+    results_[RemoveLocal(raw_hostname)] = ip->address();
   }
 
   // Regardless of what the result is, check to see if the callback can be fired
diff --git a/chrome/browser/chromeos/smb_client/discovery/netbios_host_locator.cc b/chrome/browser/chromeos/smb_client/discovery/netbios_host_locator.cc
index 1805c109..6f8ea3f 100644
--- a/chrome/browser/chromeos/smb_client/discovery/netbios_host_locator.cc
+++ b/chrome/browser/chromeos/smb_client/discovery/netbios_host_locator.cc
@@ -181,18 +181,18 @@
 void NetBiosHostLocator::AddHostToResult(const net::IPEndPoint& sender_ip,
                                          const std::string& hostname) {
   if (WouldOverwriteResult(sender_ip, hostname)) {
-    LOG(ERROR) << hostname << ":" << results_[hostname]
+    LOG(ERROR) << hostname << ":" << results_[hostname].ToString()
                << " will be overwritten by " << hostname << ":"
                << sender_ip.ToStringWithoutPort();
   }
-  results_[hostname] = sender_ip.ToStringWithoutPort();
+  results_[hostname] = sender_ip.address();
 }
 
 bool NetBiosHostLocator::WouldOverwriteResult(
     const net::IPEndPoint& sender_ip,
     const std::string& hostname) const {
   return results_.count(hostname) &&
-         results_.at(hostname) != sender_ip.ToStringWithoutPort();
+         results_.at(hostname) != sender_ip.address();
 }
 
 }  // namespace smb_client
diff --git a/chrome/browser/chromeos/smb_client/discovery/netbios_host_locator_unittest.cc b/chrome/browser/chromeos/smb_client/discovery/netbios_host_locator_unittest.cc
index 92e031b..a2191eb 100644
--- a/chrome/browser/chromeos/smb_client/discovery/netbios_host_locator_unittest.cc
+++ b/chrome/browser/chromeos/smb_client/discovery/netbios_host_locator_unittest.cc
@@ -249,9 +249,9 @@
 
   // Build the map of expected results.
   HostMap expected_results;
-  expected_results[hostnames_1[0]] = source_ip_1.ToStringWithoutPort();
-  expected_results[hostnames_1[1]] = source_ip_1.ToStringWithoutPort();
-  expected_results[hostnames_2[0]] = source_ip_2.ToStringWithoutPort();
+  expected_results[hostnames_1[0]] = source_ip_1.address();
+  expected_results[hostnames_1[1]] = source_ip_1.address();
+  expected_results[hostnames_2[0]] = source_ip_2.address();
 
   // Add the entry for a NetBios Client that returns packets.
   AddNetBiosClient(netbios_client_1);
@@ -293,11 +293,11 @@
 
   // Build the map of expected results.
   HostMap expected_results;
-  expected_results[hostnames_1[0]] = source_ip_1.ToStringWithoutPort();
-  expected_results[hostnames_1[1]] = source_ip_1.ToStringWithoutPort();
-  expected_results[hostnames_2[0]] = source_ip_2.ToStringWithoutPort();
-  expected_results[hostnames_3[0]] = source_ip_3.ToStringWithoutPort();
-  expected_results[hostnames_4[0]] = source_ip_4.ToStringWithoutPort();
+  expected_results[hostnames_1[0]] = source_ip_1.address();
+  expected_results[hostnames_1[1]] = source_ip_1.address();
+  expected_results[hostnames_2[0]] = source_ip_2.address();
+  expected_results[hostnames_3[0]] = source_ip_3.address();
+  expected_results[hostnames_4[0]] = source_ip_4.address();
 
   // Add the entry for a NetBios Clients that return packets.
   AddNetBiosClient(netbios_client_1);
@@ -338,10 +338,10 @@
 
   // Build the map of expected results.
   HostMap expected_results;
-  expected_results[hostnames_1[0]] = source_ip_1.ToStringWithoutPort();
-  expected_results[hostnames_1[1]] = source_ip_1.ToStringWithoutPort();
-  expected_results[hostnames_2[0]] = source_ip_2.ToStringWithoutPort();
-  expected_results[hostnames_4[0]] = source_ip_4.ToStringWithoutPort();
+  expected_results[hostnames_1[0]] = source_ip_1.address();
+  expected_results[hostnames_1[1]] = source_ip_1.address();
+  expected_results[hostnames_2[0]] = source_ip_2.address();
+  expected_results[hostnames_4[0]] = source_ip_4.address();
 
   // Add the entry for a NetBios Clients that return packets.
   AddNetBiosClient(netbios_client_1);
@@ -371,9 +371,9 @@
 
   // Build the map of expected results.
   HostMap expected_results;
-  expected_results[hostnames_1[0]] = source_ip_1.ToStringWithoutPort();
-  expected_results[hostnames_1[1]] = source_ip_1.ToStringWithoutPort();
-  expected_results[hostnames_2[0]] = source_ip_2.ToStringWithoutPort();
+  expected_results[hostnames_1[0]] = source_ip_1.address();
+  expected_results[hostnames_1[1]] = source_ip_1.address();
+  expected_results[hostnames_2[0]] = source_ip_2.address();
 
   // Add the entry for a NetBios Client that returns packets.
   AddNetBiosClient(netbios_client_1);
@@ -422,7 +422,7 @@
 
   // Build the map of expected results.
   HostMap expected_results;
-  expected_results[duplicate_hostname] = source_ip_2.ToStringWithoutPort();
+  expected_results[duplicate_hostname] = source_ip_2.address();
 
   // Add the entry for a NetBios Clients that return packets.
   AddNetBiosClient(netbios_client_1);
diff --git a/chrome/browser/chromeos/smb_client/discovery/network_scanner.cc b/chrome/browser/chromeos/smb_client/discovery/network_scanner.cc
index 3c553fd..e5a46a54 100644
--- a/chrome/browser/chromeos/smb_client/discovery/network_scanner.cc
+++ b/chrome/browser/chromeos/smb_client/discovery/network_scanner.cc
@@ -59,12 +59,12 @@
   locators_.push_back(std::move(locator));
 }
 
-std::string NetworkScanner::ResolveHost(const std::string& host) const {
+net::IPAddress NetworkScanner::ResolveHost(const std::string& host) const {
   DCHECK(find_hosts_returned_);
 
   const auto& host_iter = found_hosts_.find(base::ToLowerASCII(host));
   if (host_iter == found_hosts_.end()) {
-    return "";
+    return {};
   }
 
   return host_iter->second;
@@ -89,14 +89,15 @@
 
   HostMap& existing_hosts = request_iter->second.hosts_found;
   for (const auto& new_host : new_hosts) {
-    const Hostname& new_hostname = base::ToLowerASCII(new_host.first);
+    const Hostname new_hostname = base::ToLowerASCII(new_host.first);
     const Address& new_ip = new_host.second;
 
     if (!HostExists(existing_hosts, new_hostname)) {
       existing_hosts.insert(std::pair<Hostname, Address>(new_hostname, new_ip));
     } else if (existing_hosts[new_hostname] != new_ip) {
       LOG(WARNING) << "Different addresses found for host: " << new_hostname;
-      LOG(WARNING) << existing_hosts[new_hostname] << ":" << new_ip;
+      LOG(WARNING) << "Existing " << existing_hosts[new_hostname].ToString()
+                   << " new " << new_ip.ToString();
     }
   }
 }
diff --git a/chrome/browser/chromeos/smb_client/discovery/network_scanner.h b/chrome/browser/chromeos/smb_client/discovery/network_scanner.h
index 7561f5d8..8aafb16 100644
--- a/chrome/browser/chromeos/smb_client/discovery/network_scanner.h
+++ b/chrome/browser/chromeos/smb_client/discovery/network_scanner.h
@@ -11,6 +11,7 @@
 #include "base/callback.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/chromeos/smb_client/discovery/host_locator.h"
+#include "net/base/ip_address.h"
 
 namespace chromeos {
 namespace smb_client {
@@ -53,8 +54,8 @@
 
   // Resolves |host| to an address using the cached results of
   // FindHostsInNetwork(). FindHostsInNetwork() has to be called beforehand. If
-  // no address is found, this returns an empty string.
-  std::string ResolveHost(const std::string& host) const;
+  // no address is found, this returns an invalid IPAddress.
+  net::IPAddress ResolveHost(const std::string& host) const;
 
  private:
   // Callback handler for HostLocator::FindHosts().
diff --git a/chrome/browser/chromeos/smb_client/discovery/network_scanner_unittest.cc b/chrome/browser/chromeos/smb_client/discovery/network_scanner_unittest.cc
index 8fad400..731e5730 100644
--- a/chrome/browser/chromeos/smb_client/discovery/network_scanner_unittest.cc
+++ b/chrome/browser/chromeos/smb_client/discovery/network_scanner_unittest.cc
@@ -56,7 +56,7 @@
 
   void ExpectResolvedHostEquals(const std::string& expected,
                                 const std::string& host) {
-    EXPECT_EQ(expected, scanner_.ResolveHost(host));
+    EXPECT_EQ(expected, scanner_.ResolveHost(host).ToString());
   }
 
   // Registers |hosts| with a host locator and call FindHostsInNetwork() which
@@ -91,7 +91,7 @@
 
 TEST_F(NetworkScannerTest, ShouldFindOneHostWithOneLocator) {
   HostMap hosts;
-  hosts["share1"] = "1.2.3.4";
+  hosts["share1"] = {1, 2, 3, 4};
   RegisterHostLocatorWithHosts(hosts);
 
   ExpectHostMapEqual(hosts);
@@ -99,8 +99,8 @@
 
 TEST_F(NetworkScannerTest, ShouldFindMultipleHostsWithOneLocator) {
   HostMap hosts;
-  hosts["share1"] = "1.2.3.4";
-  hosts["share2"] = "5.6.7.8";
+  hosts["share1"] = {1, 2, 3, 4};
+  hosts["share2"] = {5, 6, 7, 8};
   RegisterHostLocatorWithHosts(hosts);
 
   ExpectHostMapEqual(hosts);
@@ -108,40 +108,40 @@
 
 TEST_F(NetworkScannerTest, ShouldFindMultipleHostsWithMultipleLocators) {
   HostMap hosts1;
-  hosts1["share1"] = "1.2.3.4";
-  hosts1["share2"] = "5.6.7.8";
+  hosts1["share1"] = {1, 2, 3, 4};
+  hosts1["share2"] = {5, 6, 7, 8};
   RegisterHostLocatorWithHosts(hosts1);
 
   HostMap hosts2;
-  hosts2["share3"] = "11.12.13.14";
-  hosts2["share4"] = "15.16.17.18";
+  hosts2["share3"] = {11, 12, 13, 14};
+  hosts2["share4"] = {15, 16, 17, 18};
   RegisterHostLocatorWithHosts(hosts2);
 
   HostMap expected;
-  expected["share1"] = "1.2.3.4";
-  expected["share2"] = "5.6.7.8";
-  expected["share3"] = "11.12.13.14";
-  expected["share4"] = "15.16.17.18";
+  expected["share1"] = {1, 2, 3, 4};
+  expected["share2"] = {5, 6, 7, 8};
+  expected["share3"] = {11, 12, 13, 14};
+  expected["share4"] = {15, 16, 17, 18};
 
   ExpectHostMapEqual(expected);
 }
 
 TEST_F(NetworkScannerTest, ShouldResolveMultipleHostsWithSameAddress) {
   HostMap hosts1;
-  hosts1["share1"] = "1.2.3.4";
-  hosts1["share2"] = "5.6.7.8";
+  hosts1["share1"] = {1, 2, 3, 4};
+  hosts1["share2"] = {5, 6, 7, 8};
   RegisterHostLocatorWithHosts(hosts1);
 
   HostMap hosts2;
-  hosts2["share2"] = "11.12.13.14";
-  hosts2["share3"] = "15.16.17.18";
+  hosts2["share2"] = {11, 12, 13, 14};
+  hosts2["share3"] = {15, 16, 17, 18};
   RegisterHostLocatorWithHosts(hosts2);
 
   // share2 should have the value from host1 since it is found first.
   HostMap expected;
-  expected["share1"] = "1.2.3.4";
-  expected["share2"] = "5.6.7.8";
-  expected["share3"] = "15.16.17.18";
+  expected["share1"] = {1, 2, 3, 4};
+  expected["share2"] = {5, 6, 7, 8};
+  expected["share3"] = {15, 16, 17, 18};
 
   ExpectHostMapEqual(expected);
 }
@@ -157,8 +157,8 @@
 
 TEST_F(NetworkScannerTest, ResolveHostResolvesHostsFound) {
   HostMap hosts;
-  hosts["share1"] = "1.2.3.4";
-  hosts["share2"] = "4.5.6.7";
+  hosts["share1"] = {1, 2, 3, 4};
+  hosts["share2"] = {4, 5, 6, 7};
   RegisterAndCacheHosts(hosts);
 
   ExpectResolvedHostEquals("1.2.3.4", "share1");
@@ -170,7 +170,7 @@
 
 TEST_F(NetworkScannerTest, ResolveHostWithUppercaseHost) {
   HostMap hosts;
-  hosts["share1"] = "1.2.3.4";
+  hosts["share1"] = {1, 2, 3, 4};
   RegisterAndCacheHosts(hosts);
 
   ExpectResolvedHostEquals("1.2.3.4", "SHARE1");
@@ -178,16 +178,16 @@
 
 TEST_F(NetworkScannerTest, HostsAreStoredAsLowercase) {
   HostMap hosts;
-  hosts["SHARE1"] = "1.2.3.4";
-  hosts["sHaRe2"] = "11.12.13.14";
-  hosts["Share3"] = "21.22.23.24";
+  hosts["SHARE1"] = {1, 2, 3, 4};
+  hosts["sHaRe2"] = {11, 12, 13, 14};
+  hosts["Share3"] = {21, 22, 23, 24};
   RegisterHostLocatorWithHosts(hosts);
 
   // expected_hosts should have all lowercase hosts.
   HostMap expected_hosts;
-  expected_hosts["share1"] = "1.2.3.4";
-  expected_hosts["share2"] = "11.12.13.14";
-  expected_hosts["share3"] = "21.22.23.24";
+  expected_hosts["share1"] = {1, 2, 3, 4};
+  expected_hosts["share2"] = {11, 12, 13, 14};
+  expected_hosts["share3"] = {21, 22, 23, 24};
   ExpectHostMapEqual(expected_hosts);
 
   ExpectResolvedHostEquals("1.2.3.4", "share1");
diff --git a/chrome/browser/chromeos/smb_client/smb_share_finder.cc b/chrome/browser/chromeos/smb_client/smb_share_finder.cc
index 96334ba..3d145501 100644
--- a/chrome/browser/chromeos/smb_client/smb_share_finder.cc
+++ b/chrome/browser/chromeos/smb_client/smb_share_finder.cc
@@ -87,7 +87,7 @@
 std::string SmbShareFinder::GetResolvedUrl(const SmbUrl& url) const {
   DCHECK(url.IsValid());
 
-  const std::string ip_address = scanner_.ResolveHost(url.GetHost());
+  const std::string ip_address = scanner_.ResolveHost(url.GetHost()).ToString();
   // Return the original URL if the resolved host cannot be found or if there is
   // no change in the resolved IP address.
   if (ip_address.empty() || ip_address == url.GetHost()) {
@@ -122,7 +122,7 @@
   host_counter_ = hosts.size();
   for (const auto& host : hosts) {
     const std::string& host_name = host.first;
-    const std::string& resolved_address = host.second;
+    const std::string resolved_address = host.second.ToString();
     const base::FilePath server_url(kSmbSchemePrefix + resolved_address);
 
     client_->GetShares(
diff --git a/chrome/browser/chromeos/smb_client/smb_share_finder_unittest.cc b/chrome/browser/chromeos/smb_client/smb_share_finder_unittest.cc
index 4230f69..5453580e 100644
--- a/chrome/browser/chromeos/smb_client/smb_share_finder_unittest.cc
+++ b/chrome/browser/chromeos/smb_client/smb_share_finder_unittest.cc
@@ -42,7 +42,9 @@
 
   // Adds host with |hostname| and |address| as the resolved url.
   void AddHost(const std::string& hostname, const std::string& address) {
-    host_locator_->AddHost(hostname, address);
+    net::IPAddress ip_address;
+    EXPECT_TRUE(ip_address.AssignFromIPLiteral(address));
+    host_locator_->AddHost(hostname, ip_address);
   }
 
   // Adds the default host with the default address.
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index e19e2dd..2bb0d423 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -159,7 +159,7 @@
   {
     "name": "arc-file-picker-experiment",
     "owners": [ "niwa" ],
-    "expiry_milestone": 80
+    "expiry_milestone": 88
   },
   {
     "name": "arc-graphics-buffer-visualization-tool",
diff --git a/chrome/browser/permissions/crowd_deny_fake_safe_browsing_database_manager.cc b/chrome/browser/permissions/crowd_deny_fake_safe_browsing_database_manager.cc
new file mode 100644
index 0000000..7b22fa7
--- /dev/null
+++ b/chrome/browser/permissions/crowd_deny_fake_safe_browsing_database_manager.cc
@@ -0,0 +1,63 @@
+// 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/permissions/crowd_deny_fake_safe_browsing_database_manager.h"
+
+#include "components/safe_browsing/core/db/database_manager.h"
+
+CrowdDenyFakeSafeBrowsingDatabaseManager::
+    CrowdDenyFakeSafeBrowsingDatabaseManager() = default;
+
+void CrowdDenyFakeSafeBrowsingDatabaseManager::SetSimulatedMetadataForUrl(
+    const GURL& url,
+    const safe_browsing::ThreatMetadata& metadata) {
+  url_to_simulated_threat_metadata_[url] = metadata;
+}
+
+void CrowdDenyFakeSafeBrowsingDatabaseManager::RemoveAllBlacklistedUrls() {
+  url_to_simulated_threat_metadata_.clear();
+}
+
+CrowdDenyFakeSafeBrowsingDatabaseManager::
+    ~CrowdDenyFakeSafeBrowsingDatabaseManager() {
+  EXPECT_THAT(pending_clients_, testing::IsEmpty());
+}
+
+bool CrowdDenyFakeSafeBrowsingDatabaseManager::CheckApiBlacklistUrl(
+    const GURL& url,
+    Client* client) {
+  if (simulate_synchronous_result_)
+    return true;
+
+  if (simulate_timeout_) {
+    EXPECT_THAT(pending_clients_, testing::Not(testing::Contains(client)));
+    pending_clients_.insert(client);
+  } else {
+    auto result = GetSimulatedMetadataOrSafe(url);
+    client->OnCheckApiBlacklistUrlResult(url, std::move(result));
+  }
+  return false;
+}
+
+bool CrowdDenyFakeSafeBrowsingDatabaseManager::CancelApiCheck(Client* client) {
+  EXPECT_THAT(pending_clients_, testing::Contains(client));
+  pending_clients_.erase(client);
+  return true;
+}
+
+bool CrowdDenyFakeSafeBrowsingDatabaseManager::IsSupported() const {
+  return true;
+}
+
+bool CrowdDenyFakeSafeBrowsingDatabaseManager::ChecksAreAlwaysAsync() const {
+  return false;
+}
+safe_browsing::ThreatMetadata
+CrowdDenyFakeSafeBrowsingDatabaseManager::GetSimulatedMetadataOrSafe(
+    const GURL& url) {
+  auto it = url_to_simulated_threat_metadata_.find(url);
+  return it != url_to_simulated_threat_metadata_.end()
+             ? it->second
+             : safe_browsing::ThreatMetadata();
+}
diff --git a/chrome/browser/permissions/crowd_deny_fake_safe_browsing_database_manager.h b/chrome/browser/permissions/crowd_deny_fake_safe_browsing_database_manager.h
new file mode 100644
index 0000000..3d5df50
--- /dev/null
+++ b/chrome/browser/permissions/crowd_deny_fake_safe_browsing_database_manager.h
@@ -0,0 +1,61 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_PERMISSIONS_CROWD_DENY_FAKE_SAFE_BROWSING_DATABASE_MANAGER_H_
+#define CHROME_BROWSER_PERMISSIONS_CROWD_DENY_FAKE_SAFE_BROWSING_DATABASE_MANAGER_H_
+
+#include <map>
+#include <set>
+
+#include "base/memory/weak_ptr.h"
+#include "components/safe_browsing/core/db/test_database_manager.h"
+#include "components/safe_browsing/core/db/util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+class CrowdDenyFakeSafeBrowsingDatabaseManager
+    : public safe_browsing::TestSafeBrowsingDatabaseManager {
+ public:
+  CrowdDenyFakeSafeBrowsingDatabaseManager();
+
+  void SetSimulatedMetadataForUrl(
+      const GURL& url,
+      const safe_browsing::ThreatMetadata& metadata);
+
+  void RemoveAllBlacklistedUrls();
+
+  void set_simulate_timeout(bool simulate_timeout) {
+    simulate_timeout_ = simulate_timeout;
+  }
+
+  void set_simulate_synchronous_result(bool simulate_synchronous_result) {
+    simulate_synchronous_result_ = simulate_synchronous_result;
+  }
+
+ protected:
+  ~CrowdDenyFakeSafeBrowsingDatabaseManager() override;
+
+  // safe_browsing::TestSafeBrowsingDatabaseManager:
+  bool CheckApiBlacklistUrl(const GURL& url, Client* client) override;
+  bool CancelApiCheck(Client* client) override;
+  bool IsSupported() const override;
+  bool ChecksAreAlwaysAsync() const override;
+
+ private:
+  safe_browsing::ThreatMetadata GetSimulatedMetadataOrSafe(const GURL& url);
+
+  std::set<Client*> pending_clients_;
+  std::map<GURL, safe_browsing::ThreatMetadata>
+      url_to_simulated_threat_metadata_;
+  bool simulate_timeout_ = false;
+  bool simulate_synchronous_result_ = false;
+
+  base::WeakPtrFactory<CrowdDenyFakeSafeBrowsingDatabaseManager> weak_factory_{
+      this};
+
+  DISALLOW_COPY_AND_ASSIGN(CrowdDenyFakeSafeBrowsingDatabaseManager);
+};
+
+#endif  // CHROME_BROWSER_PERMISSIONS_CROWD_DENY_FAKE_SAFE_BROWSING_DATABASE_MANAGER_H_
diff --git a/chrome/browser/permissions/crowd_deny_safe_browsing_request_unittest.cc b/chrome/browser/permissions/crowd_deny_safe_browsing_request_unittest.cc
index c133577b..122412b 100644
--- a/chrome/browser/permissions/crowd_deny_safe_browsing_request_unittest.cc
+++ b/chrome/browser/permissions/crowd_deny_safe_browsing_request_unittest.cc
@@ -10,8 +10,7 @@
 #include "base/task/post_task.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/mock_callback.h"
-#include "components/safe_browsing/core/db/database_manager.h"
-#include "components/safe_browsing/core/db/test_database_manager.h"
+#include "chrome/browser/permissions/crowd_deny_fake_safe_browsing_database_manager.h"
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -23,77 +22,6 @@
 constexpr char kTestOriginFoo[] = "https://foo.com";
 constexpr char kTestOriginBar[] = "https://bar.com";
 
-class FakeSafeBrowsingDatabaseManager
-    : public safe_browsing::TestSafeBrowsingDatabaseManager {
- public:
-  FakeSafeBrowsingDatabaseManager() = default;
-
-  void SetSimulatedMetadataForUrl(
-      const GURL& url,
-      const safe_browsing::ThreatMetadata& metadata) {
-    url_to_simulated_threat_metadata_.emplace(url, metadata);
-  }
-
-  void RemoveAllBlacklistedUrls() { url_to_simulated_threat_metadata_.clear(); }
-
-  void set_simulate_timeout(bool simulate_timeout) {
-    simulate_timeout_ = simulate_timeout;
-  }
-
-  void set_simulate_synchronous_result(bool simulate_synchronous_result) {
-    simulate_synchronous_result_ = simulate_synchronous_result;
-  }
-
- protected:
-  ~FakeSafeBrowsingDatabaseManager() override {
-    EXPECT_THAT(pending_clients_, testing::IsEmpty());
-  }
-
-  safe_browsing::ThreatMetadata GetSimulatedMetadataOrSafe(const GURL& url) {
-    auto it = url_to_simulated_threat_metadata_.find(url);
-    return it != url_to_simulated_threat_metadata_.end()
-               ? it->second
-               : safe_browsing::ThreatMetadata();
-  }
-
-  // safe_browsing::TestSafeBrowsingDatabaseManager:
-  bool CheckApiBlacklistUrl(const GURL& url, Client* client) override {
-    if (simulate_synchronous_result_)
-      return true;
-
-    if (simulate_timeout_) {
-      EXPECT_THAT(pending_clients_, testing::Not(testing::Contains(client)));
-      pending_clients_.insert(client);
-    } else {
-      auto result = GetSimulatedMetadataOrSafe(url);
-      client->OnCheckApiBlacklistUrlResult(url, std::move(result));
-    }
-    return false;
-  }
-
-  bool CancelApiCheck(Client* client) override {
-    EXPECT_THAT(pending_clients_, testing::Contains(client));
-    pending_clients_.erase(client);
-    return true;
-  }
-
-  bool IsSupported() const override { return true; }
-  bool ChecksAreAlwaysAsync() const override { return false; }
-
- private:
-  void OnCheckUrlForSubresourceFilterComplete(Client* client, const GURL& url);
-
-  std::set<Client*> pending_clients_;
-  std::map<GURL, safe_browsing::ThreatMetadata>
-      url_to_simulated_threat_metadata_;
-  bool simulate_timeout_ = false;
-  bool simulate_synchronous_result_ = false;
-
-  base::WeakPtrFactory<FakeSafeBrowsingDatabaseManager> weak_factory_{this};
-
-  DISALLOW_COPY_AND_ASSIGN(FakeSafeBrowsingDatabaseManager);
-};
-
 }  // namespace
 
 class CrowdDenySafeBrowsingRequestTest : public testing::Test {
@@ -102,7 +30,7 @@
 
   CrowdDenySafeBrowsingRequestTest()
       : fake_database_manager_(
-            base::MakeRefCounted<FakeSafeBrowsingDatabaseManager>()) {}
+            base::MakeRefCounted<CrowdDenyFakeSafeBrowsingDatabaseManager>()) {}
   ~CrowdDenySafeBrowsingRequestTest() override = default;
 
  protected:
@@ -110,7 +38,7 @@
     return &task_environment_;
   }
 
-  FakeSafeBrowsingDatabaseManager* fake_database_manager() {
+  CrowdDenyFakeSafeBrowsingDatabaseManager* fake_database_manager() {
     return fake_database_manager_.get();
   }
 
@@ -136,7 +64,8 @@
   content::BrowserTaskEnvironment task_environment_{
       base::test::TaskEnvironment::TimeSource::MOCK_TIME};
 
-  scoped_refptr<FakeSafeBrowsingDatabaseManager> fake_database_manager_;
+  scoped_refptr<CrowdDenyFakeSafeBrowsingDatabaseManager>
+      fake_database_manager_;
 
   DISALLOW_COPY_AND_ASSIGN(CrowdDenySafeBrowsingRequestTest);
 };
diff --git a/chrome/browser/permissions/permission_request_manager_unittest.cc b/chrome/browser/permissions/permission_request_manager_unittest.cc
index 759a6f2..c8942a4 100644
--- a/chrome/browser/permissions/permission_request_manager_unittest.cc
+++ b/chrome/browser/permissions/permission_request_manager_unittest.cc
@@ -17,6 +17,7 @@
 #include "build/build_config.h"
 #include "chrome/browser/engagement/site_engagement_service.h"
 #include "chrome/browser/permissions/adaptive_quiet_notification_permission_ui_enabler.h"
+#include "chrome/browser/permissions/crowd_deny_fake_safe_browsing_database_manager.h"
 #include "chrome/browser/permissions/crowd_deny_preload_data.h"
 #include "chrome/browser/permissions/mock_permission_request.h"
 #include "chrome/browser/permissions/notification_permission_ui_selector.h"
@@ -25,14 +26,17 @@
 #include "chrome/browser/permissions/permission_uma_util.h"
 #include "chrome/browser/permissions/quiet_notification_permission_ui_config.h"
 #include "chrome/browser/permissions/quiet_notification_permission_ui_state.h"
+#include "chrome/browser/safe_browsing/test_safe_browsing_service.h"
 #include "chrome/browser/ui/permission_bubble/mock_permission_prompt_factory.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/scoped_user_pref_update.h"
+#include "components/safe_browsing/core/db/test_database_manager.h"
 #include "components/user_manager/scoped_user_manager.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -45,6 +49,9 @@
 
 class PermissionRequestManagerTest : public ChromeRenderViewHostTestHarness {
  public:
+  using SiteReputation =
+      CrowdDenyPreloadData::SiteReputation::NotificationUserExperienceQuality;
+
   PermissionRequestManagerTest()
       : ChromeRenderViewHostTestHarness(),
         request1_("test1",
@@ -85,10 +92,19 @@
     PermissionRequestManager::CreateForWebContents(web_contents());
     manager_ = PermissionRequestManager::FromWebContents(web_contents());
     prompt_factory_.reset(new MockPermissionPromptFactory(manager_));
+
+    db_manager_ =
+        base::MakeRefCounted<CrowdDenyFakeSafeBrowsingDatabaseManager>();
+    sb_factory_ =
+        std::make_unique<safe_browsing::TestSafeBrowsingServiceFactory>();
+    sb_factory_->SetTestDatabaseManager(db_manager_.get());
+    TestingBrowserProcess::GetGlobal()->SetSafeBrowsingService(
+        sb_factory_->CreateSafeBrowsingService());
   }
 
   void TearDown() override {
     prompt_factory_.reset();
+    TestingBrowserProcess::GetGlobal()->SetSafeBrowsingService(nullptr);
     ChromeRenderViewHostTestHarness::TearDown();
   }
 
@@ -131,6 +147,20 @@
     manager_->NavigationEntryCommitted(details);
   }
 
+  void SetUpPreloadDataForUrl(const GURL& url, SiteReputation reputation) {
+    CrowdDenyPreloadData::GetInstance()
+        ->set_origin_notification_user_experience_for_testing(
+            url::Origin::Create(url), reputation);
+  }
+
+  void SetUpSafeBrowsingMetadataForUrl(const GURL& url,
+                                       bool unsolicited_notifications) {
+    safe_browsing::ThreatMetadata test_metadata;
+    if (unsolicited_notifications)
+      test_metadata.api_permissions.emplace("NOTIFICATIONS");
+    db_manager_->SetSimulatedMetadataForUrl(url, test_metadata);
+  }
+
 #if defined(OS_CHROMEOS)
   std::unique_ptr<MockPermissionRequest> MakeRequestInWebKioskMode(
       const GURL& url,
@@ -170,6 +200,8 @@
   MockPermissionRequest iframe_request_mic_other_domain_;
   PermissionRequestManager* manager_;
   std::unique_ptr<MockPermissionPromptFactory> prompt_factory_;
+  scoped_refptr<CrowdDenyFakeSafeBrowsingDatabaseManager> db_manager_;
+  std::unique_ptr<safe_browsing::TestSafeBrowsingServiceFactory> sb_factory_;
 };
 
 TEST_F(PermissionRequestManagerTest, SingleRequest) {
@@ -969,8 +1001,7 @@
 }
 #endif  // defined(OS_CHROMEOS)
 
-// TODO(andypaicu): re-enable ASAP. crbug.com/1042611
-TEST_F(PermissionRequestManagerTest, DISABLED_TestCrowdDenyHoldbackChance) {
+TEST_F(PermissionRequestManagerTest, TestCrowdDenyHoldbackChance) {
   const struct {
     std::string holdback_chance;
     bool enabled_in_prefs;
@@ -987,10 +1018,10 @@
   };
 
   GURL url("https://spammy.com");
-  CrowdDenyPreloadData::GetInstance()
-      ->set_origin_notification_user_experience_for_testing(
-          url::Origin::Create(url),
-          CrowdDenyPreloadData::SiteReputation::UNSOLICITED_PROMPTS);
+
+  SetUpPreloadDataForUrl(
+      url, CrowdDenyPreloadData::SiteReputation::UNSOLICITED_PROMPTS);
+  SetUpSafeBrowsingMetadataForUrl(url, true);
 
   for (const auto& test : kTestCases) {
     base::HistogramTester histograms;
@@ -1022,3 +1053,41 @@
         1);
   }
 }
+
+TEST_F(PermissionRequestManagerTest, PreloadDataNeedsSafeBrowsingConfirmation) {
+  const struct {
+    SiteReputation preload_data_reputation;
+    bool safe_browsing_unsolicited_notifications;
+    bool expect_quiet_ui;
+  } kTestCases[] = {
+      {CrowdDenyPreloadData::SiteReputation::UNSOLICITED_PROMPTS, true, true},
+      {CrowdDenyPreloadData::SiteReputation::UNSOLICITED_PROMPTS, false, false},
+      {CrowdDenyPreloadData::SiteReputation::ACCEPTABLE, true, false},
+      {CrowdDenyPreloadData::SiteReputation::UNKNOWN, true, false},
+      {CrowdDenyPreloadData::SiteReputation::UNKNOWN, false, false},
+  };
+
+  const GURL url("https://spammy.com");
+
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeatureWithParameters(
+      features::kQuietNotificationPrompts,
+      {{QuietNotificationPermissionUiConfig::kEnableAdaptiveActivation, "true"},
+       {QuietNotificationPermissionUiConfig::kEnableCrowdDenyTriggering,
+        "true"},
+       {QuietNotificationPermissionUiConfig::kCrowdDenyHoldBackChance, "0"}});
+
+  for (const auto& test : kTestCases) {
+    SetUpPreloadDataForUrl(url, test.preload_data_reputation);
+    SetUpSafeBrowsingMetadataForUrl(
+        url, test.safe_browsing_unsolicited_notifications);
+
+    MockPermissionRequest request(
+        "request", PermissionRequestType::PERMISSION_NOTIFICATIONS, url);
+
+    manager_->AddRequest(&request);
+    WaitForBubbleToBeShown();
+    EXPECT_EQ(test.expect_quiet_ui, manager_->ShouldCurrentRequestUseQuietUI());
+    Closing();
+  }
+}
diff --git a/chrome/browser/resources/chromeos/crostini_installer/app.html b/chrome/browser/resources/chromeos/crostini_installer/app.html
index 0b69f25..0ccdbdd 100644
--- a/chrome/browser/resources/chromeos/crostini_installer/app.html
+++ b/chrome/browser/resources/chromeos/crostini_installer/app.html
@@ -83,16 +83,24 @@
     </div>
     <div id="configure-message" hidden="[[!isState_(state_, State.CONFIGURE)]]">
       <div>$i18n{configureMessage}</div>
-      <div>$i18n{diskSizeMessage}</div>
-      <div class="outer">
-        <cr-slider id="diskSlider" pin="true"
-                   value="[[defaultDiskSizeTick_]]"
-                   area-describedby="configure-message"
-                   ticks="[[diskSizeTicks_]]">
-        </cr-slider>
-        <div id="labels">
-          <div id="label-begin">[[minDisk_]]</div>
-          <div id="label-end">[[maxDisk_]]</div>
+      <div hidden="[[!showUsernameSelection_()]]">
+        <div>$i18n{usernameMessage}</div>
+        <cr-input label="Username" id="username" type="text"
+                  value="{{username_}}">
+        </cr-input>
+      </div>
+      <div hidden="[[!showDiskResizing_()]]">
+        <div>$i18n{diskSizeMessage}</div>
+        <div class="outer">
+          <cr-slider id="diskSlider" pin="true"
+                    value="[[defaultDiskSizeTick_]]"
+                    area-describedby="configure-message"
+                    ticks="[[diskSizeTicks_]]">
+          </cr-slider>
+          <div id="labels">
+            <div id="label-begin">[[minDisk_]]</div>
+            <div id="label-end">[[maxDisk_]]</div>
+          </div>
         </div>
       </div>
     </div>
diff --git a/chrome/browser/resources/chromeos/crostini_installer/app.js b/chrome/browser/resources/chromeos/crostini_installer/app.js
index fa9cd765..fa5cdea5 100644
--- a/chrome/browser/resources/chromeos/crostini_installer/app.js
+++ b/chrome/browser/resources/chromeos/crostini_installer/app.js
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
+import 'chrome://resources/cr_elements/cr_input/cr_input.m.js';
 import 'chrome://resources/cr_elements/cr_slider/cr_slider.m.js';
 import 'chrome://resources/cr_elements/shared_vars_css.m.js';
 import 'chrome://resources/polymer/v3_0/paper-progress/paper-progress.js';
@@ -94,6 +95,12 @@
     chosenDiskSize_: {
       type: Number,
     },
+
+    username_: {
+      type: String,
+      notify: true,
+      value: loadTimeData.getString('defaultContainerUsername'),
+    },
   },
 
   /** @override */
@@ -167,7 +174,7 @@
     this.installerState_ = InstallerState.kStart;
     this.installerProgress_ = 0;
     this.state_ = State.INSTALLING;
-    BrowserProxy.getInstance().handler.install(diskSize);
+    BrowserProxy.getInstance().handler.install(diskSize, this.username_);
   },
 
   /** @private */
@@ -242,7 +249,7 @@
    * @private
    */
   canInstall_(state) {
-    if (loadTimeData.getBoolean('diskResizingEnabled')) {
+    if (this.configurePageAccessible_()) {
       return state === State.CONFIGURE || state === State.ERROR;
     } else {
       return state === State.PROMPT || state === State.ERROR;
@@ -255,8 +262,7 @@
    * @private
    */
   showNextButton_(state) {
-    return loadTimeData.getBoolean('diskResizingEnabled') &&
-        state === State.PROMPT;
+    return this.configurePageAccessible_() && state === State.PROMPT;
   },
 
   /**
@@ -273,10 +279,7 @@
    * @private
    */
   getInstallButtonLabel_(state) {
-    if (!loadTimeData.getBoolean('diskResizingEnabled') &&
-        state === State.PROMPT) {
-      // TODO(dmunro): Remove all the flag checks once we're rolled out and no
-      // longer need them.
+    if (!this.configurePageAccessible_() && state === State.PROMPT) {
       return loadTimeData.getString('install');
     }
     switch (state) {
@@ -393,4 +396,25 @@
 
     return messageId ? loadTimeData.getString(messageId) : '';
   },
+
+  /**
+   * @private
+   */
+  configurePageAccessible_() {
+    return this.showDiskResizing_() || this.showUsernameSelection_();
+  },
+
+  /**
+   * @private
+   */
+  showDiskResizing_() {
+    return loadTimeData.getBoolean('diskResizingEnabled');
+  },
+
+  /**
+   * @private
+   */
+  showUsernameSelection_() {
+    return loadTimeData.getBoolean('crostiniCustomUsername');
+  },
 });
diff --git a/chrome/browser/resources/chromeos/login/md_login.html b/chrome/browser/resources/chromeos/login/md_login.html
index c26d8bfa..0815557 100644
--- a/chrome/browser/resources/chromeos/login/md_login.html
+++ b/chrome/browser/resources/chromeos/login/md_login.html
@@ -54,7 +54,6 @@
 <link rel="stylesheet" href="oobe_screen_auto_enrollment_check.css">
 <link rel="stylesheet" href="oobe_screen_supervision_transition.css">
 <link rel="stylesheet" href="screen_app_launch_splash.css">
-<link rel="stylesheet" href="screen_arc_kiosk_splash.css">
 <link rel="stylesheet" href="screen_arc_terms_of_service.css">
 <link rel="stylesheet" href="screen_error_message.css">
 <link rel="stylesheet" href="screen_tpm_error.css">
diff --git a/chrome/browser/resources/chromeos/login/md_login.js b/chrome/browser/resources/chromeos/login/md_login.js
index 6950b7cc..8e83e1a 100644
--- a/chrome/browser/resources/chromeos/login/md_login.js
+++ b/chrome/browser/resources/chromeos/login/md_login.js
@@ -26,7 +26,6 @@
 // <include src="oobe_select.js">
 
 // <include src="screen_app_launch_splash.js">
-// <include src="screen_arc_kiosk_splash.js">
 // <include src="screen_arc_terms_of_service.js">
 // <include src="screen_error_message.js">
 // <include src="screen_password_changed.js">
@@ -81,7 +80,6 @@
       login.RecommendAppsScreen.register();
       login.AppDownloadingScreen.register();
       login.AppLaunchSplashScreen.register();
-      login.ArcKioskSplashScreen.register();
       login.ConfirmPasswordScreen.register();
       login.FatalErrorScreen.register();
       login.DeviceDisabledScreen.register();
diff --git a/chrome/browser/resources/chromeos/login/md_login_screens.html b/chrome/browser/resources/chromeos/login/md_login_screens.html
index 8d3cfbf0..5aef135f 100644
--- a/chrome/browser/resources/chromeos/login/md_login_screens.html
+++ b/chrome/browser/resources/chromeos/login/md_login_screens.html
@@ -17,7 +17,6 @@
 <include src="screen_tpm_error.html">
 <include src="screen_wrong_hwid.html">
 <include src="screen_app_launch_splash.html">
-<include src="screen_arc_kiosk_splash.html">
 <include src="screen_confirm_password.html">
 <include src="screen_fatal_error.html">
 <include src="screen_device_disabled.html">
diff --git a/chrome/browser/resources/chromeos/login/oobe.html b/chrome/browser/resources/chromeos/login/oobe.html
index 5cd4bb5b..06354b0 100644
--- a/chrome/browser/resources/chromeos/login/oobe.html
+++ b/chrome/browser/resources/chromeos/login/oobe.html
@@ -60,7 +60,6 @@
 <link rel="stylesheet" href="oobe_screen_supervision_transition.css">
 
 <link rel="stylesheet" href="screen_app_launch_splash.css">
-<link rel="stylesheet" href="screen_arc_kiosk_splash.css">
 <link rel="stylesheet" href="screen_arc_terms_of_service.css">
 <link rel="stylesheet" href="screen_error_message.css">
 <link rel="stylesheet" href="screen_tpm_error.css">
diff --git a/chrome/browser/resources/chromeos/login/oobe.js b/chrome/browser/resources/chromeos/login/oobe.js
index f0ad1cd..06adacf 100644
--- a/chrome/browser/resources/chromeos/login/oobe.js
+++ b/chrome/browser/resources/chromeos/login/oobe.js
@@ -27,7 +27,6 @@
 // <include src="oobe_select.js">
 
 // <include src="screen_app_launch_splash.js">
-// <include src="screen_arc_kiosk_splash.js">
 // <include src="screen_arc_terms_of_service.js">
 // <include src="screen_error_message.js">
 // <include src="screen_password_changed.js">
@@ -88,7 +87,6 @@
       login.RecommendAppsScreen.register();
       login.AppDownloadingScreen.register();
       login.AppLaunchSplashScreen.register();
-      login.ArcKioskSplashScreen.register();
       login.ConfirmPasswordScreen.register();
       login.FatalErrorScreen.register();
       login.DeviceDisabledScreen.register();
diff --git a/chrome/browser/resources/chromeos/login/oobe_screens.html b/chrome/browser/resources/chromeos/login/oobe_screens.html
index 08f7d3c7..962a9bdb 100644
--- a/chrome/browser/resources/chromeos/login/oobe_screens.html
+++ b/chrome/browser/resources/chromeos/login/oobe_screens.html
@@ -28,7 +28,6 @@
 <include src="screen_tpm_error.html">
 <include src="screen_wrong_hwid.html">
 <include src="screen_app_launch_splash.html">
-<include src="screen_arc_kiosk_splash.html">
 <include src="screen_confirm_password.html">
 <include src="screen_fatal_error.html">
 <include src="screen_device_disabled.html">
diff --git a/chrome/browser/resources/chromeos/login/screen_arc_kiosk_splash.css b/chrome/browser/resources/chromeos/login/screen_arc_kiosk_splash.css
deleted file mode 100644
index 907f329f..0000000
--- a/chrome/browser/resources/chromeos/login/screen_arc_kiosk_splash.css
+++ /dev/null
@@ -1,52 +0,0 @@
-/* Copyright 2017 The Chromium Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file. */
-
-#arc-kiosk-splash {
-  -webkit-align-items: center;
-  -webkit-justify-content: center;
-  background: white;
-  display: flex;
-  min-height: 0;
-}
-
-#arc-splash-content {
-  -webkit-align-items: center;
-  -webkit-justify-content: center;
-  display: flex;
-  flex-direction: column;
-  min-height: 0;
-  position: relative;
-}
-
-#arc-splash-header {
-  background: left center no-repeat;
-  background-size: 96px;
-  color: #666;
-  display: flex;
-  font-size: 48px;
-  height: 96px;
-  line-height: 96px;
-  min-height: 0;
-  padding-inline-start: 108px;
-}
-
-#arc-splash-launch-text {
-  color: #666;
-  font-size: 18px;
-  padding-top: 50px;
-}
-
-#arc-splash-spinner {
-  height: 32px;
-  width: 32px;
-}
-
-#arc-splash-shortcut-info {
-  bottom: 50px;
-  color: gray;
-  left: 0;
-  position: absolute;
-  right: 0;
-  text-align: center;
-}
diff --git a/chrome/browser/resources/chromeos/login/screen_arc_kiosk_splash.html b/chrome/browser/resources/chromeos/login/screen_arc_kiosk_splash.html
deleted file mode 100644
index e296c76..0000000
--- a/chrome/browser/resources/chromeos/login/screen_arc_kiosk_splash.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<div id="arc-kiosk-splash" class="step hidden fullscreen" hidden>
-    <div id="arc-splash-content">
-        <div id="arc-splash-header" i18n-content="arcKioskProductName"></div>
-        <div id="arc-splash-launch-text" i18n-content="arcKioskStartMessage"></div>
-        <div id="arc-splash-spinner" class="spinner"></div>
-    </div>
-  <p id="arc-splash-shortcut-info" i18n-content="arcKioskShortcutInfo"></p>
-</div>
diff --git a/chrome/browser/resources/chromeos/login/screen_arc_kiosk_splash.js b/chrome/browser/resources/chromeos/login/screen_arc_kiosk_splash.js
deleted file mode 100644
index 3eaced2c..0000000
--- a/chrome/browser/resources/chromeos/login/screen_arc_kiosk_splash.js
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview ARC Kiosk install/launch app splash screen implementation.
- */
-
-login.createScreen('ArcKioskSplashScreen', 'arc-kiosk-splash', function() {
-  return {
-    EXTERNAL_API: [
-      'updateArcKioskMessage',
-    ],
-
-    /** @override */
-    decorate() {},
-
-    /**
-     * Event handler that is invoked just before the frame is shown.
-     * @param {string} data Screen init payload.
-     */
-    onBeforeShow(data) {
-      this.updateApp(data['appInfo']);
-
-      Oobe.getInstance().solidBackground = true;
-    },
-
-    /**
-     * Event handler that is invoked just before the frame is hidden.
-     */
-    onBeforeHide() {
-      Oobe.getInstance().solidBackground = false;
-    },
-
-    /**
-     * Updates the app name and icon.
-     * @param {Object} app Details of app being launched.
-     */
-    updateApp(app) {
-      $('arc-splash-header').textContent = app.name;
-      $('arc-splash-header').style.backgroundImage = 'url(' + app.iconURL + ')';
-    },
-
-    /**
-     * Updates the message for the current ARC kiosk state.
-     * @param {string} message Description for current state.
-     */
-    updateArcKioskMessage(message) {
-      $('arc-splash-launch-text').textContent = message;
-    }
-  };
-});
diff --git a/chrome/browser/resources/local_ntp/local_ntp.css b/chrome/browser/resources/local_ntp/local_ntp.css
index e3d9220..74aab7e1 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.css
+++ b/chrome/browser/resources/local_ntp/local_ntp.css
@@ -227,20 +227,6 @@
 #realbox-icon {
   background-position: center center;
   background-repeat: no-repeat;
-  bottom: 0;
-  left: 16px;
-  margin: auto;
-  position: absolute;
-  top: 0;
-  width: 24px;
-}
-
-[dir=rtl] #realbox-icon {
-  left: auto;
-  right: 16px;
-}
-
-#realbox-icon.load-favicon {
   background-size: 24px;
 }
 
@@ -514,7 +500,8 @@
   right: auto;
 }
 
-#realbox-input-wrapper > :-webkit-any(#realbox-icon, .microphone-icon) {
+#realbox-input-wrapper > :-webkit-any(.google-g-icon, .microphone-icon,
+                                      .search-icon) {
   z-index: 3;
 }
 
diff --git a/chrome/browser/resources/local_ntp/local_ntp.html b/chrome/browser/resources/local_ntp/local_ntp.html
index e09bb54f..3c24062 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.html
+++ b/chrome/browser/resources/local_ntp/local_ntp.html
@@ -78,8 +78,7 @@
 
     <div id="realbox-container" $i18n{hiddenIfRealboxDisabled}>
       <div id="realbox-input-wrapper">
-        <div id="realbox-icon" class="$i18n{realboxIconClass}"
-            data-realbox-icon-class="$i18n{realboxIconClass}"></div>
+        <div id="realbox-icon" class="$i18n{realboxIconClass}"></div>
         <input id="realbox" type="search" autocomplete="off" spellcheck="false"
             aria-live="polite" autofocus>
         <button id="realbox-microphone" class="microphone-icon" hidden></button>
diff --git a/chrome/browser/resources/local_ntp/local_ntp.js b/chrome/browser/resources/local_ntp/local_ntp.js
index 0e9acb05..278ceda 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.js
+++ b/chrome/browser/resources/local_ntp/local_ntp.js
@@ -91,7 +91,6 @@
   IMAGE_CONTAINER: 'image-container',
   INITED: 'inited',  // Reveals the <body> once init() is done.
   LEFT_ALIGN_ATTRIBUTION: 'left-align-attribution',
-  LOAD_FAVICON: 'load-favicon',
   // The image next to a realbox match.
   MATCH_IMAGE: 'match-image',
   // Vertically centers the most visited section for a non-Google provided page.
@@ -2119,19 +2118,13 @@
 
 /** @param {!AutocompleteMatch|undefined} match */
 function setRealboxIcon(match) {
-  const loadFavicon = match && !match.isSearchType;
+  const showIcon = match && !match.isSearchType;
 
   const realboxIcon = $(IDS.REALBOX_ICON);
-  realboxIcon.style.webkitMask = loadFavicon ? 'none' : '';
-  realboxIcon.style.backgroundColor = loadFavicon ? 'transparent' : '';
+  realboxIcon.style.webkitMask = showIcon ? 'none' : '';
+  realboxIcon.style.backgroundColor = showIcon ? 'transparent' : '';
   realboxIcon.style.backgroundImage =
-      loadFavicon ? `url(${getIconUrl(match.destinationUrl)})` : '';
-
-  const historical = match && SEARCH_HISTORY_MATCH_TYPES.includes(match.type);
-  realboxIcon.className = loadFavicon ?
-      CLASSES.LOAD_FAVICON :
-      (historical ? CLASSES.CLOCK_ICON :
-                    realboxIcon.dataset['realboxIconClass']);
+      showIcon ? `url(${getIconUrl(match.destinationUrl)})` : '';
 }
 
 /** @param {boolean} visible */
diff --git a/chrome/browser/resources/settings/BUILD.gn b/chrome/browser/resources/settings/BUILD.gn
index f8d51f1..09fa253 100644
--- a/chrome/browser/resources/settings/BUILD.gn
+++ b/chrome/browser/resources/settings/BUILD.gn
@@ -110,6 +110,7 @@
     ":extension_control_browser_proxy",
     ":global_scroll_target_behavior",
     ":lifetime_browser_proxy",
+    ":metrics_browser_proxy",
     ":open_window_proxy",
     ":page_visibility",
     ":route",
@@ -139,6 +140,11 @@
   externs_list = [ "$externs_path/chrome_send.js" ]
 }
 
+js_library("metrics_browser_proxy") {
+  deps = [ "//ui/webui/resources/js:cr" ]
+  externs_list = [ "$externs_path/chrome_send.js" ]
+}
+
 js_library("open_window_proxy") {
   deps = [ "//ui/webui/resources/js:cr" ]
 }
diff --git a/chrome/browser/resources/settings/lazy_load.html b/chrome/browser/resources/settings/lazy_load.html
index 7800dbf..560e249a 100644
--- a/chrome/browser/resources/settings/lazy_load.html
+++ b/chrome/browser/resources/settings/lazy_load.html
@@ -10,7 +10,6 @@
   <link rel="import" href="privacy_page/security_keys_subpage.html">
   <link rel="import" href="site_settings/site_data_details_subpage.html">
   <link rel="import" href="site_settings_page/site_settings_page.html">
-<!--   <link rel="import" href="site_settings/all_sites.html"> -->
   <link rel="import" href="site_settings/category_default_setting.html">
   <link rel="import" href="site_settings/category_setting_exceptions.html">
   <link rel="import" href="site_settings/chooser_exception_list.html">
diff --git a/chrome/browser/resources/settings/metrics_browser_proxy.html b/chrome/browser/resources/settings/metrics_browser_proxy.html
new file mode 100644
index 0000000..a1ced50
--- /dev/null
+++ b/chrome/browser/resources/settings/metrics_browser_proxy.html
@@ -0,0 +1,2 @@
+<link rel="import" href="chrome://resources/html/cr.html">
+<script src="metrics_browser_proxy.js"></script>
diff --git a/chrome/browser/resources/settings/metrics_browser_proxy.js b/chrome/browser/resources/settings/metrics_browser_proxy.js
new file mode 100644
index 0000000..2c97685
--- /dev/null
+++ b/chrome/browser/resources/settings/metrics_browser_proxy.js
@@ -0,0 +1,92 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/** @fileoverview Handles metrics for the settings pages. */
+
+cr.define('settings', function() {
+  /**
+   * Contains all possible recorded interactions across privacy settings pages.
+   *
+   * These values are persisted to logs. Entries should not be renumbered and
+   * numeric values should never be reused.
+   *
+   * Must be kept in sync with enum of the same name in
+   * histograms/enums.xml
+   * @enum {number}
+   */
+  const SettingsPageInteractions = {
+    PRIVACY_SYNC_AND_GOOGLE_SERVICES: 0,
+    PRIVACY_CHROME_SIGN_IN: 1,
+    PRIVACY_DO_NOT_TRACK: 2,
+    PRIVACY_PAYMENT_METHOD: 3,
+    PRIVACY_NETWORK_PREDICTION: 4,
+    PRIVACY_MANAGE_CERTIFICATES: 5,
+    PRIVACY_SECURITY_KEYS: 6,
+    PRIVACY_SITE_SETTINGS: 7,
+    PRIVACY_CLEAR_BROWSING_DATA: 8,
+    PRIVACY_SAFE_BROWSING: 9,
+    PRIVACY_PASSWORD_CHECK: 10,
+    PRIVACY_IMPROVE_SECURITY: 11,
+    PRIVACY_SITE_SETTINGS_COOKIES: 12,
+    PRIVACY_SITE_SETTINGS_LOCATION: 13,
+    PRIVACY_SITE_SETTINGS_CAMERA: 14,
+    PRIVACY_SITE_SETTINGS_MICROPHONE: 15,
+    PRIVACY_SITE_SETTINGS_SENSORS: 16,
+    PRIVACY_SITE_SETTINGS_NOTIFICATIONS: 17,
+    PRIVACY_SITE_SETTINGS_JAVASCRIPT: 18,
+    PRIVACY_SITE_SETTINGS_FLASH: 19,
+    PRIVACY_SITE_SETTINGS_IMAGES: 20,
+    PRIVACY_SITE_SETTINGS_POPUPS: 21,
+    PRIVACY_SITE_SETTINGS_ADS: 22,
+    PRIVACY_SITE_SETTINGS_BACKGROUND_SYNC: 23,
+    PRIVACY_SITE_SETTINGS_SOUND: 24,
+    PRIVACY_SITE_SETTINGS_AUTOMATIC_DOWNLOADS: 25,
+    PRIVACY_SITE_SETTINGS_UNSANDBOXED_PLUGINS: 26,
+    PRIVACY_SITE_SETTINGS_HANDLERS: 27,
+    PRIVACY_SITE_SETTINGS_MIDI_DEVICES: 28,
+    PRIVACY_SITE_SETTINGS_ZOOM_LEVELS: 29,
+    PRIVACY_SITE_SETTINGS_USB_DEVICES: 30,
+    PRIVACY_SITE_SETTINGS_SERIAL_PORTS: 31,
+    PRIVACY_SITE_SETTINGS_NATIVE_FILE_SYSTEM_WRITE: 32,
+    PRIVACY_SITE_SETTINGS_PDF_DOCUMENTS: 33,
+    PRIVACY_SITE_SETTINGS_PROTECTED_CONTENT: 34,
+    PRIVACY_SITE_SETTINGS_CLIPBOARD: 35,
+    PRIVACY_SITE_SETTINGS_PAYMENT_HANDLER: 36,
+    PRIVACY_SITE_SETTINGS_MIXEDSCRIPT: 37,
+    PRIVACY_SITE_SETTINGS_BLUETOOTH_SCANNING: 38,
+    // Leave this at the end.
+    SETTINGS_MAX_VALUE: 38,
+  };
+
+  /** @interface */
+  class MetricsBrowserProxy {
+    /**
+     * Helper function that calls recordHistogram for the
+     * SettingsPage.SettingsPageInteractions histogram
+     * @param {!settings.SettingsPageInteractions} interaction
+     */
+    recordSettingsPageHistogram(interaction) {}
+  }
+
+  /**
+   * @implements {settings.MetricsBrowserProxy}
+   */
+  class MetricsBrowserProxyImpl {
+    /** @override*/
+    recordSettingsPageHistogram(interaction) {
+      chrome.send('metricsHandler:recordInHistogram', [
+        'SettingsPage.SettingsPageInteractions', interaction,
+        settings.SettingsPageInteractions.SETTINGS_MAX_VALUE
+      ]);
+    }
+  }
+
+  cr.addSingletonGetter(MetricsBrowserProxyImpl);
+
+  return {
+    MetricsBrowserProxy,
+    MetricsBrowserProxyImpl,
+    SettingsPageInteractions
+  };
+});
\ No newline at end of file
diff --git a/chrome/browser/resources/settings/privacy_page/BUILD.gn b/chrome/browser/resources/settings/privacy_page/BUILD.gn
index c652344..6c92cc6e 100644
--- a/chrome/browser/resources/settings/privacy_page/BUILD.gn
+++ b/chrome/browser/resources/settings/privacy_page/BUILD.gn
@@ -54,6 +54,7 @@
 js_library("privacy_page") {
   deps = [
     ":privacy_page_browser_proxy",
+    "..:metrics_browser_proxy",
     "..:page_visibility",
     "..:route",
     "..:router",
@@ -130,6 +131,7 @@
 js_library("security_page") {
   deps = [
     ":privacy_page_browser_proxy",
+    "..:metrics_browser_proxy",
     "..:route",
     "..:router",
     "../people_page:sync_browser_proxy",
diff --git a/chrome/browser/resources/settings/privacy_page/passwords_leak_detection_toggle.html b/chrome/browser/resources/settings/privacy_page/passwords_leak_detection_toggle.html
index 8ccdbcf..af12a3e 100644
--- a/chrome/browser/resources/settings/privacy_page/passwords_leak_detection_toggle.html
+++ b/chrome/browser/resources/settings/privacy_page/passwords_leak_detection_toggle.html
@@ -4,6 +4,7 @@
 <link rel="import" href="chrome://resources/html/load_time_data.html">
 <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html">
 <link rel="import" href="../controls/settings_toggle_button.html">
+<link rel="import" href="../metrics_browser_proxy.html">
 <link rel="import" href="../people_page/sync_browser_proxy.html">
 <link rel="import" href="../prefs/prefs_behavior.html">
 <link rel="import" href="../prefs/prefs.html">
diff --git a/chrome/browser/resources/settings/privacy_page/passwords_leak_detection_toggle.js b/chrome/browser/resources/settings/privacy_page/passwords_leak_detection_toggle.js
index 8f8b4f5..903143e 100644
--- a/chrome/browser/resources/settings/privacy_page/passwords_leak_detection_toggle.js
+++ b/chrome/browser/resources/settings/privacy_page/passwords_leak_detection_toggle.js
@@ -59,6 +59,7 @@
     syncBrowserProxy.getStoredAccounts().then(storedAccountsChanged);
     this.addWebUIListener('stored-accounts-updated', storedAccountsChanged);
     // </if>
+    this.metricsBrowserProxy_ = settings.MetricsBrowserProxyImpl.getInstance();
   },
 
   /**
@@ -107,6 +108,8 @@
 
   /** @private */
   onPasswordsLeakDetectionChange_() {
+    this.metricsBrowserProxy_.recordSettingsPageHistogram(
+        settings.SettingsPageInteractions.PRIVACY_PASSWORD_CHECK);
     this.setPrefValue(
         'profile.password_manager_leak_detection',
         this.$.passwordsLeakDetectionCheckbox.checked);
diff --git a/chrome/browser/resources/settings/privacy_page/personalization_options.js b/chrome/browser/resources/settings/privacy_page/personalization_options.js
index b297960..eace1d1 100644
--- a/chrome/browser/resources/settings/privacy_page/personalization_options.js
+++ b/chrome/browser/resources/settings/privacy_page/personalization_options.js
@@ -165,9 +165,6 @@
           .sendPrefChange();
       this.showRestartToast_ = true;
     }
-
-    this.browserProxy_.recordSettingsPageHistogram(
-        settings.SettingsPageInteractions.PRIVACY_CHROME_SIGN_IN);
   },
 
   /** @private */
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.html b/chrome/browser/resources/settings/privacy_page/privacy_page.html
index 7453799..078c52ba 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page.html
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.html
@@ -14,6 +14,7 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-collapse/iron-collapse.html">
 <link rel="import" href="../clear_browsing_data_dialog/clear_browsing_data_dialog.html">
 <link rel="import" href="../controls/settings_toggle_button.html">
+<link rel="import" href="../metrics_browser_proxy.html">
 <link rel="import" href="../people_page/sync_browser_proxy.html">
 <link rel="import" href="../prefs/prefs.html">
 <link rel="import" href="../prefs/prefs_behavior.html">
@@ -83,7 +84,9 @@
               class="settings-box first"
               pref="{{prefs.safebrowsing.enabled}}"
               label="$i18n{safeBrowsingEnableProtection}"
-              sub-label="$i18n{safeBrowsingEnableProtectionDesc}">
+              sub-label="$i18n{safeBrowsingEnableProtectionDesc}"
+              on-settings-boolean-control-change=
+                  "onSafeBrowsingToggleChange_">
           </settings-toggle-button>
           <settings-passwords-leak-detection-toggle
               id="passwordsLeakDetectionToggle"
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.js b/chrome/browser/resources/settings/privacy_page/privacy_page.js
index 8f4055f13..8c0608f 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page.js
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.js
@@ -7,7 +7,6 @@
  * 'settings-privacy-page' is the settings page containing privacy and
  * security settings.
  */
-
 cr.define('settings', function() {
   /**
    * @typedef {{
@@ -245,6 +244,8 @@
       this.ChooserType = settings.ChooserType;
 
       this.browserProxy_ = settings.PrivacyPageBrowserProxyImpl.getInstance();
+      this.metricsBrowserProxy_ =
+          settings.MetricsBrowserProxyImpl.getInstance();
 
       this.onBlockAutoplayStatusChanged_({
         pref: /** @type {chrome.settingsPrivate.PrefObject} */ ({value: false}),
@@ -271,6 +272,8 @@
 
     /** @private */
     onSafeBrowsingReportingToggleChange_() {
+      this.metricsBrowserProxy_.recordSettingsPageHistogram(
+          settings.SettingsPageInteractions.PRIVACY_IMPROVE_SECURITY);
       this.setPrefValue(
           'safebrowsing.scout_reporting_enabled',
           this.$$('#safeBrowsingReportingToggle').checked);
@@ -346,7 +349,7 @@
      * @private
      */
     onCanMakePaymentChange_() {
-      this.browserProxy_.recordSettingsPageHistogram(
+      this.metricsBrowserProxy_.recordSettingsPageHistogram(
           settings.SettingsPageInteractions.PRIVACY_PAYMENT_METHOD);
     },
 
@@ -357,7 +360,7 @@
      * @private
      */
     onDoNotTrackChange_(event) {
-      this.browserProxy_.recordSettingsPageHistogram(
+      this.metricsBrowserProxy_.recordSettingsPageHistogram(
           settings.SettingsPageInteractions.PRIVACY_DO_NOT_TRACK);
       const target = /** @type {!SettingsToggleButtonElement} */ (event.target);
       if (!target.checked) {
@@ -413,14 +416,14 @@
 
     /** @private */
     onManageCertificatesTap_() {
+      this.metricsBrowserProxy_.recordSettingsPageHistogram(
+          settings.SettingsPageInteractions.PRIVACY_MANAGE_CERTIFICATES);
       // <if expr="use_nss_certs">
       settings.Router.getInstance().navigateTo(settings.routes.CERTIFICATES);
       // </if>
       // <if expr="is_win or is_macosx">
       this.browserProxy_.showManageSSLCertificates();
       // </if>
-      this.browserProxy_.recordSettingsPageHistogram(
-          settings.SettingsPageInteractions.PRIVACY_MANAGE_CERTIFICATES);
     },
 
     /**
@@ -430,7 +433,7 @@
      * @private
      */
     onNetworkPredictionChange_() {
-      this.browserProxy_.recordSettingsPageHistogram(
+      this.metricsBrowserProxy_.recordSettingsPageHistogram(
           settings.SettingsPageInteractions.PRIVACY_NETWORK_PREDICTION);
     },
 
@@ -454,17 +457,23 @@
 
     /** @private */
     onSiteSettingsTap_() {
-      settings.Router.getInstance().navigateTo(settings.routes.SITE_SETTINGS);
-      this.browserProxy_.recordSettingsPageHistogram(
+      this.metricsBrowserProxy_.recordSettingsPageHistogram(
           settings.SettingsPageInteractions.PRIVACY_SITE_SETTINGS);
+      settings.Router.getInstance().navigateTo(settings.routes.SITE_SETTINGS);
+    },
+
+    /** @private */
+    onSafeBrowsingToggleChange_: function() {
+      this.metricsBrowserProxy_.recordSettingsPageHistogram(
+          settings.SettingsPageInteractions.PRIVACY_SAFE_BROWSING);
     },
 
     /** @private */
     onClearBrowsingDataTap_() {
+      this.metricsBrowserProxy_.recordSettingsPageHistogram(
+          settings.SettingsPageInteractions.PRIVACY_CLEAR_BROWSING_DATA);
       settings.Router.getInstance().navigateTo(
           settings.routes.CLEAR_BROWSER_DATA);
-      this.browserProxy_.recordSettingsPageHistogram(
-          settings.SettingsPageInteractions.PRIVACY_CLEAR_BROWSING_DATA);
     },
 
     /** @private */
@@ -476,9 +485,9 @@
 
     /** @private */
     onSecurityKeysTap_() {
-      settings.Router.getInstance().navigateTo(settings.routes.SECURITY_KEYS);
-      this.browserProxy_.recordSettingsPageHistogram(
+      this.metricsBrowserProxy_.recordSettingsPageHistogram(
           settings.SettingsPageInteractions.PRIVACY_SECURITY_KEYS);
+      settings.Router.getInstance().navigateTo(settings.routes.SECURITY_KEYS);
     },
 
     /** @private */
@@ -496,4 +505,4 @@
   });
 
   return {BlockAutoplayStatus};
-});
+});
\ No newline at end of file
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page_browser_proxy.js b/chrome/browser/resources/settings/privacy_page/privacy_page_browser_proxy.js
index d6663e0..0cfa4c5 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page_browser_proxy.js
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page_browser_proxy.js
@@ -4,29 +4,6 @@
 
 /** @fileoverview Handles interprocess communication for the privacy page. */
 
-/**
- * Contains all possible recorded interactions across privacy settings pages.
- *
- * These values are persisted to logs. Entries should not be renumbered and
- * numeric values should never be reused.
- *
- * Must be kept in sync with enum of the same name in
- * histograms/enums.xml
- */
-settings.SettingsPageInteractions = {
-  PRIVACY_SYNC_AND_GOOGLE_SERVICES: 0,
-  PRIVACY_CHROME_SIGN_IN: 1,
-  PRIVACY_DO_NOT_TRACK: 2,
-  PRIVACY_PAYMENT_METHOD: 3,
-  PRIVACY_NETWORK_PREDICTION: 4,
-  PRIVACY_MANAGE_CERTIFICATES: 5,
-  PRIVACY_SECURITY_KEYS: 6,
-  PRIVACY_SITE_SETTINGS: 7,
-  PRIVACY_CLEAR_BROWSING_DATA: 8,
-  // Leave this at the end.
-  SETTINGS_MAX_VALUE: 8,
-};
-
 /** @typedef {{enabled: boolean, managed: boolean}} */
 let MetricsReporting;
 
@@ -48,12 +25,6 @@
 
     // </if>
 
-    /**
-     * Helper function that calls recordHistogram for the
-     * SettingsPage.SettingsPageInteractions histogram
-     */
-    recordSettingsPageHistogram(value) {}
-
     /** @param {boolean} enabled */
     setBlockAutoplayEnabled(enabled) {}
   }
@@ -75,14 +46,6 @@
 
     // </if>
 
-    /** @override*/
-    recordSettingsPageHistogram(value) {
-      chrome.send('metricsHandler:recordInHistogram', [
-        'SettingsPage.SettingsPageInteractions', value,
-        settings.SettingsPageInteractions.SETTINGS_MAX_VALUE
-      ]);
-    }
-
     /** @override */
     setBlockAutoplayEnabled(enabled) {
       chrome.send('setBlockAutoplayEnabled', [enabled]);
diff --git a/chrome/browser/resources/settings/privacy_page/security_page.html b/chrome/browser/resources/settings/privacy_page/security_page.html
index a6dcd093..242abb00 100644
--- a/chrome/browser/resources/settings/privacy_page/security_page.html
+++ b/chrome/browser/resources/settings/privacy_page/security_page.html
@@ -4,6 +4,7 @@
 <link rel="import" href="passwords_leak_detection_toggle.html">
 <link rel="import" href="privacy_page_browser_proxy.html">
 <link rel="import" href="../controls/settings_toggle_button.html">
+<link rel="import" href="../metrics_browser_proxy.html">
 <link rel="import" href="../prefs/prefs.html">
 <link rel="import" href="../prefs/prefs_behavior.html">
 <link rel="import" href="../route.html">
diff --git a/chrome/browser/resources/settings/privacy_page/security_page.js b/chrome/browser/resources/settings/privacy_page/security_page.js
index dc7ec8c5..87f51e8 100644
--- a/chrome/browser/resources/settings/privacy_page/security_page.js
+++ b/chrome/browser/resources/settings/privacy_page/security_page.js
@@ -45,6 +45,8 @@
   /** @override */
   ready() {
     this.browserProxy_ = settings.PrivacyPageBrowserProxyImpl.getInstance();
+
+    this.metricsBrowserProxy_ = settings.MetricsBrowserProxyImpl.getInstance();
   },
 
   /**
@@ -88,7 +90,7 @@
     // <if expr="is_win or is_macosx">
     this.browserProxy_.showManageSSLCertificates();
     // </if>
-    this.browserProxy_.recordSettingsPageHistogram(
+    this.metricsBrowserProxy_.recordSettingsPageHistogram(
         settings.SettingsPageInteractions.PRIVACY_MANAGE_CERTIFICATES);
   },
 
@@ -100,7 +102,7 @@
   /** @private */
   onSecurityKeysClick_() {
     settings.Router.getInstance().navigateTo(settings.routes.SECURITY_KEYS);
-    this.browserProxy_.recordSettingsPageHistogram(
+    this.metricsBrowserProxy_.recordSettingsPageHistogram(
         settings.SettingsPageInteractions.PRIVACY_SECURITY_KEYS);
   },
 });
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd
index 1187d1cb..e816781 100644
--- a/chrome/browser/resources/settings/settings_resources.grd
+++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -858,6 +858,13 @@
                  file="site_settings/protocol_handlers.js"
                  preprocess="true"
                  type="chrome_html" />
+      <structure name="IDR_SETTINGS_METRICS_BROWSER_PROXY_HTML"
+                 file="metrics_browser_proxy.html"
+                 type="chrome_html" />
+      <structure name="IDR_SETTINGS_METRICS_BROWSER_PROXY_JS"
+                 file="metrics_browser_proxy.js"
+                 type="chrome_html"
+                 preprocess="true" />
       <structure name="IDR_SETTINGS_ROUTE_HTML"
                  file="route.html"
                  type="chrome_html" />
diff --git a/chrome/browser/resources/settings/site_settings_page/BUILD.gn b/chrome/browser/resources/settings/site_settings_page/BUILD.gn
index f6e7df0..f87bc41 100644
--- a/chrome/browser/resources/settings/site_settings_page/BUILD.gn
+++ b/chrome/browser/resources/settings/site_settings_page/BUILD.gn
@@ -10,6 +10,7 @@
 
 js_library("site_settings_page") {
   deps = [
+    "..:metrics_browser_proxy",
     "..:route",
     "..:router",
     "../site_settings:constants",
diff --git a/chrome/browser/resources/settings/site_settings_page/site_settings_page.html b/chrome/browser/resources/settings/site_settings_page/site_settings_page.html
index 167823b..a225efb 100644
--- a/chrome/browser/resources/settings/site_settings_page/site_settings_page.html
+++ b/chrome/browser/resources/settings/site_settings_page/site_settings_page.html
@@ -11,6 +11,7 @@
 <link rel="import" href="../site_settings/constants.html">
 <link rel="import" href="../site_settings/site_settings_behavior.html">
 <link rel="import" href="../site_settings/site_settings_prefs_browser_proxy.html">
+<link rel="import" href="../metrics_browser_proxy.html">
 
 <dom-module id="settings-site-settings-page">
   <template>
@@ -289,7 +290,7 @@
 
     <template is="dom-if" if="[[enableInsecureContentContentSetting_]]">
       <cr-link-row class="hr two-line" data-route="SITE_SETTINGS_MIXEDSCRIPT"
-          label="$i18n{siteSettingsInsecureContent}"
+          id="mixedscript" label="$i18n{siteSettingsInsecureContent}"
           on-click="onTapNavigate_"
           start-icon="settings:insecure-content"
           sub-label="$i18n{siteSettingsInsecureContentBlock}"
diff --git a/chrome/browser/resources/settings/site_settings_page/site_settings_page.js b/chrome/browser/resources/settings/site_settings_page/site_settings_page.js
index 933ed64e..ed8aeb5 100644
--- a/chrome/browser/resources/settings/site_settings_page/site_settings_page.js
+++ b/chrome/browser/resources/settings/site_settings_page/site_settings_page.js
@@ -168,6 +168,8 @@
     this.ContentSettingsTypes = settings.ContentSettingsTypes;
     this.ALL_SITES = settings.ALL_SITES;
 
+    this.metricsBrowserProxy_ = settings.MetricsBrowserProxyImpl.getInstance();
+
     const keys = Object.keys(settings.ContentSettingsTypes);
     for (let i = 0; i < keys.length; ++i) {
       const key = settings.ContentSettingsTypes[keys[i]];
@@ -252,5 +254,7 @@
     const dataSet =
         /** @type {{route: string}} */ (event.currentTarget.dataset);
     settings.Router.getInstance().navigateTo(settings.routes[dataSet.route]);
+    this.metricsBrowserProxy_.recordSettingsPageHistogram(
+        settings.SettingsPageInteractions['PRIVACY_' + dataSet.route]);
   },
 });
diff --git a/chrome/browser/sharing/webrtc/ice_config_fetcher.cc b/chrome/browser/sharing/webrtc/ice_config_fetcher.cc
new file mode 100644
index 0000000..aa582fa
--- /dev/null
+++ b/chrome/browser/sharing/webrtc/ice_config_fetcher.cc
@@ -0,0 +1,164 @@
+// Copyright 2020 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/sharing/webrtc/ice_config_fetcher.h"
+
+#include "base/bind.h"
+#include "base/json/json_reader.h"
+#include "base/optional.h"
+#include "base/strings/strcat.h"
+#include "google_apis/google_api_keys.h"
+#include "net/base/load_flags.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/simple_url_loader.h"
+
+namespace {
+const char kIceConfigApiUrl[] =
+    "https://networktraversal.googleapis.com/v1alpha/iceconfig?key=";
+
+// Response with 2 ice server configs takes ~1KB. A loose upper bound of 16KB is
+// chosen to avoid breaking the flow in case the response has longer URLs in ice
+// configs.
+constexpr int kMaxBodySize = 16 * 1024;
+
+const net::NetworkTrafficAnnotationTag kTrafficAnnotation =
+    net::DefineNetworkTrafficAnnotation("ice_config_fetcher", R"(
+        semantics {
+          sender: "IceConfigFetcher"
+          description:
+            "Fetches ice server configurations for p2p webrtc connection as "
+            "described in "
+            "https://www.w3.org/TR/webrtc/#rtciceserver-dictionary."
+          trigger:
+            "User uses any Chrome cross-device sharing feature and selects one"
+            " of their devices to send the data to."
+          data: "No data is sent in the request."
+          destination: GOOGLE_OWNED_SERVICE
+          }
+          policy {
+            cookies_allowed: NO
+            setting:
+              "Users can disable this behavior by signing out of Chrome."
+            chrome_policy {
+              BrowserSignin {
+                policy_options {mode: MANDATORY}
+                BrowserSignin: 0
+              }
+            }
+          })");
+
+bool IsLoaderSuccessful(const network::SimpleURLLoader* loader) {
+  if (!loader || loader->NetError() != net::OK)
+    return false;
+
+  if (!loader->ResponseInfo() || !loader->ResponseInfo()->headers)
+    return false;
+
+  // Success response codes are 2xx.
+  return (loader->ResponseInfo()->headers->response_code() / 100) == 2;
+}
+
+}  // namespace
+
+IceConfigFetcher::IceConfigFetcher(
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
+    : url_loader_factory_(std::move(url_loader_factory)) {}
+
+IceConfigFetcher::~IceConfigFetcher() = default;
+
+void IceConfigFetcher::GetIceServers(IceServerCallback callback) {
+  url_loader_.reset();
+
+  auto resource_request = std::make_unique<network::ResourceRequest>();
+  resource_request->url =
+      GURL(base::StrCat({kIceConfigApiUrl, google_apis::GetSharingAPIKey()}));
+  resource_request->load_flags =
+      net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE;
+  resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
+  resource_request->method = net::HttpRequestHeaders::kPostMethod;
+  resource_request->headers.SetHeader(net::HttpRequestHeaders::kContentType,
+                                      "application/json");
+
+  url_loader_ = network::SimpleURLLoader::Create(std::move(resource_request),
+                                                 kTrafficAnnotation);
+  url_loader_->DownloadToString(
+      url_loader_factory_.get(),
+      base::BindOnce(&IceConfigFetcher::OnIceServersResponse,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)),
+      kMaxBodySize);
+}
+
+void IceConfigFetcher::OnIceServersResponse(
+    IceServerCallback callback,
+    std::unique_ptr<std::string> response_body) {
+  std::vector<sharing::mojom::IceServerPtr> ice_servers;
+
+  if (IsLoaderSuccessful(url_loader_.get()) && response_body)
+    ice_servers = ParseIceConfigJson(*response_body);
+
+  if (ice_servers.empty())
+    ice_servers = GetDefaultIceServers();
+
+  std::move(callback).Run(std::move(ice_servers));
+}
+
+std::vector<sharing::mojom::IceServerPtr> IceConfigFetcher::ParseIceConfigJson(
+    std::string json) {
+  std::vector<sharing::mojom::IceServerPtr> ice_servers;
+  base::Optional<base::Value> response = base::JSONReader::Read(json);
+  if (!response)
+    return ice_servers;
+
+  base::Value* ice_servers_json = response->FindListKey("iceServers");
+  if (!ice_servers_json)
+    return ice_servers;
+
+  for (base::Value& server : ice_servers_json->GetList()) {
+    const base::Value* urls_json = server.FindListKey("urls");
+    if (!urls_json)
+      continue;
+
+    std::vector<GURL> urls;
+    for (const base::Value& url_json : urls_json->GetList()) {
+      std::string url;
+      if (!url_json.GetAsString(&url))
+        continue;
+
+      urls.emplace_back(url);
+    }
+
+    if (urls.empty())
+      continue;
+
+    sharing::mojom::IceServerPtr ice_server(sharing::mojom::IceServer::New());
+    ice_server->urls = std::move(urls);
+
+    std::string* retrieved_username = server.FindStringKey("username");
+    if (retrieved_username)
+      ice_server->username.emplace(std::move(*retrieved_username));
+
+    std::string* retrieved_credential = server.FindStringKey("credential");
+    if (retrieved_credential)
+      ice_server->credential.emplace(std::move(*retrieved_credential));
+
+    ice_servers.push_back(std::move(ice_server));
+  }
+
+  return ice_servers;
+}
+
+// static
+std::vector<sharing::mojom::IceServerPtr>
+IceConfigFetcher::GetDefaultIceServers() {
+  sharing::mojom::IceServerPtr ice_server(sharing::mojom::IceServer::New());
+  ice_server->urls.emplace_back("stun:stun.l.google.com:19302");
+  ice_server->urls.emplace_back("stun:stun1.l.google.com:19302");
+  ice_server->urls.emplace_back("stun:stun2.l.google.com:19302");
+  ice_server->urls.emplace_back("stun:stun3.l.google.com:19302");
+  ice_server->urls.emplace_back("stun:stun4.l.google.com:19302");
+
+  std::vector<sharing::mojom::IceServerPtr> default_servers;
+  default_servers.push_back(std::move(ice_server));
+  return default_servers;
+}
diff --git a/chrome/browser/sharing/webrtc/ice_config_fetcher.h b/chrome/browser/sharing/webrtc/ice_config_fetcher.h
new file mode 100644
index 0000000..630cca19
--- /dev/null
+++ b/chrome/browser/sharing/webrtc/ice_config_fetcher.h
@@ -0,0 +1,55 @@
+// Copyright 2020 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_SHARING_WEBRTC_ICE_CONFIG_FETCHER_H_
+#define CHROME_BROWSER_SHARING_WEBRTC_ICE_CONFIG_FETCHER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+#include "chrome/services/sharing/public/mojom/webrtc.mojom.h"
+#include "url/gurl.h"
+
+namespace network {
+class SharedURLLoaderFactory;
+class SimpleURLLoader;
+}  // namespace network
+
+class IceConfigFetcher {
+ public:
+  using IceServerCallback =
+      base::OnceCallback<void(std::vector<sharing::mojom::IceServerPtr>)>;
+
+  explicit IceConfigFetcher(
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
+  ~IceConfigFetcher();
+
+  IceConfigFetcher(const IceConfigFetcher& other) = delete;
+  IceConfigFetcher& operator=(const IceConfigFetcher& other) = delete;
+
+  // TODO(himanshujaju) - Cache configs fetched from server.
+  void GetIceServers(IceServerCallback callback);
+
+ private:
+  void OnIceServersResponse(IceServerCallback callback,
+                            std::unique_ptr<std::string> response_body);
+
+  std::vector<sharing::mojom::IceServerPtr> ParseIceConfigJson(
+      std::string json);
+
+  // Returns public ice servers if API fails to respond.
+  static std::vector<sharing::mojom::IceServerPtr> GetDefaultIceServers();
+
+  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
+  std::unique_ptr<network::SimpleURLLoader> url_loader_;
+
+  base::WeakPtrFactory<IceConfigFetcher> weak_ptr_factory_{this};
+};
+
+#endif  // CHROME_BROWSER_SHARING_WEBRTC_ICE_CONFIG_FETCHER_H_
diff --git a/chrome/browser/sharing/webrtc/ice_config_fetcher_unittest.cc b/chrome/browser/sharing/webrtc/ice_config_fetcher_unittest.cc
new file mode 100644
index 0000000..94768a5
--- /dev/null
+++ b/chrome/browser/sharing/webrtc/ice_config_fetcher_unittest.cc
@@ -0,0 +1,102 @@
+// Copyright 2020 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/sharing/webrtc/ice_config_fetcher.h"
+
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+#include "base/run_loop.h"
+#include "base/strings/strcat.h"
+#include "base/test/bind_test_util.h"
+#include "base/test/task_environment.h"
+#include "chrome/common/chrome_paths.h"
+#include "google_apis/google_api_keys.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/test/test_url_loader_factory.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class IceConfigFetcherTest : public testing::Test {
+ public:
+  IceConfigFetcherTest()
+      : test_shared_loader_factory_(
+            base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+                &test_url_loader_factory_)),
+        ice_config_fetcher_(test_shared_loader_factory_) {}
+  ~IceConfigFetcherTest() override = default;
+
+  std::string GetApiUrl() const {
+    return base::StrCat(
+        {"https://networktraversal.googleapis.com/v1alpha/iceconfig?key=",
+         google_apis::GetSharingAPIKey()});
+  }
+
+  void CheckSuccessResponse(
+      const std::vector<sharing::mojom::IceServerPtr>& ice_servers) {
+    ASSERT_EQ(2u, ice_servers.size());
+
+    // First response doesnt have credentials.
+    ASSERT_EQ(1u, ice_servers[0]->urls.size());
+    ASSERT_FALSE(ice_servers[0]->username);
+    ASSERT_FALSE(ice_servers[0]->credential);
+
+    // Second response has credentials.
+    ASSERT_EQ(2u, ice_servers[1]->urls.size());
+    ASSERT_EQ("username", ice_servers[1]->username);
+    ASSERT_EQ("credential", ice_servers[1]->credential);
+  }
+
+  void GetSuccessResponse(std::string* response) const {
+    base::FilePath path;
+    ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &path));
+    path = path.AppendASCII("sharing");
+    ASSERT_TRUE(base::PathExists(path));
+    ASSERT_TRUE(base::ReadFileToString(
+        path.AppendASCII("network_traversal_response.json"), response));
+  }
+
+ protected:
+  base::test::SingleThreadTaskEnvironment task_environment_;
+  network::TestURLLoaderFactory test_url_loader_factory_;
+  scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_;
+  IceConfigFetcher ice_config_fetcher_;
+};
+
+TEST_F(IceConfigFetcherTest, ResponseSuccessful) {
+  base::RunLoop run_loop;
+  ice_config_fetcher_.GetIceServers(base::BindLambdaForTesting(
+      [&](std::vector<sharing::mojom::IceServerPtr> ice_servers) {
+        CheckSuccessResponse(ice_servers);
+        run_loop.Quit();
+      }));
+
+  const std::string expected_api_url = GetApiUrl();
+  std::string response;
+  GetSuccessResponse(&response);
+
+  ASSERT_TRUE(test_url_loader_factory_.IsPending(expected_api_url, nullptr));
+
+  test_url_loader_factory_.AddResponse(expected_api_url, response,
+                                       net::HTTP_OK);
+  run_loop.Run();
+}
+
+TEST_F(IceConfigFetcherTest, ResponseError) {
+  base::RunLoop run_loop;
+  ice_config_fetcher_.GetIceServers(base::BindLambdaForTesting(
+      [&](std::vector<sharing::mojom::IceServerPtr> ice_servers) {
+        // Makes sure that we at least return default servers in case of an
+        // error.
+        EXPECT_FALSE(ice_servers.empty());
+        run_loop.Quit();
+      }));
+
+  const std::string expected_api_url = GetApiUrl();
+  ASSERT_TRUE(test_url_loader_factory_.IsPending(expected_api_url, nullptr));
+
+  test_url_loader_factory_.AddResponse(expected_api_url, "",
+                                       net::HTTP_INTERNAL_SERVER_ERROR);
+  run_loop.Run();
+}
diff --git a/chrome/browser/ssl/ssl_error_handler.cc b/chrome/browser/ssl/ssl_error_handler.cc
index 2655fc5..c70e87b 100644
--- a/chrome/browser/ssl/ssl_error_handler.cc
+++ b/chrome/browser/ssl/ssl_error_handler.cc
@@ -22,7 +22,6 @@
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/interstitials/enterprise_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ssl/captive_portal_helper.h"
 #include "chrome/browser/ssl/chrome_security_blocking_page_factory.h"
@@ -184,6 +183,8 @@
   base::TimeDelta interstitial_delay() const;
   SSLErrorHandler::TimerStartedCallback* timer_started_callback() const;
   base::Clock* clock() const;
+  SSLErrorHandler::OnBlockingPageShownCallback on_blocking_page_shown_callback()
+      const;
 
   bool IsKnownCaptivePortalCertificate(const net::SSLInfo& ssl_info);
 
@@ -212,6 +213,9 @@
       std::unique_ptr<chrome_browser_ssl::SSLErrorAssistantConfig>
           error_assistant_proto);
 
+  void SetClientCallbackOnInterstitialsShown(
+      SSLErrorHandler::OnBlockingPageShownCallback callback);
+
   int GetErrorAssistantProtoVersionIdForTesting() const;
 
   void SetOSReportsCaptivePortalForTesting(bool os_reports_captive_portal);
@@ -234,6 +238,8 @@
 
   base::OnceClosure report_network_connectivity_callback_;
 
+  SSLErrorHandler::OnBlockingPageShownCallback on_blocking_page_shown_callback_;
+
   enum OSCaptivePortalStatus {
     OS_CAPTIVE_PORTAL_STATUS_NOT_SET,
     OS_CAPTIVE_PORTAL_STATUS_BEHIND_PORTAL,
@@ -263,10 +269,17 @@
   return testing_clock_;
 }
 
+SSLErrorHandler::OnBlockingPageShownCallback
+ConfigSingleton::on_blocking_page_shown_callback() const {
+  return on_blocking_page_shown_callback_;
+}
+
 void ConfigSingleton::ResetForTesting() {
   interstitial_delay_ =
       base::TimeDelta::FromMilliseconds(kInterstitialDelayInMilliseconds);
   timer_started_callback_ = nullptr;
+  on_blocking_page_shown_callback_ =
+      SSLErrorHandler::OnBlockingPageShownCallback();
   testing_clock_ = nullptr;
   ssl_error_assistant_->ResetForTesting();
   os_captive_portal_status_for_testing_ = OS_CAPTIVE_PORTAL_STATUS_NOT_SET;
@@ -313,6 +326,11 @@
   ssl_error_assistant_->SetErrorAssistantProto(std::move(proto));
 }
 
+void ConfigSingleton::SetClientCallbackOnInterstitialsShown(
+    SSLErrorHandler::OnBlockingPageShownCallback callback) {
+  on_blocking_page_shown_callback_ = callback;
+}
+
 bool ConfigSingleton::IsKnownCaptivePortalCertificate(
     const net::SSLInfo& ssl_info) {
   return ssl_error_assistant_->IsKnownCaptivePortalCertificate(ssl_info);
@@ -340,6 +358,8 @@
       int options_mask,
       const GURL& request_url,
       std::unique_ptr<SSLCertReporter> ssl_cert_reporter,
+      SSLErrorHandler::OnBlockingPageShownCallback
+          on_blocking_page_shown_callback,
       SSLErrorHandler::BlockingPageReadyCallback blocking_page_ready_callback)
       : web_contents_(web_contents),
         ssl_info_(ssl_info),
@@ -348,6 +368,7 @@
         options_mask_(options_mask),
         request_url_(request_url),
         ssl_cert_reporter_(std::move(ssl_cert_reporter)),
+        on_blocking_page_shown_callback_(on_blocking_page_shown_callback),
         blocking_page_ready_callback_(std::move(blocking_page_ready_callback)) {
     DCHECK(!blocking_page_ready_callback_.is_null());
   }
@@ -387,6 +408,7 @@
   const GURL request_url_;
   std::unique_ptr<CommonNameMismatchHandler> common_name_mismatch_handler_;
   std::unique_ptr<SSLCertReporter> ssl_cert_reporter_;
+  SSLErrorHandler::OnBlockingPageShownCallback on_blocking_page_shown_callback_;
   SSLErrorHandler::BlockingPageReadyCallback blocking_page_ready_callback_;
 };
 
@@ -508,8 +530,11 @@
 
 void SSLErrorHandlerDelegateImpl::OnBlockingPageReady(
     security_interstitials::SecurityInterstitialPage* interstitial_page) {
-  MaybeTriggerSecurityInterstitialShownEvent(web_contents_, request_url_,
-                                             "SSL_ERROR", cert_error_);
+  if (on_blocking_page_shown_callback_) {
+    on_blocking_page_shown_callback_.Run(web_contents_, request_url_,
+                                         "SSL_ERROR", cert_error_);
+  }
+
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindOnce(std::move(blocking_page_ready_callback_),
                                 base::WrapUnique(interstitial_page)));
@@ -552,6 +577,7 @@
           new SSLErrorHandlerDelegateImpl(
               web_contents, ssl_info, profile, cert_error, options_mask,
               request_url, std::move(ssl_cert_reporter),
+              g_config.Pointer()->on_blocking_page_shown_callback(),
               std::move(blocking_page_ready_callback))),
       web_contents, profile, cert_error, ssl_info, network_time_tracker,
       request_url);
@@ -615,6 +641,12 @@
   g_config.Pointer()->SetErrorAssistantProto(std::move(config_proto));
 }
 
+// static
+void SSLErrorHandler::SetClientCallbackOnInterstitialsShown(
+    OnBlockingPageShownCallback callback) {
+  g_config.Pointer()->SetClientCallbackOnInterstitialsShown(callback);
+}
+
 SSLErrorHandler::SSLErrorHandler(
     std::unique_ptr<Delegate> delegate,
     content::WebContents* web_contents,
diff --git a/chrome/browser/ssl/ssl_error_handler.h b/chrome/browser/ssl/ssl_error_handler.h
index 895d9b7..ea64f26 100644
--- a/chrome/browser/ssl/ssl_error_handler.h
+++ b/chrome/browser/ssl/ssl_error_handler.h
@@ -75,6 +75,13 @@
       std::unique_ptr<security_interstitials::SecurityInterstitialPage>)>
       BlockingPageReadyCallback;
 
+  // Callback that is optionally used to inform the client that a blocking page
+  // has been shown in the specified WebContents for the specified URL with the
+  // given error string and network error code.
+  typedef base::RepeatingCallback<
+      void(content::WebContents*, const GURL&, const std::string&, int)>
+      OnBlockingPageShownCallback;
+
   ~SSLErrorHandler() override;
 
   // Events for UMA. Do not rename or remove values, add new values to the end.
@@ -147,6 +154,11 @@
       std::unique_ptr<chrome_browser_ssl::SSLErrorAssistantConfig>
           config_proto);
 
+  // Invoke this method to have |callback| called whenever an interstitial is
+  // shown in an SSLErrorHandler instance.
+  static void SetClientCallbackOnInterstitialsShown(
+      OnBlockingPageShownCallback callback);
+
   // Testing methods.
   static void ResetConfigForTesting();
   static void SetInterstitialDelayForTesting(const base::TimeDelta& delay);
diff --git a/chrome/browser/sync/test/integration/two_client_autofill_sync_test.cc b/chrome/browser/sync/test/integration/two_client_autofill_sync_test.cc
index ce738cd..852a32a 100644
--- a/chrome/browser/sync/test/integration/two_client_autofill_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_autofill_sync_test.cc
@@ -188,6 +188,7 @@
                                LOCAL_DELETION, 0);
 }
 
+// Flaky on all platform. See crbug.com/971666
 IN_PROC_BROWSER_TEST_F(TwoClientAutofillProfileSyncTest,
                        AddDuplicateProfiles_OneIsVerified) {
   ASSERT_TRUE(SetupClients());
@@ -209,20 +210,13 @@
   EXPECT_EQ(verified_origin, GetAllAutoFillProfiles(0)[0]->origin());
   EXPECT_EQ(verified_origin, GetAllAutoFillProfiles(1)[0]->origin());
 
-  // Among duplicate profiles, sync prefers the one with largest GUID. If
-  // |profile0| (committed first) has a smaller GUID, client 1 should upload its
-  // deletion to the server. Otherwise, no deletion should occur.
-  if (profile1.guid() > profile0.guid()) {
-    histograms.ExpectBucketCount("Sync.ModelTypeEntityChange3.AUTOFILL_PROFILE",
-                                 LOCAL_DELETION, 1);
-  } else {
-    histograms.ExpectBucketCount("Sync.ModelTypeEntityChange3.AUTOFILL_PROFILE",
-                                 LOCAL_DELETION, 0);
-  }
+  histograms.ExpectBucketCount("Sync.ModelTypeEntityChange3.AUTOFILL_PROFILE",
+                               LOCAL_DELETION, 0);
 }
 
-IN_PROC_BROWSER_TEST_F(TwoClientAutofillProfileSyncTest,
-                       AddDuplicateProfiles_OneAtStart_OtherComesLater) {
+IN_PROC_BROWSER_TEST_F(
+    TwoClientAutofillProfileSyncTest,
+    AddDuplicateProfiles_OneIsVerified_NonverifiedComesLater) {
   ASSERT_TRUE(SetupClients());
   base::HistogramTester histograms;
 
@@ -231,23 +225,26 @@
       autofill::test::GetVerifiedProfile();  // I.e. Full + Verified.
   std::string verified_origin = profile1.origin();
 
-  AddProfile(0, profile0);
+  // We start by having the verified profile.
+  AddProfile(1, profile1);
   ASSERT_TRUE(SetupSync());
   EXPECT_TRUE(AutofillProfileChecker(0, 1).Wait());
 
   EXPECT_EQ(1U, GetAllAutoFillProfiles(0).size());
+  EXPECT_EQ(verified_origin, GetAllAutoFillProfiles(0)[0]->origin());
+  EXPECT_EQ(verified_origin, GetAllAutoFillProfiles(1)[0]->origin());
 
-  // Add the same (but verified) profile on the other client, afterwards.
-  AddProfile(1, profile1);
+  // Add the same (but non-verified) profile on the other client, afterwards.
+  AddProfile(0, profile0);
   EXPECT_TRUE(AutofillProfileChecker(0, 1).Wait());
 
-  // The latter addition is caught in deduplication logic in PDM to sync. As a
-  // result, both clients end up with the non-verified profile.
+  // The profiles should de-duplicate via sync on both other client, the
+  // verified one should win.
   EXPECT_EQ(1U, GetAllAutoFillProfiles(0).size());
   EXPECT_EQ(1U, GetAllAutoFillProfiles(0).size());
 
-  EXPECT_NE(verified_origin, GetAllAutoFillProfiles(0)[0]->origin());
-  EXPECT_NE(verified_origin, GetAllAutoFillProfiles(1)[0]->origin());
+  EXPECT_EQ(verified_origin, GetAllAutoFillProfiles(0)[0]->origin());
+  EXPECT_EQ(verified_origin, GetAllAutoFillProfiles(1)[0]->origin());
 
   histograms.ExpectBucketCount("Sync.ModelTypeEntityChange3.AUTOFILL_PROFILE",
                                LOCAL_DELETION, 0);
diff --git a/chrome/browser/sync/test/integration/two_client_wallet_sync_test.cc b/chrome/browser/sync/test/integration/two_client_wallet_sync_test.cc
index 2e46ec1a..0baac6c 100644
--- a/chrome/browser/sync/test/integration/two_client_wallet_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_wallet_sync_test.cc
@@ -465,7 +465,7 @@
 
 // Flaky. http://crbug.com/917498
 IN_PROC_BROWSER_TEST_F(TwoClientWalletSyncTest,
-                       ServerAddressConvertsToSameLocalAddress) {
+                       DISABLED_ServerAddressConvertsToSameLocalAddress) {
   GetFakeServer()->SetWalletData(
       {CreateSyncWalletAddress(/*name=*/"address-1", /*company=*/"Company-1"),
        CreateDefaultSyncPaymentsCustomerData()});
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 1cb5563..13547eed 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1756,8 +1756,6 @@
       "webui/chromeos/login/app_downloading_screen_handler.h",
       "webui/chromeos/login/app_launch_splash_screen_handler.cc",
       "webui/chromeos/login/app_launch_splash_screen_handler.h",
-      "webui/chromeos/login/arc_kiosk_splash_screen_handler.cc",
-      "webui/chromeos/login/arc_kiosk_splash_screen_handler.h",
       "webui/chromeos/login/arc_terms_of_service_screen_handler.cc",
       "webui/chromeos/login/arc_terms_of_service_screen_handler.h",
       "webui/chromeos/login/assistant_optin_flow_screen_handler.cc",
@@ -3712,10 +3710,14 @@
       "app_list/search/common/url_icon_source.h",
       "app_list/search/cros_action_history/cros_action_recorder.cc",
       "app_list/search/cros_action_history/cros_action_recorder.h",
+      "app_list/search/drive_quick_access_chip_result.cc",
+      "app_list/search/drive_quick_access_chip_result.h",
       "app_list/search/drive_quick_access_provider.cc",
       "app_list/search/drive_quick_access_provider.h",
       "app_list/search/drive_quick_access_result.cc",
       "app_list/search/drive_quick_access_result.h",
+      "app_list/search/file_chip_result.cc",
+      "app_list/search/file_chip_result.h",
       "app_list/search/mixer.cc",
       "app_list/search/mixer.h",
       "app_list/search/omnibox_provider.cc",
diff --git a/chrome/browser/ui/app_list/search/drive_quick_access_chip_result.cc b/chrome/browser/ui/app_list/search/drive_quick_access_chip_result.cc
new file mode 100644
index 0000000..ae1a5e2
--- /dev/null
+++ b/chrome/browser/ui/app_list/search/drive_quick_access_chip_result.cc
@@ -0,0 +1,34 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/app_list/search/drive_quick_access_chip_result.h"
+
+#include <utility>
+
+#include "ash/public/cpp/app_list/app_list_metrics.h"
+#include "chrome/browser/profiles/profile.h"
+
+namespace app_list {
+namespace {
+
+const char kDriveQuickAccessChipResultPrefix[] = "quickaccesschip://";
+
+}
+
+DriveQuickAccessChipResult::DriveQuickAccessChipResult(
+    const base::FilePath& filepath,
+    const float relevance,
+    Profile* profile)
+    : DriveQuickAccessResult(filepath, relevance, profile) {
+  set_id(kDriveQuickAccessChipResultPrefix + filepath.value());
+  SetResultType(ResultType::kDriveQuickAccessChip);
+  // TODO(crbug.com/1034842) Add line:
+  // SetDisplayType(DisplayType::kChip);
+  // to replace DisplayType and DisplayLocation setting
+  // once CL:1980331 merged
+  SetDisplayType(DisplayType::kNone);
+  SetDisplayLocation(DisplayLocation::kSuggestionChipContainer);
+}
+
+}  // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/drive_quick_access_chip_result.h b/chrome/browser/ui/app_list/search/drive_quick_access_chip_result.h
new file mode 100644
index 0000000..ea7b9c3
--- /dev/null
+++ b/chrome/browser/ui/app_list/search/drive_quick_access_chip_result.h
@@ -0,0 +1,25 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_APP_LIST_SEARCH_DRIVE_QUICK_ACCESS_CHIP_RESULT_H_
+#define CHROME_BROWSER_UI_APP_LIST_SEARCH_DRIVE_QUICK_ACCESS_CHIP_RESULT_H_
+
+#include "chrome/browser/ui/app_list/search/drive_quick_access_result.h"
+
+namespace app_list {
+
+// A search result for a Drive QuickAccess file to be displayed in the
+// suggestion chips. This inherits from DriveQuickAccessResult because
+// most of its logic is identical, but it is important they are different
+// types for ranking purposes.
+class DriveQuickAccessChipResult : public DriveQuickAccessResult {
+ public:
+  DriveQuickAccessChipResult(const base::FilePath& filepath,
+                             float relevance,
+                             Profile* profile);
+};
+
+}  // namespace app_list
+
+#endif  // CHROME_BROWSER_UI_APP_LIST_SEARCH_DRIVE_QUICK_ACCESS_CHIP_RESULT_H_
diff --git a/chrome/browser/ui/app_list/search/drive_quick_access_provider.cc b/chrome/browser/ui/app_list/search/drive_quick_access_provider.cc
index 0103da80..ed7de825 100644
--- a/chrome/browser/ui/app_list/search/drive_quick_access_provider.cc
+++ b/chrome/browser/ui/app_list/search/drive_quick_access_provider.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <utility>
 
+#include "ash/public/cpp/app_list/app_list_features.h"
 #include "base/bind.h"
 #include "base/files/file_util.h"
 #include "base/metrics/histogram_macros.h"
@@ -14,6 +15,7 @@
 #include "base/task/task_traits.h"
 #include "base/task_runner_util.h"
 #include "chrome/browser/chromeos/drive/drive_integration_service.h"
+#include "chrome/browser/ui/app_list/search/drive_quick_access_chip_result.h"
 #include "chrome/browser/ui/app_list/search/drive_quick_access_result.h"
 
 namespace app_list {
@@ -129,9 +131,15 @@
 
   SearchProvider::Results results;
   for (const auto& result : results_cache_) {
+    const auto& path = ReparentToDriveMount(result.path, drive_service_);
+
     results.emplace_back(std::make_unique<DriveQuickAccessResult>(
-        ReparentToDriveMount(result.path, drive_service_), result.confidence,
-        profile_));
+        path, result.confidence, profile_));
+    // Add suggestion chip file results
+    if (app_list_features::IsSuggestedFilesEnabled()) {
+      results.emplace_back(std::make_unique<DriveQuickAccessChipResult>(
+          path, result.confidence, profile_));
+    }
   }
   UMA_HISTOGRAM_TIMES("Apps.AppList.DriveQuickAccessProvider.Latency",
                       base::TimeTicks::Now() - query_start_time_);
diff --git a/chrome/browser/ui/app_list/search/file_chip_result.cc b/chrome/browser/ui/app_list/search/file_chip_result.cc
new file mode 100644
index 0000000..288d715d
--- /dev/null
+++ b/chrome/browser/ui/app_list/search/file_chip_result.cc
@@ -0,0 +1,33 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/app_list/search/file_chip_result.h"
+
+#include <utility>
+
+#include "ash/public/cpp/app_list/app_list_metrics.h"
+#include "chrome/browser/profiles/profile.h"
+
+namespace app_list {
+namespace {
+
+const char kFileChipResultPrefix[] = "filechip://";
+
+}
+
+FileChipResult::FileChipResult(const base::FilePath& filepath,
+                               const float relevance,
+                               Profile* profile)
+    : ZeroStateFileResult(filepath, relevance, profile) {
+  set_id(kFileChipResultPrefix + filepath.value());
+  SetResultType(ResultType::kFileChip);
+  // TODO(crbug.com/1034842) Add line:
+  // SetDisplayType(DisplayType::kChip);
+  // to replace DisplayType and DisplayLocation setting
+  // once CL:1980331 merged
+  SetDisplayType(DisplayType::kNone);
+  SetDisplayLocation(DisplayLocation::kSuggestionChipContainer);
+}
+
+}  // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/file_chip_result.h b/chrome/browser/ui/app_list/search/file_chip_result.h
new file mode 100644
index 0000000..f78692b4
--- /dev/null
+++ b/chrome/browser/ui/app_list/search/file_chip_result.h
@@ -0,0 +1,25 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_APP_LIST_SEARCH_FILE_CHIP_RESULT_H_
+#define CHROME_BROWSER_UI_APP_LIST_SEARCH_FILE_CHIP_RESULT_H_
+
+#include "chrome/browser/ui/app_list/search/zero_state_file_result.h"
+
+namespace app_list {
+
+// A search result for a local file to be shown in the suggestion chips.
+// This inherits from ZeroStateFileResult because most of its logic is
+// identical, but it is important they are different types for ranking
+// purposes.
+class FileChipResult : public ZeroStateFileResult {
+ public:
+  FileChipResult(const base::FilePath& filepath,
+                 float relevance,
+                 Profile* profile);
+};
+
+}  // namespace app_list
+
+#endif  // CHROME_BROWSER_UI_APP_LIST_SEARCH_FILE_CHIP_RESULT_H_
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util.cc b/chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util.cc
index 04a5ed0..7a95d2e 100644
--- a/chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util.cc
+++ b/chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util.cc
@@ -33,8 +33,10 @@
       return RankingItemType::kIgnored;
     case ash::AppListSearchResultType::kArcAppShortcut:
       return RankingItemType::kArcAppShortcut;
+    case ash::AppListSearchResultType::kFileChip:
     case ash::AppListSearchResultType::kZeroStateFile:
       return RankingItemType::kZeroStateFile;
+    case ash::AppListSearchResultType::kDriveQuickAccessChip:
     case ash::AppListSearchResultType::kDriveQuickAccess:
       return RankingItemType::kDriveQuickAccess;
   }
diff --git a/chrome/browser/ui/app_list/search/zero_state_file_provider.cc b/chrome/browser/ui/app_list/search/zero_state_file_provider.cc
index 490bf75..9c640bc 100644
--- a/chrome/browser/ui/app_list/search/zero_state_file_provider.cc
+++ b/chrome/browser/ui/app_list/search/zero_state_file_provider.cc
@@ -6,6 +6,7 @@
 
 #include <string>
 
+#include "ash/public/cpp/app_list/app_list_features.h"
 #include "base/bind.h"
 #include "base/files/file_util.h"
 #include "base/metrics/histogram_macros.h"
@@ -15,6 +16,7 @@
 #include "base/threading/scoped_blocking_call.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/app_list/search/file_chip_result.h"
 #include "chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker.h"
 #include "chrome/browser/ui/app_list/search/zero_state_file_result.h"
 
@@ -104,7 +106,13 @@
   for (const auto& filepath_score : results.first) {
     new_results.emplace_back(std::make_unique<ZeroStateFileResult>(
         filepath_score.first, filepath_score.second, profile_));
+    // Add suggestion chip file results
+    if (app_list_features::IsSuggestedFilesEnabled()) {
+      new_results.emplace_back(std::make_unique<FileChipResult>(
+          filepath_score.first, filepath_score.second, profile_));
+    }
   }
+
   UMA_HISTOGRAM_TIMES("Apps.AppList.ZeroStateFileProvider.Latency",
                       base::TimeTicks::Now() - query_start_time_);
   SwapResults(&new_results);
diff --git a/chrome/browser/ui/app_list/search/zero_state_file_result.cc b/chrome/browser/ui/app_list/search/zero_state_file_result.cc
index 9a83c68..6ed1fbb 100644
--- a/chrome/browser/ui/app_list/search/zero_state_file_result.cc
+++ b/chrome/browser/ui/app_list/search/zero_state_file_result.cc
@@ -62,6 +62,7 @@
   base::i18n::SanitizeUserSuppliedString(&sanitized_name);
   SetDetails(sanitized_name);
   SetIcon(GetIconForLocalFilePath(filepath));
+  SetChipIcon(GetIconForLocalFilePath(filepath));
 }
 
 ZeroStateFileResult::~ZeroStateFileResult() = default;
diff --git a/chrome/browser/ui/tabs/tab_group_controller.h b/chrome/browser/ui/tabs/tab_group_controller.h
index 3be4334..38c4428 100644
--- a/chrome/browser/ui/tabs/tab_group_controller.h
+++ b/chrome/browser/ui/tabs/tab_group_controller.h
@@ -20,6 +20,7 @@
   virtual void CreateTabGroup(const tab_groups::TabGroupId& group) = 0;
   virtual void ChangeTabGroupContents(const tab_groups::TabGroupId& group) = 0;
   virtual void ChangeTabGroupVisuals(const tab_groups::TabGroupId& group) = 0;
+  virtual void MoveTabGroup(const tab_groups::TabGroupId& group) = 0;
   virtual void CloseTabGroup(const tab_groups::TabGroupId& group) = 0;
 
   // Methods from TabStipModel that are exposed to TabGroup.
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc
index 9a97f961..358637de 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -1088,6 +1088,41 @@
   }
 }
 
+void TabStripModel::CreateTabGroup(const tab_groups::TabGroupId& group) {
+  TabGroupChange change(group, TabGroupChange::kCreated);
+  for (auto& observer : observers_)
+    observer.OnTabGroupChanged(change);
+}
+
+void TabStripModel::ChangeTabGroupContents(
+    const tab_groups::TabGroupId& group) {
+  TabGroupChange change(group, TabGroupChange::kContentsChanged);
+  for (auto& observer : observers_)
+    observer.OnTabGroupChanged(change);
+}
+
+void TabStripModel::ChangeTabGroupVisuals(const tab_groups::TabGroupId& group) {
+  TabGroupChange change(group, TabGroupChange::kVisualsChanged);
+  for (auto& observer : observers_)
+    observer.OnTabGroupChanged(change);
+}
+
+void TabStripModel::MoveTabGroup(const tab_groups::TabGroupId& group) {
+  TabGroupChange change(group, TabGroupChange::kMoved);
+  for (auto& observer : observers_)
+    observer.OnTabGroupChanged(change);
+}
+
+void TabStripModel::CloseTabGroup(const tab_groups::TabGroupId& group) {
+  TabGroupChange change(group, TabGroupChange::kClosed);
+  for (auto& observer : observers_)
+    observer.OnTabGroupChanged(change);
+}
+
+int TabStripModel::GetTabCount() const {
+  return static_cast<int>(contents_data_.size());
+}
+
 // Context menu functions.
 bool TabStripModel::IsContextMenuCommandEnabled(
     int context_index,
@@ -1906,35 +1941,6 @@
   group_model_->GetTabGroup(group)->AddTab();
 }
 
-void TabStripModel::CreateTabGroup(const tab_groups::TabGroupId& group) {
-  TabGroupChange change(group, TabGroupChange::kCreated);
-  for (auto& observer : observers_)
-    observer.OnTabGroupChanged(change);
-}
-
-void TabStripModel::ChangeTabGroupContents(
-    const tab_groups::TabGroupId& group) {
-  TabGroupChange change(group, TabGroupChange::kContentsChanged);
-  for (auto& observer : observers_)
-    observer.OnTabGroupChanged(change);
-}
-
-void TabStripModel::ChangeTabGroupVisuals(const tab_groups::TabGroupId& group) {
-  TabGroupChange change(group, TabGroupChange::kVisualsChanged);
-  for (auto& observer : observers_)
-    observer.OnTabGroupChanged(change);
-}
-
-void TabStripModel::CloseTabGroup(const tab_groups::TabGroupId& group) {
-  TabGroupChange change(group, TabGroupChange::kClosed);
-  for (auto& observer : observers_)
-    observer.OnTabGroupChanged(change);
-}
-
-int TabStripModel::GetTabCount() const {
-  return static_cast<int>(contents_data_.size());
-}
-
 void TabStripModel::SetTabPinnedImpl(int index, bool pinned) {
   DCHECK(ContainsIndex(index));
   if (contents_data_[index]->pinned() == pinned)
diff --git a/chrome/browser/ui/tabs/tab_strip_model.h b/chrome/browser/ui/tabs/tab_strip_model.h
index e175605..43f73999 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.h
+++ b/chrome/browser/ui/tabs/tab_strip_model.h
@@ -448,6 +448,15 @@
 
   TabGroupModel* group_model() const { return group_model_.get(); }
 
+  // TabGroupController:
+  void CreateTabGroup(const tab_groups::TabGroupId& group) override;
+  void ChangeTabGroupContents(const tab_groups::TabGroupId& group) override;
+  void ChangeTabGroupVisuals(const tab_groups::TabGroupId& group) override;
+  void MoveTabGroup(const tab_groups::TabGroupId& group) override;
+  void CloseTabGroup(const tab_groups::TabGroupId& group) override;
+  // The same as count(), but overridden for TabGroup to access.
+  int GetTabCount() const override;
+
   // View API //////////////////////////////////////////////////////////////////
 
   // Context menu functions. Tab groups uses command ids following CommandLast
@@ -678,14 +687,6 @@
   // Helper function for MoveAndSetGroup. Adds the tab at |index| to |group|.
   void GroupTab(int index, const tab_groups::TabGroupId& group);
 
-  // TabGroupController:
-  void CreateTabGroup(const tab_groups::TabGroupId& group) override;
-  void ChangeTabGroupContents(const tab_groups::TabGroupId& group) override;
-  void ChangeTabGroupVisuals(const tab_groups::TabGroupId& group) override;
-  void CloseTabGroup(const tab_groups::TabGroupId& group) override;
-  // The same as count(), but overridden for TabGroup to access.
-  int GetTabCount() const override;
-
   // Changes the pinned state of the tab at |index|.
   void SetTabPinnedImpl(int index, bool pinned);
 
diff --git a/chrome/browser/ui/tabs/tab_strip_model_observer.h b/chrome/browser/ui/tabs/tab_strip_model_observer.h
index 3aacc53b..6983e6a5 100644
--- a/chrome/browser/ui/tabs/tab_strip_model_observer.h
+++ b/chrome/browser/ui/tabs/tab_strip_model_observer.h
@@ -198,8 +198,9 @@
   // A group is created when the first tab is added to it and closed when the
   // last tab is removed from it. Whenever the set of tabs in the group changes,
   // a kContentsChange event is fired. Whenever the group's visual data changes,
-  // such as its title or color, a kVisualsChange event is fired.
-  enum Type { kCreated, kContentsChanged, kVisualsChanged, kClosed };
+  // such as its title or color, a kVisualsChange event is fired. Whenever the
+  // group is moved by interacting with its header, a kMoved event is fired.
+  enum Type { kCreated, kContentsChanged, kVisualsChanged, kMoved, kClosed };
 
   TabGroupChange(tab_groups::TabGroupId group, Type type);
   ~TabGroupChange();
diff --git a/chrome/browser/ui/tabs/tab_strip_model_unittest.cc b/chrome/browser/ui/tabs/tab_strip_model_unittest.cc
index 8e1e5c1..26719e9 100644
--- a/chrome/browser/ui/tabs/tab_strip_model_unittest.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model_unittest.cc
@@ -290,6 +290,9 @@
         group_updates_[change.group].visuals_update_count++;
         break;
       }
+      case TabGroupChange::kMoved: {
+        break;
+      }
       case TabGroupChange::kClosed: {
         group_updates_.erase(change.group);
         break;
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views_browsertest.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views_browsertest.cc
index 628d694..5500ff01 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views_browsertest.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views_browsertest.cc
@@ -664,6 +664,35 @@
   EXPECT_FALSE(popup_node_data_2.HasState(ax::mojom::State::kInvisible));
 }
 
+// Omnibox returns to clean state after chrome://kill and reload.
+// https://crbug.com/993701 left the URL and icon as chrome://kill after reload.
+IN_PROC_BROWSER_TEST_F(OmniboxViewViewsTest, ReloadAfterKill) {
+  OmniboxView* omnibox_view = nullptr;
+  ASSERT_NO_FATAL_FAILURE(GetOmniboxViewForBrowser(browser(), &omnibox_view));
+  OmniboxViewViews* omnibox_view_views =
+      static_cast<OmniboxViewViews*>(omnibox_view);
+
+  // Open new tab page.
+  ui_test_utils::NavigateToURL(browser(), GURL("chrome://newtab"));
+
+  content::WebContents* tab =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  // Kill the tab with chrome://kill
+  {
+    content::ScopedAllowRendererCrashes scoped_allow_renderer_crashes;
+    ui_test_utils::NavigateToURL(browser(), GURL("chrome://kill"));
+    EXPECT_TRUE(tab->IsCrashed());
+  }
+
+  // Reload the tab.
+  tab->GetController().Reload(content::ReloadType::NORMAL, false);
+  content::WaitForLoadStop(tab);
+
+  // Verify the omnibox contents, URL and icon.
+  EXPECT_EQ(base::ASCIIToUTF16(""), omnibox_view_views->GetText());
+  EXPECT_EQ(GURL("about:blank"), browser()->location_bar_model()->GetURL());
+}
+
 // The following set of tests require UIA accessibility support, which only
 // exists on Windows.
 #if defined(OS_WIN)
diff --git a/chrome/browser/ui/views/plugin_vm/plugin_vm_installer_view.cc b/chrome/browser/ui/views/plugin_vm/plugin_vm_installer_view.cc
index d2b52a0..bda542c 100644
--- a/chrome/browser/ui/views/plugin_vm/plugin_vm_installer_view.cc
+++ b/chrome/browser/ui/views/plugin_vm/plugin_vm_installer_view.cc
@@ -222,6 +222,19 @@
   return gfx::Size(kWindowWidth, kWindowHeight);
 }
 
+void PluginVmInstallerView::OnVmExists() {
+  // This case should only occur if the user manually installed a VM via vmc,
+  // which is rare enough so we just re-use the regular success strings.
+  DCHECK_EQ(state_, State::DOWNLOADING_DLC);
+  state_ = State::FINISHED;
+  OnStateUpdated();
+
+  plugin_vm::RecordPluginVmSetupResultHistogram(
+      plugin_vm::PluginVmSetupResult::kVmAlreadyExists);
+  plugin_vm::RecordPluginVmSetupTimeHistogram(base::TimeTicks::Now() -
+                                              setup_start_tick_);
+}
+
 void PluginVmInstallerView::OnDlcDownloadProgressUpdated(
     double progress,
     base::TimeDelta elapsed_time) {
diff --git a/chrome/browser/ui/views/plugin_vm/plugin_vm_installer_view.h b/chrome/browser/ui/views/plugin_vm/plugin_vm_installer_view.h
index 36f02285..b1a95ace 100644
--- a/chrome/browser/ui/views/plugin_vm/plugin_vm_installer_view.h
+++ b/chrome/browser/ui/views/plugin_vm/plugin_vm_installer_view.h
@@ -33,6 +33,7 @@
   gfx::Size CalculatePreferredSize() const override;
 
   // plugin_vm::PluginVmImageDownload::Observer implementation.
+  void OnVmExists() override;
   void OnDlcDownloadProgressUpdated(double progress,
                                     base::TimeDelta elapsed_time) override;
   void OnDlcDownloadCompleted() override;
diff --git a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
index 0eb1b70..b8734eb 100644
--- a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
+++ b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
@@ -586,6 +586,10 @@
       tabstrip_->OnGroupVisualsChanged(change.group);
       break;
     }
+    case TabGroupChange::kMoved: {
+      tabstrip_->OnGroupMoved(change.group);
+      break;
+    }
     case TabGroupChange::kClosed: {
       tabstrip_->OnGroupClosed(change.group);
       break;
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
index e8f1d15..c92ffb8 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
@@ -1025,8 +1025,11 @@
 
       attached_model->MoveSelectedTabsTo(to_index);
 
-      if (!header_drag_)
+      if (header_drag_) {
+        attached_model->MoveTabGroup(group_.value());
+      } else {
         UpdateGroupForDraggedTabs();
+      }
 
       // Move may do nothing in certain situations (such as when dragging pinned
       // tabs). Make sure the tabstrip actually changed before updating
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index 5f1cbc69..884a3c1d 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -1076,14 +1076,10 @@
 }
 
 void TabStrip::AddTabAt(int model_index, TabRendererData data, bool is_active) {
-  // Get view child index of where we want to insert.
-  const int view_index =
-      (model_index > 0) ? (GetIndexOf(tab_at(model_index - 1)) + 1) : 0;
-
   Tab* tab = new Tab(this);
   tab->set_context_menu_controller(&context_menu_controller_);
   tab->AddObserver(this);
-  AddChildViewAt(tab, view_index);
+  AddChildViewAt(tab, GetViewInsertionIndex(tab, base::nullopt, model_index));
   const bool pinned = data.pinned;
   tabs_.Add(tab, model_index);
   selected_tabs_.IncrementFrom(model_index);
@@ -1155,9 +1151,9 @@
   const bool pinned = data.pinned;
   moving_tab->SetData(std::move(data));
 
-  // Keep child views in same order as tab strip model.
-  const int to_view_index = GetIndexOf(tab_at(to_model_index));
-  ReorderChildView(tab_at(from_model_index), to_view_index);
+  ReorderChildView(
+      moving_tab,
+      GetViewInsertionIndex(moving_tab, from_model_index, to_model_index));
 
   if (touch_layout_) {
     tabs_.MoveViewOnly(from_model_index, to_model_index);
@@ -1261,9 +1257,11 @@
 
 void TabStrip::OnGroupContentsChanged(const tab_groups::TabGroupId& group) {
   DCHECK(group_views_[group]);
+
   // The group header may be in the wrong place if the tab didn't actually
   // move in terms of model indices.
-  layout_helper_->UpdateGroupHeaderIndex(group);
+  OnGroupMoved(group);
+
   group_views_[group]->UpdateVisuals();
   UpdateIdealBounds();
   AnimateToIdealBounds();
@@ -1277,6 +1275,26 @@
   AnimateToIdealBounds();
 }
 
+void TabStrip::OnGroupMoved(const tab_groups::TabGroupId& group) {
+  DCHECK(group_views_[group]);
+
+  layout_helper_->UpdateGroupHeaderIndex(group);
+
+  TabGroupHeader* group_header = group_views_[group]->header();
+  const int first_tab = controller_->ListTabsInGroup(group).front();
+  const int header_index = GetIndexOf(group_header);
+  const int first_tab_index = GetIndexOf(tab_at(first_tab));
+
+  // The header should be just before the first tab. If it isn't, reorder the
+  // header such that it is. Note that the index to reorder to is different
+  // depending on whether the header is before or after the tab, since the
+  // header itself occupies an index.
+  if (header_index < first_tab_index - 1)
+    ReorderChildView(group_header, first_tab_index - 1);
+  if (header_index > first_tab_index - 1)
+    ReorderChildView(group_header, first_tab_index);
+}
+
 void TabStrip::OnGroupClosed(const tab_groups::TabGroupId& group) {
   bounds_animator_.StopAnimatingView(group_header(group));
   layout_helper_->RemoveGroupHeader(group);
@@ -2647,6 +2665,44 @@
   return nullptr;
 }
 
+int TabStrip::GetViewInsertionIndex(Tab* tab,
+                                    base::Optional<int> from_model_index,
+                                    int to_model_index) const {
+  // If to_model_index is beyond the end of the tab strip, then the tab is newly
+  // added to the end of the tab strip. In that case we can just return the last
+  // TabSlotView view index, which should be at the sum of the number of tabs
+  // and groups.
+  if (to_model_index >= tab_count())
+    return tab_count() + group_views_.size();
+
+  // If there is no from_model_index, then the tab is newly added in the middle
+  // of the tab strip. In that case we treat it as coming from the end of the
+  // tab strip, since new views are ordered at the end by default.
+  if (!from_model_index.has_value())
+    from_model_index = tab_count();
+
+  DCHECK_NE(to_model_index, from_model_index.value());
+
+  // Since we don't have an absolute mapping from model index to view index, we
+  // anchor on the last known view index at the given to_model_index.
+  Tab* other_tab = tab_at(to_model_index);
+  int other_view_index = GetIndexOf(other_tab);
+
+  // When moving to the right, just use the anchor index because the tab will
+  // replace that position in both the model and the view. This happens because
+  // the tab itself occupies a lower index that the other tabs will shift into.
+  if (to_model_index > from_model_index.value())
+    return other_view_index;
+
+  // When moving to the left, the tab may end up on either the left or right
+  // side of a group header, depending on if it's in that group. This affects
+  // its view index but not its model index, so we adjust the former only.
+  if (other_tab->group().has_value() && other_tab->group() != tab->group())
+    return other_view_index - 1;
+
+  return other_view_index;
+}
+
 void TabStrip::RemoveTabFromViewModel(int index) {
   Tab* closing_tab = tab_at(index);
   bool closing_tab_was_active = closing_tab->IsActive();
diff --git a/chrome/browser/ui/views/tabs/tab_strip.h b/chrome/browser/ui/views/tabs/tab_strip.h
index 5f10c21..7e7f437 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.h
+++ b/chrome/browser/ui/views/tabs/tab_strip.h
@@ -184,6 +184,10 @@
   // |TabStripController::GetGroupColorId(group)| changes.
   void OnGroupVisualsChanged(const tab_groups::TabGroupId& group);
 
+  // Updates the ordering of the group header when the whole group is moved.
+  // Needed to ensure display and focus order of the group header view.
+  void OnGroupMoved(const tab_groups::TabGroupId& group);
+
   // Destroys the views associated with a recently deleted tab group. The
   // associated view mappings are erased in OnGroupCloseAnimationCompleted().
   void OnGroupClosed(const tab_groups::TabGroupId& group);
@@ -215,8 +219,8 @@
   Tab* tab_at(int index) const { return tabs_.view_at(index); }
 
   // Returns the TabGroupHeader with ID |id|.
-  TabGroupHeader* group_header(const tab_groups::TabGroupId& id) {
-    return group_views_[id].get()->header();
+  TabGroupHeader* group_header(const tab_groups::TabGroupId& id) const {
+    return group_views_.at(id).get()->header();
   }
 
   // Returns the NewTabButton.
@@ -491,6 +495,13 @@
   // the actual last tab unless the strip is in the overflow node_data.
   const Tab* GetLastVisibleTab() const;
 
+  // Returns the view index (the order of ChildViews of the TabStrip) of the
+  // given |tab| based on its model index when it moves. Used to reorder the
+  // child views of the tabstrip so that focus order stays consistent.
+  int GetViewInsertionIndex(Tab* tab,
+                            base::Optional<int> from_model_index,
+                            int to_model_index) const;
+
   // Removes the tab at |index| from |tabs_|.
   void RemoveTabFromViewModel(int index);
 
diff --git a/chrome/browser/ui/views/tabs/tab_strip_unittest.cc b/chrome/browser/ui/views/tabs/tab_strip_unittest.cc
index 7274bce..8888482c 100644
--- a/chrome/browser/ui/views/tabs/tab_strip_unittest.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip_unittest.cc
@@ -226,6 +226,41 @@
     return result;
   }
 
+  // Returns all TabSlotViews in the order that they have as ViewChildren of
+  // TabStrip. This should match the actual order that they appear in visually.
+  views::View::Views GetTabSlotViewsInFocusOrder() {
+    views::View::Views all_children = tab_strip_->children();
+
+    const int num_tab_slot_views =
+        tab_strip_->tab_count() + tab_strip_->group_views_.size();
+
+    return views::View::Views(all_children.begin(),
+                              all_children.begin() + num_tab_slot_views);
+  }
+
+  // Returns all TabSlotViews in the order that they appear visually. This is
+  // the expected order of the ViewChildren of TabStrip.
+  views::View::Views GetTabSlotViewsInVisualOrder() {
+    views::View::Views ordered_views;
+
+    base::Optional<tab_groups::TabGroupId> prev_group = base::nullopt;
+
+    for (int i = 0; i < tab_strip_->tab_count(); ++i) {
+      Tab* tab = tab_strip_->tab_at(i);
+
+      // If the current Tab is the first one in a group, first add the
+      // TabGroupHeader to the list of views.
+      base::Optional<tab_groups::TabGroupId> curr_group = tab->group();
+      if (curr_group.has_value() && curr_group != prev_group)
+        ordered_views.push_back(tab_strip_->group_header(curr_group.value()));
+      prev_group = curr_group;
+
+      ordered_views.push_back(tab);
+    }
+
+    return ordered_views;
+  }
+
   // Owned by TabStrip.
   FakeBaseTabStripController* controller_ = nullptr;
   TabStrip* tab_strip_ = nullptr;
@@ -352,38 +387,55 @@
   EXPECT_EQ(0, observer.last_tab_removed());
 }
 
-namespace {
-
-bool TabViewsInOrder(TabStrip* tab_strip) {
-  for (int i = 1; i < tab_strip->tab_count(); ++i) {
-    Tab* left = tab_strip->tab_at(i - 1);
-    Tab* right = tab_strip->tab_at(i);
-
-    if (tab_strip->FindChild(right) < tab_strip->FindChild(left)) {
-      return false;
-    }
-  }
-
-  return true;
-}
-
-}  // namespace
-
 // Verifies child view order matches model order.
 TEST_P(TabStripTest, TabViewOrder) {
   controller_->AddTab(0, false);
   controller_->AddTab(1, false);
   controller_->AddTab(2, false);
-  EXPECT_TRUE(TabViewsInOrder(tab_strip_));
+  EXPECT_EQ(GetTabSlotViewsInFocusOrder(), GetTabSlotViewsInVisualOrder());
 
   tab_strip_->MoveTab(0, 1, TabRendererData());
-  EXPECT_TRUE(TabViewsInOrder(tab_strip_));
+  EXPECT_EQ(GetTabSlotViewsInFocusOrder(), GetTabSlotViewsInVisualOrder());
   tab_strip_->MoveTab(1, 2, TabRendererData());
-  EXPECT_TRUE(TabViewsInOrder(tab_strip_));
+  EXPECT_EQ(GetTabSlotViewsInFocusOrder(), GetTabSlotViewsInVisualOrder());
   tab_strip_->MoveTab(1, 0, TabRendererData());
-  EXPECT_TRUE(TabViewsInOrder(tab_strip_));
+  EXPECT_EQ(GetTabSlotViewsInFocusOrder(), GetTabSlotViewsInVisualOrder());
   tab_strip_->MoveTab(0, 2, TabRendererData());
-  EXPECT_TRUE(TabViewsInOrder(tab_strip_));
+  EXPECT_EQ(GetTabSlotViewsInFocusOrder(), GetTabSlotViewsInVisualOrder());
+}
+
+// Verifies child view order matches slot order with group headers.
+TEST_P(TabStripTest, TabViewOrderWithGroups) {
+  controller_->AddTab(0, false);
+  controller_->AddTab(1, false);
+  controller_->AddTab(2, false);
+  controller_->AddTab(3, false);
+  EXPECT_EQ(GetTabSlotViewsInFocusOrder(), GetTabSlotViewsInVisualOrder());
+
+  base::Optional<tab_groups::TabGroupId> group1 =
+      tab_groups::TabGroupId::GenerateNew();
+  base::Optional<tab_groups::TabGroupId> group2 =
+      tab_groups::TabGroupId::GenerateNew();
+
+  // Add multiple tabs to a group and verify view order.
+  controller_->MoveTabIntoGroup(0, group1);
+  EXPECT_EQ(GetTabSlotViewsInFocusOrder(), GetTabSlotViewsInVisualOrder());
+  controller_->MoveTabIntoGroup(1, group1);
+  EXPECT_EQ(GetTabSlotViewsInFocusOrder(), GetTabSlotViewsInVisualOrder());
+
+  // Move tabs within a group and verify view order.
+  controller_->MoveTab(1, 0);
+  EXPECT_EQ(GetTabSlotViewsInFocusOrder(), GetTabSlotViewsInVisualOrder());
+
+  // Add a single tab to a group and verify view order.
+  controller_->MoveTabIntoGroup(2, group2);
+  EXPECT_EQ(GetTabSlotViewsInFocusOrder(), GetTabSlotViewsInVisualOrder());
+
+  // Move and add tabs near a group and verify view order.
+  controller_->AddTab(2, false);
+  EXPECT_EQ(GetTabSlotViewsInFocusOrder(), GetTabSlotViewsInVisualOrder());
+  controller_->MoveTab(4, 3);
+  EXPECT_EQ(GetTabSlotViewsInFocusOrder(), GetTabSlotViewsInVisualOrder());
 }
 
 TEST_P(TabStripTest, VisibilityInOverflow) {
diff --git a/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer.mojom b/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer.mojom
index 84c173a..4111ffb 100644
--- a/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer.mojom
+++ b/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer.mojom
@@ -17,8 +17,9 @@
 // Lives in the browser process. A renderer use this to control Crostini
 // installation.
 interface PageHandler {
-  // Start installation, |disk_size| is in bytes.
-  Install(int64 disk_size);
+  // Start installation, |disk_size| is in bytes, username is the user's
+  // desired username for inside the container.
+  Install(int64 disk_size, string username);
   // Cancel an on-going installation
   Cancel();
   // If a user cancels the installation without starting it at all, this should
diff --git a/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_page_handler.cc b/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_page_handler.cc
index 7ff2d89..b8ae9b6 100644
--- a/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_page_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_page_handler.cc
@@ -41,12 +41,14 @@
 
 CrostiniInstallerPageHandler::~CrostiniInstallerPageHandler() = default;
 
-void CrostiniInstallerPageHandler::Install(int64_t disk_size) {
-  // TODO(crbug.com/1016195): Web page should allow input container username,
-  // and here we will pass that to Install().
+void CrostiniInstallerPageHandler::Install(int64_t disk_size_bytes,
+                                           const std::string& username) {
   crostini::CrostiniManager::RestartOptions options{};
   if (base::FeatureList::IsEnabled(chromeos::features::kCrostiniDiskResizing)) {
-    options.disk_size = disk_size;
+    options.disk_size_bytes = disk_size_bytes;
+  }
+  if (base::FeatureList::IsEnabled(chromeos::features::kCrostiniUsername)) {
+    options.container_username = username;
   }
   installer_ui_delegate_->Install(
       std::move(options),
diff --git a/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_page_handler.h b/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_page_handler.h
index e66adce0..dbe657f 100644
--- a/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_page_handler.h
+++ b/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_page_handler.h
@@ -34,7 +34,7 @@
   ~CrostiniInstallerPageHandler() override;
 
   // chromeos::crostini_installer::mojom::PageHandler:
-  void Install(int64_t disk_size) override;
+  void Install(int64_t disk_size_bytes, const std::string& username) override;
   void Cancel() override;
   void CancelBeforeStart() override;
   void Close() override;
diff --git a/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_ui.cc b/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_ui.cc
index 42bed82..3d7d03db 100644
--- a/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_ui.cc
@@ -72,6 +72,7 @@
 
       {"configureMessage", IDS_CROSTINI_INSTALLER_CONFIGURE_MESSAGE},
       {"diskSizeMessage", IDS_CROSTINI_INSTALLER_DISK_SIZE_MESSAGE},
+      {"usernameMessage", IDS_CROSTINI_INSTALLER_USERNAME_MESSAGE},
   };
   AddLocalizedStringsBulk(source, kStrings);
 
@@ -111,12 +112,18 @@
     : ui::MojoWebDialogUI{web_ui} {
   content::WebUIDataSource* source =
       content::WebUIDataSource::Create(chrome::kChromeUICrostiniInstallerHost);
+  auto* profile = Profile::FromWebUI(web_ui);
   source->OverrideContentSecurityPolicyScriptSrc(
       "script-src chrome://resources chrome://test 'self';");
   AddStringResources(source);
   source->AddBoolean(
       "diskResizingEnabled",
       base::FeatureList::IsEnabled(chromeos::features::kCrostiniDiskResizing));
+  source->AddBoolean(
+      "crostiniCustomUsername",
+      base::FeatureList::IsEnabled(chromeos::features::kCrostiniUsername));
+  source->AddString("defaultContainerUsername",
+                    crostini::DefaultContainerUserNameForProfile(profile));
 
   source->AddResourcePath("app.js", IDR_CROSTINI_INSTALLER_APP_JS);
   source->AddResourcePath("browser_proxy.js",
@@ -133,7 +140,7 @@
   source->UseStringsJs();
   source->EnableReplaceI18nInJS();
 
-  content::WebUIDataSource::Add(Profile::FromWebUI(web_ui), source);
+  content::WebUIDataSource::Add(profile, source);
 }
 
 CrostiniInstallerUI::~CrostiniInstallerUI() = default;
diff --git a/chrome/browser/ui/webui/chromeos/login/arc_kiosk_splash_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/arc_kiosk_splash_screen_handler.cc
deleted file mode 100644
index 3cf432e7..0000000
--- a/chrome/browser/ui/webui/chromeos/login/arc_kiosk_splash_screen_handler.cc
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/webui/chromeos/login/arc_kiosk_splash_screen_handler.h"
-
-#include <memory>
-
-#include "base/values.h"
-#include "chrome/browser/chromeos/login/arc_kiosk_controller.h"
-#include "chrome/grit/chrome_unscaled_resources.h"
-#include "chrome/grit/chromium_strings.h"
-#include "chrome/grit/generated_resources.h"
-#include "components/login/localized_values_builder.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/base/webui/web_ui_util.h"
-#include "ui/gfx/image/image_skia.h"
-
-namespace chromeos {
-
-constexpr StaticOobeScreenId ArcKioskSplashScreenView::kScreenId;
-
-ArcKioskSplashScreenHandler::ArcKioskSplashScreenHandler(
-    JSCallsContainer* js_calls_container)
-    : BaseScreenHandler(kScreenId, js_calls_container) {}
-
-ArcKioskSplashScreenHandler::~ArcKioskSplashScreenHandler() {
-  if (controller_)
-    controller_->OnDeletingSplashScreenView();
-}
-
-void ArcKioskSplashScreenHandler::DeclareLocalizedValues(
-    ::login::LocalizedValuesBuilder* builder) {
-  builder->Add("arcKioskStartMessage", IDS_APP_START_APP_WAIT_MESSAGE);
-
-  const base::string16 product_os_name =
-      l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_OS_NAME);
-  builder->Add("arcKioskShortcutInfo",
-               l10n_util::GetStringFUTF16(IDS_APP_START_BAILOUT_SHORTCUT_FORMAT,
-                                          product_os_name));
-  builder->Add("arcKioskProductName", product_os_name);
-}
-
-void ArcKioskSplashScreenHandler::Initialize() {
-  if (!show_on_init_)
-    return;
-  show_on_init_ = false;
-  Show();
-}
-
-void ArcKioskSplashScreenHandler::Show() {
-  if (!page_is_ready()) {
-    show_on_init_ = true;
-    return;
-  }
-
-  base::DictionaryValue data;
-  // |data| will take ownership of |app_info|.
-  std::unique_ptr<base::DictionaryValue> app_info =
-      std::make_unique<base::DictionaryValue>();
-  PopulateAppInfo(app_info.get());
-  data.Set("appInfo", std::move(app_info));
-  ShowScreenWithData(kScreenId, &data);
-}
-
-void ArcKioskSplashScreenHandler::RegisterMessages() {
-  AddCallback("cancelArcKioskLaunch",
-              &ArcKioskSplashScreenHandler::HandleCancelArcKioskLaunch);
-}
-
-void ArcKioskSplashScreenHandler::UpdateArcKioskState(ArcKioskState state) {
-  if (!page_is_ready())
-    return;
-  SetLaunchText(l10n_util::GetStringUTF8(GetProgressMessageFromState(state)));
-}
-
-void ArcKioskSplashScreenHandler::SetDelegate(ArcKioskController* controller) {
-  controller_ = controller;
-}
-
-void ArcKioskSplashScreenHandler::PopulateAppInfo(
-    base::DictionaryValue* out_info) {
-  out_info->SetString("name", l10n_util::GetStringUTF8(IDS_SHORT_PRODUCT_NAME));
-  out_info->SetString(
-      "iconURL",
-      webui::GetBitmapDataUrl(*ui::ResourceBundle::GetSharedInstance()
-                                   .GetImageSkiaNamed(IDR_PRODUCT_LOGO_128)
-                                   ->bitmap()));
-}
-
-void ArcKioskSplashScreenHandler::SetLaunchText(const std::string& text) {
-  CallJS("login.ArcKioskSplashScreen.updateArcKioskMessage", text);
-}
-
-int ArcKioskSplashScreenHandler::GetProgressMessageFromState(
-    ArcKioskState state) {
-  switch (state) {
-    case ArcKioskState::STARTING_SESSION:
-      return IDS_SYNC_SETUP_SPINNER_TITLE;
-    case ArcKioskState::WAITING_APP_LAUNCH:
-      return IDS_APP_START_APP_WAIT_MESSAGE;
-    case ArcKioskState::WAITING_APP_WINDOW:
-      return IDS_APP_START_WAIT_FOR_APP_WINDOW_MESSAGE;
-    default:
-      NOTREACHED();
-      break;
-  }
-  return IDS_SYNC_SETUP_SPINNER_TITLE;
-}
-
-void ArcKioskSplashScreenHandler::HandleCancelArcKioskLaunch() {
-  if (!controller_) {
-    LOG(WARNING) << "No delegate set to handle cancel app launch";
-    return;
-  }
-  controller_->OnCancelArcKioskLaunch();
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/login/arc_kiosk_splash_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/arc_kiosk_splash_screen_handler.h
deleted file mode 100644
index 2eccabc7..0000000
--- a/chrome/browser/ui/webui/chromeos/login/arc_kiosk_splash_screen_handler.h
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_ARC_KIOSK_SPLASH_SCREEN_HANDLER_H_
-#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_ARC_KIOSK_SPLASH_SCREEN_HANDLER_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "chrome/browser/ui/webui/chromeos/login/base_screen_handler.h"
-
-namespace base {
-class DictionaryValue;
-}
-
-namespace chromeos {
-
-class ArcKioskController;
-
-// Interface for UI implementations of the ArcKioskSplashScreen.
-class ArcKioskSplashScreenView {
- public:
-  enum class ArcKioskState {
-    STARTING_SESSION,
-    WAITING_APP_LAUNCH,
-    WAITING_APP_WINDOW,
-  };
-
-  constexpr static StaticOobeScreenId kScreenId{"arc-kiosk-splash"};
-
-  ArcKioskSplashScreenView() = default;
-
-  virtual ~ArcKioskSplashScreenView() = default;
-
-  // Shows the contents of the screen.
-  virtual void Show() = 0;
-
-  // Set the current ARC kiosk state.
-  virtual void UpdateArcKioskState(ArcKioskState state) = 0;
-
-  // Sets screen this view belongs to.
-  virtual void SetDelegate(ArcKioskController* controller) = 0;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ArcKioskSplashScreenView);
-};
-
-// A class that handles the WebUI hooks for the ARC kiosk splash screen.
-class ArcKioskSplashScreenHandler : public BaseScreenHandler,
-                                    public ArcKioskSplashScreenView {
- public:
-  using TView = ArcKioskSplashScreenView;
-
-  explicit ArcKioskSplashScreenHandler(JSCallsContainer* js_calls_container);
-  ~ArcKioskSplashScreenHandler() override;
-
- private:
-  // BaseScreenHandler implementation:
-  void DeclareLocalizedValues(
-      ::login::LocalizedValuesBuilder* builder) override;
-  void Initialize() override;
-
-  // WebUIMessageHandler implementation:
-  void RegisterMessages() override;
-
-  // ArcKioskSplashScreenView implementation:
-  void Show() override;
-  void UpdateArcKioskState(ArcKioskState state) override;
-  void SetDelegate(ArcKioskController* controller) override;
-
-  void PopulateAppInfo(base::DictionaryValue* out_info);
-  void SetLaunchText(const std::string& text);
-  int GetProgressMessageFromState(ArcKioskState state);
-  void HandleCancelArcKioskLaunch();
-
-  ArcKioskController* controller_ = nullptr;
-  bool show_on_init_ = false;
-
-  DISALLOW_COPY_AND_ASSIGN(ArcKioskSplashScreenHandler);
-};
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_ARC_KIOSK_SPLASH_SCREEN_HANDLER_H_
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
index 2b7baf7..762cbe3 100644
--- a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
@@ -41,7 +41,6 @@
 #include "chrome/browser/ui/webui/chromeos/login/active_directory_password_change_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/app_downloading_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h"
-#include "chrome/browser/ui/webui/chromeos/login/arc_kiosk_splash_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/auto_enrollment_check_screen_handler.h"
@@ -114,7 +113,6 @@
 namespace {
 
 const char* kKnownDisplayTypes[] = {OobeUI::kAppLaunchSplashDisplay,
-                                    OobeUI::kArcKioskSplashDisplay,
                                     OobeUI::kDiscoverDisplay,
                                     OobeUI::kGaiaSigninDisplay,
                                     OobeUI::kLoginDisplay,
@@ -326,7 +324,6 @@
 
 // static
 const char OobeUI::kAppLaunchSplashDisplay[] = "app-launch-splash";
-const char OobeUI::kArcKioskSplashDisplay[] = "arc-kiosk-splash";
 const char OobeUI::kDiscoverDisplay[] = "discover";
 const char OobeUI::kGaiaSigninDisplay[] = "gaia-signin";
 const char OobeUI::kLockDisplay[] = "lock";
@@ -447,9 +444,6 @@
       js_calls_container_.get(), network_state_informer_, error_screen));
 
   AddScreenHandler(
-      std::make_unique<ArcKioskSplashScreenHandler>(js_calls_container_.get()));
-
-  AddScreenHandler(
       std::make_unique<DeviceDisabledScreenHandler>(js_calls_container_.get()));
 
   AddScreenHandler(std::make_unique<EncryptionMigrationScreenHandler>(
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_ui.h b/chrome/browser/ui/webui/chromeos/login/oobe_ui.h
index 95da61d..93160f7 100644
--- a/chrome/browser/ui/webui/chromeos/login/oobe_ui.h
+++ b/chrome/browser/ui/webui/chromeos/login/oobe_ui.h
@@ -45,7 +45,6 @@
   // List of known types of OobeUI. Type added as path in chrome://oobe url, for
   // example chrome://oobe/user-adding.
   static const char kAppLaunchSplashDisplay[];
-  static const char kArcKioskSplashDisplay[];
   static const char kDiscoverDisplay[];
   static const char kGaiaSigninDisplay[];
   static const char kLockDisplay[];
diff --git a/chrome/browser/ui/webui/tab_strip/tab_strip_ui_handler.cc b/chrome/browser/ui/webui/tab_strip/tab_strip_ui_handler.cc
index c30c000..fdd8177 100644
--- a/chrome/browser/ui/webui/tab_strip/tab_strip_ui_handler.cc
+++ b/chrome/browser/ui/webui/tab_strip/tab_strip_ui_handler.cc
@@ -238,6 +238,10 @@
       break;
     }
 
+    case TabGroupChange::kMoved: {
+      break;
+    }
+
     case TabGroupChange::kClosed: {
       FireWebUIListener("tab-group-closed",
                         base::Value(change.group.ToString()));
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn
index d6c3c149..c52e58b 100644
--- a/chrome/browser/web_applications/BUILD.gn
+++ b/chrome/browser/web_applications/BUILD.gn
@@ -16,14 +16,20 @@
 # Extension codepaths have been removed.
 source_set("common") {
   sources = [
+    "manifest_update_manager.cc",
+    "manifest_update_manager.h",
+    "manifest_update_task.cc",
+    "manifest_update_task.h",
     "web_app_tab_helper.cc",
     "web_app_tab_helper.h",
   ]
 
   deps = [
     ":web_app_group",
+    "//base/util/values:values_util",
     "//chrome/browser/web_applications/components",
     "//chrome/common",
+    "//components/content_settings/core/browser",
     "//content/public/browser",
     "//skia",
   ]
@@ -216,6 +222,23 @@
   ]
 }
 
+source_set("common_browser_tests") {
+  testonly = true
+
+  sources = [ "manifest_update_manager_browsertest.cc" ]
+
+  defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
+
+  deps = [
+    ":common",
+    ":web_applications_test_support",
+    "//chrome/app:command_ids",
+    "//chrome/browser/web_applications/components",
+    "//chrome/test:test_support",
+    "//chrome/test:test_support_ui",
+  ]
+}
+
 # TODO(crbug.com/877898): Erase this and move WebAppProvider into
 # web_applications set.
 source_set("web_applications_on_extensions") {
@@ -227,6 +250,7 @@
   ]
 
   deps = [
+    ":common",
     ":web_app_group",
     ":web_applications",
     "//chrome/browser/web_applications/components",
@@ -277,6 +301,7 @@
   testonly = true
 
   deps = [
+    ":common_browser_tests",
     ":web_app_test_group",
     ":web_applications_browser_tests",
     "//chrome/browser/web_applications/components:browser_tests",
diff --git a/chrome/browser/web_applications/components/BUILD.gn b/chrome/browser/web_applications/components/BUILD.gn
index a571dba..ec1c373 100644
--- a/chrome/browser/web_applications/components/BUILD.gn
+++ b/chrome/browser/web_applications/components/BUILD.gn
@@ -25,10 +25,6 @@
     "install_finalizer.h",
     "install_manager.cc",
     "install_manager.h",
-    "manifest_update_manager.cc",
-    "manifest_update_manager.h",
-    "manifest_update_task.cc",
-    "manifest_update_task.h",
     "pending_app_manager.cc",
     "pending_app_manager.h",
     "policy/web_app_policy_constants.cc",
@@ -107,7 +103,6 @@
   }
 
   deps = [
-    "//base/util/values:values_util",
     "//chrome/app/resources:platform_locale_settings",
     "//chrome/app/theme:chrome_unscaled_resources",
 
@@ -123,7 +118,6 @@
     "//chrome/browser/engagement:mojo_bindings",
     "//chrome/browser/web_applications:web_app_group",
     "//chrome/common",
-    "//components/content_settings/core/browser",
     "//components/crx_file",
     "//components/keyed_service/content",
     "//components/pref_registry",
@@ -188,16 +182,12 @@
 source_set("browser_tests") {
   testonly = true
 
-  sources = [
-    "manifest_update_manager_browsertest.cc",
-    "web_app_url_loader_browsertest.cc",
-  ]
+  sources = [ "web_app_url_loader_browsertest.cc" ]
 
   defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
 
   deps = [
     ":components",
-    "//chrome/app:command_ids",
     "//chrome/browser/web_applications:web_applications_test_support",
     "//chrome/test:test_support",
     "//chrome/test:test_support_ui",
diff --git a/chrome/browser/web_applications/components/web_app_file_handler_registration_linux.cc b/chrome/browser/web_applications/components/web_app_file_handler_registration_linux.cc
index 828b5de00..7aef4c2 100644
--- a/chrome/browser/web_applications/components/web_app_file_handler_registration_linux.cc
+++ b/chrome/browser/web_applications/components/web_app_file_handler_registration_linux.cc
@@ -6,7 +6,6 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
-#include "chrome/browser/web_applications/components/app_registrar.h"
 #include "chrome/browser/web_applications/components/app_shortcut_manager.h"
 #include "chrome/browser/web_applications/components/web_app_provider_base.h"
 #include "chrome/browser/web_applications/components/web_app_shortcut.h"
@@ -27,16 +26,6 @@
       base::DoNothing());
 }
 
-void UpdateFileHandlerRegistrationInOs(const AppId& app_id, Profile* profile) {
-  // On Linux, file associations are managed through shortcuts in the app menu,
-  // so after enabling or disabling file handling for an app its shortcuts
-  // need to be recreated.
-  AppShortcutManager& shortcut_manager =
-      WebAppProviderBase::GetProviderBase(profile)->shortcut_manager();
-  shortcut_manager.GetShortcutInfoForApp(
-      app_id, base::BindOnce(&OnShortcutInfoReceived));
-}
-
 }  // namespace
 
 bool ShouldRegisterFileHandlersWithOs() {
@@ -48,18 +37,14 @@
                                 Profile* profile,
                                 const std::set<std::string>& file_extensions,
                                 const std::set<std::string>& mime_types) {
-  UpdateFileHandlerRegistrationInOs(app_id, profile);
+  AppShortcutManager& shortcut_manager =
+      WebAppProviderBase::GetProviderBase(profile)->shortcut_manager();
+  shortcut_manager.GetShortcutInfoForApp(
+      app_id, base::BindOnce(OnShortcutInfoReceived));
 }
 
 void UnregisterFileHandlersWithOs(const AppId& app_id, Profile* profile) {
-  // If this was triggered as part of the uninstallation process, nothing more
-  // is needed. Uninstalling already cleans up shortcuts (and thus, file
-  // handlers).
-  auto* provider = WebAppProviderBase::GetProviderBase(profile);
-  if (!provider->registrar().IsInstalled(app_id))
-    return;
-
-  UpdateFileHandlerRegistrationInOs(app_id, profile);
+  // TODO(harrisjay): Add support for unregistering file handlers.
 }
 
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/extensions/web_app_extension_shortcut.cc b/chrome/browser/web_applications/extensions/web_app_extension_shortcut.cc
index 0a30ec7..7a09aaa 100644
--- a/chrome/browser/web_applications/extensions/web_app_extension_shortcut.cc
+++ b/chrome/browser/web_applications/extensions/web_app_extension_shortcut.cc
@@ -20,7 +20,6 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/web_applications/components/file_handler_manager.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
-#include "chrome/browser/web_applications/components/web_app_provider_base.h"
 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
 #include "chrome/common/pref_names.h"
 #include "components/prefs/pref_service.h"
@@ -179,18 +178,11 @@
   shortcut_info->profile_name =
       profile->GetPrefs()->GetString(prefs::kProfileName);
   shortcut_info->version_for_display = app->GetVersionForDisplay();
-
-  // File Handlers should only be included in bookmark apps.
-  if (app->from_bookmark()) {
-    FileHandlerManager& file_handler_manager =
-        WebAppProviderBase::GetProviderBase(profile)->file_handler_manager();
-    if (const auto* file_handlers =
-            file_handler_manager.GetEnabledFileHandlers(app->id())) {
-      shortcut_info->file_handler_extensions =
-          web_app::GetFileExtensionsFromFileHandlers(*file_handlers);
-      shortcut_info->file_handler_mime_types =
-          web_app::GetMimeTypesFromFileHandlers(*file_handlers);
-    }
+  if (const auto* info = extensions::FileHandlers::GetFileHandlers(app)) {
+    shortcut_info->file_handler_extensions =
+        web_app::GetFileExtensionsFromFileHandlers(*info);
+    shortcut_info->file_handler_mime_types =
+        web_app::GetMimeTypesFromFileHandlers(*info);
   }
 
   return shortcut_info;
diff --git a/chrome/browser/web_applications/components/manifest_update_manager.cc b/chrome/browser/web_applications/manifest_update_manager.cc
similarity index 98%
rename from chrome/browser/web_applications/components/manifest_update_manager.cc
rename to chrome/browser/web_applications/manifest_update_manager.cc
index 1d67cabb..5258667d 100644
--- a/chrome/browser/web_applications/components/manifest_update_manager.cc
+++ b/chrome/browser/web_applications/manifest_update_manager.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/web_applications/components/manifest_update_manager.h"
+#include "chrome/browser/web_applications/manifest_update_manager.h"
 
 #include "base/metrics/histogram_macros.h"
 #include "base/util/values/values_util.h"
diff --git a/chrome/browser/web_applications/components/manifest_update_manager.h b/chrome/browser/web_applications/manifest_update_manager.h
similarity index 90%
rename from chrome/browser/web_applications/components/manifest_update_manager.h
rename to chrome/browser/web_applications/manifest_update_manager.h
index 4160000..2677cad 100644
--- a/chrome/browser/web_applications/components/manifest_update_manager.h
+++ b/chrome/browser/web_applications/manifest_update_manager.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 CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_MANIFEST_UPDATE_MANAGER_H_
-#define CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_MANIFEST_UPDATE_MANAGER_H_
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_MANIFEST_UPDATE_MANAGER_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_MANIFEST_UPDATE_MANAGER_H_
 
 #include <memory>
 
@@ -14,8 +14,8 @@
 #include "base/time/time.h"
 #include "chrome/browser/web_applications/components/app_registrar.h"
 #include "chrome/browser/web_applications/components/app_registrar_observer.h"
-#include "chrome/browser/web_applications/components/manifest_update_task.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
+#include "chrome/browser/web_applications/manifest_update_task.h"
 
 class Profile;
 
@@ -92,4 +92,4 @@
 
 }  // namespace web_app
 
-#endif  // CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_MANIFEST_UPDATE_MANAGER_H_
+#endif  // CHROME_BROWSER_WEB_APPLICATIONS_MANIFEST_UPDATE_MANAGER_H_
diff --git a/chrome/browser/web_applications/components/manifest_update_manager_browsertest.cc b/chrome/browser/web_applications/manifest_update_manager_browsertest.cc
similarity index 99%
rename from chrome/browser/web_applications/components/manifest_update_manager_browsertest.cc
rename to chrome/browser/web_applications/manifest_update_manager_browsertest.cc
index 1ec4d7d..f45642c 100644
--- a/chrome/browser/web_applications/components/manifest_update_manager_browsertest.cc
+++ b/chrome/browser/web_applications/manifest_update_manager_browsertest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/web_applications/components/manifest_update_manager.h"
+#include "chrome/browser/web_applications/manifest_update_manager.h"
 
 #include <string>
 #include <vector>
diff --git a/chrome/browser/web_applications/components/manifest_update_task.cc b/chrome/browser/web_applications/manifest_update_task.cc
similarity index 98%
rename from chrome/browser/web_applications/components/manifest_update_task.cc
rename to chrome/browser/web_applications/manifest_update_task.cc
index f58f1f7..803cd7d 100644
--- a/chrome/browser/web_applications/components/manifest_update_task.cc
+++ b/chrome/browser/web_applications/manifest_update_task.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/web_applications/components/manifest_update_task.h"
+#include "chrome/browser/web_applications/manifest_update_task.h"
 
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/installable/installable_manager.h"
diff --git a/chrome/browser/web_applications/components/manifest_update_task.h b/chrome/browser/web_applications/manifest_update_task.h
similarity index 92%
rename from chrome/browser/web_applications/components/manifest_update_task.h
rename to chrome/browser/web_applications/manifest_update_task.h
index 468da57..28dc8166 100644
--- a/chrome/browser/web_applications/components/manifest_update_task.h
+++ b/chrome/browser/web_applications/manifest_update_task.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 CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_MANIFEST_UPDATE_TASK_H_
-#define CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_MANIFEST_UPDATE_TASK_H_
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_MANIFEST_UPDATE_TASK_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_MANIFEST_UPDATE_TASK_H_
 
 #include "base/logging.h"
 #include "base/memory/weak_ptr.h"
@@ -97,4 +97,4 @@
 
 }  // namespace web_app
 
-#endif  // CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_MANIFEST_UPDATE_TASK_H_
+#endif  // CHROME_BROWSER_WEB_APPLICATIONS_MANIFEST_UPDATE_TASK_H_
diff --git a/chrome/browser/web_applications/web_app_provider.cc b/chrome/browser/web_applications/web_app_provider.cc
index 4bfa9e8..496eada2 100644
--- a/chrome/browser/web_applications/web_app_provider.cc
+++ b/chrome/browser/web_applications/web_app_provider.cc
@@ -11,7 +11,6 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/web_applications/components/externally_installed_web_app_prefs.h"
 #include "chrome/browser/web_applications/components/install_bounce_metric.h"
-#include "chrome/browser/web_applications/components/manifest_update_manager.h"
 #include "chrome/browser/web_applications/components/policy/web_app_policy_manager.h"
 #include "chrome/browser/web_applications/components/web_app_audio_focus_id_map.h"
 #include "chrome/browser/web_applications/components/web_app_prefs_utils.h"
@@ -25,6 +24,7 @@
 #include "chrome/browser/web_applications/extensions/bookmark_app_shortcut_manager.h"
 #include "chrome/browser/web_applications/external_web_app_manager.h"
 #include "chrome/browser/web_applications/file_utils_wrapper.h"
+#include "chrome/browser/web_applications/manifest_update_manager.h"
 #include "chrome/browser/web_applications/pending_app_manager_impl.h"
 #include "chrome/browser/web_applications/system_web_app_manager.h"
 #include "chrome/browser/web_applications/web_app_database_factory.h"
diff --git a/chrome/browser/web_applications/web_app_tab_helper.cc b/chrome/browser/web_applications/web_app_tab_helper.cc
index 31da9345..0860c0d 100644
--- a/chrome/browser/web_applications/web_app_tab_helper.cc
+++ b/chrome/browser/web_applications/web_app_tab_helper.cc
@@ -6,11 +6,11 @@
 
 #include "base/unguessable_token.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/web_applications/components/manifest_update_manager.h"
 #include "chrome/browser/web_applications/components/policy/web_app_policy_manager.h"
 #include "chrome/browser/web_applications/components/web_app_audio_focus_id_map.h"
 #include "chrome/browser/web_applications/components/web_app_provider_base.h"
 #include "chrome/browser/web_applications/components/web_app_ui_manager.h"
+#include "chrome/browser/web_applications/manifest_update_manager.h"
 #include "content/public/browser/media_session.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/site_instance.h"
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index beb85488..277bee7 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -98,6 +98,8 @@
   sources = [
     "../browser/autofill/automated_tests/cache_replayer.cc",
     "../browser/autofill/automated_tests/cache_replayer.h",
+    "../browser/permissions/crowd_deny_fake_safe_browsing_database_manager.cc",
+    "../browser/permissions/crowd_deny_fake_safe_browsing_database_manager.h",
     "base/chrome_render_view_host_test_harness.cc",
     "base/chrome_render_view_host_test_harness.h",
     "base/chrome_test_launcher.cc",
@@ -4191,6 +4193,7 @@
       "../browser/sharing/shared_clipboard/shared_clipboard_utils_unittest.cc",
       "../browser/sharing/sms/sms_fetch_request_handler_unittest.cc",
       "../browser/sharing/sms/sms_remote_fetcher_unittest.cc",
+      "../browser/sharing/webrtc/ice_config_fetcher_unittest.cc",
       "../browser/ui/autofill/payments/local_card_migration_bubble_controller_impl_unittest.cc",
       "../browser/ui/autofill/payments/save_card_bubble_controller_impl_unittest.cc",
       "../browser/ui/bluetooth/bluetooth_chooser_controller_unittest.cc",
diff --git a/chrome/test/data/local_ntp/local_ntp_browsertest.html b/chrome/test/data/local_ntp/local_ntp_browsertest.html
index d8a1fb6..610bff72 100644
--- a/chrome/test/data/local_ntp/local_ntp_browsertest.html
+++ b/chrome/test/data/local_ntp/local_ntp_browsertest.html
@@ -70,8 +70,7 @@
 
       <div id="realbox-container">
         <div id="realbox-input-wrapper">
-          <div id="realbox-icon" class="search-icon"
-              data-realbox-icon-class="search-icon"></div>
+          <div id="realbox-icon" class="search-icon"></div>
           <input id="realbox" type="search" autocomplete="off"
               spellcheck="false" autofocus>
           <button id="realbox-microphone" class="microphone-icon" hidden>
diff --git a/chrome/test/data/local_ntp/realbox_browsertest.js b/chrome/test/data/local_ntp/realbox_browsertest.js
index f2bd877..2e25b831 100644
--- a/chrome/test/data/local_ntp/realbox_browsertest.js
+++ b/chrome/test/data/local_ntp/realbox_browsertest.js
@@ -27,7 +27,6 @@
  * @const
  */
 test.realbox.CLASSES = {
-  CLOCK_ICON: 'clock-icon',
   HAS_IMAGE: 'has-image',
   IMAGE_CONTAINER: 'image-container',
   MATCH_IMAGE: 'match-image',
@@ -1262,14 +1261,13 @@
     matches: [
       test.realbox.getUrlMatch({allowedToBeDefaultMatch: true}),
       test.realbox.getSearchMatch(),
-      test.realbox.getSearchMatch({type: 'search-history'}),
     ],
   });
   assertTrue(test.realbox.areMatchesShowing());
 
   // First URL match should be showing and the favicon should be in the realbox.
   const matchEls = $(test.realbox.IDS.REALBOX_MATCHES).children;
-  assertEquals(3, matchEls.length);
+  assertEquals(2, matchEls.length);
   assertTrue(matchEls[0].classList.contains(test.realbox.CLASSES.SELECTED));
   assertTrue(!!realboxIcon.style.backgroundImage);
 
@@ -1285,12 +1283,6 @@
   assertTrue(matchEls[1].classList.contains(test.realbox.CLASSES.SELECTED));
   assertFalse(!!realboxIcon.style.backgroundImage);
 
-  test.realbox.realboxEl.dispatchEvent(arrowDown);
-
-  // Third search match should change to clock icon.
-  assertTrue(matchEls[2].classList.contains(test.realbox.CLASSES.SELECTED));
-  assertEquals(realboxIcon.className, test.realbox.CLASSES.CLOCK_ICON);
-
   const escapeToDefaultMatch = new KeyboardEvent('keydown', {
     bubbles: true,
     cancelable: true,
diff --git a/chrome/test/data/sharing/network_traversal_response.json b/chrome/test/data/sharing/network_traversal_response.json
new file mode 100644
index 0000000..274b094
--- /dev/null
+++ b/chrome/test/data/sharing/network_traversal_response.json
@@ -0,0 +1,21 @@
+{
+  "lifetimeDuration": "400s",
+  "iceServers": [
+    {
+      "urls": [
+        "stun:url1"
+      ]
+    },
+    {
+      "urls": [
+        "turn:url2?transport=udp",
+        "turn:url3?transport=tcp"
+      ],
+      "username": "username",
+      "credential": "credential",
+      "maxRateKbps": "1"
+    }
+  ],
+  "blockStatus": "NOT_BLOCKED",
+  "iceTransportPolicy": "all"
+}
\ No newline at end of file
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js
index c9c75d1..d8eb554 100644
--- a/chrome/test/data/webui/settings/cr_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -897,6 +897,7 @@
     '../test_util.js',
     '../test_browser_proxy.js',
     'test_privacy_page_browser_proxy.js',
+    'test_metrics_browser_proxy.js',
     'test_sync_browser_proxy.js',
     'privacy_page_test.js',
   ]),
@@ -950,6 +951,40 @@
 
 /**
  * Test fixture for
+ * chrome/browser/resources/settings/site_settings_page/site_settings_page.html.
+ * @constructor
+ * @extends {CrSettingsBrowserTest}
+ */
+function CrSettingsSiteSettingsPageTest() {}
+
+CrSettingsSiteSettingsPageTest.prototype = {
+  __proto__: CrSettingsBrowserTest.prototype,
+
+  /** @override */
+  browsePreload: 'chrome://settings/site_settings_page/site_settings_page.html',
+
+  /** @override */
+  extraLibraries: CrSettingsBrowserTest.prototype.extraLibraries.concat([
+    '//ui/webui/resources/js/promise_resolver.js',
+    '../test_util.js',
+    '../test_browser_proxy.js',
+    'test_metrics_browser_proxy.js',
+    'site_settings_page_test.js',
+  ])
+};
+
+TEST_F('CrSettingsSiteSettingsPageTest', 'UMALoggingTests', function() {
+  settings_site_settings_page.registerUMALoggingTests();
+  mocha.run();
+});
+
+TEST_F('CrSettingsSiteSettingsPageTest', 'UMALoggingTestsPart2', function() {
+  settings_site_settings_page.registerUMALoggingTestsPart2();
+  mocha.run();
+});
+
+/**
+ * Test fixture for
  * chrome/browser/resources/settings/privacy_page/
  *        passwords-leak-detection-toggle.html.
  * @constructor
@@ -968,6 +1003,7 @@
   extraLibraries: CrSettingsBrowserTest.prototype.extraLibraries.concat([
     'sync_test_util.js',
     '../test_browser_proxy.js',
+    'test_metrics_browser_proxy.js',
     'test_privacy_page_browser_proxy.js',
     'test_sync_browser_proxy.js',
     'passwords_leak_detection_toggle_test.js',
@@ -1216,6 +1252,7 @@
     '../test_browser_proxy.js',
     'test_sync_browser_proxy.js',
     'test_privacy_page_browser_proxy.js',
+    'test_metrics_browser_proxy.js',
     'security_page_test.js',
   ]),
 };
diff --git a/chrome/test/data/webui/settings/passwords_leak_detection_toggle_test.js b/chrome/test/data/webui/settings/passwords_leak_detection_toggle_test.js
index f63b0fd..580e276 100644
--- a/chrome/test/data/webui/settings/passwords_leak_detection_toggle_test.js
+++ b/chrome/test/data/webui/settings/passwords_leak_detection_toggle_test.js
@@ -3,6 +3,9 @@
 // found in the LICENSE file.
 
 suite('CrSettingsPasswordsLeakDetectionToggleTest', function() {
+  /** @type {settings.TestMetricsBrowserProxy} */
+  let testMetricsBrowserProxy;
+
   /** @type {settings.TestPrivacyPageBrowserProxy} */
   let privacyPageBrowserProxy;
 
@@ -17,6 +20,8 @@
     settings.PrivacyPageBrowserProxyImpl.instance_ = privacyPageBrowserProxy;
     syncBrowserProxy = new TestSyncBrowserProxy();
     settings.SyncBrowserProxyImpl.instance_ = syncBrowserProxy;
+    testMetricsBrowserProxy = new TestMetricsBrowserProxy();
+    settings.MetricsBrowserProxyImpl.instance_ = testMetricsBrowserProxy;
     PolymerTest.clearBody();
     testElement =
         document.createElement('settings-passwords-leak-detection-toggle');
@@ -33,6 +38,20 @@
     testElement.remove();
   });
 
+  test('logPasswordLeakDetectionClick', function() {
+    testElement.set(
+        'prefs.profile.password_manager_leak_detection.value', true);
+    testElement.syncStatus = {signedIn: true};
+    Polymer.dom.flush();
+    console.log(testElement.$$('#passwordsLeakDetectionCheckbox').disabled);
+    testElement.$$('#passwordsLeakDetectionCheckbox').click();
+    return testMetricsBrowserProxy.whenCalled('recordSettingsPageHistogram')
+        .then(result => {
+          assertEquals(
+              settings.SettingsPageInteractions.PRIVACY_PASSWORD_CHECK, result);
+        });
+  });
+
   test('leakDetectionToggleSignedOutWithFalsePref', function() {
     testElement.set(
         'prefs.profile.password_manager_leak_detection.value', false);
diff --git a/chrome/test/data/webui/settings/privacy_page_test.js b/chrome/test/data/webui/settings/privacy_page_test.js
index 5a1a058..ae6df71b 100644
--- a/chrome/test/data/webui/settings/privacy_page_test.js
+++ b/chrome/test/data/webui/settings/privacy_page_test.js
@@ -149,14 +149,30 @@
       /** @type {settings.TestPrivacyPageBrowserProxy} */
       let testBrowserProxy;
 
+      /** @type {settings.TestMetricsBrowserProxy} */
+      let testMetricsBrowserProxy;
+
       /** @type {SettingsPrivacyPageElement} */
       let page;
 
       setup(function() {
+        testMetricsBrowserProxy = new TestMetricsBrowserProxy();
+        settings.MetricsBrowserProxyImpl.instance_ = testMetricsBrowserProxy;
         testBrowserProxy = new TestPrivacyPageBrowserProxy();
         settings.PrivacyPageBrowserProxyImpl.instance_ = testBrowserProxy;
+        const testSyncBrowserProxy = new TestSyncBrowserProxy();
+        settings.SyncBrowserProxyImpl.instance_ = testSyncBrowserProxy;
         PolymerTest.clearBody();
         page = document.createElement('settings-privacy-page');
+        page.prefs = {
+          profile: {password_manager_leak_detection: {value: true}},
+          signin: {
+            allowed_on_next_startup:
+                {type: chrome.settingsPrivate.PrefType.BOOLEAN, value: true}
+          },
+          safebrowsing:
+              {enabled: {value: true}, scout_reporting_enabled: {value: true}},
+        };
         document.body.appendChild(page);
       });
 
@@ -166,7 +182,7 @@
 
       test('LogMangeCerfificatesClick', function() {
         page.$$('#manageCertificates').click();
-        return testBrowserProxy.whenCalled('recordSettingsPageHistogram')
+        return testMetricsBrowserProxy.whenCalled('recordSettingsPageHistogram')
             .then(result => {
               assertEquals(
                   settings.SettingsPageInteractions.PRIVACY_MANAGE_CERTIFICATES,
@@ -176,7 +192,7 @@
 
       test('LogClearBrowsingClick', function() {
         page.$$('#clearBrowsingData').click();
-        return testBrowserProxy.whenCalled('recordSettingsPageHistogram')
+        return testMetricsBrowserProxy.whenCalled('recordSettingsPageHistogram')
             .then(result => {
               assertEquals(
                   settings.SettingsPageInteractions.PRIVACY_CLEAR_BROWSING_DATA,
@@ -186,7 +202,7 @@
 
       test('LogDoNotTrackClick', function() {
         page.$$('#doNotTrack').click();
-        return testBrowserProxy.whenCalled('recordSettingsPageHistogram')
+        return testMetricsBrowserProxy.whenCalled('recordSettingsPageHistogram')
             .then(result => {
               assertEquals(
                   settings.SettingsPageInteractions.PRIVACY_DO_NOT_TRACK,
@@ -196,7 +212,7 @@
 
       test('LogCanMakePaymentToggleClick', function() {
         page.$$('#canMakePaymentToggle').click();
-        return testBrowserProxy.whenCalled('recordSettingsPageHistogram')
+        return testMetricsBrowserProxy.whenCalled('recordSettingsPageHistogram')
             .then(result => {
               assertEquals(
                   settings.SettingsPageInteractions.PRIVACY_PAYMENT_METHOD,
@@ -206,13 +222,35 @@
 
       test('LogSiteSettingsSubpageClick', function() {
         page.$$('#site-settings-subpage-trigger').click();
-        return testBrowserProxy.whenCalled('recordSettingsPageHistogram')
+        return testMetricsBrowserProxy.whenCalled('recordSettingsPageHistogram')
             .then(result => {
               assertEquals(
                   settings.SettingsPageInteractions.PRIVACY_SITE_SETTINGS,
                   result);
             });
       });
+
+      test('LogSafeBrowsingToggleClick', function() {
+        Polymer.dom.flush();
+        page.$$('#safeBrowsingToggle').click();
+        return testMetricsBrowserProxy.whenCalled('recordSettingsPageHistogram')
+            .then(result => {
+              assertEquals(
+                  settings.SettingsPageInteractions.PRIVACY_SAFE_BROWSING,
+                  result);
+            });
+      });
+
+      test('LogSafeBrowsingReportingToggleClick', function() {
+        Polymer.dom.flush();
+        page.$$('#safeBrowsingReportingToggle').click();
+        return testMetricsBrowserProxy.whenCalled('recordSettingsPageHistogram')
+            .then(result => {
+              assertEquals(
+                  settings.SettingsPageInteractions.PRIVACY_IMPROVE_SECURITY,
+                  result);
+            });
+      });
     });
   }
 
diff --git a/chrome/test/data/webui/settings/security_page_test.js b/chrome/test/data/webui/settings/security_page_test.js
index d5508917..395058ce 100644
--- a/chrome/test/data/webui/settings/security_page_test.js
+++ b/chrome/test/data/webui/settings/security_page_test.js
@@ -3,6 +3,9 @@
 // found in the LICENSE file.
 
 suite('CrSettingsSecurityPageTest', function() {
+  /** @type {settings.TestMetricsBrowserProxy} */
+  let testMetricsBrowserProxy;
+
   /** @type {settings.SyncBrowserProxy} */
   let syncBrowserProxy;
 
@@ -13,6 +16,8 @@
   let page;
 
   setup(function() {
+    testMetricsBrowserProxy = new TestMetricsBrowserProxy();
+    settings.MetricsBrowserProxyImpl.instance_ = testMetricsBrowserProxy;
     testPrivacyBrowserProxy = new TestPrivacyPageBrowserProxy();
     settings.PrivacyPageBrowserProxyImpl.instance_ = testPrivacyBrowserProxy;
     syncBrowserProxy = new TestSyncBrowserProxy();
@@ -45,7 +50,7 @@
 
   test('LogManageCerfificatesClick', function() {
     page.$$('#manageCertificates').click();
-    return testPrivacyBrowserProxy.whenCalled('recordSettingsPageHistogram')
+    return testMetricsBrowserProxy.whenCalled('recordSettingsPageHistogram')
         .then(result => {
           assertEquals(
               settings.SettingsPageInteractions.PRIVACY_MANAGE_CERTIFICATES,
diff --git a/chrome/test/data/webui/settings/site_settings_page_test.js b/chrome/test/data/webui/settings/site_settings_page_test.js
new file mode 100644
index 0000000..a2433745
--- /dev/null
+++ b/chrome/test/data/webui/settings/site_settings_page_test.js
@@ -0,0 +1,363 @@
+// 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.
+
+cr.define('settings_site_settings_page', function() {
+  function registerUMALoggingTests() {
+    suite('SiteSettingsPageUMACheck', function() {
+      /** @type {settings.TestMetricsBrowserProxy} */
+      let testBrowserProxy;
+
+      /** @type {SettingsSiteSettingsPageElement} */
+      let page;
+
+      setup(function() {
+        testBrowserProxy = new TestMetricsBrowserProxy();
+        settings.MetricsBrowserProxyImpl.instance_ = testBrowserProxy;
+        PolymerTest.clearBody();
+        page = document.createElement('settings-site-settings-page');
+        document.body.appendChild(page);
+        Polymer.dom.flush();
+      });
+
+      teardown(function() {
+        page.remove();
+      });
+
+      test('LogCookiesClick', function() {
+        page.$$('#cookies').click();
+        return testBrowserProxy.whenCalled('recordSettingsPageHistogram')
+            .then(result => {
+              assertEquals(
+                  settings.SettingsPageInteractions
+                      .PRIVACY_SITE_SETTINGS_COOKIES,
+                  result);
+            });
+      });
+
+      test('LogLocationClick', function() {
+        page.$$('#location').click();
+        return testBrowserProxy.whenCalled('recordSettingsPageHistogram')
+            .then(result => {
+              assertEquals(
+                  settings.SettingsPageInteractions
+                      .PRIVACY_SITE_SETTINGS_LOCATION,
+                  result);
+            });
+      });
+
+      test('LogCameraClick', function() {
+        page.$$('#camera').click();
+        return testBrowserProxy.whenCalled('recordSettingsPageHistogram')
+            .then(result => {
+              assertEquals(
+                  settings.SettingsPageInteractions
+                      .PRIVACY_SITE_SETTINGS_CAMERA,
+                  result);
+            });
+      });
+
+      test('LogMicrophoneClick', function() {
+        page.$$('#microphone').click();
+        return testBrowserProxy.whenCalled('recordSettingsPageHistogram')
+            .then(result => {
+              assertEquals(
+                  settings.SettingsPageInteractions
+                      .PRIVACY_SITE_SETTINGS_MICROPHONE,
+                  result);
+            });
+      });
+
+      test('LogSensorsClick', function() {
+        page.$$('#sensors').click();
+        return testBrowserProxy.whenCalled('recordSettingsPageHistogram')
+            .then(result => {
+              assertEquals(
+                  settings.SettingsPageInteractions
+                      .PRIVACY_SITE_SETTINGS_SENSORS,
+                  result);
+            });
+      });
+
+      test('LogNotificationsClick', function() {
+        page.$$('#notifications').click();
+        return testBrowserProxy.whenCalled('recordSettingsPageHistogram')
+            .then(result => {
+              assertEquals(
+                  settings.SettingsPageInteractions
+                      .PRIVACY_SITE_SETTINGS_NOTIFICATIONS,
+                  result);
+            });
+      });
+
+      test('LogJavascriptClick', function() {
+        page.$$('#javascript').click();
+        return testBrowserProxy.whenCalled('recordSettingsPageHistogram')
+            .then(result => {
+              assertEquals(
+                  settings.SettingsPageInteractions
+                      .PRIVACY_SITE_SETTINGS_JAVASCRIPT,
+                  result);
+            });
+      });
+
+      test('LogFlashClick', function() {
+        page.$$('#flash').click();
+        return testBrowserProxy.whenCalled('recordSettingsPageHistogram')
+            .then(result => {
+              assertEquals(
+                  settings.SettingsPageInteractions.PRIVACY_SITE_SETTINGS_FLASH,
+                  result);
+            });
+      });
+
+      test('LogImagesClick', function() {
+        page.$$('#images').click();
+        return testBrowserProxy.whenCalled('recordSettingsPageHistogram')
+            .then(result => {
+              assertEquals(
+                  settings.SettingsPageInteractions
+                      .PRIVACY_SITE_SETTINGS_IMAGES,
+                  result);
+            });
+      });
+
+      test('LogPopupsClick', function() {
+        page.$$('#popups').click();
+        return testBrowserProxy.whenCalled('recordSettingsPageHistogram')
+            .then(result => {
+              assertEquals(
+                  settings.SettingsPageInteractions
+                      .PRIVACY_SITE_SETTINGS_POPUPS,
+                  result);
+            });
+      });
+
+      if (loadTimeData.getBoolean('enableSafeBrowsingSubresourceFilter')) {
+        test('LogAdsClick', function() {
+          page.$$('#ads').click();
+          return testBrowserProxy.whenCalled('recordSettingsPageHistogram')
+              .then(result => {
+                assertEquals(
+                    settings.SettingsPageInteractions.PRIVACY_SITE_SETTINGS_ADS,
+                    result);
+              });
+        });
+      }
+
+      test('LogBackgroundSyncClick', function() {
+        page.$$('#background-sync').click();
+        return testBrowserProxy.whenCalled('recordSettingsPageHistogram')
+            .then(result => {
+              assertEquals(
+                  settings.SettingsPageInteractions
+                      .PRIVACY_SITE_SETTINGS_BACKGROUND_SYNC,
+                  result);
+            });
+      });
+    });
+  }
+
+  // Split tests into 2 to prevent timeout.
+  function registerUMALoggingTestsPart2() {
+    suite('SiteSettingsPageUMACheckPart2', function() {
+      /** @type {settings.TestPrivacyPageBrowserProxy} */
+      let testBrowserProxy;
+
+      /** @type {SettingsSiteSettingsPageElement} */
+      let page;
+
+      setup(function() {
+        testBrowserProxy = new TestMetricsBrowserProxy();
+        settings.MetricsBrowserProxyImpl.instance_ = testBrowserProxy;
+        PolymerTest.clearBody();
+        page = document.createElement('settings-site-settings-page');
+        document.body.appendChild(page);
+        Polymer.dom.flush();
+      });
+
+      teardown(function() {
+        page.remove();
+      });
+
+      test('LogSoundClick', function() {
+        page.$$('#sound').click();
+        return testBrowserProxy.whenCalled('recordSettingsPageHistogram')
+            .then(result => {
+              assertEquals(
+                  settings.SettingsPageInteractions.PRIVACY_SITE_SETTINGS_SOUND,
+                  result);
+            });
+      });
+
+      test('LogAutomaticDownloadsClick', function() {
+        page.$$('#automatic-downloads').click();
+        return testBrowserProxy.whenCalled('recordSettingsPageHistogram')
+            .then(result => {
+              assertEquals(
+                  settings.SettingsPageInteractions
+                      .PRIVACY_SITE_SETTINGS_AUTOMATIC_DOWNLOADS,
+                  result);
+            });
+      });
+
+      test('LogUnsandboxedPluginsClick', function() {
+        page.$$('#unsandboxed-plugins').click();
+        return testBrowserProxy.whenCalled('recordSettingsPageHistogram')
+            .then(result => {
+              assertEquals(
+                  settings.SettingsPageInteractions
+                      .PRIVACY_SITE_SETTINGS_UNSANDBOXED_PLUGINS,
+                  result);
+            });
+      });
+
+      if (!loadTimeData.getBoolean('isGuest')) {
+        test('LogHandlersClick', function() {
+          page.$$('#protocol-handlers').click();
+          return testBrowserProxy.whenCalled('recordSettingsPageHistogram')
+              .then(result => {
+                assertEquals(
+                    settings.SettingsPageInteractions
+                        .PRIVACY_SITE_SETTINGS_HANDLERS,
+                    result);
+              });
+        });
+      }
+
+      test('LogMidiDevicesClick', function() {
+        page.$$('#midi-devices').click();
+        return testBrowserProxy.whenCalled('recordSettingsPageHistogram')
+            .then(result => {
+              assertEquals(
+                  settings.SettingsPageInteractions
+                      .PRIVACY_SITE_SETTINGS_MIDI_DEVICES,
+                  result);
+            });
+      });
+
+      test('LogZoomLevelsClick', function() {
+        page.$$('#zoom-levels').click();
+        return testBrowserProxy.whenCalled('recordSettingsPageHistogram')
+            .then(result => {
+              assertEquals(
+                  settings.SettingsPageInteractions
+                      .PRIVACY_SITE_SETTINGS_ZOOM_LEVELS,
+                  result);
+            });
+      });
+
+      test('LogUSBDevicesClick', function() {
+        page.$$('#usb-devices').click();
+        return testBrowserProxy.whenCalled('recordSettingsPageHistogram')
+            .then(result => {
+              assertEquals(
+                  settings.SettingsPageInteractions
+                      .PRIVACY_SITE_SETTINGS_USB_DEVICES,
+                  result);
+            });
+      });
+
+      test('LogSerialPortsClick', function() {
+        page.$$('#serial-ports').click();
+        return testBrowserProxy.whenCalled('recordSettingsPageHistogram')
+            .then(result => {
+              assertEquals(
+                  settings.SettingsPageInteractions
+                      .PRIVACY_SITE_SETTINGS_SERIAL_PORTS,
+                  result);
+            });
+      });
+
+      if (loadTimeData.getBoolean(
+              'enableNativeFileSystemWriteContentSetting')) {
+        test('LogNativeFileSystemWriteClick', function() {
+          page.$$('#native-file-system-write').click();
+          return testBrowserProxy.whenCalled('recordSettingsPageHistogram')
+              .then(result => {
+                assertEquals(
+                    settings.SettingsPageInteractions
+                        .PRIVACY_SITE_SETTINGS_NATIVE_FILE_SYSTEM_WRITE,
+                    result);
+              });
+        });
+      }
+
+      test('LogPDFDocumentsClick', function() {
+        page.$$('#pdf-documents').click();
+        return testBrowserProxy.whenCalled('recordSettingsPageHistogram')
+            .then(result => {
+              assertEquals(
+                  settings.SettingsPageInteractions
+                      .PRIVACY_SITE_SETTINGS_PDF_DOCUMENTS,
+                  result);
+            });
+      });
+
+      test('LogProtectedContentClick', function() {
+        page.$$('#protected-content').click();
+        return testBrowserProxy.whenCalled('recordSettingsPageHistogram')
+            .then(result => {
+              assertEquals(
+                  settings.SettingsPageInteractions
+                      .PRIVACY_SITE_SETTINGS_PROTECTED_CONTENT,
+                  result);
+            });
+      });
+
+      test('LogClipboardClick', function() {
+        page.$$('#clipboard').click();
+        return testBrowserProxy.whenCalled('recordSettingsPageHistogram')
+            .then(result => {
+              assertEquals(
+                  settings.SettingsPageInteractions
+                      .PRIVACY_SITE_SETTINGS_CLIPBOARD,
+                  result);
+            });
+      });
+
+      if (loadTimeData.getBoolean('enablePaymentHandlerContentSetting')) {
+        test('LogPaymentHandlerClick', function() {
+          page.$$('#paymentHandler').click();
+          return testBrowserProxy.whenCalled('recordSettingsPageHistogram')
+              .then(result => {
+                assertEquals(
+                    settings.SettingsPageInteractions
+                        .PRIVACY_SITE_SETTINGS_PAYMENT_HANDLER,
+                    result);
+              });
+        });
+      }
+
+      if (loadTimeData.getBoolean('enableInsecureContentContentSetting')) {
+        test('LogMixedscriptClick', function() {
+          page.$$('#mixedscript').click();
+          return testBrowserProxy.whenCalled('recordSettingsPageHistogram')
+              .then(result => {
+                assertEquals(
+                    settings.SettingsPageInteractions
+                        .PRIVACY_SITE_SETTINGS_MIXEDSCRIPT,
+                    result);
+              });
+        });
+      }
+
+      if (loadTimeData.getBoolean('enableExperimentalWebPlatformFeatures')) {
+        test('LogBluetoothScanningClick', function() {
+          page.$$('#bluetooth-scanning').click();
+          return testBrowserProxy.whenCalled('recordSettingsPageHistogram')
+              .then(result => {
+                assertEquals(
+                    settings.SettingsPageInteractions
+                        .PRIVACY_SITE_SETTINGS_BLUETOOTH_SCANNING,
+                    result);
+              });
+        });
+      }
+    });
+  }
+  return {
+    registerUMALoggingTests,
+    registerUMALoggingTestsPart2,
+  };
+});
\ No newline at end of file
diff --git a/chrome/test/data/webui/settings/test_metrics_browser_proxy.js b/chrome/test/data/webui/settings/test_metrics_browser_proxy.js
new file mode 100644
index 0000000..27bbc8e
--- /dev/null
+++ b/chrome/test/data/webui/settings/test_metrics_browser_proxy.js
@@ -0,0 +1,17 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/** @implements {settings.PrivacyPageBrowserProxy} */
+class TestMetricsBrowserProxy extends TestBrowserProxy {
+  constructor() {
+    super([
+      'recordSettingsPageHistogram',
+    ]);
+  }
+
+  /** @override*/
+  recordSettingsPageHistogram(value) {
+    this.methodCalled('recordSettingsPageHistogram', value);
+  }
+}
\ No newline at end of file
diff --git a/chromecast/public/media/decoder_config.h b/chromecast/public/media/decoder_config.h
index cef1d97..686299e 100644
--- a/chromecast/public/media/decoder_config.h
+++ b/chromecast/public/media/decoder_config.h
@@ -362,11 +362,10 @@
          config.channel_layout != ChannelLayout::UNSUPPORTED &&
          config.sample_format >= kSampleFormatMin &&
          config.sample_format <= kSampleFormatMax &&
-         config.sample_format != kUnknownSampleFormat &&
-         (config.channel_number > 0 ||
+         ((config.sample_format != kUnknownSampleFormat &&
+           config.channel_number > 0 && config.bytes_per_channel > 0 &&
+           config.bytes_per_channel <= kMaxBytesPerSample) ||
           config.channel_layout == ChannelLayout::BITSTREAM) &&
-         config.bytes_per_channel > 0 &&
-         config.bytes_per_channel <= kMaxBytesPerSample &&
          config.samples_per_second > 0 &&
          config.samples_per_second <= kMaxSampleRate;
 }
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index f0c6e718..cd0be71 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-12847.0.0
\ No newline at end of file
+12849.0.0
\ No newline at end of file
diff --git a/components/arc/session/arc_session_impl.cc b/components/arc/session/arc_session_impl.cc
index 9ed591be..e5feb44 100644
--- a/components/arc/session/arc_session_impl.cc
+++ b/components/arc/session/arc_session_impl.cc
@@ -99,6 +99,7 @@
   void GetLcdDensity(GetLcdDensityCallback callback) override;
   void GetFreeDiskSpace(GetFreeDiskSpaceCallback callback) override;
   version_info::Channel GetChannel() override;
+  std::unique_ptr<ArcClientAdapter> CreateClient() override;
 
  private:
   // Synchronously create a UNIX domain socket. This is designed to run on a
@@ -192,6 +193,10 @@
   return channel_;
 }
 
+std::unique_ptr<ArcClientAdapter> ArcSessionDelegateImpl::CreateClient() {
+  return ArcClientAdapter::Create(GetChannel());
+}
+
 // static
 base::ScopedFD ArcSessionDelegateImpl::CreateSocketInternal() {
   auto endpoint = mojo::NamedPlatformChannel({kArcBridgeSocketPath});
@@ -315,7 +320,7 @@
                                chromeos::SchedulerConfigurationManagerBase*
                                    scheduler_configuration_manager)
     : delegate_(std::move(delegate)),
-      client_(ArcClientAdapter::Create(delegate_->GetChannel())),
+      client_(delegate_->CreateClient()),
       scheduler_configuration_manager_(scheduler_configuration_manager) {
   DCHECK(client_);
   client_->AddObserver(this);
diff --git a/components/arc/session/arc_session_impl.h b/components/arc/session/arc_session_impl.h
index 4af9a9f..b1c3ee72 100644
--- a/components/arc/session/arc_session_impl.h
+++ b/components/arc/session/arc_session_impl.h
@@ -169,11 +169,14 @@
 
     // Returns the channel for the installation.
     virtual version_info::Channel GetChannel() = 0;
+
+    // Creates and returns a client adapter.
+    virtual std::unique_ptr<ArcClientAdapter> CreateClient() = 0;
   };
 
   ArcSessionImpl(std::unique_ptr<Delegate> delegate,
                  chromeos::SchedulerConfigurationManagerBase*
-                     scheduler_configuration_manager_);
+                     scheduler_configuration_manager);
   ~ArcSessionImpl() override;
 
   // Returns default delegate implementation used for the production.
@@ -183,6 +186,7 @@
       version_info::Channel channel);
 
   State GetStateForTesting() { return state_; }
+  ArcClientAdapter* GetClientForTesting() { return client_.get(); }
 
   // ArcSession overrides:
   void StartMiniInstance() override;
diff --git a/components/arc/session/arc_session_impl_unittest.cc b/components/arc/session/arc_session_impl_unittest.cc
index fbcf8e3..c79bb55 100644
--- a/components/arc/session/arc_session_impl_unittest.cc
+++ b/components/arc/session/arc_session_impl_unittest.cc
@@ -11,27 +11,25 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/files/file_path.h"
 #include "base/location.h"
 #include "base/optional.h"
 #include "base/run_loop.h"
 #include "base/test/task_environment.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chromeos/constants/chromeos_switches.h"
-#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "chromeos/system/scheduler_configuration_manager_base.h"
-#include "components/account_id/account_id.h"
+#include "components/arc/session/arc_client_adapter.h"
 #include "components/arc/session/arc_session_impl.h"
+#include "components/arc/session/arc_start_params.h"
+#include "components/arc/session/arc_upgrade_params.h"
 #include "components/arc/test/fake_arc_bridge_host.h"
-#include "components/user_manager/fake_user_manager.h"
-#include "components/user_manager/scoped_user_manager.h"
 #include "components/version_info/channel.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace arc {
 namespace {
 
-constexpr char kFakeGmail[] = "user@gmail.com";
-constexpr char kFakeGmailGaiaId[] = "1234567890";
 constexpr char kDefaultLocale[] = "en-US";
 
 UpgradeParams DefaultUpgradeParams() {
@@ -40,6 +38,78 @@
   return params;
 }
 
+// An ArcClientAdapter implementation that does the same as the real ones but
+// without any D-Bus calls.
+class FakeArcClientAdapter : public ArcClientAdapter {
+ public:
+  FakeArcClientAdapter() = default;
+  ~FakeArcClientAdapter() override = default;
+
+  FakeArcClientAdapter(const FakeArcClientAdapter&) = delete;
+  FakeArcClientAdapter& operator=(const FakeArcClientAdapter&) = delete;
+
+  // ArcClientAdapter overrides:
+  void StartMiniArc(StartParams params,
+                    chromeos::VoidDBusMethodCallback callback) override {
+    last_start_params_ = std::move(params);
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(&FakeArcClientAdapter::OnMiniArcStarted,
+                                  base::Unretained(this), std::move(callback),
+                                  arc_available_));
+  }
+
+  void UpgradeArc(UpgradeParams params,
+                  chromeos::VoidDBusMethodCallback callback) override {
+    last_upgrade_params_ = std::move(params);
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(&FakeArcClientAdapter::OnArcUpgraded,
+                                  base::Unretained(this), std::move(callback),
+                                  !force_upgrade_failure_));
+  }
+
+  void StopArcInstance(bool on_shutdown) override {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::BindOnce(&FakeArcClientAdapter::NotifyArcInstanceStopped,
+                       base::Unretained(this)));
+  }
+
+  void SetUserInfo(const std::string& hash,
+                   const std::string& serial_number) override {}
+
+  // Notifies ArcSessionImpl of the ARC instance stop event.
+  void NotifyArcInstanceStopped() {
+    for (auto& observer : observer_list_)
+      observer.ArcInstanceStopped();
+  }
+
+  void set_arc_available(bool arc_available) { arc_available_ = arc_available; }
+  void set_force_upgrade_failure(bool force_upgrade_failure) {
+    force_upgrade_failure_ = force_upgrade_failure;
+  }
+  const StartParams& last_start_params() const { return last_start_params_; }
+  const UpgradeParams& last_upgrade_params() const {
+    return last_upgrade_params_;
+  }
+
+ private:
+  void OnMiniArcStarted(chromeos::VoidDBusMethodCallback callback,
+                        bool result) {
+    std::move(callback).Run(result);
+  }
+
+  void OnArcUpgraded(chromeos::VoidDBusMethodCallback callback, bool result) {
+    std::move(callback).Run(result);
+    if (!result)
+      NotifyArcInstanceStopped();
+  }
+
+  bool arc_available_ = true;
+  bool force_upgrade_failure_ = false;
+  StartParams last_start_params_;
+  UpgradeParams last_upgrade_params_;
+};
+
 class FakeDelegate : public ArcSessionImpl::Delegate {
  public:
   explicit FakeDelegate(int32_t lcd_density = 160)
@@ -99,6 +169,10 @@
     return version_info::Channel::DEFAULT;
   }
 
+  std::unique_ptr<ArcClientAdapter> CreateClient() override {
+    return std::make_unique<FakeArcClientAdapter>();
+  }
+
   void SetLcdDensity(int32_t lcd_density) {
     lcd_density_ = lcd_density;
     ASSERT_TRUE(!lcd_density_callback_.is_null());
@@ -201,32 +275,8 @@
 
 class ArcSessionImplTest : public testing::Test {
  public:
-  ArcSessionImplTest() {
-    // Create a user and set it as the primary user.
-    const AccountId account_id =
-        AccountId::FromUserEmailGaiaId(kFakeGmail, kFakeGmailGaiaId);
-    const user_manager::User* user = GetUserManager()->AddUser(account_id);
-    GetUserManager()->UserLoggedIn(account_id, user->username_hash(),
-                                   false /* browser_restart */,
-                                   false /* is_child */);
-  }
-
-  ~ArcSessionImplTest() override {
-    GetUserManager()->RemoveUserFromList(
-        AccountId::FromUserEmailGaiaId(kFakeGmail, kFakeGmailGaiaId));
-  }
-
-  void SetUp() override {
-    chromeos::SessionManagerClient::InitializeFakeInMemory();
-    chromeos::FakeSessionManagerClient::Get()->set_arc_available(true);
-  }
-
-  void TearDown() override { chromeos::SessionManagerClient::Shutdown(); }
-
-  user_manager::FakeUserManager* GetUserManager() {
-    return static_cast<user_manager::FakeUserManager*>(
-        user_manager::UserManager::Get());
-  }
+  ArcSessionImplTest() = default;
+  ~ArcSessionImplTest() override = default;
 
   std::unique_ptr<ArcSessionImpl, ArcSessionDeleter> CreateArcSession(
       std::unique_ptr<ArcSessionImpl::Delegate> delegate = nullptr,
@@ -254,6 +304,10 @@
   }
 
  protected:
+  FakeArcClientAdapter* GetClient(ArcSessionImpl* session) {
+    return static_cast<FakeArcClientAdapter*>(session->GetClientForTesting());
+  }
+
   FakeSchedulerConfigurationManager fake_schedule_configuration_manager_;
 
  private:
@@ -268,8 +322,6 @@
   }
 
   base::test::TaskEnvironment task_environment_;
-  user_manager::ScopedUserManager scoped_user_manager_{
-      std::make_unique<user_manager::FakeUserManager>()};
 
   DISALLOW_COPY_AND_ASSIGN(ArcSessionImplTest);
 };
@@ -286,13 +338,12 @@
   EXPECT_FALSE(observer.on_session_stopped_args().has_value());
 }
 
-// SessionManagerClient::StartArcMiniContainer() reports an error, causing the
-// mini-container start to fail.
+// ArcClientAdapter::StartMiniArc() reports an error, causing the mini instance
+// start to fail.
 TEST_F(ArcSessionImplTest, MiniInstance_DBusFail) {
-  chromeos::FakeSessionManagerClient::Get()->set_arc_available(false);
-
   auto arc_session = CreateArcSession();
   TestArcSessionObserver observer(arc_session.get());
+  GetClient(arc_session.get())->set_arc_available(false);
   arc_session->StartMiniInstance();
   base::RunLoop().RunUntilIdle();
 
@@ -304,7 +355,7 @@
   EXPECT_FALSE(observer.on_session_stopped_args()->upgrade_requested);
 }
 
-// SessionManagerClient::UpgradeArcContainer() reports an error due to low disk,
+// ArcClientAdapter::UpgradeArc() reports an error due to low disk,
 // causing the container upgrade to fail to start container with reason
 // LOW_DISK_SPACE.
 TEST_F(ArcSessionImplTest, Upgrade_LowDisk) {
@@ -346,16 +397,15 @@
   EXPECT_FALSE(observer.on_session_stopped_args().has_value());
 }
 
-// SessionManagerClient::UpgradeArcContainer() reports an error, then the
-// upgrade fails.
+// ArcClientAdapter::UpgradeArc() reports an error, then the upgrade fails.
 TEST_F(ArcSessionImplTest, Upgrade_DBusFail) {
   // Set up. Start a mini instance.
   auto arc_session = CreateArcSession();
   TestArcSessionObserver observer(arc_session.get());
   ASSERT_NO_FATAL_FAILURE(SetupMiniContainer(arc_session.get(), &observer));
 
-  // Hereafter, let SessionManagerClient::UpgradeArcContainer() fail.
-  chromeos::FakeSessionManagerClient::Get()->set_force_upgrade_failure(true);
+  // Hereafter, let ArcClientAdapter::UpgradeArc() fail.
+  GetClient(arc_session.get())->set_force_upgrade_failure(true);
 
   // Then upgrade, which should fail.
   arc_session->RequestUpgrade(DefaultUpgradeParams());
@@ -573,8 +623,8 @@
   ASSERT_EQ(ArcSessionImpl::State::RUNNING_FULL_INSTANCE,
             arc_session->GetStateForTesting());
 
-  // Deliver the ArcInstanceStopped D-Bus signal.
-  chromeos::FakeSessionManagerClient::Get()->NotifyArcInstanceStopped();
+  // Notify ArcClientAdapter's observers of the crash event.
+  GetClient(arc_session.get())->NotifyArcInstanceStopped();
 
   EXPECT_EQ(ArcSessionImpl::State::STOPPED, arc_session->GetStateForTesting());
   ASSERT_TRUE(observer.on_session_stopped_args().has_value());
@@ -587,24 +637,18 @@
   // Possible values for chromeos::switches::kArcPackagesCacheMode
   const char* chrome_switch;
   bool full_container;
-  login_manager::UpgradeArcContainerRequest_PackageCacheMode
-      expected_packages_cache_mode;
+  UpgradeParams::PackageCacheMode expected_packages_cache_mode;
 };
 
 constexpr PackagesCacheModeState kPackagesCacheModeStates[] = {
-    {nullptr, true,
-     login_manager::UpgradeArcContainerRequest_PackageCacheMode_DEFAULT},
-    {nullptr, false,
-     login_manager::UpgradeArcContainerRequest_PackageCacheMode_DEFAULT},
+    {nullptr, true, UpgradeParams::PackageCacheMode::DEFAULT},
+    {nullptr, false, UpgradeParams::PackageCacheMode::DEFAULT},
     {kPackagesCacheModeCopy, true,
-     login_manager::UpgradeArcContainerRequest_PackageCacheMode_COPY_ON_INIT},
-    {kPackagesCacheModeCopy, false,
-     login_manager::UpgradeArcContainerRequest_PackageCacheMode_DEFAULT},
+     UpgradeParams::PackageCacheMode::COPY_ON_INIT},
+    {kPackagesCacheModeCopy, false, UpgradeParams::PackageCacheMode::DEFAULT},
     {kPackagesCacheModeSkipCopy, true,
-     login_manager::
-         UpgradeArcContainerRequest_PackageCacheMode_SKIP_SETUP_COPY_ON_INIT},
-    {kPackagesCacheModeCopy, false,
-     login_manager::UpgradeArcContainerRequest_PackageCacheMode_DEFAULT},
+     UpgradeParams::PackageCacheMode::SKIP_SETUP_COPY_ON_INIT},
+    {kPackagesCacheModeCopy, false, UpgradeParams::PackageCacheMode::DEFAULT},
 };
 
 class ArcSessionImplPackagesCacheModeTest
@@ -625,10 +669,9 @@
   if (state.full_container)
     arc_session->RequestUpgrade(DefaultUpgradeParams());
   base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(state.expected_packages_cache_mode,
-            chromeos::FakeSessionManagerClient::Get()
-                ->last_upgrade_arc_request()
-                .packages_cache_mode());
+  EXPECT_EQ(
+      state.expected_packages_cache_mode,
+      GetClient(arc_session.get())->last_upgrade_params().packages_cache_mode);
 }
 
 INSTANTIATE_TEST_SUITE_P(All,
@@ -650,9 +693,9 @@
   arc_session->StartMiniInstance();
   arc_session->RequestUpgrade(DefaultUpgradeParams());
   base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(GetParam(), chromeos::FakeSessionManagerClient::Get()
-                            ->last_upgrade_arc_request()
-                            .skip_gms_core_cache());
+  EXPECT_EQ(
+      GetParam(),
+      GetClient(arc_session.get())->last_upgrade_params().skip_gms_core_cache);
 }
 
 INSTANTIATE_TEST_SUITE_P(All,
@@ -663,8 +706,8 @@
   auto arc_session = CreateArcSession();
   arc_session->StartMiniInstance();
 
-  const std::string demo_apps_path =
-      "/run/imageloader/demo_mode_resources/android_apps.squash";
+  const base::FilePath demo_apps_path(
+      "/run/imageloader/demo_mode_resources/android_apps.squash");
   UpgradeParams params;
   params.is_demo_session = true;
   params.demo_session_apps_path = base::FilePath(demo_apps_path);
@@ -672,12 +715,11 @@
   arc_session->RequestUpgrade(std::move(params));
 
   base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(chromeos::FakeSessionManagerClient::Get()
-                  ->last_upgrade_arc_request()
-                  .is_demo_session());
-  EXPECT_EQ(demo_apps_path, chromeos::FakeSessionManagerClient::Get()
-                                ->last_upgrade_arc_request()
-                                .demo_session_apps_path());
+  EXPECT_TRUE(
+      GetClient(arc_session.get())->last_upgrade_params().is_demo_session);
+  EXPECT_EQ(demo_apps_path, GetClient(arc_session.get())
+                                ->last_upgrade_params()
+                                .demo_session_apps_path);
 }
 
 TEST_F(ArcSessionImplTest, DemoSessionWithoutOfflineDemoApps) {
@@ -690,12 +732,11 @@
   arc_session->RequestUpgrade(std::move(params));
 
   base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(chromeos::FakeSessionManagerClient::Get()
-                  ->last_upgrade_arc_request()
-                  .is_demo_session());
-  EXPECT_EQ(std::string(), chromeos::FakeSessionManagerClient::Get()
-                               ->last_upgrade_arc_request()
-                               .demo_session_apps_path());
+  EXPECT_TRUE(
+      GetClient(arc_session.get())->last_upgrade_params().is_demo_session);
+  EXPECT_EQ(base::FilePath(), GetClient(arc_session.get())
+                                  ->last_upgrade_params()
+                                  .demo_session_apps_path);
 }
 
 TEST_F(ArcSessionImplTest, SupervisionTransitionShouldGraduate) {
@@ -708,15 +749,11 @@
   arc_session->RequestUpgrade(std::move(params));
 
   base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(
-      login_manager::
-          UpgradeArcContainerRequest_SupervisionTransition_CHILD_TO_REGULAR,
-      chromeos::FakeSessionManagerClient::Get()
-          ->last_upgrade_arc_request()
-          .supervision_transition());
-  EXPECT_EQ(160, chromeos::FakeSessionManagerClient::Get()
-                     ->last_start_arc_mini_container_request()
-                     .lcd_density());
+  EXPECT_EQ(ArcSupervisionTransition::CHILD_TO_REGULAR,
+            GetClient(arc_session.get())
+                ->last_upgrade_params()
+                .supervision_transition);
+  EXPECT_EQ(160, GetClient(arc_session.get())->last_start_params().lcd_density);
 }
 
 TEST_F(ArcSessionImplTest, StartArcMiniContainerWithDensity) {
@@ -729,9 +766,7 @@
 
   EXPECT_EQ(ArcSessionImpl::State::RUNNING_MINI_INSTANCE,
             arc_session->GetStateForTesting());
-  EXPECT_EQ(240, chromeos::FakeSessionManagerClient::Get()
-                     ->last_start_arc_mini_container_request()
-                     .lcd_density());
+  EXPECT_EQ(240, GetClient(arc_session.get())->last_start_params().lcd_density);
 }
 
 TEST_F(ArcSessionImplTest, StartArcMiniContainerWithDensityAsync) {
@@ -749,9 +784,7 @@
             arc_session->GetStateForTesting());
   base::RunLoop().RunUntilIdle();
 
-  EXPECT_EQ(240, chromeos::FakeSessionManagerClient::Get()
-                     ->last_start_arc_mini_container_request()
-                     .lcd_density());
+  EXPECT_EQ(240, GetClient(arc_session.get())->last_start_params().lcd_density);
 }
 
 TEST_F(ArcSessionImplTest, StartArcMiniContainerWithDensityAsyncReversedOrder) {
@@ -768,9 +801,7 @@
             arc_session->GetStateForTesting());
   base::RunLoop().RunUntilIdle();
 
-  EXPECT_EQ(240, chromeos::FakeSessionManagerClient::Get()
-                     ->last_start_arc_mini_container_request()
-                     .lcd_density());
+  EXPECT_EQ(240, GetClient(arc_session.get())->last_start_params().lcd_density);
 }
 
 TEST_F(ArcSessionImplTest, StartArcMiniContainerWithDensityAsyncCpuInfoEarly) {
@@ -787,9 +818,7 @@
             arc_session->GetStateForTesting());
   base::RunLoop().RunUntilIdle();
 
-  EXPECT_EQ(240, chromeos::FakeSessionManagerClient::Get()
-                     ->last_start_arc_mini_container_request()
-                     .lcd_density());
+  EXPECT_EQ(240, GetClient(arc_session.get())->last_start_params().lcd_density);
 }
 
 TEST_F(ArcSessionImplTest, StopWhileWaitingForLcdDensity) {
diff --git a/components/autofill/core/browser/webdata/OWNERS b/components/autofill/core/browser/webdata/OWNERS
index 44502b7..0953786 100644
--- a/components/autofill/core/browser/webdata/OWNERS
+++ b/components/autofill/core/browser/webdata/OWNERS
@@ -1,8 +1,8 @@
 per-file *sync_bridge*=jkrcal@chromium.org
 per-file *sync_bridge*=file://components/sync/OWNERS
 
-per-file autofill_profile_sync_difference_tracker*=jkrcal@chromium.org
-per-file autofill_profile_sync_difference_tracker*=file://components/sync/OWNERS
+per-file *syncable_service*=jkrcal@chromium.org
+per-file *syncable_service*=file://components/sync/OWNERS
 
 per-file *type_controller*=jkrcal@chromium.org
 per-file *type_controller*=file://components/sync/OWNERS
diff --git a/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.cc b/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.cc
index 627a0aac..a7f39a9b 100644
--- a/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.cc
+++ b/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.cc
@@ -251,18 +251,13 @@
                      base::Unretained(web_data_backend_))));
 
   std::vector<std::unique_ptr<AutofillProfile>> profiles_to_upload_to_sync;
-  std::vector<std::string> profiles_to_delete_from_sync;
-  RETURN_IF_ERROR(tracker->FlushToSync(&profiles_to_upload_to_sync,
-                                       &profiles_to_delete_from_sync));
+  RETURN_IF_ERROR(tracker->FlushToSync(&profiles_to_upload_to_sync));
   for (const std::unique_ptr<AutofillProfile>& entry :
        profiles_to_upload_to_sync) {
     change_processor()->Put(GetStorageKeyFromAutofillProfile(*entry),
                             CreateEntityDataFromAutofillProfile(*entry),
                             metadata_change_list.get());
   }
-  for (const std::string& storage_key : profiles_to_delete_from_sync) {
-    change_processor()->Delete(storage_key, metadata_change_list.get());
-  }
 
   return static_cast<syncer::SyncMetadataStoreChangeList*>(
              metadata_change_list.get())
diff --git a/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.cc b/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.cc
index 005c0d1..8f96bb8 100644
--- a/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.cc
+++ b/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.cc
@@ -64,11 +64,6 @@
   }
 
   // Check if profile appears under a different storage key to be de-duplicated.
-  // TODO(crbug.com/1043683): Deal with rare cases when an remote update
-  // contains several exact duplicates (with different guids). We should not
-  // only search in local only entries but also in |update_to_local_| and
-  // |add_to_local_|. Likely needs a bit of refactoring to make the resulting
-  // code easy to understand.
   for (const auto& pair : *GetLocalOnlyEntries()) {
     const std::string& local_storage_key = pair.first;
     const AutofillProfile& local = *pair.second;
@@ -76,76 +71,30 @@
     // Look for exact duplicates, compare only profile contents (and
     // ignore origin and language code in comparison).
     if (local.Compare(*remote) == 0) {
-      // A duplicate found: keep the version with the bigger storage key.
+      // We found a duplicate, we keep the new (remote) one and delete the
+      // local one.
       DVLOG(2)
           << "[AUTOFILL SYNC] The profile "
           << base::UTF16ToUTF8(local.GetRawInfo(NAME_FIRST))
           << base::UTF16ToUTF8(local.GetRawInfo(NAME_LAST))
-          << " already exists with a different storage key; keep the bigger "
-          << (remote_storage_key > local_storage_key ? "remote" : "local")
-          << " key " << std::max(remote_storage_key, local_storage_key)
-          << " and delete the smaller key "
-          << std::min(remote_storage_key, local_storage_key);
-      if (remote_storage_key > local_storage_key) {
-        // We keep the remote entity and delete the local one.
-        // Ensure that a verified profile can never revert back to an unverified
-        // one. In such a case, take over the old origin for the new entry.
-        if (local.IsVerified() && !remote->IsVerified()) {
-          remote->set_origin(local.origin());
-          // Save a copy of the remote profile also to sync.
-          save_to_sync_.push_back(std::make_unique<AutofillProfile>(*remote));
-        }
-        add_to_local_.push_back(std::move(remote));
-        // Deleting from sync is a no-op if it is local-only so far.
-        // There are a few ways how a synced local entry A could theoretically
-        // receive a remote duplicate B with a larger GUID:
-        //  1) Remote entity B got uploaded by another client through initial
-        //     sync. That client thus also knew about A and issued a deletion of
-        //     A at the same time. This client (if receiving creation of B
-        //     first) resolves the conflict in the same way and re-issues the
-        //     deletion of A. In most cases the redundant deletion does not even
-        //     get sent as the processor already knows A got deleted remotely.
-        //  2) Remote entity B got uploaded by another client through race
-        //     condition (i.e. not knowing about A, yet). In practice, this only
-        //     happens when two clients simultaneously convert a server profile
-        //     into local profiles. If the other client goes offline before
-        //     receiving A, this client is responsible for deleting A from the
-        //     server and thus must issue a deletion. (In most cases, the other
-        //     client does not go offline and thus both clients issue a deletion
-        //     of A independently).
-        //  3) (a paranoid case) Remote entity B got uploaded by another client
-        //     by an error, i.e. already as a duplicate given their local state.
-        //     Through standard flows, it should be impossible (duplicates are
-        //     cought early in PDM code so such a change attempt does not even
-        //     propagate to the sync bridge). Still, it's good to treat this
-        //     case here for robustness.
-        delete_from_sync_.insert(local_storage_key);
-        DeleteFromLocal(local_storage_key);
-      } else {
-        // We keep the local entity and delete the remote one.
-        // Ensure that a verified profile can never revert back to an unverified
-        // one. In such a case, modify the origin and re-upload. Otherwise,
-        // there's no need to upload it: either is was already uploaded before
-        // (if this is incremental sync) or we'll upload it with all the
-        // remaining data in GetLocalOnlyEntries (if this is an initial sync).
-        if (remote->IsVerified() && !local.IsVerified()) {
-          auto modified_local = std::make_unique<AutofillProfile>(local);
-          modified_local->set_origin(remote->origin());
-          update_to_local_.push_back(
-              std::make_unique<AutofillProfile>(*modified_local));
-          save_to_sync_.push_back(std::move(modified_local));
-          // The local entity is already marked for upload so it is not local
-          // only anymore (we do not want to upload it once again while flushing
-          // if this is initial sync).
-          GetLocalOnlyEntries()->erase(local_storage_key);
-        }
-        delete_from_sync_.insert(remote_storage_key);
+          << " already exists with a different storage key; keep the remote key"
+          << remote_storage_key << " and delete the local key "
+          << local_storage_key;
+
+      // Ensure that a verified profile can never revert back to an unverified
+      // one. In such a case, take over the local origin for the new (remote)
+      // entry.
+      if (local.IsVerified() && !remote->IsVerified()) {
+        remote->set_origin(local.origin());
+        // Save a copy of the remote profile also to sync.
+        save_to_sync_.push_back(std::make_unique<AutofillProfile>(*remote));
       }
-      return base::nullopt;
+      // Delete the local profile that gets replaced by |remote|.
+      DeleteFromLocal(local_storage_key);
+      break;
     }
   }
 
-  // If no duplicate was found, just add the remote profile.
   add_to_local_.push_back(std::move(remote));
   return base::nullopt;
 }
@@ -183,14 +132,10 @@
 }
 
 Optional<ModelError> AutofillProfileSyncDifferenceTracker::FlushToSync(
-    std::vector<std::unique_ptr<AutofillProfile>>* profiles_to_upload_to_sync,
-    std::vector<std::string>* profiles_to_delete_from_sync) {
+    std::vector<std::unique_ptr<AutofillProfile>>* profiles_to_upload_to_sync) {
   for (std::unique_ptr<AutofillProfile>& entry : save_to_sync_) {
     profiles_to_upload_to_sync->push_back(std::move(entry));
   }
-  for (const std::string& entry : delete_from_sync_) {
-    profiles_to_delete_from_sync->push_back(std::move(entry));
-  }
   return base::nullopt;
 }
 
@@ -255,11 +200,9 @@
 }
 
 Optional<ModelError> AutofillProfileInitialSyncDifferenceTracker::FlushToSync(
-    std::vector<std::unique_ptr<AutofillProfile>>* profiles_to_upload_to_sync,
-    std::vector<std::string>* profiles_to_delete_from_sync) {
+    std::vector<std::unique_ptr<AutofillProfile>>* profiles_to_upload_to_sync) {
   // First, flush standard updates to sync.
-  AutofillProfileSyncDifferenceTracker::FlushToSync(
-      profiles_to_upload_to_sync, profiles_to_delete_from_sync);
+  AutofillProfileSyncDifferenceTracker::FlushToSync(profiles_to_upload_to_sync);
 
   // For initial sync, we additionally need to upload all local only entries.
   if (!GetLocalOnlyEntries()) {
diff --git a/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.h b/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.h
index 2ef17366..055de2e 100644
--- a/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.h
+++ b/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.h
@@ -50,12 +50,11 @@
       base::OnceClosure autofill_changes_callback);
 
   // Writes into |profiles_to_upload_to_sync| all autofill profiles to be sent
-  // to the sync server, and into |profiles_to_delete_from_sync| the storage
-  // keys of all profiles to be deleted from the server. After flushing, no
-  // further remote changes should get incorporated.
+  // to the sync server. After flushing, not further remote changes should get
+  // incorporated.
   virtual base::Optional<syncer::ModelError> FlushToSync(
-      std::vector<std::unique_ptr<AutofillProfile>>* profiles_to_upload_to_sync,
-      std::vector<std::string>* profiles_to_delete_from_sync);
+      std::vector<std::unique_ptr<AutofillProfile>>*
+          profiles_to_upload_to_sync);
 
  protected:
   // If the entry is found, |entry| will be return, otherwise base::nullopt is
@@ -90,7 +89,7 @@
 
   // We use unique_ptrs for storing AutofillProfile to avoid unnecessary copies.
 
-  // Local data, mapped by storage key. Use GetLocalOnlyEntries() to access it.
+  // Local data, mapped by storage key. Use unique_to_local() to access it.
   std::map<std::string, std::unique_ptr<AutofillProfile>> local_only_entries_;
 
   // Contain changes (originating from sync) that need to be saved to the local
@@ -99,13 +98,9 @@
   std::vector<std::unique_ptr<AutofillProfile>> add_to_local_;
   std::vector<std::unique_ptr<AutofillProfile>> update_to_local_;
 
-  // Contains data for entries that existed on both sync and local sides
+  // Contains merged data for entries that existed on both sync and local sides
   // and need to be saved back to sync.
   std::vector<std::unique_ptr<AutofillProfile>> save_to_sync_;
-  // Contains storage keys for entries that existed on both sync and local
-  // sides and need to be deleted from sync (because the conflict resolution
-  // preferred the local copies).
-  std::set<std::string> delete_from_sync_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(AutofillProfileSyncDifferenceTracker);
@@ -121,8 +116,8 @@
       const std::string& storage_key) override;
 
   base::Optional<syncer::ModelError> FlushToSync(
-      std::vector<std::unique_ptr<AutofillProfile>>* profiles_to_upload_to_sync,
-      std::vector<std::string>* profiles_to_delete_from_sync) override;
+      std::vector<std::unique_ptr<AutofillProfile>>* profiles_to_upload_to_sync)
+      override;
 
   // Performs an additional pass through remote entries incorporated from sync
   // to find any similarities with local entries. Should be run after all
diff --git a/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker_unittest.cc b/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker_unittest.cc
index 403f270..5a30b96 100644
--- a/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker_unittest.cc
+++ b/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker_unittest.cc
@@ -30,18 +30,13 @@
 using testing::IsEmpty;
 
 // Some guids for testing.
-const char kSmallerGuid[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44A";
-const char kBiggerGuid[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44B";
+const char kGuidA[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44A";
+const char kGuidB[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44B";
 const char kHttpOrigin[] = "http://www.example.com/";
 const char kHttpsOrigin[] = "https://www.example.com/";
 const char kLocaleString[] = "en-US";
 const base::Time kJune2017 = base::Time::FromDoubleT(1497552271);
 
-struct UpdatesToSync {
-  std::vector<AutofillProfile> profiles_to_upload_to_sync;
-  std::vector<std::string> profiles_to_delete_from_sync;
-};
-
 }  // namespace
 
 class AutofillProfileSyncDifferenceTrackerTestBase : public testing::Test {
@@ -70,26 +65,24 @@
                                  std::make_unique<AutofillProfile>(profile)));
   }
 
-  UpdatesToSync FlushToSync() {
+  std::vector<AutofillProfile> FlushAndReturnProfilesToUploadToSync() {
     EXPECT_EQ(base::nullopt,
               tracker()->FlushToLocal(
                   /*autofill_changes_callback=*/base::DoNothing()));
 
-    UpdatesToSync updates;
     std::vector<std::unique_ptr<AutofillProfile>> vector_of_unique_ptrs;
     EXPECT_EQ(base::nullopt,
               tracker()->FlushToSync(
-                  /*profiles_to_upload_to_sync=*/&vector_of_unique_ptrs,
-                  /*profiles_to_delete_from_sync=*/&updates
-                      .profiles_to_delete_from_sync));
+                  /*profiles_to_upload_to_sync=*/&vector_of_unique_ptrs));
 
     // Copy all the elements by value so that we have a vector that is easier to
     // work with in the test.
+    std::vector<AutofillProfile> vector_of_values;
     for (const std::unique_ptr<AutofillProfile>& entry :
          vector_of_unique_ptrs) {
-      updates.profiles_to_upload_to_sync.push_back(*entry);
+      vector_of_values.push_back(*entry);
     }
-    return updates;
+    return vector_of_values;
   }
 
   std::vector<AutofillProfile> GetAllLocalData() {
@@ -137,69 +130,63 @@
 
 TEST_F(AutofillProfileSyncDifferenceTrackerTest,
        IncorporateRemoteProfileShouldOverwriteProfileWithSameKey) {
-  AutofillProfile local = AutofillProfile(kSmallerGuid, kHttpOrigin);
+  AutofillProfile local = AutofillProfile(kGuidA, kHttpOrigin);
   local.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
   AddAutofillProfilesToTable({local});
 
   // The remote profile is completely different but it has the same key.
-  AutofillProfile remote = AutofillProfile(kSmallerGuid, kHttpsOrigin);
+  AutofillProfile remote = AutofillProfile(kGuidA, kHttpsOrigin);
   remote.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Tom"));
 
   IncorporateRemoteProfile(remote);
 
   // Nothing gets uploaded to sync and the remote profile wins.
-  UpdatesToSync updates = FlushToSync();
-  EXPECT_THAT(updates.profiles_to_upload_to_sync, IsEmpty());
-  EXPECT_THAT(updates.profiles_to_delete_from_sync, IsEmpty());
+  EXPECT_THAT(FlushAndReturnProfilesToUploadToSync(), IsEmpty());
   EXPECT_THAT(GetAllLocalData(), ElementsAre(remote));
 }
 
 TEST_F(AutofillProfileSyncDifferenceTrackerTest,
        IncorporateRemoteProfileShouldOverwriteUnverifiedProfileByVerified) {
-  AutofillProfile local = AutofillProfile(kSmallerGuid, kHttpsOrigin);
+  AutofillProfile local = AutofillProfile(kGuidA, kHttpsOrigin);
   local.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
   AddAutofillProfilesToTable({local});
 
   // The remote profile has the same key but it is not verified.
-  AutofillProfile remote = AutofillProfile(kSmallerGuid, kSettingsOrigin);
+  AutofillProfile remote = AutofillProfile(kGuidA, kSettingsOrigin);
   remote.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Tom"));
 
   IncorporateRemoteProfile(remote);
 
   // Nothing gets uploaded to sync and the local profile wins.
-  UpdatesToSync updates = FlushToSync();
-  EXPECT_THAT(updates.profiles_to_upload_to_sync, IsEmpty());
-  EXPECT_THAT(updates.profiles_to_delete_from_sync, IsEmpty());
+  EXPECT_THAT(FlushAndReturnProfilesToUploadToSync(), IsEmpty());
   EXPECT_THAT(GetAllLocalData(), ElementsAre(remote));
 }
 
 TEST_F(AutofillProfileSyncDifferenceTrackerTest,
        IncorporateRemoteProfileShouldNotOverwriteVerifiedProfileByUnverified) {
-  AutofillProfile local = AutofillProfile(kSmallerGuid, kSettingsOrigin);
+  AutofillProfile local = AutofillProfile(kGuidA, kSettingsOrigin);
   local.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
   AddAutofillProfilesToTable({local});
 
   // The remote profile has the same key but it is not verified.
-  AutofillProfile remote = AutofillProfile(kSmallerGuid, kHttpsOrigin);
+  AutofillProfile remote = AutofillProfile(kGuidA, kHttpsOrigin);
   remote.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Tom"));
 
   IncorporateRemoteProfile(remote);
 
   // Nothing gets uploaded to sync and the local profile wins.
-  UpdatesToSync updates = FlushToSync();
-  EXPECT_THAT(updates.profiles_to_upload_to_sync, IsEmpty());
-  EXPECT_THAT(updates.profiles_to_delete_from_sync, IsEmpty());
+  EXPECT_THAT(FlushAndReturnProfilesToUploadToSync(), IsEmpty());
   EXPECT_THAT(GetAllLocalData(), ElementsAre(local));
 }
 
 TEST_F(AutofillProfileSyncDifferenceTrackerTest,
        IncorporateRemoteProfileShouldNotOverwriteFullNameByEmptyString) {
-  AutofillProfile local = AutofillProfile(kSmallerGuid, kHttpOrigin);
+  AutofillProfile local = AutofillProfile(kGuidA, kHttpOrigin);
   local.SetRawInfo(NAME_FULL, ASCIIToUTF16("John"));
   AddAutofillProfilesToTable({local});
 
   // The remote profile has the same key.
-  AutofillProfile remote = AutofillProfile(kSmallerGuid, kHttpsOrigin);
+  AutofillProfile remote = AutofillProfile(kGuidA, kHttpsOrigin);
   remote.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("2 2st st"));
 
   AutofillProfile merged(remote);
@@ -209,46 +196,40 @@
 
   // Nothing gets uploaded to sync and the remote profile wins except for the
   // full name.
-  UpdatesToSync updates = FlushToSync();
-  EXPECT_THAT(updates.profiles_to_upload_to_sync, IsEmpty());
-  EXPECT_THAT(updates.profiles_to_delete_from_sync, IsEmpty());
+  EXPECT_THAT(FlushAndReturnProfilesToUploadToSync(), IsEmpty());
   EXPECT_THAT(GetAllLocalData(), ElementsAre(merged));
 }
 
-TEST_F(
-    AutofillProfileSyncDifferenceTrackerTest,
-    IncorporateRemoteProfileShouldKeepRemoteKeyWhenMergingDuplicateProfileWithBiggerKey) {
-  AutofillProfile local = AutofillProfile(kSmallerGuid, kHttpOrigin);
+TEST_F(AutofillProfileSyncDifferenceTrackerTest,
+       IncorporateRemoteProfileShouldMergeIdenticalProfilesWithDifferentKeys) {
+  AutofillProfile local = AutofillProfile(kGuidA, kHttpOrigin);
   local.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
   local.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
   AddAutofillProfilesToTable({local});
 
   // The remote profile is identical to the local one, except that the guids and
   // origins are different.
-  AutofillProfile remote = AutofillProfile(kBiggerGuid, kHttpsOrigin);
+  AutofillProfile remote = AutofillProfile(kGuidB, kHttpsOrigin);
   remote.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
   remote.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
 
   IncorporateRemoteProfile(remote);
 
   // Nothing gets uploaded to sync and the remote profile wins.
-  UpdatesToSync updates = FlushToSync();
-  EXPECT_THAT(updates.profiles_to_upload_to_sync, IsEmpty());
-  EXPECT_THAT(updates.profiles_to_delete_from_sync,
-              ElementsAre(std::string(kSmallerGuid)));
+  EXPECT_THAT(FlushAndReturnProfilesToUploadToSync(), IsEmpty());
   EXPECT_THAT(GetAllLocalData(), ElementsAre(remote));
 }
 
 TEST_F(
     AutofillProfileSyncDifferenceTrackerTest,
-    IncorporateRemoteProfileShouldKeepRemoteKeyAndLocalOriginWhenMergingDuplicateProfileWithBiggerKey) {
-  AutofillProfile local = AutofillProfile(kSmallerGuid, kSettingsOrigin);
+    IncorporateRemoteProfileShouldMergeIdenticalProfilesWithDifferentKeysButKeepVerifiedOrigin) {
+  AutofillProfile local = AutofillProfile(kGuidA, kSettingsOrigin);
   local.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
   local.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
   AddAutofillProfilesToTable({local});
 
   // The remote profile has the same key.
-  AutofillProfile remote = AutofillProfile(kBiggerGuid, kHttpsOrigin);
+  AutofillProfile remote = AutofillProfile(kGuidB, kHttpsOrigin);
   remote.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
   remote.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
 
@@ -259,61 +240,7 @@
 
   // Nothing gets uploaded to sync and the remote profile wins except for the
   // full name.
-  UpdatesToSync updates = FlushToSync();
-  EXPECT_THAT(updates.profiles_to_upload_to_sync, ElementsAre(merged));
-  EXPECT_THAT(updates.profiles_to_delete_from_sync,
-              ElementsAre(std::string(kSmallerGuid)));
-  EXPECT_THAT(GetAllLocalData(), ElementsAre(merged));
-}
-
-TEST_F(
-    AutofillProfileSyncDifferenceTrackerTest,
-    IncorporateRemoteProfileShouldKeepLocalKeyWhenMergingDuplicateProfileWithSmallerKey) {
-  AutofillProfile local = AutofillProfile(kBiggerGuid, kHttpOrigin);
-  local.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
-  local.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
-  AddAutofillProfilesToTable({local});
-
-  // The remote profile is identical to the local one, except that the guids and
-  // origins are different.
-  AutofillProfile remote = AutofillProfile(kSmallerGuid, kHttpsOrigin);
-  remote.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
-  remote.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
-
-  IncorporateRemoteProfile(remote);
-
-  // Nothing gets uploaded to sync and the remote profile wins.
-  UpdatesToSync updates = FlushToSync();
-  EXPECT_THAT(updates.profiles_to_upload_to_sync, IsEmpty());
-  EXPECT_THAT(updates.profiles_to_delete_from_sync,
-              ElementsAre(std::string(kSmallerGuid)));
-  EXPECT_THAT(GetAllLocalData(), ElementsAre(local));
-}
-
-TEST_F(
-    AutofillProfileSyncDifferenceTrackerTest,
-    IncorporateRemoteProfileShouldKeepLocalKeyAndRemoteOriginWhenMergingDuplicateProfileWithSmallerKey) {
-  AutofillProfile local = AutofillProfile(kBiggerGuid, kHttpsOrigin);
-  local.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
-  local.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
-  AddAutofillProfilesToTable({local});
-
-  // The remote profile has the same key.
-  AutofillProfile remote = AutofillProfile(kSmallerGuid, kSettingsOrigin);
-  remote.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
-  remote.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
-
-  AutofillProfile merged(local);
-  merged.set_origin(kSettingsOrigin);
-
-  IncorporateRemoteProfile(remote);
-
-  // Nothing gets uploaded to sync and the remote profile wins except for the
-  // full name.
-  UpdatesToSync updates = FlushToSync();
-  EXPECT_THAT(updates.profiles_to_upload_to_sync, ElementsAre(merged));
-  EXPECT_THAT(updates.profiles_to_delete_from_sync,
-              ElementsAre(std::string(kSmallerGuid)));
+  EXPECT_THAT(FlushAndReturnProfilesToUploadToSync(), ElementsAre(merged));
   EXPECT_THAT(GetAllLocalData(), ElementsAre(merged));
 }
 
@@ -328,10 +255,10 @@
 
 TEST_F(AutofillProfileSyncDifferenceTrackerTest,
        FlushToLocalShouldCallbackWhenProfileDeleted) {
-  AutofillProfile local = AutofillProfile(kSmallerGuid, kSettingsOrigin);
+  AutofillProfile local = AutofillProfile(kGuidA, kSettingsOrigin);
   AddAutofillProfilesToTable({local});
 
-  tracker()->IncorporateRemoteDelete(kSmallerGuid);
+  tracker()->IncorporateRemoteDelete(kGuidA);
 
   MockCallback<base::OnceClosure> autofill_changes_callback;
   EXPECT_CALL(autofill_changes_callback, Run()).Times(1);
@@ -344,7 +271,7 @@
 
 TEST_F(AutofillProfileSyncDifferenceTrackerTest,
        FlushToLocalShouldCallbackWhenProfileAdded) {
-  AutofillProfile remote = AutofillProfile(kSmallerGuid, kSettingsOrigin);
+  AutofillProfile remote = AutofillProfile(kGuidA, kSettingsOrigin);
   IncorporateRemoteProfile(remote);
 
   MockCallback<base::OnceClosure> autofill_changes_callback;
@@ -358,10 +285,10 @@
 
 TEST_F(AutofillProfileSyncDifferenceTrackerTest,
        FlushToLocalShouldCallbackWhenProfileUpdated) {
-  AutofillProfile local = AutofillProfile(kSmallerGuid, kHttpsOrigin);
+  AutofillProfile local = AutofillProfile(kGuidA, kHttpsOrigin);
   AddAutofillProfilesToTable({local});
 
-  AutofillProfile remote = AutofillProfile(kSmallerGuid, kHttpsOrigin);
+  AutofillProfile remote = AutofillProfile(kGuidA, kHttpsOrigin);
   remote.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
   IncorporateRemoteProfile(remote);
 
@@ -370,7 +297,7 @@
   EXPECT_EQ(base::nullopt,
             tracker()->FlushToLocal(autofill_changes_callback.Get()));
 
-  // On top of that, the profile with key kSmallerGuid should also get updated.
+  // On top of that, the profile with key kGuidA should also get updated.
   EXPECT_THAT(GetAllLocalData(), ElementsAre(remote));
 }
 
@@ -397,13 +324,13 @@
 
 TEST_F(AutofillProfileInitialSyncDifferenceTrackerTest,
        MergeSimilarEntriesForInitialSyncShouldSyncUpChanges) {
-  AutofillProfile local = AutofillProfile(kSmallerGuid, kHttpOrigin);
+  AutofillProfile local = AutofillProfile(kGuidA, kHttpOrigin);
   local.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
   local.set_use_count(27);
   AddAutofillProfilesToTable({local});
 
   // The remote profile matches the local one (except for origin and use count).
-  AutofillProfile remote = AutofillProfile(kBiggerGuid, kHttpsOrigin);
+  AutofillProfile remote = AutofillProfile(kGuidB, kHttpsOrigin);
   remote.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
   remote.SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Frobbers, Inc."));
   remote.set_use_count(13);
@@ -419,21 +346,19 @@
   MergeSimilarEntriesForInitialSync();
 
   // The merged profile needs to get uploaded back to sync and stored locally.
-  UpdatesToSync updates = FlushToSync();
-  EXPECT_THAT(updates.profiles_to_upload_to_sync, ElementsAre(merged));
-  EXPECT_THAT(updates.profiles_to_delete_from_sync, IsEmpty());
+  EXPECT_THAT(FlushAndReturnProfilesToUploadToSync(), ElementsAre(merged));
   EXPECT_THAT(GetAllLocalData(), ElementsAre(merged));
 }
 
 TEST_F(AutofillProfileInitialSyncDifferenceTrackerTest,
        MergeSimilarEntriesForInitialSyncShouldNotSyncUpWhenNotNeeded) {
-  AutofillProfile local = AutofillProfile(kSmallerGuid, kHttpOrigin);
+  AutofillProfile local = AutofillProfile(kGuidA, kHttpOrigin);
   local.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
   local.set_use_count(13);
   AddAutofillProfilesToTable({local});
 
   // The remote profile matches the local one and has some additional data.
-  AutofillProfile remote = AutofillProfile(kBiggerGuid, kHttpOrigin);
+  AutofillProfile remote = AutofillProfile(kGuidB, kHttpOrigin);
   remote.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
   remote.SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Frobbers, Inc."));
   // Merging two profile takes their max use count, so use count of 27 is taken.
@@ -443,21 +368,19 @@
   MergeSimilarEntriesForInitialSync();
 
   // Nothing gets uploaded to sync and the remote profile wins.
-  UpdatesToSync updates = FlushToSync();
-  EXPECT_THAT(updates.profiles_to_upload_to_sync, IsEmpty());
-  EXPECT_THAT(updates.profiles_to_delete_from_sync, IsEmpty());
+  EXPECT_THAT(FlushAndReturnProfilesToUploadToSync(), IsEmpty());
   EXPECT_THAT(GetAllLocalData(), ElementsAre(remote));
 }
 
 TEST_F(AutofillProfileInitialSyncDifferenceTrackerTest,
        MergeSimilarEntriesForInitialSyncNotMatchNonsimilarEntries) {
-  AutofillProfile local = AutofillProfile(kSmallerGuid, kHttpOrigin);
+  AutofillProfile local = AutofillProfile(kGuidA, kHttpOrigin);
   local.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
   local.SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Frobbers, Inc."));
   AddAutofillProfilesToTable({local});
 
   // The remote profile has a different street address.
-  AutofillProfile remote = AutofillProfile(kBiggerGuid, kHttpOrigin);
+  AutofillProfile remote = AutofillProfile(kGuidB, kHttpOrigin);
   remote.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("2 2st st"));
   remote.SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Frobbers, Inc."));
 
@@ -466,21 +389,19 @@
 
   // The local profile gets uploaded (due to initial sync) and the remote
   // profile gets stored locally.
-  UpdatesToSync updates = FlushToSync();
-  EXPECT_THAT(updates.profiles_to_upload_to_sync, ElementsAre(local));
-  EXPECT_THAT(updates.profiles_to_delete_from_sync, IsEmpty());
+  EXPECT_THAT(FlushAndReturnProfilesToUploadToSync(), ElementsAre(local));
   EXPECT_THAT(GetAllLocalData(), ElementsAre(local, remote));
 }
 
 TEST_F(AutofillProfileInitialSyncDifferenceTrackerTest,
        MergeSimilarEntriesForInitialSyncDoesNotMatchLocalVerifiedEntry) {
   // The local entry is verified, should not get merged.
-  AutofillProfile local = AutofillProfile(kSmallerGuid, kSettingsOrigin);
+  AutofillProfile local = AutofillProfile(kGuidA, kSettingsOrigin);
   local.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
   AddAutofillProfilesToTable({local});
 
   // The remote profile is similar to the local one.
-  AutofillProfile remote = AutofillProfile(kBiggerGuid, kHttpOrigin);
+  AutofillProfile remote = AutofillProfile(kGuidB, kHttpOrigin);
   remote.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
   remote.SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Frobbers, Inc."));
 
@@ -489,21 +410,19 @@
 
   // The local profile gets uploaded (due to initial sync) and the remote
   // profile gets stored locally.
-  UpdatesToSync updates = FlushToSync();
-  EXPECT_THAT(updates.profiles_to_upload_to_sync, ElementsAre(local));
-  EXPECT_THAT(updates.profiles_to_delete_from_sync, IsEmpty());
+  EXPECT_THAT(FlushAndReturnProfilesToUploadToSync(), ElementsAre(local));
   EXPECT_THAT(GetAllLocalData(), ElementsAre(local, remote));
 }
 
 TEST_F(AutofillProfileInitialSyncDifferenceTrackerTest,
        MergeSimilarEntriesForInitialSyncDoesNotMatchRemoteVerifiedEntry) {
-  AutofillProfile local = AutofillProfile(kSmallerGuid, kHttpOrigin);
+  AutofillProfile local = AutofillProfile(kGuidA, kHttpOrigin);
   local.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
   AddAutofillProfilesToTable({local});
 
   // The remote profile is similar to the local one but is verified and thus it
   // should not get merged.
-  AutofillProfile remote = AutofillProfile(kBiggerGuid, kSettingsOrigin);
+  AutofillProfile remote = AutofillProfile(kGuidB, kSettingsOrigin);
   remote.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
   remote.SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Frobbers, Inc."));
 
@@ -512,9 +431,7 @@
 
   // The local profile gets uploaded (due to initial sync) and the remote
   // profile gets stored locally.
-  UpdatesToSync updates = FlushToSync();
-  EXPECT_THAT(updates.profiles_to_upload_to_sync, ElementsAre(local));
-  EXPECT_THAT(updates.profiles_to_delete_from_sync, IsEmpty());
+  EXPECT_THAT(FlushAndReturnProfilesToUploadToSync(), ElementsAre(local));
   EXPECT_THAT(GetAllLocalData(), ElementsAre(local, remote));
 }
 
diff --git a/components/browsing_data/core/counters/history_counter.cc b/components/browsing_data/core/counters/history_counter.cc
index 40a8a4f..f473959 100644
--- a/components/browsing_data/core/counters/history_counter.cc
+++ b/components/browsing_data/core/counters/history_counter.cc
@@ -38,7 +38,7 @@
                                          base::Unretained(this)));
 }
 
-bool HistoryCounter::HasTrackedTasks() {
+bool HistoryCounter::HasTrackedTasksForTesting() {
   return cancelable_task_tracker_.HasTrackedTasks();
 }
 
diff --git a/components/browsing_data/core/counters/history_counter.h b/components/browsing_data/core/counters/history_counter.h
index 597980c..fa4632e 100644
--- a/components/browsing_data/core/counters/history_counter.h
+++ b/components/browsing_data/core/counters/history_counter.h
@@ -44,7 +44,7 @@
   void OnInitialized() override;
 
   // Whether there are counting tasks in progress. Only used for testing.
-  bool HasTrackedTasks();
+  bool HasTrackedTasksForTesting();
 
   const char* GetPrefName() const override;
 
diff --git a/components/domain_reliability/quic_error_mapping.cc b/components/domain_reliability/quic_error_mapping.cc
index df33039..640916c 100644
--- a/components/domain_reliability/quic_error_mapping.cc
+++ b/components/domain_reliability/quic_error_mapping.cc
@@ -320,6 +320,13 @@
      "quic.stream.data.beyond.close.offset"},
     {quic::QUIC_STREAM_MULTIPLE_OFFSET, "quic.stream.multiple.offset"},
 
+    {quic::QUIC_HTTP_FRAME_TOO_LARGE, "quic.http.frame.too.large,"},
+    {quic::QUIC_HTTP_FRAME_ERROR, "quic.http.frame.error"},
+    {quic::QUIC_HTTP_FRAME_UNEXPECTED_ON_SPDY_STREAM,
+     "quic.http.frame.unexpected.on.spdy.stream"},
+    {quic::QUIC_HTTP_FRAME_UNEXPECTED_ON_CONTROL_STREAM,
+     "quic.http.frame.unexpected.on.control.stream"},
+
     // QUIC_INVALID_APPLICATION_CLOSE_DATA was code 101. The code has been
     // deprecated, but to keep the assert below happy, there needs to be
     // an entry for it, but the symbol is gone.
diff --git a/components/minidump_uploader/BUILD.gn b/components/minidump_uploader/BUILD.gn
index f8e9301..a29b42d 100644
--- a/components/minidump_uploader/BUILD.gn
+++ b/components/minidump_uploader/BUILD.gn
@@ -38,6 +38,7 @@
     "android/java/src/org/chromium/components/minidump_uploader/MinidumpUploadJob.java",
     "android/java/src/org/chromium/components/minidump_uploader/MinidumpUploadJobImpl.java",
     "android/java/src/org/chromium/components/minidump_uploader/MinidumpUploadJobService.java",
+    "android/java/src/org/chromium/components/minidump_uploader/MinidumpUploader.java",
     "android/java/src/org/chromium/components/minidump_uploader/MinidumpUploaderDelegate.java",
     "android/java/src/org/chromium/components/minidump_uploader/util/CrashReportingPermissionManager.java",
     "android/java/src/org/chromium/components/minidump_uploader/util/HttpURLConnectionFactory.java",
@@ -62,6 +63,7 @@
     "android/javatests/src/org/chromium/components/minidump_uploader/MinidumpUploadCallableTest.java",
     "android/javatests/src/org/chromium/components/minidump_uploader/MinidumpUploadJobImplTest.java",
     "android/javatests/src/org/chromium/components/minidump_uploader/MinidumpUploadTestUtility.java",
+    "android/javatests/src/org/chromium/components/minidump_uploader/MinidumpUploaderTest.java",
     "android/javatests/src/org/chromium/components/minidump_uploader/TestMinidumpUploadJobImpl.java",
     "android/javatests/src/org/chromium/components/minidump_uploader/TestMinidumpUploaderDelegate.java",
   ]
diff --git a/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/MinidumpUploadCallable.java b/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/MinidumpUploadCallable.java
index fc2edfe7..a25e74c 100644
--- a/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/MinidumpUploadCallable.java
+++ b/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/MinidumpUploadCallable.java
@@ -5,29 +5,17 @@
 package org.chromium.components.minidump_uploader;
 
 import androidx.annotation.IntDef;
-import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.Log;
-import org.chromium.base.StreamUtil;
 import org.chromium.components.minidump_uploader.util.CrashReportingPermissionManager;
-import org.chromium.components.minidump_uploader.util.HttpURLConnectionFactory;
-import org.chromium.components.minidump_uploader.util.HttpURLConnectionFactoryImpl;
 
-import java.io.BufferedReader;
-import java.io.ByteArrayOutputStream;
 import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileReader;
 import java.io.FileWriter;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.net.HttpURLConnection;
 import java.util.Locale;
 import java.util.concurrent.Callable;
-import java.util.zip.GZIPOutputStream;
 
 /**
  * This class tries to upload a minidump to the crash server.
@@ -42,12 +30,6 @@
     // "crash_dump_week_upload_size" - Deprecated prefs used for limiting crash report uploads over
     // cellular network. Last used in M47, removed in M78.
 
-    @VisibleForTesting
-    protected static final String CRASH_URL_STRING = "https://clients2.google.com/cr/report";
-
-    @VisibleForTesting
-    protected static final String CONTENT_TYPE_TMPL = "multipart/form-data; boundary=%s";
-
     @IntDef({MinidumpUploadStatus.SUCCESS, MinidumpUploadStatus.FAILURE,
             MinidumpUploadStatus.USER_DISABLED, MinidumpUploadStatus.DISABLED_BY_SAMPLING})
     @Retention(RetentionPolicy.SOURCE)
@@ -60,20 +42,19 @@
 
     private final File mFileToUpload;
     private final File mLogfile;
-    private final HttpURLConnectionFactory mHttpURLConnectionFactory;
     private final CrashReportingPermissionManager mPermManager;
+    private final MinidumpUploader mMinidumpUploader;
 
     public MinidumpUploadCallable(
             File fileToUpload, File logfile, CrashReportingPermissionManager permissionManager) {
-        this(fileToUpload, logfile, new HttpURLConnectionFactoryImpl(), permissionManager);
+        this(fileToUpload, logfile, new MinidumpUploader(), permissionManager);
     }
 
     public MinidumpUploadCallable(File fileToUpload, File logfile,
-            HttpURLConnectionFactory httpURLConnectionFactory,
-            CrashReportingPermissionManager permissionManager) {
+            MinidumpUploader minidumpUploader, CrashReportingPermissionManager permissionManager) {
         mFileToUpload = fileToUpload;
         mLogfile = logfile;
-        mHttpURLConnectionFactory = httpURLConnectionFactory;
+        mMinidumpUploader = minidumpUploader;
         mPermManager = permissionManager;
     }
 
@@ -102,74 +83,9 @@
             }
         }
 
-        HttpURLConnection connection =
-                mHttpURLConnectionFactory.createHttpURLConnection(CRASH_URL_STRING);
-        if (connection == null) {
-            return MinidumpUploadStatus.FAILURE;
-        }
-
-        FileInputStream minidumpInputStream = null;
-        try {
-            if (!configureConnectionForHttpPost(connection)) {
-                return MinidumpUploadStatus.FAILURE;
-            }
-            minidumpInputStream = new FileInputStream(mFileToUpload);
-            streamCopy(minidumpInputStream, new GZIPOutputStream(connection.getOutputStream()));
-            boolean success = handleExecutionResponse(connection);
-
-            return success ? MinidumpUploadStatus.SUCCESS : MinidumpUploadStatus.FAILURE;
-        } catch (IOException | ArrayIndexOutOfBoundsException e) {
-            // ArrayIndexOutOfBoundsException due to bad GZIPOutputStream implementation on some
-            // old sony devices.
-            // For now just log the stack trace.
-            Log.w(TAG, "Error while uploading " + mFileToUpload.getName(), e);
-            return MinidumpUploadStatus.FAILURE;
-        } finally {
-            connection.disconnect();
-
-            if (minidumpInputStream != null) {
-                StreamUtil.closeQuietly(minidumpInputStream);
-            }
-        }
-    }
-
-    /**
-     * Configures a HttpURLConnection to send a HTTP POST request for uploading the minidump.
-     *
-     * This also reads the content-type from the minidump file.
-     *
-     * @param connection the HttpURLConnection to configure
-     * @return true if successful.
-     * @throws IOException
-     */
-    private boolean configureConnectionForHttpPost(HttpURLConnection connection)
-            throws IOException {
-        // Read the boundary which we need for the content type.
-        String boundary = readBoundary();
-        if (boundary == null) {
-            return false;
-        }
-
-        connection.setDoOutput(true);
-        connection.setRequestProperty("Connection", "Keep-Alive");
-        connection.setRequestProperty("Content-Encoding", "gzip");
-        connection.setRequestProperty("Content-Type", String.format(CONTENT_TYPE_TMPL, boundary));
-        return true;
-    }
-
-    /**
-     * Reads the HTTP response and cleans up successful uploads.
-     *
-     * @param connection the connection to read the response from
-     * @return true if the upload was successful, false otherwise.
-     * @throws IOException
-     */
-    private Boolean handleExecutionResponse(HttpURLConnection connection) throws IOException {
-        int responseCode = connection.getResponseCode();
-        if (isSuccessful(responseCode)) {
-            String responseContent = getResponseContentAsString(connection);
-            // The crash server returns the crash ID.
-            String uploadId = responseContent != null ? responseContent : "unknown";
+        MinidumpUploader.Result result = mMinidumpUploader.upload(mFileToUpload);
+        if (result.isSuccess()) {
+            String uploadId = result.message();
             String crashFileName = mFileToUpload.getName();
             Log.i(TAG, "Minidump " + crashFileName + " uploaded successfully, id: " + uploadId);
 
@@ -184,18 +100,25 @@
             } catch (IOException ioe) {
                 Log.e(TAG, "Fail to write uploaded entry to log file");
             }
-            return true;
-        } else {
+
+            return MinidumpUploadStatus.SUCCESS;
+        }
+
+        if (result.isUploadError()) {
             // Log the results of the upload. Note that periodic upload failures aren't bad
             // because we will need to throttle uploads in the future anyway.
             String msg = String.format(Locale.US, "Failed to upload %s with code: %d (%s).",
-                    mFileToUpload.getName(), responseCode, connection.getResponseMessage());
+                    mFileToUpload.getName(), result.errorCode(), result.message());
             Log.i(TAG, msg);
 
             // TODO(acleung): The return status informs us about why an upload might be
             // rejected. The next logical step is to put the reasons in an UMA histogram.
-            return false;
+        } else {
+            Log.e(TAG,
+                    "Local error while uploading " + mFileToUpload.getName() + ": "
+                            + result.message());
         }
+        return MinidumpUploadStatus.FAILURE;
     }
 
     /**
@@ -228,83 +151,4 @@
         }
     }
 
-    /**
-     * Get the boundary from the file, we need it for the content-type.
-     *
-     * @return the boundary if found, else null.
-     * @throws IOException
-     */
-    private String readBoundary() throws IOException {
-        BufferedReader reader = new BufferedReader(new FileReader(mFileToUpload));
-        String boundary = reader.readLine();
-        reader.close();
-        if (boundary == null || boundary.trim().isEmpty()) {
-            Log.e(TAG, "Ignoring invalid crash dump: '" + mFileToUpload + "'");
-            return null;
-        }
-        boundary = boundary.trim();
-        if (!boundary.startsWith("--") || boundary.length() < 10) {
-            Log.e(TAG, "Ignoring invalidly bound crash dump: '" + mFileToUpload + "'");
-            return null;
-        }
-        // Note: The regex allows all alphanumeric characters, as well as dashes.
-        // This matches the code that generates minidumps boundaries:
-        // https://chromium.googlesource.com/crashpad/crashpad/+/0c322ecc3f711c34fbf85b2cbe69f38b8dbccf05/util/net/http_multipart_builder.cc#36
-        if (!boundary.matches("^[a-zA-Z0-9-]*$")) {
-            Log.e(TAG,
-                    "Ignoring invalidly bound crash dump '" + mFileToUpload
-                            + "' due to invalid boundary characters: '" + boundary + "'");
-            return null;
-        }
-        boundary = boundary.substring(2);  // Remove the initial --
-        return boundary;
-    }
-
-    /**
-     * Returns whether the response code indicates a successful HTTP request.
-     *
-     * @param responseCode the response code
-     * @return true if response code indicates success, false otherwise.
-     */
-    private static boolean isSuccessful(int responseCode) {
-        return responseCode == 200 || responseCode == 201 || responseCode == 202;
-    }
-
-    /**
-     * Reads the response from |connection| as a String.
-     *
-     * @param connection the connection to read the response from.
-     * @return the content of the response.
-     * @throws IOException
-     */
-    private static String getResponseContentAsString(HttpURLConnection connection)
-            throws IOException {
-        String responseContent = null;
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        streamCopy(connection.getInputStream(), baos);
-        if (baos.size() > 0) {
-            responseContent = baos.toString();
-        }
-        return responseContent;
-    }
-
-    /**
-     * Copies all available data from |inStream| to |outStream|. Closes both
-     * streams when done.
-     *
-     * @param inStream the stream to read
-     * @param outStream the stream to write to
-     * @throws IOException
-     */
-    private static void streamCopy(InputStream inStream, OutputStream outStream)
-            throws IOException {
-        byte[] temp = new byte[4096];
-        int bytesRead = inStream.read(temp);
-        while (bytesRead >= 0) {
-            outStream.write(temp, 0, bytesRead);
-            bytesRead = inStream.read(temp);
-        }
-        inStream.close();
-        outStream.close();
-    }
 }
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/MinidumpUploader.java b/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/MinidumpUploader.java
similarity index 65%
rename from weblayer/browser/java/org/chromium/weblayer_private/MinidumpUploader.java
rename to components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/MinidumpUploader.java
index f84ccfa..645a041 100644
--- a/weblayer/browser/java/org/chromium/weblayer_private/MinidumpUploader.java
+++ b/components/minidump_uploader/android/java/src/org/chromium/components/minidump_uploader/MinidumpUploader.java
@@ -1,8 +1,8 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.weblayer_private;
+package org.chromium.components.minidump_uploader;
 
 import org.chromium.components.minidump_uploader.util.HttpURLConnectionFactory;
 import org.chromium.components.minidump_uploader.util.HttpURLConnectionFactoryImpl;
@@ -25,33 +25,75 @@
  * boundary forms the first line of the file.
  */
 public class MinidumpUploader {
-    // TODO(crbug.com/1029724) unfork this class back to //components/minidump_uploader
-    private static final String CRASH_URL_STRING = "https://clients2.google.com/cr/report";
-    private static final String CONTENT_TYPE_TMPL = "multipart/form-data; boundary=%s";
+    /* package */
+    static final String CRASH_URL_STRING = "https://clients2.google.com/cr/report";
+    /* package */
+    static final String CONTENT_TYPE_TMPL = "multipart/form-data; boundary=%s";
 
     private final HttpURLConnectionFactory mHttpURLConnectionFactory;
 
-    /* package */ static final class Result {
-        final boolean mSuccess;
-        final int mStatus;
-        final String mResult;
+    /**
+     * The result of an upload attempt.
+     *
+     * An upload attempt may succeed, in which case the result message is the upload ID.
+     * Alternatively it may fail either as a result of either a local or a remote error.
+     */
+    public static final class Result {
+        private final int mErrorCode;
+        private final String mResult;
 
-        private Result(boolean success, int status, String result) {
-            mSuccess = success;
-            mStatus = status;
+        private Result(int errorCode, String result) {
+            mErrorCode = errorCode;
             mResult = result;
         }
 
-        static Result failure(String result) {
-            return new Result(false, -1, result);
+        /** Returns true if this result represents a succesful upload. */
+        public boolean isSuccess() {
+            return mErrorCode == 0;
         }
 
-        static Result failure(int status, String result) {
-            return new Result(false, status, result);
+        /** Returns true if this result represents a remote error. */
+        public boolean isUploadError() {
+            return mErrorCode > 0;
+        }
+
+        /** Returns true if this result represents a local error. */
+        public boolean isFailure() {
+            return mErrorCode < 0;
+        }
+
+        /**
+         * Returns the upload error code.
+         *
+         * @return 0 on success
+         * @return <0 on local error
+         * @return HTTP status code on remote error
+         */
+        public int errorCode() {
+            return mErrorCode;
+        }
+
+        /**
+         * The message associated with this result.
+         *
+         * @return the remotely assigned upload id, on success
+         * @return descriptive error text otherwise.
+         */
+        public String message() {
+            return mResult;
+        }
+
+        static Result failure(String result) {
+            return new Result(-1, result);
+        }
+
+        static Result uploadError(int status, String result) {
+            assert status > 0;
+            return new Result(status, result);
         }
 
         static Result success(String result) {
-            return new Result(true, 0, result);
+            return new Result(0, result);
         }
     }
 
@@ -63,6 +105,16 @@
         mHttpURLConnectionFactory = httpURLConnectionFactory;
     }
 
+    /**
+     * Attempt to upload a single file to the crash server.
+     *
+     * The result of the upload attempt is either success (and an associated report ID), or failure.
+     * Failure may occur locally (the file is invalid or the network connection could not be
+     * created) or remotely (the crash server rejected the upload with a HTTP error).
+     *
+     * @param fileToUpload the file containing a MIME-body with an attached minidump.
+     * @return the success/failure result of the upload attempt.
+     */
     public Result upload(File fileToUpload) {
         try {
             if (fileToUpload == null || !fileToUpload.exists()) {
@@ -87,13 +139,13 @@
                     return Result.success(uploadId);
                 } else {
                     // Return the remote error code and message.
-                    return Result.failure(responseCode, connection.getResponseMessage());
+                    return Result.uploadError(responseCode, connection.getResponseMessage());
                 }
             } finally {
                 connection.disconnect();
             }
         } catch (IOException | RuntimeException e) {
-            return Result.failure(e.getMessage());
+            return Result.failure(e.toString());
         }
     }
 
@@ -113,28 +165,28 @@
     }
 
     /**
-     * Get the boundary from the file, we need it for the content-type.
+     * Get the MIME boundary from the file, for inclusion in Content-Type header.
      *
-     * @return the boundary if found, else null.
-     * @throws IOException
+     * @return the MIME boundary used in the file.
+     * @throws IOException if fileToUpload cannot be read
+     * @throws RuntimeException if the MIME boundary is missing or malformed.
      */
     private String readBoundary(File fileToUpload) throws IOException {
         try (FileReader fileReader = new FileReader(fileToUpload);
                 BufferedReader reader = new BufferedReader(fileReader)) {
             String boundary = reader.readLine();
             if (boundary == null || boundary.trim().isEmpty()) {
-                throw new RuntimeException(fileToUpload + " does not have a MIME boundary");
+                throw new RuntimeException("File does not have a MIME boundary");
             }
             boundary = boundary.trim();
             if (!boundary.startsWith("--") || boundary.length() < 10) {
-                throw new RuntimeException(fileToUpload + " does not have a MIME boundary");
+                throw new RuntimeException("File does not have a MIME boundary");
             }
             // Note: The regex allows all alphanumeric characters, as well as dashes.
             // This matches the code that generates minidumps boundaries:
             // https://chromium.googlesource.com/crashpad/crashpad/+/0c322ecc3f711c34fbf85b2cbe69f38b8dbccf05/util/net/http_multipart_builder.cc#36
             if (!boundary.matches("^[a-zA-Z0-9-]*$")) {
-                throw new RuntimeException(
-                        fileToUpload.getName() + " has an illegal MIME boundary: " + boundary);
+                throw new RuntimeException("File has an illegal MIME boundary: " + boundary);
             }
             boundary = boundary.substring(2); // Remove the initial --
             return boundary;
diff --git a/components/minidump_uploader/android/javatests/src/org/chromium/components/minidump_uploader/MinidumpUploadCallableTest.java b/components/minidump_uploader/android/javatests/src/org/chromium/components/minidump_uploader/MinidumpUploadCallableTest.java
index c8b00ce..a2997ce 100644
--- a/components/minidump_uploader/android/javatests/src/org/chromium/components/minidump_uploader/MinidumpUploadCallableTest.java
+++ b/components/minidump_uploader/android/javatests/src/org/chromium/components/minidump_uploader/MinidumpUploadCallableTest.java
@@ -12,173 +12,61 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.Feature;
 import org.chromium.components.minidump_uploader.CrashTestRule.MockCrashReportingPermissionManager;
 import org.chromium.components.minidump_uploader.MinidumpUploadCallable.MinidumpUploadStatus;
 import org.chromium.components.minidump_uploader.util.CrashReportingPermissionManager;
-import org.chromium.components.minidump_uploader.util.HttpURLConnectionFactory;
 
 import java.io.BufferedReader;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileReader;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.HttpURLConnection;
-import java.net.URL;
 
 /**
  * Unittests for {@link MinidumpUploadCallable}.
  */
 @RunWith(BaseJUnit4ClassRunner.class)
 public class MinidumpUploadCallableTest {
+    private static final String LOCAL_CRASH_ID = "123_log";
+    private static final String LOG_FILE_NAME = "chromium_renderer-123_log.dmp224";
+
     @Rule
     public CrashTestRule mTestRule = new CrashTestRule();
 
-    private static final String BOUNDARY = "TESTBOUNDARY";
-    private static final String UPLOAD_CRASH_ID = "IMACRASHID";
-    private static final String LOCAL_CRASH_ID = "123_log";
-    private static final String LOG_FILE_NAME = "chromium_renderer-123_log.dmp224";
     private File mTestUpload;
     private File mUploadLog;
     private File mExpectedFileAfterUpload;
 
-    /**
-     * A HttpURLConnection that performs some basic checks to ensure we are uploading
-     * minidumps correctly.
-     */
-    public static class TestHttpURLConnection extends HttpURLConnection {
-        static final String DEFAULT_EXPECTED_CONTENT_TYPE =
-                String.format(MinidumpUploadCallable.CONTENT_TYPE_TMPL, BOUNDARY);
-        private final String mExpectedContentType;
+    private static class MockMinidumpUploader extends MinidumpUploader {
+        private Result mMockResult;
 
-        /**
-         * The value of the "Content-Type" property if the property has been set.
-         */
-        private String mContentTypePropertyValue = "";
-
-        public TestHttpURLConnection(URL url) {
-            this(url, DEFAULT_EXPECTED_CONTENT_TYPE);
+        public static MinidumpUploader returnsSuccess() {
+            return new MockMinidumpUploader(Result.success(MinidumpUploaderTest.UPLOAD_CRASH_ID));
         }
 
-        public TestHttpURLConnection(URL url, String contentType) {
-            super(url);
-            mExpectedContentType = contentType;
-            Assert.assertEquals(MinidumpUploadCallable.CRASH_URL_STRING, url.toString());
+        public static MinidumpUploader returnsFailure(String message) {
+            return new MockMinidumpUploader(Result.failure(message));
+        }
+
+        public static MinidumpUploader returnsUploadError(int status, String message) {
+            return new MockMinidumpUploader(Result.uploadError(status, message));
+        }
+
+        private MockMinidumpUploader(Result mockResult) {
+            super(null);
+            mMockResult = mockResult;
         }
 
         @Override
-        public void disconnect() {
-            // Check that the "Content-Type" property has been set and the property's value.
-            Assert.assertEquals(mExpectedContentType, mContentTypePropertyValue);
-        }
-
-        @Override
-        public InputStream getInputStream() {
-            return new ByteArrayInputStream(ApiCompatibilityUtils.getBytesUtf8(UPLOAD_CRASH_ID));
-        }
-
-        @Override
-        public OutputStream getOutputStream() {
-            return new ByteArrayOutputStream();
-        }
-
-        @Override
-        public int getResponseCode() {
-            return 200;
-        }
-
-        @Override
-        public String getResponseMessage() {
-            return null;
-        }
-
-        @Override
-        public boolean usingProxy() {
-            return false;
-        }
-
-        @Override
-        public void connect() {
-        }
-
-        @Override
-        public void setRequestProperty(String key, String value) {
-            if (key.equals("Content-Type")) {
-                mContentTypePropertyValue = value;
-            }
-        }
-    }
-
-    /**
-     * A HttpURLConnectionFactory that performs some basic checks to ensure we are uploading
-     * minidumps correctly.
-     */
-    public static class TestHttpURLConnectionFactory implements HttpURLConnectionFactory {
-        String mContentType;
-
-        public TestHttpURLConnectionFactory() {
-            mContentType = TestHttpURLConnection.DEFAULT_EXPECTED_CONTENT_TYPE;
-        }
-
-        @Override
-        public HttpURLConnection createHttpURLConnection(String url) {
-            try {
-                return new TestHttpURLConnection(new URL(url), mContentType);
-            } catch (IOException e) {
-                return null;
-            }
-        }
-    }
-
-    private static class ErrorCodeHttpUrlConnectionFactory implements HttpURLConnectionFactory {
-        private final int mErrorCode;
-
-        ErrorCodeHttpUrlConnectionFactory(int errorCode) {
-            mErrorCode = errorCode;
-        }
-
-        @Override
-        public HttpURLConnection createHttpURLConnection(String url) {
-            try {
-                return new TestHttpURLConnection(new URL(url)) {
-                    @Override
-                    public int getResponseCode() {
-                        return mErrorCode;
-                    }
-                };
-            } catch (IOException e) {
-                return null;
-            }
-        }
-    }
-
-    private static class FailHttpURLConnectionFactory implements HttpURLConnectionFactory {
-        @Override
-        public HttpURLConnection createHttpURLConnection(String url) {
-            Assert.fail();
-            return null;
-        }
-    }
-
-    /**
-     * This class calls |getInstrumentation| which cannot be done in a static context.
-     */
-    private class MockMinidumpUploadCallable extends MinidumpUploadCallable {
-        MockMinidumpUploadCallable(
-                HttpURLConnectionFactory httpURLConnectionFactory,
-                CrashReportingPermissionManager permManager) {
-            super(mTestUpload, mUploadLog, httpURLConnectionFactory, permManager);
+        public Result upload(File fileToUpload) {
+            return mMockResult;
         }
     }
 
     private void createMinidumpFile() throws Exception {
         mTestUpload = new File(mTestRule.getCrashDir(), LOG_FILE_NAME);
-        CrashTestRule.setUpMinidumpFile(mTestUpload, BOUNDARY);
+        CrashTestRule.setUpMinidumpFile(mTestUpload, MinidumpUploaderTest.BOUNDARY);
     }
 
     private void setForcedUpload() {
@@ -204,6 +92,50 @@
     @Test
     @SmallTest
     @Feature({"Android-AppBase"})
+    public void testSuccessfulUpload() throws Exception {
+        final CrashReportingPermissionManager testPermManager =
+                new MockCrashReportingPermissionManager() {
+                    { mIsEnabledForTests = true; }
+                };
+        MinidumpUploadCallable minidumpUploadCallable = new MinidumpUploadCallable(
+                mTestUpload, mUploadLog, MockMinidumpUploader.returnsSuccess(), testPermManager);
+        Assert.assertEquals(MinidumpUploadStatus.SUCCESS, minidumpUploadCallable.call().intValue());
+        Assert.assertTrue(mExpectedFileAfterUpload.exists());
+        assertValidUploadLogEntry();
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Android-AppBase"})
+    public void testFailedUploadLocalError() throws Exception {
+        final CrashReportingPermissionManager testPermManager =
+                new MockCrashReportingPermissionManager() {
+                    { mIsEnabledForTests = true; }
+                };
+        MinidumpUploadCallable minidumpUploadCallable = new MinidumpUploadCallable(mTestUpload,
+                mUploadLog, MockMinidumpUploader.returnsFailure("Failed"), testPermManager);
+        Assert.assertEquals(MinidumpUploadStatus.FAILURE, minidumpUploadCallable.call().intValue());
+        Assert.assertFalse(mExpectedFileAfterUpload.exists());
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Android-AppBase"})
+    public void testFailedUploadRemoteError() throws Exception {
+        final CrashReportingPermissionManager testPermManager =
+                new MockCrashReportingPermissionManager() {
+                    { mIsEnabledForTests = true; }
+                };
+        MinidumpUploadCallable minidumpUploadCallable =
+                new MinidumpUploadCallable(mTestUpload, mUploadLog,
+                        MockMinidumpUploader.returnsUploadError(404, "Not Found"), testPermManager);
+        Assert.assertEquals(MinidumpUploadStatus.FAILURE, minidumpUploadCallable.call().intValue());
+        Assert.assertFalse(mExpectedFileAfterUpload.exists());
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Android-AppBase"})
     public void testCallWhenCurrentlyPermitted() throws Exception {
         CrashReportingPermissionManager testPermManager =
                 new MockCrashReportingPermissionManager() {
@@ -215,10 +147,8 @@
                     }
                 };
 
-        HttpURLConnectionFactory httpURLConnectionFactory = new TestHttpURLConnectionFactory();
-
-        MinidumpUploadCallable minidumpUploadCallable =
-                new MockMinidumpUploadCallable(httpURLConnectionFactory, testPermManager);
+        MinidumpUploadCallable minidumpUploadCallable = new MinidumpUploadCallable(
+                mTestUpload, mUploadLog, MockMinidumpUploader.returnsSuccess(), testPermManager);
         Assert.assertEquals(MinidumpUploadStatus.SUCCESS, minidumpUploadCallable.call().intValue());
         Assert.assertTrue(mExpectedFileAfterUpload.exists());
         assertValidUploadLogEntry();
@@ -238,10 +168,8 @@
                     }
                 };
 
-        HttpURLConnectionFactory httpURLConnectionFactory = new FailHttpURLConnectionFactory();
-
-        MinidumpUploadCallable minidumpUploadCallable =
-                new MockMinidumpUploadCallable(httpURLConnectionFactory, testPermManager);
+        MinidumpUploadCallable minidumpUploadCallable = new MinidumpUploadCallable(
+                mTestUpload, mUploadLog, MockMinidumpUploader.returnsSuccess(), testPermManager);
         Assert.assertEquals(
                 MinidumpUploadStatus.USER_DISABLED, minidumpUploadCallable.call().intValue());
 
@@ -265,10 +193,8 @@
                     }
                 };
 
-        HttpURLConnectionFactory httpURLConnectionFactory = new TestHttpURLConnectionFactory();
-
-        MinidumpUploadCallable minidumpUploadCallable =
-                new MockMinidumpUploadCallable(httpURLConnectionFactory, testPermManager);
+        MinidumpUploadCallable minidumpUploadCallable = new MinidumpUploadCallable(
+                mTestUpload, mUploadLog, MockMinidumpUploader.returnsSuccess(), testPermManager);
         Assert.assertEquals(MinidumpUploadStatus.DISABLED_BY_SAMPLING,
                 minidumpUploadCallable.call().intValue());
 
@@ -292,10 +218,8 @@
                     }
                 };
 
-        HttpURLConnectionFactory httpURLConnectionFactory = new FailHttpURLConnectionFactory();
-
-        MinidumpUploadCallable minidumpUploadCallable =
-                new MockMinidumpUploadCallable(httpURLConnectionFactory, testPermManager);
+        MinidumpUploadCallable minidumpUploadCallable = new MinidumpUploadCallable(
+                mTestUpload, mUploadLog, MockMinidumpUploader.returnsSuccess(), testPermManager);
         Assert.assertEquals(MinidumpUploadStatus.FAILURE, minidumpUploadCallable.call().intValue());
         Assert.assertFalse(mExpectedFileAfterUpload.exists());
     }
@@ -314,10 +238,8 @@
                     }
                 };
 
-        HttpURLConnectionFactory httpURLConnectionFactory = new TestHttpURLConnectionFactory();
-
-        MinidumpUploadCallable minidumpUploadCallable =
-                new MockMinidumpUploadCallable(httpURLConnectionFactory, testPermManager);
+        MinidumpUploadCallable minidumpUploadCallable = new MinidumpUploadCallable(
+                mTestUpload, mUploadLog, MockMinidumpUploader.returnsSuccess(), testPermManager);
         Assert.assertEquals(MinidumpUploadStatus.SUCCESS, minidumpUploadCallable.call().intValue());
         Assert.assertTrue(mExpectedFileAfterUpload.exists());
         assertValidUploadLogEntry();
@@ -338,10 +260,8 @@
                     }
                 };
 
-        HttpURLConnectionFactory httpURLConnectionFactory = new TestHttpURLConnectionFactory();
-
-        MinidumpUploadCallable minidumpUploadCallable =
-                new MockMinidumpUploadCallable(httpURLConnectionFactory, testPermManager);
+        MinidumpUploadCallable minidumpUploadCallable = new MinidumpUploadCallable(
+                mTestUpload, mUploadLog, MockMinidumpUploader.returnsSuccess(), testPermManager);
         Assert.assertEquals(MinidumpUploadStatus.SUCCESS, minidumpUploadCallable.call().intValue());
         Assert.assertTrue(mExpectedFileAfterUpload.exists());
         assertValidUploadLogEntry();
@@ -362,10 +282,8 @@
                     }
                 };
 
-        HttpURLConnectionFactory httpURLConnectionFactory = new TestHttpURLConnectionFactory();
-
-        MinidumpUploadCallable minidumpUploadCallable =
-                new MockMinidumpUploadCallable(httpURLConnectionFactory, testPermManager);
+        MinidumpUploadCallable minidumpUploadCallable = new MinidumpUploadCallable(
+                mTestUpload, mUploadLog, MockMinidumpUploader.returnsSuccess(), testPermManager);
         Assert.assertEquals(MinidumpUploadStatus.SUCCESS, minidumpUploadCallable.call().intValue());
 
         File expectedSkippedFileAfterUpload = new File(
@@ -389,10 +307,8 @@
                     }
                 };
 
-        HttpURLConnectionFactory httpURLConnectionFactory = new TestHttpURLConnectionFactory();
-
-        MinidumpUploadCallable minidumpUploadCallable =
-                new MockMinidumpUploadCallable(httpURLConnectionFactory, testPermManager);
+        MinidumpUploadCallable minidumpUploadCallable = new MinidumpUploadCallable(
+                mTestUpload, mUploadLog, MockMinidumpUploader.returnsSuccess(), testPermManager);
         Assert.assertEquals(MinidumpUploadStatus.SUCCESS, minidumpUploadCallable.call().intValue());
 
         File expectedSkippedFileAfterUpload = new File(
@@ -416,10 +332,8 @@
                     }
                 };
 
-        HttpURLConnectionFactory httpURLConnectionFactory = new TestHttpURLConnectionFactory();
-
-        MinidumpUploadCallable minidumpUploadCallable =
-                new MockMinidumpUploadCallable(httpURLConnectionFactory, testPermManager);
+        MinidumpUploadCallable minidumpUploadCallable = new MinidumpUploadCallable(
+                mTestUpload, mUploadLog, MockMinidumpUploader.returnsSuccess(), testPermManager);
         Assert.assertEquals(MinidumpUploadStatus.SUCCESS, minidumpUploadCallable.call().intValue());
 
         File expectedSkippedFileAfterUpload = new File(
@@ -428,82 +342,6 @@
         Assert.assertTrue(mExpectedFileAfterUpload.exists());
     }
 
-    // This is a regression test for http://crbug.com/712420
-    @Test
-    @SmallTest
-    @Feature({"Android-AppBase"})
-    public void testCallWithInvalidMinidumpBoundary() throws Exception {
-        // Include an invalid character, '[', in the test string.
-        CrashTestRule.setUpMinidumpFile(mTestUpload, "--InvalidBoundaryWithSpecialCharacter--[");
-        CrashReportingPermissionManager testPermManager =
-                new MockCrashReportingPermissionManager() {
-                    { mIsEnabledForTests = true; }
-                };
-        HttpURLConnectionFactory httpURLConnectionFactory = new TestHttpURLConnectionFactory() {
-            { mContentType = ""; }
-        };
-
-        MinidumpUploadCallable minidumpUploadCallable =
-                new MockMinidumpUploadCallable(httpURLConnectionFactory, testPermManager);
-
-        Assert.assertEquals(MinidumpUploadStatus.FAILURE, minidumpUploadCallable.call().intValue());
-        Assert.assertFalse(mExpectedFileAfterUpload.exists());
-    }
-
-    @Test
-    @SmallTest
-    @Feature({"Android-AppBase"})
-    public void testCallWithValidMinidumpBoundary() throws Exception {
-        // Include all valid characters in the test string.
-        final String boundary = "--0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
-        final String expectedContentType =
-                String.format(MinidumpUploadCallable.CONTENT_TYPE_TMPL, boundary);
-        CrashReportingPermissionManager testPermManager =
-                new MockCrashReportingPermissionManager() {
-                    { mIsEnabledForTests = true; }
-                };
-        HttpURLConnectionFactory httpURLConnectionFactory = new TestHttpURLConnectionFactory() {
-            { mContentType = expectedContentType; }
-        };
-
-        CrashTestRule.setUpMinidumpFile(mTestUpload, boundary);
-
-        MinidumpUploadCallable minidumpUploadCallable =
-                new MockMinidumpUploadCallable(httpURLConnectionFactory, testPermManager);
-
-        Assert.assertEquals(MinidumpUploadStatus.SUCCESS, minidumpUploadCallable.call().intValue());
-        Assert.assertTrue(mExpectedFileAfterUpload.exists());
-        assertValidUploadLogEntry();
-    }
-
-    @Test
-    @SmallTest
-    @Feature({"Android-AppBase"})
-    public void testReceivingErrorCodes() {
-        CrashReportingPermissionManager testPermManager =
-                new MockCrashReportingPermissionManager() {
-                    {
-                        mIsInSample = true;
-                        mIsUserPermitted = true;
-                        mIsNetworkAvailable = true;
-                        mIsEnabledForTests = false;
-                    }
-                };
-
-        final int[] errorCodes = {400, 401, 403, 404, 500};
-
-        for (int n = 0; n < errorCodes.length; n++) {
-            HttpURLConnectionFactory httpURLConnectionFactory =
-                    new ErrorCodeHttpUrlConnectionFactory(errorCodes[n]);
-            MinidumpUploadCallable minidumpUploadCallable =
-                    new MockMinidumpUploadCallable(httpURLConnectionFactory, testPermManager);
-            Assert.assertEquals(
-                    MinidumpUploadStatus.FAILURE, minidumpUploadCallable.call().intValue());
-            // Note that mTestUpload is not renamed on failure - so we can try to upload that file
-            // several times during the same test.
-        }
-    }
-
     private void assertValidUploadLogEntry() throws IOException {
         File logfile = new File(mTestRule.getCrashDir(), CrashFileManager.CRASH_DUMP_LOGFILE);
         BufferedReader input =  new BufferedReader(new FileReader(logfile));
@@ -532,7 +370,7 @@
         Assert.assertTrue(time <= now);
         Assert.assertTrue(time > now - 60 * 60);
 
-        Assert.assertEquals(uploadId, UPLOAD_CRASH_ID);
+        Assert.assertEquals(uploadId, MinidumpUploaderTest.UPLOAD_CRASH_ID);
         Assert.assertEquals(localId, LOCAL_CRASH_ID);
     }
 }
diff --git a/components/minidump_uploader/android/javatests/src/org/chromium/components/minidump_uploader/MinidumpUploadJobImplTest.java b/components/minidump_uploader/android/javatests/src/org/chromium/components/minidump_uploader/MinidumpUploadJobImplTest.java
index 5404cc1..edf4e81a 100644
--- a/components/minidump_uploader/android/javatests/src/org/chromium/components/minidump_uploader/MinidumpUploadJobImplTest.java
+++ b/components/minidump_uploader/android/javatests/src/org/chromium/components/minidump_uploader/MinidumpUploadJobImplTest.java
@@ -14,6 +14,8 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.components.minidump_uploader.CrashTestRule.MockCrashReportingPermissionManager;
+import org.chromium.components.minidump_uploader.MinidumpUploaderTest.TestHttpURLConnection;
+import org.chromium.components.minidump_uploader.MinidumpUploaderTest.TestHttpURLConnectionFactory;
 import org.chromium.components.minidump_uploader.util.CrashReportingPermissionManager;
 import org.chromium.components.minidump_uploader.util.HttpURLConnectionFactory;
 
@@ -40,6 +42,31 @@
     private static final String BOUNDARY = "TESTBOUNDARY";
 
     /**
+     * Test to ensure the minidump uploading mechanism allows the expected number of upload retries.
+     */
+    @Test
+    @MediumTest
+    public void testRetryCountRespected() throws IOException {
+        final CrashReportingPermissionManager permManager =
+                new MockCrashReportingPermissionManager() {
+                    {
+                        mIsInSample = true;
+                        mIsUserPermitted = true;
+                        mIsNetworkAvailable = false; // Will cause us to fail uploads
+                        mIsEnabledForTests = false;
+                    }
+                };
+
+        File firstFile = createMinidumpFileInCrashDir("1_abc.dmp0.try0");
+
+        for (int i = 0; i < MinidumpUploadJobImpl.MAX_UPLOAD_TRIES_ALLOWED; ++i) {
+            MinidumpUploadTestUtility.uploadMinidumpsSync(
+                    new TestMinidumpUploadJobImpl(mTestRule.getExistingCacheDir(), permManager),
+                    i + 1 < MinidumpUploadJobImpl.MAX_UPLOAD_TRIES_ALLOWED);
+        }
+    }
+
+    /**
      * Test to ensure the minidump uploading mechanism behaves as expected when we fail to upload
      * minidumps.
      */
@@ -94,15 +121,15 @@
         callables.add(new MinidumpUploadCallableCreator() {
             @Override
             public MinidumpUploadCallable createCallable(File minidumpFile, File logfile) {
-                return new MinidumpUploadCallable(
-                        minidumpFile, logfile, new FailingHttpUrlConnectionFactory(), permManager);
+                return new MinidumpUploadCallable(minidumpFile, logfile,
+                        new MinidumpUploader(new FailingHttpUrlConnectionFactory()), permManager);
             }
         });
         callables.add(new MinidumpUploadCallableCreator() {
             @Override
             public MinidumpUploadCallable createCallable(File minidumpFile, File logfile) {
                 return new MinidumpUploadCallable(minidumpFile, logfile,
-                        new MinidumpUploadCallableTest.TestHttpURLConnectionFactory(), permManager);
+                        new MinidumpUploader(new TestHttpURLConnectionFactory()), permManager);
             }
         });
         MinidumpUploadJob minidumpUploadJob = createCallableListMinidumpUploadJob(
@@ -328,7 +355,8 @@
         public MinidumpUploadCallable createMinidumpUploadCallable(
                 File minidumpFile, File logfile) {
             return new MinidumpUploadCallable(minidumpFile, logfile,
-                    new StallingHttpUrlConnectionFactory(mStopStallingLatch, mSuccessfulUpload),
+                    new MinidumpUploader(new StallingHttpUrlConnectionFactory(
+                            mStopStallingLatch, mSuccessfulUpload)),
                     mDelegate.createCrashReportingPermissionManager());
         }
     }
@@ -359,7 +387,7 @@
         @Override
         public HttpURLConnection createHttpURLConnection(String url) {
             try {
-                return new MinidumpUploadCallableTest.TestHttpURLConnection(new URL(url)) {
+                return new TestHttpURLConnection(new URL(url)) {
                     @Override
                     public OutputStream getOutputStream() {
                         return new StallingOutputStream();
diff --git a/components/minidump_uploader/android/javatests/src/org/chromium/components/minidump_uploader/MinidumpUploadTestUtility.java b/components/minidump_uploader/android/javatests/src/org/chromium/components/minidump_uploader/MinidumpUploadTestUtility.java
index 106a95a..c8bde442 100644
--- a/components/minidump_uploader/android/javatests/src/org/chromium/components/minidump_uploader/MinidumpUploadTestUtility.java
+++ b/components/minidump_uploader/android/javatests/src/org/chromium/components/minidump_uploader/MinidumpUploadTestUtility.java
@@ -13,6 +13,7 @@
 
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * Utility class for testing the minidump-uploading mechanism.
@@ -69,17 +70,19 @@
     public static void uploadMinidumpsSync(
             MinidumpUploadJob minidumpUploadJob, final boolean expectReschedule) {
         final CountDownLatch uploadsFinishedLatch = new CountDownLatch(1);
+        AtomicBoolean wasRescheduled = new AtomicBoolean();
         uploadAllMinidumpsOnUiThread(
                 minidumpUploadJob, new MinidumpUploadJob.UploadsFinishedCallback() {
                     @Override
                     public void uploadsFinished(boolean reschedule) {
-                        assertEquals(expectReschedule, reschedule);
+                        wasRescheduled.set(reschedule);
                         uploadsFinishedLatch.countDown();
                     }
                 });
         try {
             assertTrue(uploadsFinishedLatch.await(
                     scaleTimeout(TIME_OUT_MILLIS), TimeUnit.MILLISECONDS));
+            assertEquals(expectReschedule, wasRescheduled.get());
         } catch (InterruptedException e) {
             throw new RuntimeException(e);
         }
diff --git a/components/minidump_uploader/android/javatests/src/org/chromium/components/minidump_uploader/MinidumpUploaderTest.java b/components/minidump_uploader/android/javatests/src/org/chromium/components/minidump_uploader/MinidumpUploaderTest.java
new file mode 100644
index 0000000..1e4fe70
--- /dev/null
+++ b/components/minidump_uploader/android/javatests/src/org/chromium/components/minidump_uploader/MinidumpUploaderTest.java
@@ -0,0 +1,225 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.components.minidump_uploader;
+
+import android.support.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.ApiCompatibilityUtils;
+import org.chromium.base.test.BaseJUnit4ClassRunner;
+import org.chromium.base.test.util.Feature;
+import org.chromium.components.minidump_uploader.util.HttpURLConnectionFactory;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+/**
+ * Unittests for {@link MinidumpUploadCallable}.
+ */
+@RunWith(BaseJUnit4ClassRunner.class)
+public class MinidumpUploaderTest {
+    /* package */ static final String BOUNDARY = "TESTBOUNDARY";
+    /* package */ static final String UPLOAD_CRASH_ID = "IMACRASHID";
+
+    @Rule
+    public CrashTestRule mTestRule = new CrashTestRule();
+    private File mUploadTestFile;
+
+    /**
+     * A HttpURLConnection that performs some basic checks to ensure we are uploading
+     * minidumps correctly.
+     */
+    /* package */ static class TestHttpURLConnection extends HttpURLConnection {
+        static final String DEFAULT_EXPECTED_CONTENT_TYPE =
+                String.format(MinidumpUploader.CONTENT_TYPE_TMPL, BOUNDARY);
+        private final String mExpectedContentType;
+
+        /**
+         * The value of the "Content-Type" property if the property has been set.
+         */
+        private String mContentTypePropertyValue = "";
+
+        public TestHttpURLConnection(URL url) {
+            this(url, DEFAULT_EXPECTED_CONTENT_TYPE);
+        }
+
+        public TestHttpURLConnection(URL url, String contentType) {
+            super(url);
+            mExpectedContentType = contentType;
+            Assert.assertEquals(MinidumpUploader.CRASH_URL_STRING, url.toString());
+        }
+
+        @Override
+        public void disconnect() {
+            // Check that the "Content-Type" property has been set and the property's value.
+            Assert.assertEquals(mExpectedContentType, mContentTypePropertyValue);
+        }
+
+        @Override
+        public InputStream getInputStream() {
+            return new ByteArrayInputStream(ApiCompatibilityUtils.getBytesUtf8(UPLOAD_CRASH_ID));
+        }
+
+        @Override
+        public OutputStream getOutputStream() {
+            return new ByteArrayOutputStream();
+        }
+
+        @Override
+        public int getResponseCode() {
+            return 200;
+        }
+
+        @Override
+        public String getResponseMessage() {
+            return null;
+        }
+
+        @Override
+        public boolean usingProxy() {
+            return false;
+        }
+
+        @Override
+        public void connect() {}
+
+        @Override
+        public void setRequestProperty(String key, String value) {
+            if (key.equals("Content-Type")) {
+                mContentTypePropertyValue = value;
+            }
+        }
+    }
+
+    /**
+     * A HttpURLConnectionFactory that performs some basic checks to ensure we are uploading
+     * minidumps correctly.
+     */
+    /* package */ static class TestHttpURLConnectionFactory implements HttpURLConnectionFactory {
+        String mContentType;
+
+        public TestHttpURLConnectionFactory() {
+            mContentType = TestHttpURLConnection.DEFAULT_EXPECTED_CONTENT_TYPE;
+        }
+
+        @Override
+        public HttpURLConnection createHttpURLConnection(String url) {
+            try {
+                return new TestHttpURLConnection(new URL(url), mContentType);
+            } catch (IOException e) {
+                return null;
+            }
+        }
+    }
+
+    /* package */ static class ErrorCodeHttpURLConnectionFactory
+            implements HttpURLConnectionFactory {
+        private final int mErrorCode;
+
+        ErrorCodeHttpURLConnectionFactory(int errorCode) {
+            mErrorCode = errorCode;
+        }
+
+        @Override
+        public HttpURLConnection createHttpURLConnection(String url) {
+            try {
+                return new TestHttpURLConnection(new URL(url)) {
+                    @Override
+                    public int getResponseCode() {
+                        return mErrorCode;
+                    }
+                };
+            } catch (IOException e) {
+                return null;
+            }
+        }
+    }
+
+    /* package */ static class FailHttpURLConnectionFactory implements HttpURLConnectionFactory {
+        @Override
+        public HttpURLConnection createHttpURLConnection(String url) {
+            Assert.fail();
+            return null;
+        }
+    }
+
+    @Before
+    public void setUp() throws IOException {
+        mUploadTestFile = new File(mTestRule.getCrashDir(), "crashFile");
+        CrashTestRule.setUpMinidumpFile(mUploadTestFile, MinidumpUploaderTest.BOUNDARY);
+    }
+
+    @After
+    public void tearDown() throws IOException {
+        mUploadTestFile.delete();
+    }
+
+    // This is a regression test for http://crbug.com/712420
+    @Test
+    @SmallTest
+    @Feature({"Android-AppBase"})
+    public void testCallWithInvalidMinidumpBoundary() throws Exception {
+        // Include an invalid character, '[', in the test string.
+        final String boundary = "--InvalidBoundaryWithSpecialCharacter--[";
+
+        CrashTestRule.setUpMinidumpFile(mUploadTestFile, boundary);
+
+        HttpURLConnectionFactory httpURLConnectionFactory = new TestHttpURLConnectionFactory() {
+            { mContentType = ""; }
+        };
+
+        MinidumpUploader minidumpUploader = new MinidumpUploader(httpURLConnectionFactory);
+        MinidumpUploader.Result result = minidumpUploader.upload(mUploadTestFile);
+        Assert.assertTrue(result.isFailure());
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Android-AppBase"})
+    public void testCallWithValidMinidumpBoundary() throws Exception {
+        // Include all valid characters in the test string.
+        final String boundary = "--0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+        final String expectedContentType =
+                String.format(MinidumpUploader.CONTENT_TYPE_TMPL, boundary);
+
+        CrashTestRule.setUpMinidumpFile(mUploadTestFile, boundary);
+
+        HttpURLConnectionFactory httpURLConnectionFactory = new TestHttpURLConnectionFactory() {
+            { mContentType = expectedContentType; }
+        };
+
+        MinidumpUploader minidumpUploader = new MinidumpUploader(httpURLConnectionFactory);
+        MinidumpUploader.Result result = minidumpUploader.upload(mUploadTestFile);
+        Assert.assertTrue(result.isSuccess());
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Android-AppBase"})
+    public void testReceivingErrorCodes() {
+        final int[] errorCodes = {400, 401, 403, 404, 500};
+
+        for (int n = 0; n < errorCodes.length; n++) {
+            HttpURLConnectionFactory httpURLConnectionFactory =
+                    new ErrorCodeHttpURLConnectionFactory(errorCodes[n]);
+            MinidumpUploader minidumpUploader = new MinidumpUploader(httpURLConnectionFactory);
+            MinidumpUploader.Result result = minidumpUploader.upload(mUploadTestFile);
+            Assert.assertTrue(result.isUploadError());
+            Assert.assertEquals(result.errorCode(), errorCodes[n]);
+        }
+    }
+}
diff --git a/components/minidump_uploader/android/javatests/src/org/chromium/components/minidump_uploader/TestMinidumpUploadJobImpl.java b/components/minidump_uploader/android/javatests/src/org/chromium/components/minidump_uploader/TestMinidumpUploadJobImpl.java
index 87396af4..f295f70b 100644
--- a/components/minidump_uploader/android/javatests/src/org/chromium/components/minidump_uploader/TestMinidumpUploadJobImpl.java
+++ b/components/minidump_uploader/android/javatests/src/org/chromium/components/minidump_uploader/TestMinidumpUploadJobImpl.java
@@ -4,6 +4,7 @@
 
 package org.chromium.components.minidump_uploader;
 
+import org.chromium.components.minidump_uploader.MinidumpUploaderTest.TestHttpURLConnectionFactory;
 import org.chromium.components.minidump_uploader.util.CrashReportingPermissionManager;
 
 import java.io.File;
@@ -32,7 +33,7 @@
     @Override
     public MinidumpUploadCallable createMinidumpUploadCallable(File minidumpFile, File logfile) {
         return new MinidumpUploadCallable(minidumpFile, logfile,
-                new MinidumpUploadCallableTest.TestHttpURLConnectionFactory(),
+                new MinidumpUploader(new TestHttpURLConnectionFactory()),
                 mDelegate.createCrashReportingPermissionManager());
     }
 }
diff --git a/components/policy/core/common/configuration_policy_provider.cc b/components/policy/core/common/configuration_policy_provider.cc
index a8f75ec..5478e3d 100644
--- a/components/policy/core/common/configuration_policy_provider.cc
+++ b/components/policy/core/common/configuration_policy_provider.cc
@@ -11,7 +11,7 @@
 
 namespace policy {
 
-ConfigurationPolicyProvider::Observer::~Observer() {}
+ConfigurationPolicyProvider::Observer::~Observer() = default;
 
 ConfigurationPolicyProvider::ConfigurationPolicyProvider()
     : initialized_(false), schema_registry_(nullptr) {}
diff --git a/components/policy/proto/device_management_backend.proto b/components/policy/proto/device_management_backend.proto
index 6fc7d1f3..42b8868 100644
--- a/components/policy/proto/device_management_backend.proto
+++ b/components/policy/proto/device_management_backend.proto
@@ -1030,6 +1030,19 @@
   repeated DisplayInfo displays = 2;
 }
 
+// Status of a crash report.
+message CrashReportInfo {
+  // ID as provided by chrome://crashes.
+  optional string remote_id = 1;
+
+  // The timestamp when the crash is captured.
+  // [timestamp] is milliseconds since Epoch in UTC timezone (Java time).
+  optional int64 capture_timestamp = 2;
+
+  // Human readable string that identifies what caused the crash.
+  optional string cause = 3;
+}
+
 // Report device level status.
 message DeviceStatusReportRequest {
   reserved 4, 7, 13, 20;
@@ -1127,6 +1140,9 @@
 
   // Status of the graphics adapter(s) and display(s).
   optional GraphicsStatus graphics_status = 33;
+
+  // Information about the crash report(s) generated from the local device.
+  repeated CrashReportInfo crash_report_infos = 34;
 }
 
 message OsUpdateStatus {
diff --git a/components/sync/protocol/proto_visitors.h b/components/sync/protocol/proto_visitors.h
index d0a08b7..2b7afa4 100644
--- a/components/sync/protocol/proto_visitors.h
+++ b/components/sync/protocol/proto_visitors.h
@@ -795,24 +795,30 @@
 }
 
 VISIT_PROTO_FIELDS(const sync_pb::SharingMessageSpecifics& proto) {
-  VISIT(fcm_channel_configuration);
-  VISIT(server_channel_configuration);
+  VISIT(channel_configuration);
   VISIT_BYTES(payload);
 }
 
 VISIT_PROTO_FIELDS(
-    const sync_pb::SharingMessageSpecifics::ServerChannelConfiguration& proto) {
+    const sync_pb::SharingMessageSpecifics::ChannelConfiguration::
+        ServerChannelConfiguration& proto) {
   VISIT(channel_id);
   VISIT_BYTES(session_cookie);
 }
 
-VISIT_PROTO_FIELDS(
-    const sync_pb::SharingMessageSpecifics::FCMChannelConfiguration& proto) {
+VISIT_PROTO_FIELDS(const sync_pb::SharingMessageSpecifics::
+                       ChannelConfiguration::FCMChannelConfiguration& proto) {
   VISIT(token);
   VISIT(ttl);
   VISIT(priority);
 }
 
+VISIT_PROTO_FIELDS(
+    const sync_pb::SharingMessageSpecifics::ChannelConfiguration& proto) {
+  VISIT(fcm);
+  VISIT(server);
+}
+
 VISIT_PROTO_FIELDS(const sync_pb::SyncCycleCompletedEventInfo& proto) {
   VISIT(num_encryption_conflicts);
   VISIT(num_hierarchy_conflicts);
diff --git a/components/sync/protocol/sharing_message_specifics.proto b/components/sync/protocol/sharing_message_specifics.proto
index 3da5368..25e09d9 100644
--- a/components/sync/protocol/sharing_message_specifics.proto
+++ b/components/sync/protocol/sharing_message_specifics.proto
@@ -17,39 +17,43 @@
 package sync_pb;
 
 message SharingMessageSpecifics {
-  message ServerChannelConfiguration {
-    // Where to send the message to.
-    optional string channel_id = 1;
-    // Optional cookie set on the original request.
-    optional bytes session_cookie = 2;
+  message ChannelConfiguration {
+    message ServerChannelConfiguration {
+      // Where to send the message to.
+      optional string channel_id = 1;
+      // Optional cookie set on the original request.
+      optional bytes session_cookie = 2;
+    }
+
+    message FCMChannelConfiguration {
+      // FCM registration token of target device.
+      optional string token = 1;
+
+      // Time to live for a FCM message (in seconds) - if specified, the message
+      // will expire based on the TTL.
+      optional int32 ttl = 2;
+
+      // Priority level of a FCM message. 5 = normal, 10 = high.
+      optional int32 priority = 3;
+    }
+
+    oneof channel_configuration {
+      // FCM channel configuration. Message will be delivered as a FCM message.
+      FCMChannelConfiguration fcm = 1;
+
+      // Server channel configuration. Message will be delivered through server
+      // channel.
+      ServerChannelConfiguration server = 2;
+    }
   }
 
-  message FCMChannelConfiguration {
-    // FCM registration token of target device.
-    optional string token = 1;
-
-    // Time to live for a FCM message (in seconds) - if specified, the message
-    // will expire based on the TTL.
-    optional int32 ttl = 2;
-
-    // Priority level of a FCM message. 5 = normal, 10 = high.
-    optional int32 priority = 3;
-  }
-
-  oneof channel_configuration {
-    // FCM channel configuration. Message will be delivered as a FCM message.
-    FCMChannelConfiguration fcm_channel_configuration = 1;
-
-    // Server channel configuration. Message will be delivered through server
-    // channel.
-    ServerChannelConfiguration server_channel_configuration = 2;
-  }
+  optional ChannelConfiguration channel_configuration = 1;
 
   // Payload encrypted using the target user keys according to WebPush
   // encryption scheme. The payload has to be a valid
   // chrome/browser/sharing/proto/sharing_message.proto serialized using
   // SerializeToString.
-  optional bytes payload = 3;
+  optional bytes payload = 2;
 }
 
 // Used for the server to return fine grained commit errors back to the client.
diff --git a/content/browser/back_forward_cache_browsertest.cc b/content/browser/back_forward_cache_browsertest.cc
index 0c8385e5..deb0d869 100644
--- a/content/browser/back_forward_cache_browsertest.cc
+++ b/content/browser/back_forward_cache_browsertest.cc
@@ -287,6 +287,8 @@
 
   net::EmbeddedTestServer* https_server() { return https_server_.get(); }
 
+  base::HistogramTester histogram_tester_;
+
  private:
   void AddSampleToBuckets(std::vector<base::Bucket>* buckets,
                           base::HistogramBase::Sample sample) {
@@ -303,7 +305,6 @@
   base::test::ScopedFeatureList feature_list_;
 
   FrameTreeVisualizer visualizer_;
-  base::HistogramTester histogram_tester_;
   std::vector<base::Bucket> expected_outcomes_;
   std::vector<base::Bucket> expected_not_restored_;
   std::vector<base::Bucket> expected_blocklisted_features_;
@@ -5337,4 +5338,52 @@
       FROM_HERE);
 }
 
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, PageshowMetrics) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  const char kHistogramName[] =
+      "BackForwardCache.MainFrameHasPageshowListenersOnRestore";
+
+  const GURL url1(embedded_test_server()->GetURL("a.com", "/title1.html"));
+  const GURL url2(embedded_test_server()->GetURL("b.com", "/title1.html"));
+
+  // 1) Navigate to the page.
+  EXPECT_TRUE(NavigateToURL(shell(), url1));
+  EXPECT_TRUE(ExecJs(current_frame_host(), R"(
+    window.foo = 42;
+  )"));
+
+  // 2) Navigate away and back.
+  EXPECT_TRUE(NavigateToURL(shell(), url2));
+  web_contents()->GetController().GoBack();
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+
+  // As we don't get an explicit ACK when the page is restored (yet), force
+  // a round-trip to the renderer to effectively flush the queue.
+  EXPECT_EQ(42, EvalJs(current_frame_host(), "window.foo"));
+
+  // Expect the back-forward restore without pageshow to be detected.
+  content::FetchHistogramsFromChildProcesses();
+  EXPECT_THAT(histogram_tester_.GetAllSamples(kHistogramName),
+              ElementsAre(base::Bucket(0, 1)));
+
+  EXPECT_TRUE(ExecJs(current_frame_host(), R"(
+    window.addEventListener("pageshow", () => {});
+  )"));
+
+  // 3) Navigate away and back (again).
+  EXPECT_TRUE(NavigateToURL(shell(), url2));
+  web_contents()->GetController().GoBack();
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+
+  // As we don't get an explicit ACK when the page is restored (yet), force
+  // a round-trip to the renderer to effectively flush the queue.
+  EXPECT_EQ(42, EvalJs(current_frame_host(), "window.foo"));
+
+  // Expect the back-forward restore with pageshow to be detected.
+  content::FetchHistogramsFromChildProcesses();
+  EXPECT_THAT(histogram_tester_.GetAllSamples(kHistogramName),
+              ElementsAre(base::Bucket(0, 1), base::Bucket(1, 1)));
+}
+
 }  // namespace content
diff --git a/content/browser/browsing_data/clear_site_data_handler.h b/content/browser/browsing_data/clear_site_data_handler.h
index c377368..a923cfe6 100644
--- a/content/browser/browsing_data/clear_site_data_handler.h
+++ b/content/browser/browsing_data/clear_site_data_handler.h
@@ -55,7 +55,9 @@
     virtual void OutputMessages(
         const base::RepeatingCallback<WebContents*()>& web_contents_getter);
 
-    const std::vector<Message>& messages() const { return messages_; }
+    const std::vector<Message>& GetMessagesForTesting() const {
+      return messages_;
+    }
 
    protected:
     void SetOutputFormattedMessageFunctionForTesting(
diff --git a/content/browser/browsing_data/clear_site_data_handler_unittest.cc b/content/browser/browsing_data/clear_site_data_handler_unittest.cc
index d5fc1bc7..59aaab464 100644
--- a/content/browser/browsing_data/clear_site_data_handler_unittest.cc
+++ b/content/browser/browsing_data/clear_site_data_handler_unittest.cc
@@ -101,7 +101,7 @@
 
   void OutputMessages(const base::RepeatingCallback<WebContents*()>&
                           web_contents_getter) override {
-    *message_buffer_ = messages();
+    *message_buffer_ = GetMessagesForTesting();
   }
 
  private:
@@ -282,7 +282,7 @@
         &console_delegate, GURL()));
 
     std::string multiline_message;
-    for (const auto& message : console_delegate.messages()) {
+    for (const auto& message : console_delegate.GetMessagesForTesting()) {
       EXPECT_EQ(blink::mojom::ConsoleMessageLevel::kError, message.level);
       multiline_message += message.text + "\n";
     }
diff --git a/content/browser/browsing_data/conditional_cache_deletion_helper.cc b/content/browser/browsing_data/conditional_cache_deletion_helper.cc
index acf2286..62b51bf 100644
--- a/content/browser/browsing_data/conditional_cache_deletion_helper.cc
+++ b/content/browser/browsing_data/conditional_cache_deletion_helper.cc
@@ -44,19 +44,6 @@
 base::RepeatingCallback<bool(const disk_cache::Entry*)>
 ConditionalCacheDeletionHelper::CreateURLAndTimeCondition(
     base::RepeatingCallback<bool(const GURL&)> url_predicate,
-    base::Time begin_time,
-    base::Time end_time) {
-  return base::BindRepeating(
-      &EntryPredicateFromURLsAndTime, std::move(url_predicate),
-      base::RepeatingCallback<std::string(const std::string&)>(),
-      begin_time.is_null() ? base::Time() : begin_time,
-      end_time.is_null() ? base::Time::Max() : end_time);
-}
-
-// static
-base::RepeatingCallback<bool(const disk_cache::Entry*)>
-ConditionalCacheDeletionHelper::CreateCustomKeyURLAndTimeCondition(
-    base::RepeatingCallback<bool(const GURL&)> url_predicate,
     base::RepeatingCallback<std::string(const std::string&)> get_url_from_key,
     base::Time begin_time,
     base::Time end_time) {
diff --git a/content/browser/browsing_data/conditional_cache_deletion_helper.h b/content/browser/browsing_data/conditional_cache_deletion_helper.h
index 3db6b8e..5bee71a1 100644
--- a/content/browser/browsing_data/conditional_cache_deletion_helper.h
+++ b/content/browser/browsing_data/conditional_cache_deletion_helper.h
@@ -31,23 +31,12 @@
 
   // A convenience method to create a condition matching cache entries whose
   // last modified time is between |begin_time| (inclusively), |end_time|
-  // (exclusively) and whose URL is matched by the |url_predicate|. Note that
-  // |begin_time| and |end_time| can be null to indicate unbounded time interval
-  // in their respective direction.
-  static base::RepeatingCallback<bool(const disk_cache::Entry*)>
-  CreateURLAndTimeCondition(
-      base::RepeatingCallback<bool(const GURL&)> url_predicate,
-      base::Time begin_time,
-      base::Time end_time);
-
-  // A convenience method to create a condition matching cache entries whose
-  // last modified time is between |begin_time| (inclusively), |end_time|
   // (exclusively) and whose URL obtained by passing the key to the
   // |get_url_from_key| is matched by the |url_predicate|. The
   // |get_url_from_key| method is useful when the entries are not keyed by the
   // resource url alone. For ex: using two keys for site isolation.
   static base::RepeatingCallback<bool(const disk_cache::Entry*)>
-  CreateCustomKeyURLAndTimeCondition(
+  CreateURLAndTimeCondition(
       base::RepeatingCallback<bool(const GURL&)> url_predicate,
       base::RepeatingCallback<std::string(const std::string&)> get_url_from_key,
       base::Time begin_time,
diff --git a/content/browser/browsing_data/storage_partition_code_cache_data_remover.cc b/content/browser/browsing_data/storage_partition_code_cache_data_remover.cc
index df92e53f08..e4c4b54 100644
--- a/content/browser/browsing_data/storage_partition_code_cache_data_remover.cc
+++ b/content/browser/browsing_data/storage_partition_code_cache_data_remover.cc
@@ -74,12 +74,11 @@
   if (!url_predicate_.is_null()) {
     result =
         (new ConditionalCacheDeletionHelper(
-             backend,
-             ConditionalCacheDeletionHelper::CreateCustomKeyURLAndTimeCondition(
-                 std::move(url_predicate_),
-                 base::BindRepeating(
-                     &GeneratedCodeCache::GetResourceURLFromKey),
-                 begin_time_, end_time_)))
+             backend, ConditionalCacheDeletionHelper::CreateURLAndTimeCondition(
+                          std::move(url_predicate_),
+                          base::BindRepeating(
+                              &GeneratedCodeCache::GetResourceURLFromKey),
+                          begin_time_, end_time_)))
             ->DeleteAndDestroySelfWhenFinished(copyable_callback);
   } else if (begin_time_.is_null() && end_time_.is_max()) {
     result = backend->DoomAllEntries(copyable_callback);
diff --git a/content/browser/devtools/devtools_renderer_channel.cc b/content/browser/devtools/devtools_renderer_channel.cc
index f0cb4ee..80268c27 100644
--- a/content/browser/devtools/devtools_renderer_channel.cc
+++ b/content/browser/devtools/devtools_renderer_channel.cc
@@ -38,7 +38,8 @@
     agent_remote_.set_disconnect_handler(std::move(connection_error));
   if (host_receiver)
     receiver_.Bind(std::move(host_receiver));
-  SetRendererInternal(agent, process_id, nullptr);
+  const bool force_using_io = true;
+  SetRendererInternal(agent, process_id, nullptr, force_using_io);
 }
 
 void DevToolsRendererChannel::SetRendererAssociated(
@@ -55,7 +56,8 @@
   }
   if (host_receiver)
     associated_receiver_.Bind(std::move(host_receiver));
-  SetRendererInternal(agent, process_id, frame_host);
+  const bool force_using_io = false;
+  SetRendererInternal(agent, process_id, frame_host, force_using_io);
 }
 
 void DevToolsRendererChannel::CleanupConnection() {
@@ -73,7 +75,8 @@
 void DevToolsRendererChannel::SetRendererInternal(
     blink::mojom::DevToolsAgent* agent,
     int process_id,
-    RenderFrameHostImpl* frame_host) {
+    RenderFrameHostImpl* frame_host,
+    bool force_using_io) {
   ReportChildWorkersCallback();
   process_id_ = process_id;
   frame_host_ = frame_host;
@@ -85,7 +88,7 @@
   for (DevToolsSession* session : owner_->sessions()) {
     for (auto& pair : session->handlers())
       pair.second->SetRenderer(process_id_, frame_host_);
-    session->AttachToAgent(agent);
+    session->AttachToAgent(agent, force_using_io);
   }
 }
 
@@ -95,9 +98,9 @@
   for (auto& pair : session->handlers())
     pair.second->SetRenderer(process_id_, frame_host_);
   if (agent_remote_)
-    session->AttachToAgent(agent_remote_.get());
+    session->AttachToAgent(agent_remote_.get(), true);
   else if (associated_agent_remote_)
-    session->AttachToAgent(associated_agent_remote_.get());
+    session->AttachToAgent(associated_agent_remote_.get(), false);
 }
 
 void DevToolsRendererChannel::InspectElement(const gfx::Point& point) {
diff --git a/content/browser/devtools/devtools_renderer_channel.h b/content/browser/devtools/devtools_renderer_channel.h
index 0ab7b2c..e4c4f62 100644
--- a/content/browser/devtools/devtools_renderer_channel.h
+++ b/content/browser/devtools/devtools_renderer_channel.h
@@ -80,7 +80,8 @@
   void CleanupConnection();
   void SetRendererInternal(blink::mojom::DevToolsAgent* agent,
                            int process_id,
-                           RenderFrameHostImpl* frame_host);
+                           RenderFrameHostImpl* frame_host,
+                           bool force_using_io);
   void ReportChildWorkersCallback();
 
   DevToolsAgentHostImpl* owner_;
diff --git a/content/browser/devtools/devtools_session.cc b/content/browser/devtools/devtools_session.cc
index 8e82e346..7fca25e 100644
--- a/content/browser/devtools/devtools_session.cc
+++ b/content/browser/devtools/devtools_session.cc
@@ -117,7 +117,8 @@
   proxy_delegate_->Attach(this);
 }
 
-void DevToolsSession::AttachToAgent(blink::mojom::DevToolsAgent* agent) {
+void DevToolsSession::AttachToAgent(blink::mojom::DevToolsAgent* agent,
+                                    bool force_using_io_session) {
   DCHECK(agent_host_);
   if (!agent) {
     receiver_.reset();
@@ -134,6 +135,7 @@
     io_session_.reset();
   }
 
+  use_io_session_ = force_using_io_session;
   agent->AttachDevToolsSession(receiver_.BindNewEndpointAndPassRemote(),
                                session_.BindNewEndpointAndPassReceiver(),
                                io_session_.BindNewPipeAndPassReceiver(),
@@ -290,7 +292,9 @@
 
 void DevToolsSession::DispatchToAgent(const PendingMessage& message) {
   DCHECK(!browser_only_);
-  if (ShouldSendOnIO(message.method)) {
+  // We send all messages on the IO channel for workers so that messages like
+  // Debugger.pause don't get stuck behind other blocking messages.
+  if (ShouldSendOnIO(message.method) || use_io_session_) {
     if (io_session_) {
       TRACE_EVENT_WITH_FLOW2(
           "devtools", "DevToolsSession::DispatchToAgent on IO", message.call_id,
diff --git a/content/browser/devtools/devtools_session.h b/content/browser/devtools/devtools_session.h
index 7ff990b..a53bd04 100644
--- a/content/browser/devtools/devtools_session.h
+++ b/content/browser/devtools/devtools_session.h
@@ -52,7 +52,8 @@
   void AddHandler(std::unique_ptr<protocol::DevToolsDomainHandler> handler);
   void TurnIntoExternalProxy(DevToolsExternalAgentProxyDelegate* delegate);
 
-  void AttachToAgent(blink::mojom::DevToolsAgent* agent);
+  void AttachToAgent(blink::mojom::DevToolsAgent* agent,
+                     bool force_using_io_session);
   bool DispatchProtocolMessage(base::span<const uint8_t> message);
   void SuspendSendingMessagesToAgent();
   void ResumeSendingMessagesToAgent();
@@ -124,6 +125,7 @@
   mojo::AssociatedReceiver<blink::mojom::DevToolsSessionHost> receiver_{this};
   mojo::AssociatedRemote<blink::mojom::DevToolsSession> session_;
   mojo::Remote<blink::mojom::DevToolsSession> io_session_;
+  bool use_io_session_{false};
   DevToolsAgentHostImpl* agent_host_ = nullptr;
   DevToolsAgentHostClient* client_;
   bool browser_only_ = false;
diff --git a/content/browser/devtools/worker_devtools_agent_host.cc b/content/browser/devtools/worker_devtools_agent_host.cc
index 0ad1c25..1eefe013 100644
--- a/content/browser/devtools/worker_devtools_agent_host.cc
+++ b/content/browser/devtools/worker_devtools_agent_host.cc
@@ -38,7 +38,7 @@
                                     std::move(connection_error));
 }
 
-WorkerDevToolsAgentHost::~WorkerDevToolsAgentHost() {}
+WorkerDevToolsAgentHost::~WorkerDevToolsAgentHost() = default;
 
 void WorkerDevToolsAgentHost::Disconnected() {
   ForceDetachAllSessions();
diff --git a/content/browser/frame_host/navigation_controller_impl_browsertest.cc b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
index 892a8ce9..3ae0c17 100644
--- a/content/browser/frame_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
@@ -10266,27 +10266,6 @@
 
 namespace {
 
-// A request handler that returns a 301 or 307 response to /redirect-301 or
-// /redirect-307 respectively, redirecting to the URL provided in the query
-// string. The error codes 301 and 307 are used as examples of codes that switch
-// the method to GET across the redirect (301) versus those that preserve the
-// method (307).
-std::unique_ptr<net::test_server::HttpResponse> HandleRedirect(
-    const net::test_server::HttpRequest& request) {
-  GURL url = request.base_url.Resolve(request.relative_url);
-  std::unique_ptr<net::test_server::BasicHttpResponse> response =
-      std::make_unique<net::test_server::BasicHttpResponse>();
-  if (url.path() == "/redirect-301") {
-    response->set_code(net::HTTP_MOVED_PERMANENTLY);
-  } else if (url.path() == "/redirect-307") {
-    response->set_code(net::HTTP_TEMPORARY_REDIRECT);
-  } else {
-    return nullptr;
-  }
-  response->AddCustomHeader("Location", url.query());
-  return std::move(response);
-}
-
 // A request handler that returns a simple page for requests using |method| to
 // /handle-method-only, and closes the socket for any other method.
 std::unique_ptr<net::test_server::HttpResponse> HandleMethodOnly(
@@ -10311,13 +10290,6 @@
 // 301 redirect that encounters an error page. See https://crbug.com/1041597.
 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTestNoServer,
                        UpdateMethodOn301RedirectError) {
-  // Install a request handler to serve 301 or 307 redirects. In this test,
-  // which uses a 301 redirect, the default handler for "/server-redirect?..."
-  // would work. But this test still installs a custom request handler anyway
-  // just for symmetry with the PreserveMethodOn307RedirectError test below,
-  // which requires a custom handler to serve 307 responses.
-  embedded_test_server()->RegisterRequestHandler(
-      base::BindRepeating(&HandleRedirect));
   // HandleMethodOnly serves the final endpoint that the test ends up at. It
   // lets the test distinguish a GET from a POST by serving a response only for
   // POST requests.
@@ -10330,8 +10302,8 @@
   EXPECT_TRUE(NavigateToURL(shell(), start_url));
 
   GURL post_only_url = embedded_test_server()->GetURL("/handle-method-only");
-  GURL form_action_url(
-      embedded_test_server()->GetURL("/redirect-301?" + post_only_url.spec()));
+  GURL form_action_url(embedded_test_server()->GetURL("/server-redirect-301?" +
+                                                      post_only_url.spec()));
 
   // Inject a form into the page and submit it, to create a POST request to
   // |form_action_url|. This POST request will redirect to |post_only_url|. The
@@ -10374,8 +10346,6 @@
 // should be preserved as POST.
 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTestNoServer,
                        UpdateMethodOn307RedirectError) {
-  embedded_test_server()->RegisterRequestHandler(
-      base::BindRepeating(&HandleRedirect));
   // HandleMethodOnly serves the final endpoint that the test ends up at. It
   // lets the test distinguish a GET from a POST by serving a response only for
   // GET requests.
@@ -10388,8 +10358,8 @@
   EXPECT_TRUE(NavigateToURL(shell(), start_url));
 
   GURL get_only_url = embedded_test_server()->GetURL("/handle-method-only");
-  GURL form_action_url(
-      embedded_test_server()->GetURL("/redirect-307?" + get_only_url.spec()));
+  GURL form_action_url(embedded_test_server()->GetURL("/server-redirect-307?" +
+                                                      get_only_url.spec()));
 
   // Inject a form into the page and submit it, to create a POST request to
   // |form_action_url|. This POST request will redirect to |get_only_url|. The
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 91922e42..b7e0e73 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -1668,7 +1668,6 @@
     IPC_MESSAGE_HANDLER(FrameHostMsg_Detach, OnDetach)
     IPC_MESSAGE_HANDLER(FrameHostMsg_UpdateState, OnUpdateState)
     IPC_MESSAGE_HANDLER(FrameHostMsg_OpenURL, OnOpenURL)
-    IPC_MESSAGE_HANDLER(FrameHostMsg_BeforeUnload_ACK, OnBeforeUnloadACK)
     IPC_MESSAGE_HANDLER(FrameHostMsg_Unload_ACK, OnUnloadACK)
     IPC_MESSAGE_HANDLER(FrameHostMsg_ContextMenu, OnContextMenu)
     IPC_MESSAGE_HANDLER(FrameHostMsg_VisualStateResponse, OnVisualStateResponse)
@@ -1682,7 +1681,6 @@
     IPC_MESSAGE_HANDLER(FrameHostMsg_DidChangeFrameOwnerProperties,
                         OnDidChangeFrameOwnerProperties)
     IPC_MESSAGE_HANDLER(FrameHostMsg_UpdateTitle, OnUpdateTitle)
-    IPC_MESSAGE_HANDLER(FrameHostMsg_DispatchLoad, OnDispatchLoad)
     IPC_MESSAGE_HANDLER(FrameHostMsg_ForwardResourceTimingToParent,
                         OnForwardResourceTimingToParent)
     IPC_MESSAGE_HANDLER(AccessibilityHostMsg_EventBundle, OnAccessibilityEvents)
@@ -2861,15 +2859,6 @@
   PendingDeletionCheckCompletedOnSubtree();  // May delete |this|.
 }
 
-void RenderFrameHostImpl::OnBeforeUnloadACK(
-    bool proceed,
-    const base::TimeTicks& renderer_before_unload_start_time,
-    const base::TimeTicks& renderer_before_unload_end_time) {
-  ProcessBeforeUnloadACK(proceed, false /* treat_as_final_ack */,
-                         renderer_before_unload_start_time,
-                         renderer_before_unload_end_time);
-}
-
 void RenderFrameHostImpl::ProcessBeforeUnloadACK(
     bool proceed,
     bool treat_as_final_ack,
@@ -3612,6 +3601,32 @@
   delegate_->OnDidBlockNavigation(blocked_url, initiator_url, reason);
 }
 
+void RenderFrameHostImpl::DispatchLoad() {
+  TRACE_EVENT1("navigation", "RenderFrameHostImpl::DispatchLoad",
+               "frame_tree_node", frame_tree_node_->frame_tree_node_id());
+
+  // Don't forward the load event if this RFH is pending deletion. This can
+  // happen in a race where this RenderFrameHost finishes loading just after
+  // the frame navigates away. See https://crbug.com/626802.
+  if (!is_active())
+    return;
+
+  // We should never be receiving this message from a speculative RFH.
+  DCHECK(IsCurrent());
+
+  // Only frames with an out-of-process parent frame should be sending this
+  // message.
+  RenderFrameProxyHost* proxy =
+      frame_tree_node()->render_manager()->GetProxyToParent();
+  if (!proxy) {
+    bad_message::ReceivedBadMessage(GetProcess(),
+                                    bad_message::RFH_NO_PROXY_TO_PARENT);
+    return;
+  }
+
+  proxy->GetAssociatedRemoteFrame()->DispatchLoadEventForFrameOwner();
+}
+
 void RenderFrameHostImpl::GoToEntryAtOffset(int32_t offset,
                                             bool has_user_gesture) {
   delegate_->OnGoToEntryAtOffset(this, offset, has_user_gesture);
@@ -3671,32 +3686,6 @@
                                                          resource_timing));
 }
 
-void RenderFrameHostImpl::OnDispatchLoad() {
-  TRACE_EVENT1("navigation", "RenderFrameHostImpl::OnDispatchLoad",
-               "frame_tree_node", frame_tree_node_->frame_tree_node_id());
-
-  // Don't forward the load event if this RFH is pending deletion. This can
-  // happen in a race where this RenderFrameHost finishes loading just after
-  // the frame navigates away. See https://crbug.com/626802.
-  if (!is_active())
-    return;
-
-  // We should never be receiving this message from a speculative RFH.
-  DCHECK(IsCurrent());
-
-  // Only frames with an out-of-process parent frame should be sending this
-  // message.
-  RenderFrameProxyHost* proxy =
-      frame_tree_node()->render_manager()->GetProxyToParent();
-  if (!proxy) {
-    bad_message::ReceivedBadMessage(GetProcess(),
-                                    bad_message::RFH_NO_PROXY_TO_PARENT);
-    return;
-  }
-
-  proxy->GetAssociatedRemoteFrame()->DispatchLoadEventForFrameOwner();
-}
-
 RenderWidgetHostViewBase* RenderFrameHostImpl::GetViewForAccessibility() {
   return static_cast<RenderWidgetHostViewBase*>(
       frame_tree_node_->IsMainFrame()
@@ -5047,7 +5036,7 @@
     // ACKs.
     beforeunload_pending_replies_.insert(rfh);
 
-    rfh->Send(new FrameMsg_BeforeUnload(rfh->GetRoutingID(), is_reload));
+    SendBeforeUnload(is_reload, rfh->GetWeakPtr());
   }
 
   return found_beforeunload;
@@ -7633,6 +7622,24 @@
       base::Unretained(this), navigation_request);
 }
 
+void RenderFrameHostImpl::SendBeforeUnload(
+    bool is_reload,
+    base::WeakPtr<RenderFrameHostImpl> rfh) {
+  auto before_unload_closure = base::BindOnce(
+      [](base::WeakPtr<RenderFrameHostImpl> impl, bool proceed,
+         base::TimeTicks renderer_before_unload_start_time,
+         base::TimeTicks renderer_before_unload_end_time) {
+        if (!impl)
+          return;
+        impl->ProcessBeforeUnloadACK(proceed, false /* treat_as_final_ack */,
+                                     renderer_before_unload_start_time,
+                                     renderer_before_unload_end_time);
+      },
+      rfh);
+  rfh->GetAssociatedLocalFrame()->BeforeUnload(
+      is_reload, std::move(before_unload_closure));
+}
+
 void RenderFrameHostImpl::AddServiceWorkerContainerHost(
     const std::string& uuid,
     base::WeakPtr<content::ServiceWorkerContainerHost> host) {
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index a196d800..9a0f3aa 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -907,6 +907,11 @@
     return frame_host_associated_receiver_;
   }
 
+  mojo::AssociatedReceiver<blink::mojom::LocalFrameHost>&
+  local_frame_host_receiver_for_testing() {
+    return local_frame_host_receiver_;
+  }
+
   mojo::Receiver<blink::mojom::BrowserInterfaceBroker>&
   browser_interface_broker_receiver_for_testing() {
     return broker_receiver_;
@@ -1321,6 +1326,7 @@
       const GURL& blocked_url,
       const GURL& initiator_url,
       blink::mojom::NavigationBlockedReason reason) override;
+  void DispatchLoad() override;
   void GoToEntryAtOffset(int32_t offset, bool has_user_gesture) override;
   void RenderFallbackContentInParentProcess() override;
   void HandleAccessibilityFindInPageResult(
@@ -1385,6 +1391,10 @@
   mojom::NavigationClient::CommitFailedNavigationCallback
   BuildCommitFailedNavigationCallback(NavigationRequest* navigation_request);
 
+  // Protected / virtual so it can be overriden by tests.
+  virtual void SendBeforeUnload(bool is_reload,
+                                base::WeakPtr<RenderFrameHostImpl> impl);
+
  private:
   friend class RenderFrameHostFeaturePolicyTest;
   friend class TestRenderFrameHost;
@@ -1470,10 +1480,6 @@
   void OnDetach();
   void OnOpenURL(const FrameHostMsg_OpenURL_Params& params);
   void OnUpdateState(const PageState& state);
-  void OnBeforeUnloadACK(
-      bool proceed,
-      const base::TimeTicks& renderer_before_unload_start_time,
-      const base::TimeTicks& renderer_before_unload_end_time);
   void OnUnloadACK();
   void OnContextMenu(const ContextMenuParams& params);
   void OnVisualStateResponse(uint64_t id);
@@ -1492,7 +1498,6 @@
                      blink::WebTextDirection title_direction);
   void OnForwardResourceTimingToParent(
       const ResourceTimingInfo& resource_timing);
-  void OnDispatchLoad();
   void OnAccessibilityEvents(
       const AccessibilityHostMsg_EventBundleParams& params,
       int reset_token,
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 5cc68d93..60defe6 100644
--- a/content/browser/frame_host/render_frame_host_impl_browsertest.cc
+++ b/content/browser/frame_host/render_frame_host_impl_browsertest.cc
@@ -48,6 +48,7 @@
 #include "content/test/did_commit_navigation_interceptor.h"
 #include "content/test/frame_host_test_interface.mojom.h"
 #include "content/test/test_content_browser_client.h"
+#include "content/test/test_render_frame_host_factory.h"
 #include "net/base/features.h"
 #include "net/base/net_errors.h"
 #include "net/cookies/cookie_constants.h"
@@ -65,6 +66,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "third_party/blink/public/mojom/browser_interface_broker.mojom-test-utils.h"
 #include "third_party/blink/public/mojom/choosers/file_chooser.mojom.h"
+#include "third_party/blink/public/mojom/frame/frame.mojom-test-utils.h"
 #include "url/gurl.h"
 #include "url/origin.h"
 
@@ -412,20 +414,38 @@
   DISALLOW_COPY_AND_ASSIGN(TestJavaScriptDialogManager);
 };
 
-class DropBeforeUnloadACKFilter : public BrowserMessageFilter {
+// A RenderFrameHostImpl that discards callback for BeforeUnload.
+class RenderFrameHostImplForBeforeUnloadInterceptor
+    : public RenderFrameHostImpl {
  public:
-  DropBeforeUnloadACKFilter() : BrowserMessageFilter(FrameMsgStart) {}
+  using RenderFrameHostImpl::RenderFrameHostImpl;
 
- protected:
-  ~DropBeforeUnloadACKFilter() override {}
-
- private:
-  // BrowserMessageFilter:
-  bool OnMessageReceived(const IPC::Message& message) override {
-    return message.type() == FrameHostMsg_BeforeUnload_ACK::ID;
+  void SendBeforeUnload(bool is_reload,
+                        base::WeakPtr<RenderFrameHostImpl> rfh) override {
+    rfh->GetAssociatedLocalFrame()->BeforeUnload(is_reload, base::DoNothing());
   }
 
-  DISALLOW_COPY_AND_ASSIGN(DropBeforeUnloadACKFilter);
+ private:
+  friend class RenderFrameHostFactoryForBeforeUnloadInterceptor;
+};
+
+class RenderFrameHostFactoryForBeforeUnloadInterceptor
+    : public TestRenderFrameHostFactory {
+ protected:
+  std::unique_ptr<RenderFrameHostImpl> CreateRenderFrameHost(
+      SiteInstance* site_instance,
+      scoped_refptr<RenderViewHostImpl> render_view_host,
+      RenderFrameHostDelegate* delegate,
+      FrameTree* frame_tree,
+      FrameTreeNode* frame_tree_node,
+      int32_t routing_id,
+      int32_t widget_routing_id,
+      bool renderer_initiated_creation) override {
+    return base::WrapUnique(new RenderFrameHostImplForBeforeUnloadInterceptor(
+        site_instance, std::move(render_view_host), delegate, frame_tree,
+        frame_tree_node, routing_id, widget_routing_id,
+        renderer_initiated_creation));
+  }
 };
 
 mojo::ScopedMessagePipeHandle CreateDisconnectedMessagePipeHandle() {
@@ -445,6 +465,8 @@
 #endif
 IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest,
                        MAYBE_IframeBeforeUnloadParentHang) {
+  RenderFrameHostFactoryForBeforeUnloadInterceptor interceptor;
+
   WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
   TestJavaScriptDialogManager dialog_manager;
   wc->SetDelegate(&dialog_manager);
@@ -473,12 +495,6 @@
       static_cast<RenderFrameHostImpl*>(wc->GetMainFrame());
   EXPECT_TRUE(main_frame->is_waiting_for_beforeunload_ack());
 
-  // Set up a filter to make sure that when the dialog is answered below and the
-  // renderer sends the beforeunload ACK, it gets... ahem... lost.
-  scoped_refptr<DropBeforeUnloadACKFilter> filter =
-      new DropBeforeUnloadACKFilter();
-  main_frame->GetProcess()->AddFilter(filter.get());
-
   // Answer the dialog.
   dialog_manager.Run(true, base::string16());
 
diff --git a/content/browser/frame_host/render_frame_host_manager_unittest.cc b/content/browser/frame_host/render_frame_host_manager_unittest.cc
index 3f0bc73a..d5eadca 100644
--- a/content/browser/frame_host/render_frame_host_manager_unittest.cc
+++ b/content/browser/frame_host/render_frame_host_manager_unittest.cc
@@ -1756,7 +1756,6 @@
   const GURL kUrl1("http://www.google.com/");
   const GURL kUrl2 = isolated_cross_site_url();
   RenderFrameHostImpl* pending_rfh = nullptr;
-  base::TimeTicks now = base::TimeTicks::Now();
 
   // Navigate to the first page.
   contents()->NavigateAndCommit(kUrl1);
@@ -1771,8 +1770,7 @@
     RenderFrameDeletedObserver rfh_deleted_observer(pending_rfh);
 
     // Cancel the navigation by simulating a declined beforeunload dialog.
-    contents()->GetMainFrame()->OnMessageReceived(
-        FrameHostMsg_BeforeUnload_ACK(0, false, now, now));
+    contents()->GetMainFrame()->SendBeforeUnloadACK(false);
     EXPECT_FALSE(contents()->CrossProcessNavigationPending());
 
     // Since the pending RFH is the only one for the new SiteInstance, it should
@@ -1794,8 +1792,7 @@
         pending_rfh->GetSiteInstance();
     site_instance->IncrementActiveFrameCount();
 
-    contents()->GetMainFrame()->OnMessageReceived(
-        FrameHostMsg_BeforeUnload_ACK(0, false, now, now));
+    contents()->GetMainFrame()->SendBeforeUnloadACK(false);
     EXPECT_FALSE(contents()->CrossProcessNavigationPending());
 
     EXPECT_TRUE(rfh_deleted_observer.deleted());
diff --git a/content/browser/service_worker/service_worker_client_utils.cc b/content/browser/service_worker/service_worker_client_utils.cc
index 8658a6c..d65f0d5 100644
--- a/content/browser/service_worker/service_worker_client_utils.cc
+++ b/content/browser/service_worker/service_worker_client_utils.cc
@@ -140,8 +140,8 @@
   return blink::mojom::ServiceWorkerClientInfo::New(
       render_frame_host->GetLastCommittedURL(),
       render_frame_host->GetParent()
-          ? network::mojom::RequestContextFrameType::kNested
-          : network::mojom::RequestContextFrameType::kTopLevel,
+          ? blink::mojom::RequestContextFrameType::kNested
+          : blink::mojom::RequestContextFrameType::kTopLevel,
       client_uuid, blink::mojom::ServiceWorkerClientType::kWindow, page_hidden,
       render_frame_host->IsFocused(),
       render_frame_host->IsFrozen()
@@ -348,7 +348,7 @@
   // TODO(dtapuska): Need to get frozen state for dedicated workers from
   // DedicatedWorkerHost. crbug.com/968417
   auto client_info = blink::mojom::ServiceWorkerClientInfo::New(
-      container_host->url(), network::mojom::RequestContextFrameType::kNone,
+      container_host->url(), blink::mojom::RequestContextFrameType::kNone,
       container_host->client_uuid(), host_client_type,
       /*page_hidden=*/true,
       /*is_focused=*/false,
@@ -629,7 +629,7 @@
   // TODO(dtapuska): Need to get frozen state for dedicated workers from
   // DedicatedWorkerHost. crbug.com/968417
   auto client_info = blink::mojom::ServiceWorkerClientInfo::New(
-      container_host->url(), network::mojom::RequestContextFrameType::kNone,
+      container_host->url(), blink::mojom::RequestContextFrameType::kNone,
       container_host->client_uuid(), container_host->client_type(),
       /*page_hidden=*/true,
       /*is_focused=*/false,
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 38a5e38e..a4aac9e 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -122,6 +122,7 @@
 #include "third_party/blink/public/common/feature_policy/policy_value.h"
 #include "third_party/blink/public/common/frame/sandbox_flags.h"
 #include "third_party/blink/public/common/input/web_input_event.h"
+#include "third_party/blink/public/mojom/frame/frame.mojom-test-utils.h"
 #include "third_party/blink/public/platform/web_insecure_request_policy.h"
 #include "ui/display/display_switches.h"
 #include "ui/display/screen.h"
@@ -8438,21 +8439,27 @@
   EXPECT_EQ(child2_last_url, child2->current_url());
 }
 
-// A BrowserMessageFilter that drops FrameHostMsg_OnDispatchLoad messages.
-class DispatchLoadMessageFilter : public BrowserMessageFilter {
+// Intercepts calls to LocalFrameHost::DispatchLoad method(), and discards them.
+class DispatchLoadInterceptor
+    : public blink::mojom::LocalFrameHostInterceptorForTesting {
  public:
-  DispatchLoadMessageFilter() : BrowserMessageFilter(FrameMsgStart) {}
-
- protected:
-  ~DispatchLoadMessageFilter() override {}
-
- private:
-  // BrowserMessageFilter:
-  bool OnMessageReceived(const IPC::Message& message) override {
-    return message.type() == FrameHostMsg_DispatchLoad::ID;
+  explicit DispatchLoadInterceptor(RenderFrameHostImpl* render_frame_host)
+      : render_frame_host_(render_frame_host) {
+    render_frame_host_->local_frame_host_receiver_for_testing()
+        .SwapImplForTesting(this);
   }
 
-  DISALLOW_COPY_AND_ASSIGN(DispatchLoadMessageFilter);
+  ~DispatchLoadInterceptor() override = default;
+
+  LocalFrameHost* GetForwardingInterface() override {
+    return render_frame_host_;
+  }
+
+  // Discard incoming calls to LocalFrameHost::DispatchLoad().
+  void DispatchLoad() override {}
+
+ private:
+  RenderFrameHostImpl* render_frame_host_;
 };
 
 // Test that the renderer isn't killed when a frame generates a load event just
@@ -8470,13 +8477,6 @@
   Shell* popup_shell = OpenPopup(root, popup_url, "foo");
   EXPECT_TRUE(popup_shell);
 
-  // Install a filter to drop DispatchLoad messages from b.com.
-  scoped_refptr<DispatchLoadMessageFilter> filter =
-      new DispatchLoadMessageFilter();
-  RenderProcessHost* b_process =
-      popup_shell->web_contents()->GetMainFrame()->GetProcess();
-  b_process->AddFilter(filter.get());
-
   // Navigate subframe to b.com.  Wait for commit but not full load.
   GURL b_url(embedded_test_server()->GetURL("b.com", "/title2.html"));
   {
@@ -8491,6 +8491,9 @@
   // SiteInstance, a.com.
   EXPECT_TRUE(child->render_manager()->GetProxyToParent());
 
+  // Intercept calls to the LocalFrameHost::DispatchLoad() method.
+  DispatchLoadInterceptor interceptor(child_rfh);
+
   // Now, go back to a.com in the subframe and wait for commit.
   {
     TestFrameNavigationObserver commit_observer(child);
@@ -8505,9 +8508,9 @@
 
   // Simulate that the load event is dispatched from |child_rfh| just after
   // it's become pending deletion.
-  child_rfh->OnDispatchLoad();
+  child_rfh->DispatchLoad();
 
-  // In the bug, OnDispatchLoad killed the b.com renderer.  Ensure that this is
+  // In the bug, DispatchLoad killed the b.com renderer.  Ensure that this is
   // not the case. Note that the process kill doesn't happen immediately, so
   // IsRenderFrameLive() can't be checked here (yet).  Instead, check that
   // JavaScript can still execute in b.com using the popup.
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc
index 3bf6e33b..fd564ed6 100644
--- a/content/browser/web_contents/web_contents_impl_unittest.cc
+++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -1071,9 +1071,7 @@
   controller().LoadURL(
       url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
   EXPECT_TRUE(orig_rfh->is_waiting_for_beforeunload_ack());
-  base::TimeTicks now = base::TimeTicks::Now();
-  orig_rfh->OnMessageReceived(
-      FrameHostMsg_BeforeUnload_ACK(0, false, now, now));
+  orig_rfh->SendBeforeUnloadACK(false);
   EXPECT_FALSE(orig_rfh->is_waiting_for_beforeunload_ack());
   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
   EXPECT_EQ(orig_rfh, main_test_rfh());
diff --git a/content/common/fetch/fetch_api_request_proto.cc b/content/common/fetch/fetch_api_request_proto.cc
index 52e33c1..669d8dd 100644
--- a/content/common/fetch/fetch_api_request_proto.cc
+++ b/content/common/fetch/fetch_api_request_proto.cc
@@ -50,7 +50,7 @@
   request_ptr->request_context_type =
       static_cast<blink::mojom::RequestContextType>(
           request_proto.request_context_type());
-  request_ptr->frame_type = network::mojom::RequestContextFrameType::kNone;
+  request_ptr->frame_type = blink::mojom::RequestContextFrameType::kNone;
   request_ptr->url = GURL(request_proto.url());
   request_ptr->method = request_proto.method();
   request_ptr->headers = {request_proto.headers().begin(),
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index 16726ba..ffa77f0 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -658,10 +658,6 @@
 // commit, activation and frame swap of the current DOM tree in blink.
 IPC_MESSAGE_ROUTED1(FrameMsg_VisualStateRequest, uint64_t /* id */)
 
-// Instructs the renderer to invoke the frame's beforeunload event handler.
-// Expects the result to be returned via FrameHostMsg_BeforeUnload_ACK.
-IPC_MESSAGE_ROUTED1(FrameMsg_BeforeUnload, bool /* is_reload */)
-
 // Requests that a provisional RenderFrame swap itself into the frame tree,
 // replacing the RenderFrameProxy that it is associated with.  This is used
 // with remote-to-local frame navigations when the RenderFrameProxy corresponds
@@ -1051,14 +1047,6 @@
                      bool /* is_throttled */)
 #endif  // BUILDFLAG(ENABLE_PLUGINS)
 
-// Provides the result from handling BeforeUnload.  |proceed| matches the return
-// value of the frame's beforeunload handler: true if the user decided to
-// proceed with leaving the page.
-IPC_MESSAGE_ROUTED3(FrameHostMsg_BeforeUnload_ACK,
-                    bool /* proceed */,
-                    base::TimeTicks /* before_unload_start_time */,
-                    base::TimeTicks /* before_unload_end_time */)
-
 // Indicates that the current frame has finished running its unload handler (if
 // one was registered) and has been detached, as a response to
 // UnfreezableFrameMsg_Unload message from the browser process.
@@ -1151,10 +1139,6 @@
 IPC_MESSAGE_ROUTED1(FrameHostMsg_ForwardResourceTimingToParent,
                     content::ResourceTimingInfo)
 
-// Dispatch a load event for this frame in the iframe element of an
-// out-of-process parent frame.
-IPC_MESSAGE_ROUTED0(FrameHostMsg_DispatchLoad)
-
 // Sent to the browser from a frame proxy to post a message to the frame's
 // active renderer.
 IPC_MESSAGE_ROUTED1(FrameHostMsg_RouteMessageEvent,
diff --git a/content/public/browser/shared_worker_instance.h b/content/public/browser/shared_worker_instance.h
index c52b6953..0d3657b 100644
--- a/content/public/browser/shared_worker_instance.h
+++ b/content/public/browser/shared_worker_instance.h
@@ -82,9 +82,11 @@
   int64_t id_;
 
   GURL url_;
-  // Used for fetching the top-level worker script.
   blink::mojom::ScriptType script_type_;
+
+  // Used for fetching the top-level worker script.
   network::mojom::CredentialsMode credentials_mode_;
+
   std::string name_;
 
   // The origin of the document that created this shared worker instance. Used
diff --git a/content/public/test/fake_local_frame.cc b/content/public/test/fake_local_frame.cc
index ab3d312..fe689d5 100644
--- a/content/public/test/fake_local_frame.cc
+++ b/content/public/test/fake_local_frame.cc
@@ -52,6 +52,12 @@
 
 void FakeLocalFrame::RenderFallbackContent() {}
 
+void FakeLocalFrame::BeforeUnload(bool is_reload,
+                                  BeforeUnloadCallback callback) {
+  base::TimeTicks now = base::TimeTicks::Now();
+  std::move(callback).Run(true /*leave the page*/, now, now);
+}
+
 void FakeLocalFrame::BindFrameHostReceiver(
     mojo::ScopedInterfaceEndpointHandle handle) {
   receiver_.Bind(mojo::PendingAssociatedReceiver<blink::mojom::LocalFrame>(
diff --git a/content/public/test/fake_local_frame.h b/content/public/test/fake_local_frame.h
index 0681816..32f2347 100644
--- a/content/public/test/fake_local_frame.h
+++ b/content/public/test/fake_local_frame.h
@@ -47,6 +47,7 @@
   void ReportBlinkFeatureUsage(
       const std::vector<blink::mojom::WebFeature>&) override;
   void RenderFallbackContent() override;
+  void BeforeUnload(bool is_reload, BeforeUnloadCallback callback) override;
 
  private:
   void BindFrameHostReceiver(mojo::ScopedInterfaceEndpointHandle handle);
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 6d4992c..7d87d78 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -2181,7 +2181,6 @@
 
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(RenderFrameImpl, msg)
-    IPC_MESSAGE_HANDLER(FrameMsg_BeforeUnload, OnBeforeUnload)
     IPC_MESSAGE_HANDLER(UnfreezableFrameMsg_Unload, OnUnload)
     IPC_MESSAGE_HANDLER(FrameMsg_SwapIn, OnSwapIn)
     IPC_MESSAGE_HANDLER(FrameMsg_Stop, OnStop)
@@ -2286,26 +2285,6 @@
   navigation_client_impl_->Bind(std::move(receiver));
 }
 
-void RenderFrameImpl::OnBeforeUnload(bool is_reload) {
-  TRACE_EVENT1("navigation,rail", "RenderFrameImpl::OnBeforeUnload",
-               "id", routing_id_);
-  // Save the routing_id, as the RenderFrameImpl can be deleted in
-  // dispatchBeforeUnloadEvent. See https://crbug.com/666714 for details.
-  int routing_id = routing_id_;
-
-  base::TimeTicks before_unload_start_time = base::TimeTicks::Now();
-
-  // This will execute the BeforeUnload event in this frame and all of its
-  // local descendant frames, including children of remote frames.  The browser
-  // process will send separate IPCs to dispatch beforeunload in any
-  // out-of-process child frames.
-  bool proceed = frame_->DispatchBeforeUnloadEvent(is_reload);
-
-  base::TimeTicks before_unload_end_time = base::TimeTicks::Now();
-  RenderThread::Get()->Send(new FrameHostMsg_BeforeUnload_ACK(
-      routing_id, proceed, before_unload_start_time, before_unload_end_time));
-}
-
 // Unload this RenderFrame so the frame can navigate to a document rendered by
 // a different process. We also allow this process to exit if there are no other
 // active RenderFrames in it.
@@ -4795,10 +4774,6 @@
       routing_id_, WebResourceTimingInfoToResourceTimingInfo(info)));
 }
 
-void RenderFrameImpl::DispatchLoad() {
-  Send(new FrameHostMsg_DispatchLoad(routing_id_));
-}
-
 base::UnguessableToken RenderFrameImpl::GetDevToolsFrameToken() {
   return devtools_frame_token_;
 }
@@ -5943,21 +5918,11 @@
     }
   }
 
-  bool should_dispatch_before_unload =
-      info->navigation_policy == blink::kWebNavigationPolicyCurrentTab &&
-      // No need to dispatch beforeunload if the frame has not committed a
-      // navigation and contains an empty initial document.
-      // TODO(dtapuska): crbug.com/1040954 Try to remove the
-      // HasAccessedInitialDocument interface for this. There shouldn't be a
-      // beforeunload handler if it hasn't accessed the initial document so it
-      // should be fine to dispatch in those cases.
-      (frame_->HasAccessedInitialDocument() || !current_history_item_.IsNull());
-
-  if (should_dispatch_before_unload) {
+  if (info->navigation_policy == blink::kWebNavigationPolicyCurrentTab) {
     // Execute the BeforeUnload event. If asked not to proceed or the frame is
     // destroyed, ignore the navigation.
     // Keep a WeakPtr to this RenderFrameHost to detect if executing the
-    // BeforeUnload event destriyed this frame.
+    // BeforeUnload event destroyed this frame.
     base::WeakPtr<RenderFrameImpl> weak_self = weak_factory_.GetWeakPtr();
 
     if (!frame_->DispatchBeforeUnloadEvent(info->navigation_type ==
@@ -6507,7 +6472,7 @@
 
   // Set SiteForCookies.
   WebDocument frame_document = frame_->GetDocument();
-  if (info->frame_type == network::mojom::RequestContextFrameType::kTopLevel)
+  if (info->frame_type == blink::mojom::RequestContextFrameType::kTopLevel)
     request.SetSiteForCookies(net::SiteForCookies::FromUrl(request.Url()));
   else
     request.SetSiteForCookies(frame_document.SiteForCookies());
@@ -6551,10 +6516,9 @@
   DCHECK_EQ(network::mojom::RedirectMode::kManual,
             info->url_request.GetRedirectMode());
   DCHECK(frame_->Parent() ||
-         info->frame_type ==
-             network::mojom::RequestContextFrameType::kTopLevel);
+         info->frame_type == blink::mojom::RequestContextFrameType::kTopLevel);
   DCHECK(!frame_->Parent() ||
-         info->frame_type == network::mojom::RequestContextFrameType::kNested);
+         info->frame_type == blink::mojom::RequestContextFrameType::kNested);
 
   bool is_form_submission =
       info->navigation_type == blink::kWebNavigationTypeFormSubmitted ||
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 263784c6..ca41e58a 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -737,7 +737,6 @@
   void DidUpdateCurrentHistoryItem() override;
   void ForwardResourceTimingToParent(
       const blink::WebResourceTimingInfo& info) override;
-  void DispatchLoad() override;
   base::UnguessableToken GetDevToolsFrameToken() override;
   void AbortClientNavigation() override;
   void DidChangeSelection(bool is_empty_selection) override;
@@ -1053,7 +1052,6 @@
   //
   // The documentation for these functions should be in
   // content/common/*_messages.h for the message that the function is handling.
-  void OnBeforeUnload(bool is_reload);
   void OnSwapIn();
   void OnUnload(int proxy_routing_id,
                 bool is_loading,
diff --git a/content/renderer/render_view_browsertest.cc b/content/renderer/render_view_browsertest.cc
index a3f10cf..b9c20b11 100644
--- a/content/renderer/render_view_browsertest.cc
+++ b/content/renderer/render_view_browsertest.cc
@@ -839,7 +839,7 @@
   auto navigation_info = std::make_unique<blink::WebNavigationInfo>();
   navigation_info->url_request = request;
   navigation_info->frame_type =
-      network::mojom::RequestContextFrameType::kTopLevel;
+      blink::mojom::RequestContextFrameType::kTopLevel;
   navigation_info->navigation_type = blink::kWebNavigationTypeLinkClicked;
   navigation_info->navigation_policy = blink::kWebNavigationPolicyCurrentTab;
   DCHECK(!navigation_info->url_request.RequestorOrigin().IsNull());
@@ -858,7 +858,7 @@
   form_navigation_info->url_request.SetHttpBody(post_body);
   form_navigation_info->url_request.SetRequestorOrigin(requestor_origin);
   form_navigation_info->frame_type =
-      network::mojom::RequestContextFrameType::kTopLevel;
+      blink::mojom::RequestContextFrameType::kTopLevel;
   form_navigation_info->navigation_type =
       blink::kWebNavigationTypeFormSubmitted;
   form_navigation_info->navigation_policy =
@@ -874,7 +874,7 @@
   popup_navigation_info->url_request = blink::WebURLRequest(GetWebUIURL("foo"));
   popup_navigation_info->url_request.SetRequestorOrigin(requestor_origin);
   popup_navigation_info->frame_type =
-      network::mojom::RequestContextFrameType::kAuxiliary;
+      blink::mojom::RequestContextFrameType::kAuxiliary;
   popup_navigation_info->navigation_type = blink::kWebNavigationTypeLinkClicked;
   popup_navigation_info->navigation_policy =
       blink::kWebNavigationPolicyNewForegroundTab;
@@ -904,7 +904,7 @@
     navigation_info->url_request.SetRequestorOrigin(
         blink::WebSecurityOrigin::Create(GURL("http://foo.com")));
     navigation_info->frame_type =
-        network::mojom::RequestContextFrameType::kTopLevel;
+        blink::mojom::RequestContextFrameType::kTopLevel;
     navigation_info->navigation_policy = blink::kWebNavigationPolicyCurrentTab;
     navigation_info->navigation_type = kNavTypes[i];
 
@@ -927,7 +927,7 @@
   navigation_info->url_request = blink::WebURLRequest(GURL("http://foo.com"));
   navigation_info->url_request.SetRequestorOrigin(requestor_origin);
   navigation_info->frame_type =
-      network::mojom::RequestContextFrameType::kTopLevel;
+      blink::mojom::RequestContextFrameType::kTopLevel;
   navigation_info->navigation_type = blink::kWebNavigationTypeLinkClicked;
   navigation_info->navigation_policy = blink::kWebNavigationPolicyCurrentTab;
 
@@ -941,7 +941,7 @@
   webui_navigation_info->url_request = blink::WebURLRequest(GetWebUIURL("foo"));
   webui_navigation_info->url_request.SetRequestorOrigin(requestor_origin);
   webui_navigation_info->frame_type =
-      network::mojom::RequestContextFrameType::kTopLevel;
+      blink::mojom::RequestContextFrameType::kTopLevel;
   webui_navigation_info->navigation_type = blink::kWebNavigationTypeLinkClicked;
   webui_navigation_info->navigation_policy =
       blink::kWebNavigationPolicyCurrentTab;
@@ -961,7 +961,7 @@
   post_body.AppendData("blah");
   data_navigation_info->url_request.SetHttpBody(post_body);
   data_navigation_info->frame_type =
-      network::mojom::RequestContextFrameType::kTopLevel;
+      blink::mojom::RequestContextFrameType::kTopLevel;
   data_navigation_info->navigation_type =
       blink::kWebNavigationTypeFormSubmitted;
   data_navigation_info->navigation_policy =
@@ -985,7 +985,7 @@
   auto popup_navigation_info = std::make_unique<blink::WebNavigationInfo>();
   popup_navigation_info->url_request = popup_request;
   popup_navigation_info->frame_type =
-      network::mojom::RequestContextFrameType::kAuxiliary;
+      blink::mojom::RequestContextFrameType::kAuxiliary;
   popup_navigation_info->navigation_type = blink::kWebNavigationTypeLinkClicked;
   popup_navigation_info->navigation_policy =
       blink::kWebNavigationPolicyNewForegroundTab;
@@ -2545,8 +2545,7 @@
       })));
 
   // Simulate a BeforeUnload IPC received from the browser.
-  frame()->OnMessageReceived(
-      FrameMsg_BeforeUnload(frame()->GetRoutingID(), false));
+  frame()->SimulateBeforeUnload(false);
 
   run_loop.Run();
   ASSERT_TRUE(was_callback_run);
diff --git a/content/test/test_render_frame.cc b/content/test/test_render_frame.cc
index cc1f1ff..2691e4bc1 100644
--- a/content/test/test_render_frame.cc
+++ b/content/test/test_render_frame.cc
@@ -372,6 +372,14 @@
   return mock_frame_host_->TakeLastBrowserInterfaceBrokerReceiver();
 }
 
+void TestRenderFrame::SimulateBeforeUnload(bool is_reload) {
+  // This will execute the BeforeUnload event in this frame and all of its
+  // local descendant frames, including children of remote frames. The browser
+  // process will send separate IPCs to dispatch beforeunload in any
+  // out-of-process child frames.
+  frame_->DispatchBeforeUnloadEvent(is_reload);
+}
+
 mojom::FrameHost* TestRenderFrame::GetFrameHost() {
   // Need to mock this interface directly without going through a binding,
   // otherwise calling its sync methods could lead to a deadlock.
diff --git a/content/test/test_render_frame.h b/content/test/test_render_frame.h
index 30da550..0a89db9 100644
--- a/content/test/test_render_frame.h
+++ b/content/test/test_render_frame.h
@@ -82,6 +82,8 @@
   mojo::PendingReceiver<blink::mojom::BrowserInterfaceBroker>
   TakeLastBrowserInterfaceBrokerReceiver();
 
+  void SimulateBeforeUnload(bool is_reload);
+
  private:
   explicit TestRenderFrame(RenderFrameImpl::CreateParams params);
 
diff --git a/content/test/test_render_frame_host.cc b/content/test/test_render_frame_host.cc
index 97645b1..21ae1f2 100644
--- a/content/test/test_render_frame_host.cc
+++ b/content/test/test_render_frame_host.cc
@@ -211,7 +211,7 @@
 
 void TestRenderFrameHost::SendBeforeUnloadACK(bool proceed) {
   base::TimeTicks now = base::TimeTicks::Now();
-  OnBeforeUnloadACK(proceed, now, now);
+  ProcessBeforeUnloadACK(proceed, false /* treat_as_final_ack */, now, now);
 }
 
 void TestRenderFrameHost::SimulateUnloadACK() {
diff --git a/docs/mac_build_instructions.md b/docs/mac_build_instructions.md
index 389a1fe..71a926b0 100644
--- a/docs/mac_build_instructions.md
+++ b/docs/mac_build_instructions.md
@@ -12,16 +12,16 @@
 
 ## System requirements
 
-*   A 64-bit Mac running 10.12+.
-*   [Xcode](https://developer.apple.com/xcode) 8+
-*   The OS X 10.12 SDK. Run
+*   A 64-bit Mac running 10.13+.
+*   [Xcode](https://developer.apple.com/xcode) 10+
+*   The OS X 10.14 SDK. Run
 
     ```shell
     $ ls `xcode-select -p`/Platforms/MacOSX.platform/Developer/SDKs
     ```
 
     to check whether you have it.  Building with a newer SDK works too, but
-    the releases currently use the 10.12 SDK.
+    the releases currently use the 10.14 SDK.
 
 ## Install `depot_tools`
 
diff --git a/google_apis/google_api_keys.cc b/google_apis/google_api_keys.cc
index ff46314..c271426 100644
--- a/google_apis/google_api_keys.cc
+++ b/google_apis/google_api_keys.cc
@@ -83,6 +83,11 @@
 #define GOOGLE_API_KEY_REMOTING DUMMY_API_TOKEN
 #endif
 
+// API key for SharingService.
+#if !defined(GOOGLE_API_KEY_SHARING)
+#define GOOGLE_API_KEY_SHARING DUMMY_API_TOKEN
+#endif
+
 // These are used as shortcuts for developers and users providing
 // OAuth credentials via preprocessor defines or environment
 // variables.  If set, they will be used to replace any of the client
@@ -126,6 +131,10 @@
         STRINGIZE_NO_EXPANSION(GOOGLE_API_KEY_REMOTING), nullptr, std::string(),
         environment.get(), command_line);
 
+    api_key_sharing_ = CalculateKeyValue(
+        GOOGLE_API_KEY_SHARING, STRINGIZE_NO_EXPANSION(GOOGLE_API_KEY_SHARING),
+        nullptr, std::string(), environment.get(), command_line);
+
     metrics_key_ = CalculateKeyValue(
         GOOGLE_METRICS_SIGNING_KEY,
         STRINGIZE_NO_EXPANSION(GOOGLE_METRICS_SIGNING_KEY), nullptr,
@@ -195,6 +204,7 @@
 #endif
   std::string api_key_non_stable() const { return api_key_non_stable_; }
   std::string api_key_remoting() const { return api_key_remoting_; }
+  std::string api_key_sharing() const { return api_key_sharing_; }
 
   std::string metrics_key() const { return metrics_key_; }
 
@@ -293,6 +303,7 @@
   std::string api_key_;
   std::string api_key_non_stable_;
   std::string api_key_remoting_;
+  std::string api_key_sharing_;
   std::string metrics_key_;
   std::string client_ids_[CLIENT_NUM_ITEMS];
   std::string client_secrets_[CLIENT_NUM_ITEMS];
@@ -317,6 +328,10 @@
   return g_api_key_cache.Get().api_key_remoting();
 }
 
+std::string GetSharingAPIKey() {
+  return g_api_key_cache.Get().api_key_sharing();
+}
+
 #if defined(OS_IOS)
 void SetAPIKey(const std::string& api_key) {
   g_api_key_cache.Get().set_api_key(api_key);
diff --git a/google_apis/google_api_keys.h b/google_apis/google_api_keys.h
index 255b753c..590e3c1e 100644
--- a/google_apis/google_api_keys.h
+++ b/google_apis/google_api_keys.h
@@ -76,6 +76,9 @@
 // Retrieves the Chrome Remote Desktop API key.
 std::string GetRemotingAPIKey();
 
+// Retrieves the Sharing API Key.
+std::string GetSharingAPIKey();
+
 #if defined(OS_IOS)
 // Sets the API key. This should be called as early as possible before this
 // API key is even accessed.
diff --git a/gpu/ipc/service/gpu_init.cc b/gpu/ipc/service/gpu_init.cc
index 433a6bd7..04883fc 100644
--- a/gpu/ipc/service/gpu_init.cc
+++ b/gpu/ipc/service/gpu_init.cc
@@ -221,6 +221,11 @@
   delayed_watchdog_enable = true;
 #endif
 
+  // PreSandbox is mainly for resource handling and not related to the GPU
+  // driver, it doesn't need the GPU watchdog. The loadLibrary may take long
+  // time that killing and restarting the GPU process will not help.
+  sandbox_helper_->PreSandboxStartup();
+
   // Start the GPU watchdog only after anything that is expected to be time
   // consuming has completed, otherwise the process is liable to be aborted.
   if (enable_watchdog && !delayed_watchdog_enable) {
@@ -303,14 +308,6 @@
       return false;
     }
 
-    // The ContentSandboxHelper is currently the only one implementation of
-    // gpu::GpuSandboxHelper and it has no dependency. Except on Linux where
-    // VaapiWrapper checks the GL implementation to determine which display
-    // to use. So call PreSandboxStartup after GL initialization. But make
-    // sure the watchdog is still in pause as loadLibrary may take a long time
-    // and restarting the GPU process will not help.
-    sandbox_helper_->PreSandboxStartup();
-
     if (watchdog_thread_)
       watchdog_thread_->ResumeWatchdog();
     if (gl::GetGLImplementation() != gl::kGLImplementationDisabled) {
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm
index 2e9bdda..6c46ae2 100644
--- a/ios/chrome/browser/flags/about_flags.mm
+++ b/ios/chrome/browser/flags/about_flags.mm
@@ -597,6 +597,10 @@
      flag_descriptions::kSSLCommittedInterstitialsName,
      flag_descriptions::kSSLCommittedInterstitialsDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(web::features::kSSLCommittedInterstitials)},
+    {"change-tab-switcher-position",
+     flag_descriptions::kChangeTabSwitcherPositionName,
+     flag_descriptions::kChangeTabSwitcherPositionDescription, flags_ui::kOsIos,
+     FEATURE_VALUE_TYPE(kChangeTabSwitcherPosition)},
 };
 
 // Add all switches from experimental flags to |command_line|.
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
index e2afe0c..e095e6e 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -126,6 +126,12 @@
     "presented with the option to clear synced data from the local "
     "device when signing out.";
 
+extern const char kChangeTabSwitcherPositionName[] =
+    "Change tab switcher button position";
+extern const char kChangeTabSwitcherPositionDescription[] =
+    "When enable, the tab switcher button position changes from tab strip to "
+    "toolbar and bookmark button is removed.";
+
 const char kCollectionsCardPresentationStyleName[] =
     "Card style presentation for Collections.";
 const char kCollectionsCardPresentationStyleDescription[] =
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
index 16b5fa8..568cf0a8 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -98,6 +98,10 @@
 extern const char kClearSyncedDataName[];
 extern const char kClearSyncedDataDescription[];
 
+// Title and description for the flag that controls the tab switcher position.
+extern const char kChangeTabSwitcherPositionName[];
+extern const char kChangeTabSwitcherPositionDescription[];
+
 // Title and description for the flag that controls whether Collections are
 // presented using the new iOS13 Card style or the custom legacy one.
 extern const char kCollectionsCardPresentationStyleName[];
diff --git a/ios/chrome/browser/gcm/instance_id/ios_chrome_instance_id_profile_service_factory.h b/ios/chrome/browser/gcm/instance_id/ios_chrome_instance_id_profile_service_factory.h
index cd526331..245d29d7 100644
--- a/ios/chrome/browser/gcm/instance_id/ios_chrome_instance_id_profile_service_factory.h
+++ b/ios/chrome/browser/gcm/instance_id/ios_chrome_instance_id_profile_service_factory.h
@@ -10,15 +10,12 @@
 #include "base/macros.h"
 #include "base/no_destructor.h"
 #include "components/keyed_service/ios/browser_state_keyed_service_factory.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state_forward.h"
 
 namespace instance_id {
 class InstanceIDProfileService;
 }
 
-namespace ios {
-class ChromeBrowserState;
-}
-
 // Singleton that owns all InstanceIDProfileService and associates them with
 // ios::ChromeBrowserState.
 class IOSChromeInstanceIDProfileServiceFactory
diff --git a/ios/chrome/browser/gcm/ios_chrome_gcm_profile_service_factory.h b/ios/chrome/browser/gcm/ios_chrome_gcm_profile_service_factory.h
index 50906de..1399b037 100644
--- a/ios/chrome/browser/gcm/ios_chrome_gcm_profile_service_factory.h
+++ b/ios/chrome/browser/gcm/ios_chrome_gcm_profile_service_factory.h
@@ -11,15 +11,12 @@
 #include "base/macros.h"
 #include "base/no_destructor.h"
 #include "components/keyed_service/ios/browser_state_keyed_service_factory.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state_forward.h"
 
 namespace gcm {
 class GCMProfileService;
 }
 
-namespace ios {
-class ChromeBrowserState;
-}
-
 // Singleton that owns all GCMProfileService and associates them with
 // ios::ChromeBrowserState.
 class IOSChromeGCMProfileServiceFactory
diff --git a/ios/chrome/browser/ui/bubble/BUILD.gn b/ios/chrome/browser/ui/bubble/BUILD.gn
index ad8adbc..a3b527d7 100644
--- a/ios/chrome/browser/ui/bubble/BUILD.gn
+++ b/ios/chrome/browser/ui/bubble/BUILD.gn
@@ -27,6 +27,7 @@
     "//ios/chrome/browser/feature_engagement",
     "//ios/chrome/browser/ui/colors",
     "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/toolbar/public:feature_flags",
     "//ios/chrome/browser/ui/util",
     "//ios/chrome/common",
     "//ios/chrome/common/colors",
diff --git a/ios/chrome/browser/ui/bubble/bubble_presenter.mm b/ios/chrome/browser/ui/bubble/bubble_presenter.mm
index 211e870..60485e7 100644
--- a/ios/chrome/browser/ui/bubble/bubble_presenter.mm
+++ b/ios/chrome/browser/ui/bubble/bubble_presenter.mm
@@ -18,6 +18,7 @@
 #import "ios/chrome/browser/ui/bubble/bubble_util.h"
 #import "ios/chrome/browser/ui/bubble/bubble_view_controller_presenter.h"
 #import "ios/chrome/browser/ui/commands/toolbar_commands.h"
+#import "ios/chrome/browser/ui/toolbar/public/features.h"
 #import "ios/chrome/browser/ui/util/named_guide.h"
 #import "ios/chrome/browser/ui/util/named_guide_util.h"
 #include "ios/chrome/browser/ui/util/ui_util.h"
@@ -184,7 +185,8 @@
   NSString* text =
       l10n_util::GetNSString(IDS_IOS_LONG_PRESS_TOOLBAR_IPH_PROMOTION_TEXT);
   CGPoint searchButtonAnchor =
-      IsRegularXRegularSizeClass()
+      IsRegularXRegularSizeClass() &&
+              !base::FeatureList::IsEnabled(kChangeTabSwitcherPosition)
           ? [self anchorPointToGuide:kTabStripTabSwitcherGuide
                            direction:arrowDirection]
           : [self anchorPointToGuide:kTabSwitcherGuide
@@ -288,7 +290,8 @@
   NSString* text =
       l10n_util::GetNSStringWithFixup(IDS_IOS_NEW_TAB_IPH_PROMOTION_TEXT);
   CGPoint tabSwitcherAnchor;
-  if (IsRegularXRegularSizeClass()) {
+  if (IsRegularXRegularSizeClass() &&
+      !base::FeatureList::IsEnabled(kChangeTabSwitcherPosition)) {
     tabSwitcherAnchor = [self anchorPointToGuide:kTabStripTabSwitcherGuide
                                        direction:arrowDirection];
   } else {
diff --git a/ios/chrome/browser/ui/download/activities/open_downloads_folder_activity.mm b/ios/chrome/browser/ui/download/activities/open_downloads_folder_activity.mm
index 933da84..d88c4d0 100644
--- a/ios/chrome/browser/ui/download/activities/open_downloads_folder_activity.mm
+++ b/ios/chrome/browser/ui/download/activities/open_downloads_folder_activity.mm
@@ -4,6 +4,8 @@
 
 #import "ios/chrome/browser/ui/download/activities/open_downloads_folder_activity.h"
 
+#include "base/metrics/user_metrics.h"
+#include "base/metrics/user_metrics_action.h"
 #import "ios/chrome/browser/ui/commands/browser_commands.h"
 #include "ios/chrome/grit/ios_strings.h"
 #include "ui/base/l10n/l10n_util_mac.h"
@@ -49,6 +51,8 @@
 }
 
 - (void)performActivity {
+  base::RecordAction(base::UserMetricsAction(
+      "MobileDownloadFolderUIShownFromDownloadManager"));
   [self.browserHandler showDownloadsFolder];
   [self activityDidFinish:YES];
 }
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer_unittest.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer_unittest.mm
index e8e6184..18688d4 100644
--- a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer_unittest.mm
+++ b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer_unittest.mm
@@ -32,7 +32,7 @@
 class TestWebStateWithProxy : public web::TestWebState {
  public:
   TestWebStateWithProxy() {
-    scroll_view_proxy_ = OCMClassMock([CRWWebViewScrollViewProxy class]);
+    scroll_view_proxy_ = [[CRWWebViewScrollViewProxy alloc] init];
     id web_view_proxy_mock = OCMProtocolMock(@protocol(CRWWebViewProxy));
     [[[web_view_proxy_mock stub] andReturn:scroll_view_proxy_] scrollViewProxy];
     web_view_proxy_ = web_view_proxy_mock;
diff --git a/ios/chrome/browser/ui/infobars/coordinators/BUILD.gn b/ios/chrome/browser/ui/infobars/coordinators/BUILD.gn
index 724630e..fffe703 100644
--- a/ios/chrome/browser/ui/infobars/coordinators/BUILD.gn
+++ b/ios/chrome/browser/ui/infobars/coordinators/BUILD.gn
@@ -37,6 +37,7 @@
     "//ios/chrome/browser/ui/infobars/banners:public",
     "//ios/chrome/browser/ui/infobars/modals",
     "//ios/chrome/browser/ui/infobars/presentation",
+    "//ios/chrome/browser/ui/toolbar/public:feature_flags",
     "//ios/chrome/browser/ui/util",
     "//ui/base",
   ]
diff --git a/ios/chrome/browser/ui/infobars/coordinators/infobar_coordinator.mm b/ios/chrome/browser/ui/infobars/coordinators/infobar_coordinator.mm
index f1580df..6609b808 100644
--- a/ios/chrome/browser/ui/infobars/coordinators/infobar_coordinator.mm
+++ b/ios/chrome/browser/ui/infobars/coordinators/infobar_coordinator.mm
@@ -18,6 +18,7 @@
 #import "ios/chrome/browser/ui/infobars/presentation/infobar_banner_transition_driver.h"
 #import "ios/chrome/browser/ui/infobars/presentation/infobar_modal_positioner.h"
 #import "ios/chrome/browser/ui/infobars/presentation/infobar_modal_transition_driver.h"
+#import "ios/chrome/browser/ui/toolbar/public/features.h"
 #import "ios/chrome/browser/ui/util/named_guide.h"
 #import "ios/chrome/browser/ui/util/ui_util.h"
 
@@ -26,9 +27,8 @@
 #endif
 
 namespace {
-// Banner View constants.
-const CGFloat kiPhoneBannerOverlapWithOmnibox = 5.0;
-const CGFloat kiPadBannerOverlapWithOmnibox = 10.0;
+// Banner View constant.
+const CGFloat kBannerOverlapWithOmnibox = 5.0;
 }  // namespace
 
 @interface InfobarCoordinator () <InfobarCoordinatorImplementation,
@@ -277,23 +277,12 @@
   NamedGuide* omniboxGuide =
       [NamedGuide guideWithName:kOmniboxGuide
                            view:self.baseViewController.view];
-  UIView* omniboxView = omniboxGuide.constrainedView;
-  CGRect omniboxFrame = omniboxView.frame;
+  UIView* omniboxView = omniboxGuide.owningView;
+  CGRect omniboxFrame = [omniboxView convertRect:omniboxGuide.layoutFrame
+                                          toView:self.baseViewController.view];
 
-  // TODO(crbug.com/964136): The TabStrip on iPad is pushing down the Omnibox
-  // view. On iPad when the TabStrip is visible convert the Omnibox frame to the
-  // self.baseViewController.view coordinate system.
-  CGFloat bannerOverlap = kiPhoneBannerOverlapWithOmnibox;
-  NamedGuide* tabStripGuide =
-      [NamedGuide guideWithName:kTabStripTabSwitcherGuide
-                           view:self.baseViewController.view];
-  if (tabStripGuide.constrainedFrame.size.height) {
-    omniboxFrame = [omniboxView convertRect:omniboxView.frame
-                                     toView:self.baseViewController.view];
-    bannerOverlap = kiPadBannerOverlapWithOmnibox;
-  }
-
-  return omniboxFrame.origin.y + omniboxFrame.size.height - bannerOverlap;
+  return omniboxFrame.origin.y + omniboxFrame.size.height -
+         kBannerOverlapWithOmnibox;
 }
 
 - (UIView*)bannerView {
diff --git a/ios/chrome/browser/ui/main/BUILD.gn b/ios/chrome/browser/ui/main/BUILD.gn
index f493b04..d82071c3 100644
--- a/ios/chrome/browser/ui/main/BUILD.gn
+++ b/ios/chrome/browser/ui/main/BUILD.gn
@@ -9,6 +9,7 @@
   deps = [
     "//ios/chrome/app/application_delegate:application_delegate_internal",
     "//ios/chrome/browser:utils",
+    "//ios/chrome/browser/browser_state:forward",
     "//ios/chrome/browser/url_loading",
     "//ios/chrome/browser/web_state_list",
   ]
diff --git a/ios/chrome/browser/ui/main/browser_interface_provider.h b/ios/chrome/browser/ui/main/browser_interface_provider.h
index 9e46939..d822daf 100644
--- a/ios/chrome/browser/ui/main/browser_interface_provider.h
+++ b/ios/chrome/browser/ui/main/browser_interface_provider.h
@@ -8,16 +8,13 @@
 #import <UIKit/UIKit.h>
 
 #include "base/ios/block_types.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state_forward.h"
 
 class Browser;
 @class BrowserCoordinator;
 @class BrowserViewController;
 @class TabModel;
 
-namespace ios {
-class ChromeBrowserState;
-}
-
 // A BrowserInterface is an abstraction that exposes an interface to the Chrome
 // user interface (and related model objects) to the application layer. Each
 // BrowserInterface is roughly equivalent to a window on a desktop browser --
diff --git a/ios/chrome/browser/ui/main/browser_view_wrangler.h b/ios/chrome/browser/ui/main/browser_view_wrangler.h
index a2ef2d8d0..f62f3fc9 100644
--- a/ios/chrome/browser/ui/main/browser_view_wrangler.h
+++ b/ios/chrome/browser/ui/main/browser_view_wrangler.h
@@ -7,6 +7,7 @@
 
 #import <UIKit/UIKit.h>
 
+#include "ios/chrome/browser/browser_state/chrome_browser_state_forward.h"
 #import "ios/chrome/browser/ui/main/browser_interface_provider.h"
 
 @protocol ApplicationCommands;
@@ -17,10 +18,6 @@
 
 class AppUrlLoadingService;
 
-namespace ios {
-class ChromeBrowserState;
-}
-
 // Protocol for objects that can handle switching browser state storage.
 @protocol BrowserStateStorageSwitching
 - (void)changeStorageFromBrowserState:(ios::ChromeBrowserState*)oldState
diff --git a/ios/chrome/browser/ui/main/scene_controller_guts.h b/ios/chrome/browser/ui/main/scene_controller_guts.h
index af774b0..8f7d939 100644
--- a/ios/chrome/browser/ui/main/scene_controller_guts.h
+++ b/ios/chrome/browser/ui/main/scene_controller_guts.h
@@ -9,16 +9,13 @@
 
 #include "ios/chrome/app/application_delegate/startup_information.h"
 #import "ios/chrome/app/application_delegate/tab_opening.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state_forward.h"
 #import "ios/chrome/browser/procedural_block_types.h"
 #import "ios/chrome/browser/url_loading/url_loading_params.h"
 #import "ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h"
 
 @class TabModel;
 
-namespace ios {
-class ChromeBrowserState;
-}  // namespace ios
-
 @protocol SceneControllerGuts <WebStateListObserving>
 
 - (void)dismissModalDialogsWithCompletion:(ProceduralBlock)completion
diff --git a/ios/chrome/browser/ui/main/test/BUILD.gn b/ios/chrome/browser/ui/main/test/BUILD.gn
index 9d3709a..9a67c3b 100644
--- a/ios/chrome/browser/ui/main/test/BUILD.gn
+++ b/ios/chrome/browser/ui/main/test/BUILD.gn
@@ -10,5 +10,8 @@
     "stub_browser_interface_provider.h",
     "stub_browser_interface_provider.mm",
   ]
-  deps = [ "//ios/chrome/browser/ui/main" ]
+  deps = [
+    "//ios/chrome/browser/browser_state:forward",
+    "//ios/chrome/browser/ui/main",
+  ]
 }
diff --git a/ios/chrome/browser/ui/main/test/stub_browser_interface.h b/ios/chrome/browser/ui/main/test/stub_browser_interface.h
index 8f0a755b..a6decf77 100644
--- a/ios/chrome/browser/ui/main/test/stub_browser_interface.h
+++ b/ios/chrome/browser/ui/main/test/stub_browser_interface.h
@@ -7,13 +7,11 @@
 
 #import <Foundation/Foundation.h>
 
+#include "ios/chrome/browser/browser_state/chrome_browser_state_forward.h"
 #import "ios/chrome/browser/ui/main/browser_interface_provider.h"
 
 class Browser;
 @class BrowserViewController;
-namespace ios {
-class ChromeBrowserState;
-}
 @class TabModel;
 
 // Test double for BrowserInterface implementors. All properties are writable,
diff --git a/ios/chrome/browser/ui/omnibox/popup/BUILD.gn b/ios/chrome/browser/ui/omnibox/popup/BUILD.gn
index c5818f1..e399e1c 100644
--- a/ios/chrome/browser/ui/omnibox/popup/BUILD.gn
+++ b/ios/chrome/browser/ui/omnibox/popup/BUILD.gn
@@ -67,10 +67,6 @@
     "omnibox_popup_base_view_controller+internal.h",
     "omnibox_popup_base_view_controller.h",
     "omnibox_popup_base_view_controller.mm",
-    "omnibox_popup_legacy_view_controller.h",
-    "omnibox_popup_legacy_view_controller.mm",
-    "omnibox_popup_row.h",
-    "omnibox_popup_row.mm",
     "omnibox_popup_row_cell.h",
     "omnibox_popup_row_cell.mm",
     "omnibox_popup_view_controller.h",
@@ -136,10 +132,7 @@
 source_set("unit_tests") {
   configs += [ "//build/config/compiler:enable_arc" ]
   testonly = true
-  sources = [
-    "omnibox_popup_row_cell_unittest.mm",
-    "omnibox_popup_view_controller_unittest.mm",
-  ]
+  sources = [ "omnibox_popup_row_cell_unittest.mm" ]
   deps = [
     ":popup",
     ":popup_internal",
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_base_view_controller.h b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_base_view_controller.h
index 0900dc8..7d47be54 100644
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_base_view_controller.h
+++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_base_view_controller.h
@@ -10,7 +10,6 @@
 #import "ios/chrome/browser/ui/commands/omnibox_suggestion_commands.h"
 #import "ios/chrome/browser/ui/omnibox/popup/autocomplete_result_consumer.h"
 #import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_base_view_controller.h"
-#include "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row.h"
 
 @protocol ImageRetriever;
 @protocol FaviconRetriever;
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_base_view_controller.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_base_view_controller.mm
index c6e82b5..c388cc3 100644
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_base_view_controller.mm
+++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_base_view_controller.mm
@@ -9,7 +9,6 @@
 #include "base/time/time.h"
 #import "ios/chrome/browser/ui/ntp_tile_views/ntp_tile_layout_util.h"
 #include "ios/chrome/browser/ui/omnibox/omnibox_constants.h"
-#include "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row.h"
 #include "ios/chrome/browser/ui/omnibox/popup/self_sizing_table_view.h"
 #include "ios/chrome/browser/ui/toolbar/buttons/toolbar_configuration.h"
 #include "ios/chrome/browser/ui/util/ui_util.h"
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm
index a64bd1f..cb7ef2a5 100644
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm
+++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm
@@ -14,7 +14,6 @@
 #include "ios/chrome/browser/search_engines/template_url_service_factory.h"
 #import "ios/chrome/browser/ui/commands/command_dispatcher.h"
 #import "ios/chrome/browser/ui/ntp/ntp_util.h"
-#import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_legacy_view_controller.h"
 #import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_mediator.h"
 #import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_presenter.h"
 #import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller.h"
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_legacy_view_controller.h b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_legacy_view_controller.h
deleted file mode 100644
index 9095dad..0000000
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_legacy_view_controller.h
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_OMNIBOX_POPUP_OMNIBOX_POPUP_LEGACY_VIEW_CONTROLLER_H_
-#define IOS_CHROME_BROWSER_UI_OMNIBOX_POPUP_OMNIBOX_POPUP_LEGACY_VIEW_CONTROLLER_H_
-
-#import "ios/chrome/browser/ui/commands/omnibox_suggestion_commands.h"
-#import "ios/chrome/browser/ui/omnibox/popup/autocomplete_result_consumer.h"
-#import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_base_view_controller.h"
-
-@interface OmniboxPopupLegacyViewController : OmniboxPopupBaseViewController
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_OMNIBOX_POPUP_OMNIBOX_POPUP_LEGACY_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_legacy_view_controller.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_legacy_view_controller.mm
deleted file mode 100644
index dae9075..0000000
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_legacy_view_controller.mm
+++ /dev/null
@@ -1,415 +0,0 @@
-// Copyright (c) 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_legacy_view_controller.h"
-#import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_base_view_controller+internal.h"
-
-#include <memory>
-
-#include "base/ios/ios_util.h"
-#include "base/metrics/histogram_macros.h"
-#import "ios/chrome/browser/ui/elements/fade_truncating_label.h"
-#import "ios/chrome/browser/ui/omnibox/omnibox_constants.h"
-#import "ios/chrome/browser/ui/omnibox/popup/image_retriever.h"
-#import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row.h"
-#import "ios/chrome/browser/ui/omnibox/popup/self_sizing_table_view.h"
-#import "ios/chrome/browser/ui/toolbar/buttons/toolbar_configuration.h"
-#include "ios/chrome/browser/ui/util/animation_util.h"
-#include "ios/chrome/browser/ui/util/rtl_geometry.h"
-#include "ios/chrome/browser/ui/util/ui_util.h"
-#import "ios/chrome/browser/ui/util/uikit_ui_util.h"
-#include "ios/chrome/common/ui_util/constraints_ui_util.h"
-#include "ios/chrome/grit/ios_strings.h"
-#include "ios/chrome/grit/ios_theme_resources.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "url/gurl.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-const int kRowCount = 12;
-const CGFloat kRowHeight = 48.0;
-const CGFloat kAnswerRowHeight = 64.0;
-}  // namespace
-
-@interface OmniboxPopupLegacyViewController () <
-    OmniboxPopupRowAccessibilityDelegate> {
-  // Array containing the OmniboxPopupRow objects displayed in the view.
-  NSArray* _rows;
-}
-
-// A flag to track if since the last viewWillAppear, the view ever adopted a
-// non-zero size. This is a pretty sad workaround for the new iOS 13 behaviour
-// where the half-autolayout, half-manual layout code of this legacy class ends
-// up sizing cells to a zero width because -layoutRows is never called on the
-// first appearance. This should be removed, together with this class, when the
-// non-legacy OmniboxPopupViewController becomes the default.
-@property(nonatomic, assign) BOOL viewHadNonZeroWidth;
-
-@end
-
-@implementation OmniboxPopupLegacyViewController
-
-- (void)viewDidLoad {
-  [super viewDidLoad];
-
-  // Cache fonts needed for omnibox attributed string.
-  NSMutableArray* rowsBuilder = [[NSMutableArray alloc] init];
-  for (int i = 0; i < kRowCount; i++) {
-    OmniboxPopupRow* row =
-        [[OmniboxPopupRow alloc] initWithIncognito:self.incognito];
-    row.accessibilityIdentifier =
-        [NSString stringWithFormat:@"omnibox suggestion %i", i];
-    row.autoresizingMask = UIViewAutoresizingFlexibleWidth;
-    [rowsBuilder addObject:row];
-    [row.trailingButton addTarget:self
-                           action:@selector(trailingButtonTapped:)
-                 forControlEvents:UIControlEventTouchUpInside];
-    [row.trailingButton setTag:i];
-    row.rowNumber = i;
-    row.delegate = self;
-    row.rowHeight = kRowHeight;
-  }
-  _rows = [rowsBuilder copy];
-}
-
-- (void)didReceiveMemoryWarning {
-  [super didReceiveMemoryWarning];
-  if (![self isViewLoaded]) {
-    _rows = nil;
-  }
-}
-
-- (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection {
-  [super traitCollectionDidChange:previousTraitCollection];
-  [self layoutRows];
-}
-
-- (void)viewWillTransitionToSize:(CGSize)size
-       withTransitionCoordinator:
-           (id<UIViewControllerTransitionCoordinator>)coordinator {
-  [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
-  [coordinator
-      animateAlongsideTransition:^(
-          id<UIViewControllerTransitionCoordinatorContext> context) {
-        [self layoutRows];
-      }
-                      completion:nil];
-}
-
-- (void)viewWillAppear:(BOOL)animated {
-  [super viewWillAppear:animated];
-  if (self.view.bounds.size.width == 0) {
-    self.viewHadNonZeroWidth = NO;
-  }
-}
-
-- (void)viewDidLayoutSubviews {
-  [super viewDidLayoutSubviews];
-
-  // This method will be called multiple times, including after the self-sizing
-  // table view will have taken its final (non-zero) size. Calling -layoutRows
-  // will result in another viewDidLayoutSubviews call, so a flag is necessary
-  // to avoid an infinite loop.
-  if (self.view.bounds.size.width > 0 && !self.viewHadNonZeroWidth) {
-    self.viewHadNonZeroWidth = YES;
-    [self layoutRows];
-  }
-}
-
-#pragma mark -
-#pragma mark Updating data and UI
-
-- (void)updateRow:(OmniboxPopupRow*)row
-        withMatch:(id<AutocompleteSuggestion>)match {
-  CGFloat kTextCellLeadingPadding =
-      [self showsLeadingIcons] ? ([self useRegularWidthOffset] ? 192 : 100)
-                               : 16;
-  kTextCellLeadingPadding = [self showsLeadingIcons] ? 221 : 24;
-
-  const CGFloat kTextCellTopPadding = 6;
-  const CGFloat kDetailCellTopPadding = 26;
-  const CGFloat kTextLabelHeight = 24;
-  const CGFloat kTextDetailLabelHeight = 22;
-  const CGFloat kTrailingButtonWidth = 40;
-  const CGFloat kAnswerLabelHeight = 36;
-  const CGFloat kAnswerImageWidth = 30;
-  const CGFloat kAnswerImageLeftPadding = -1;
-  const CGFloat kAnswerImageRightPadding = 4;
-  const CGFloat kAnswerImageTopPadding = 2;
-  const BOOL alignmentRight = self.alignment == NSTextAlignmentRight;
-
-  BOOL LTRTextInRTLLayout =
-      self.alignment == NSTextAlignmentLeft && UseRTLLayout();
-
-  row.rowHeight = match.hasAnswer ? kAnswerRowHeight : kRowHeight;
-
-  // Fetch the answer image if specified.  Currently, no answer types specify an
-  // image on the first line so for now we only look at the second line.
-  if (match.hasImage) {
-    [self.imageRetriever fetchImage:match.imageURL
-                         completion:^(UIImage* image) {
-                           row.answerImageView.image = image;
-                         }];
-    // Answers in suggest do not support RTL, left align only.
-    CGFloat imageLeftPadding =
-        kTextCellLeadingPadding + kAnswerImageLeftPadding;
-    if (alignmentRight) {
-      imageLeftPadding =
-          row.frame.size.width - (kAnswerImageWidth + kTrailingButtonWidth);
-    }
-    CGFloat imageTopPadding = kDetailCellTopPadding + kAnswerImageTopPadding;
-    row.answerImageView.frame =
-        CGRectMake(imageLeftPadding, imageTopPadding, kAnswerImageWidth,
-                   kAnswerImageWidth);
-    row.answerImageView.hidden = NO;
-  } else {
-    row.answerImageView.hidden = YES;
-  }
-
-  // DetailTextLabel and textLabel are fading labels placed in each row. The
-  // textLabel is laid out above the detailTextLabel, and vertically centered
-  // if the detailTextLabel is empty.
-  // For the detail text label, we use either the regular detail label, which
-  // truncates by fading, or the answer label, which uses UILabel's standard
-  // truncation by ellipse for the multi-line text sometimes shown in answers.
-  row.detailTruncatingLabel.hidden = match.hasAnswer;
-  row.detailAnswerLabel.hidden = !match.hasAnswer;
-  // URLs have have special layout requirements that need to be invoked here.
-  row.detailTruncatingLabel.displayAsURL = match.isURL;
-
-  // TODO(crbug.com/697647): The complexity of managing these two separate
-  // labels could probably be encapusulated in the row class if we moved the
-  // layout logic there.
-  UILabel* detailTextLabel =
-      match.hasAnswer ? row.detailAnswerLabel : row.detailTruncatingLabel;
-  [detailTextLabel setTextAlignment:self.alignment];
-
-  // The width must be positive for CGContextRef to be valid.
-  UIEdgeInsets safeAreaInsets = self.view.safeAreaInsets;
-  CGRect rowBounds = UIEdgeInsetsInsetRect(self.view.bounds, safeAreaInsets);
-  CGFloat labelWidth =
-      MAX(40, floorf(rowBounds.size.width) - kTextCellLeadingPadding);
-  CGFloat labelHeight =
-      match.hasAnswer ? kAnswerLabelHeight : kTextDetailLabelHeight;
-  CGFloat answerImagePadding = kAnswerImageWidth + kAnswerImageRightPadding;
-  CGFloat leadingPadding =
-      (match.hasImage && !alignmentRight ? answerImagePadding : 0) +
-      kTextCellLeadingPadding;
-
-  LayoutRect detailTextLabelLayout =
-      LayoutRectMake(leadingPadding, CGRectGetWidth(rowBounds),
-                     kDetailCellTopPadding, labelWidth, labelHeight);
-  detailTextLabel.frame = LayoutRectGetRect(detailTextLabelLayout);
-
-  detailTextLabel.attributedText = match.detailText;
-
-  // Set detail text label number of lines
-  if (match.hasAnswer) {
-    detailTextLabel.numberOfLines = match.numberOfLines;
-  }
-
-  [detailTextLabel setNeedsDisplay];
-
-  FadeTruncatingLabel* textLabel = row.textTruncatingLabel;
-  [textLabel setTextAlignment:self.alignment];
-  LayoutRect textLabelLayout =
-      LayoutRectMake(kTextCellLeadingPadding, CGRectGetWidth(rowBounds), 0,
-                     labelWidth, kTextLabelHeight);
-  textLabel.frame = LayoutRectGetRect(textLabelLayout);
-
-  // Set the text.
-  textLabel.attributedText = match.text;
-
-  // Center the textLabel if detailLabel is empty.
-  if (!match.hasAnswer && [match.detailText length] == 0) {
-    textLabel.center = CGPointMake(textLabel.center.x, floor(kRowHeight / 2));
-    textLabel.frame = AlignRectToPixel(textLabel.frame);
-  } else {
-    CGRect frame = textLabel.frame;
-    frame.origin.y = kTextCellTopPadding;
-    textLabel.frame = frame;
-  }
-
-  // The leading image (e.g. magnifying glass, star, clock) is only shown on
-  // iPad.
-  if ([self showsLeadingIcons]) {
-    UIImage* image = nil;
-    image = match.suggestionTypeIcon;
-    DCHECK(image);
-    [row updateLeadingImage:image];
-  }
-
-  row.tabMatch = match.isTabMatch;
-
-  // Show append button for search history/search suggestions as the right
-  // control element (aka an accessory element of a table view cell).
-  BOOL hasVisibleTrailingButton = match.isAppendable || match.isTabMatch;
-  row.trailingButton.hidden = !hasVisibleTrailingButton;
-  [row.trailingButton cancelTrackingWithEvent:nil];
-
-  // If a right accessory element is present or the text alignment is right
-  // aligned, adjust the width to align with the accessory element.
-  if (hasVisibleTrailingButton || alignmentRight) {
-    LayoutRect layout =
-        LayoutRectForRectInBoundingRect(textLabel.frame, self.view.frame);
-    layout.size.width -= kTrailingButtonWidth;
-    textLabel.frame = LayoutRectGetRect(layout);
-    layout =
-        LayoutRectForRectInBoundingRect(detailTextLabel.frame, self.view.frame);
-    layout.size.width -=
-        kTrailingButtonWidth + (match.hasImage ? answerImagePadding : 0);
-    detailTextLabel.frame = LayoutRectGetRect(layout);
-  }
-
-  // Since it's a common use case to type in a left-to-right URL while the
-  // device is set to a native RTL language, make sure the left alignment looks
-  // good by anchoring the leading edge to the left.
-  if (LTRTextInRTLLayout) {
-    // This is really a left padding, not a leading padding.
-    const CGFloat kLTRTextInRTLLayoutLeftPadding =
-        [self showsLeadingIcons] ? ([self useRegularWidthOffset] ? 176 : 94)
-                                 : 94;
-    CGRect frame = textLabel.frame;
-    frame.size.width -= kLTRTextInRTLLayoutLeftPadding - frame.origin.x;
-    frame.origin.x = kLTRTextInRTLLayoutLeftPadding;
-    textLabel.frame = frame;
-
-    frame = detailTextLabel.frame;
-    frame.size.width -= kLTRTextInRTLLayoutLeftPadding - frame.origin.x;
-    frame.origin.x = kLTRTextInRTLLayoutLeftPadding;
-    detailTextLabel.frame = frame;
-  }
-
-  NSString* trailingButtonActionName =
-      row.tabMatch
-          ? l10n_util::GetNSString(IDS_IOS_OMNIBOX_POPUP_SWITCH_TO_OPEN_TAB)
-          : l10n_util::GetNSString(IDS_IOS_OMNIBOX_POPUP_APPEND);
-  UIAccessibilityCustomAction* trailingButtonAction =
-      [[UIAccessibilityCustomAction alloc]
-          initWithName:trailingButtonActionName
-                target:row
-              selector:@selector(accessibilityTrailingButtonTapped)];
-
-  row.accessibilityCustomActions =
-      hasVisibleTrailingButton ? @[ trailingButtonAction ] : nil;
-
-  [textLabel setNeedsDisplay];
-}
-
-- (void)updateTableViewWithAnimation:(BOOL)animation {
-  [self layoutRows];
-
-  size_t size = self.currentResult.count;
-  if (animation && size > 0) {
-    [self fadeInRows];
-  }
-}
-
-- (void)layoutRows {
-  size_t size = self.currentResult.count;
-
-  [self.tableView reloadData];
-  for (size_t i = 0; i < kRowCount; i++) {
-    OmniboxPopupRow* row = _rows[i];
-
-    if (i < size) {
-      [self updateRow:row withMatch:self.currentResult[i]];
-      row.hidden = NO;
-    } else {
-      row.hidden = YES;
-    }
-  }
-
-  if (IsIPadIdiom())
-    [self updateContentInsetForKeyboard];
-}
-
-- (void)fadeInRows {
-  [CATransaction begin];
-  [CATransaction
-      setAnimationTimingFunction:[CAMediaTimingFunction
-                                     functionWithControlPoints:
-                                                             0:0:0.2:1]];
-  for (size_t i = 0; i < kRowCount; i++) {
-    OmniboxPopupRow* row = _rows[i];
-    CGFloat beginTime = (i + 1) * .05;
-    CABasicAnimation* transformAnimation =
-        [CABasicAnimation animationWithKeyPath:@"transform"];
-    [transformAnimation
-        setFromValue:[NSValue
-                         valueWithCATransform3D:CATransform3DMakeTranslation(
-                                                    0, -20, 0)]];
-    [transformAnimation
-        setToValue:[NSValue valueWithCATransform3D:CATransform3DIdentity]];
-    [transformAnimation setDuration:0.5];
-    [transformAnimation setBeginTime:beginTime];
-
-    CAAnimation* fadeAnimation = OpacityAnimationMake(0, 1);
-    [fadeAnimation setDuration:0.5];
-    [fadeAnimation setBeginTime:beginTime];
-
-    [[row layer]
-        addAnimation:AnimationGroupMake(@[ transformAnimation, fadeAnimation ])
-              forKey:@"animateIn"];
-  }
-  [CATransaction commit];
-}
-
-#pragma mark -
-#pragma mark UIScrollViewDelegate
-
-- (void)scrollViewDidScroll:(UIScrollView*)scrollView {
-  [super scrollViewDidScroll:scrollView];
-
-  // TODO(crbug.com/733650): Default to the dragging check once it's been tested
-  // on trunk.
-  if (!scrollView.dragging)
-    return;
-
-  for (OmniboxPopupRow* row in _rows) {
-    row.highlighted = NO;
-  }
-}
-
-#pragma mark -
-#pragma mark Table view data source
-
-- (CGFloat)tableView:(UITableView*)tableView
-    heightForRowAtIndexPath:(NSIndexPath*)indexPath {
-
-  DCHECK_EQ(0U, (NSUInteger)indexPath.section);
-  DCHECK_LT((NSUInteger)indexPath.row, self.currentResult.count);
-  return ((OmniboxPopupRow*)(_rows[indexPath.row])).rowHeight;
-}
-
-// Customize the appearance of table view cells.
-- (UITableViewCell*)tableView:(UITableView*)tableView
-        cellForRowAtIndexPath:(NSIndexPath*)indexPath {
-  DCHECK_EQ(0U, (NSUInteger)indexPath.section);
-
-  DCHECK_LT((NSUInteger)indexPath.row, self.currentResult.count);
-  return _rows[indexPath.row];
-}
-
-#pragma mark - private
-
-- (BOOL)showsLeadingIcons {
-  return IsRegularXRegularSizeClass();
-}
-
-- (BOOL)useRegularWidthOffset {
-  return [self showsLeadingIcons] && !IsCompactWidth();
-}
-
-#pragma mark - OmniboxPopupRowAccessibilityDelegate
-
-- (void)accessibilityTrailingButtonTappedOmniboxPopupRow:(OmniboxPopupRow*)row {
-  [self.delegate autocompleteResultConsumer:self
-                 didTapTrailingButtonForRow:row.rowNumber];
-}
-
-@end
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row.h b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row.h
deleted file mode 100644
index 0e504775..0000000
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright (c) 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_OMNIBOX_OMNIBOX_POPUP_ROW_H_
-#define IOS_CHROME_BROWSER_UI_OMNIBOX_OMNIBOX_POPUP_ROW_H_
-
-#import <UIKit/UIKit.h>
-
-@class FadeTruncatingLabel;
-
-@class OmniboxPopupRow;
-
-// Accessibility delegate for handling the row actions.
-@protocol OmniboxPopupRowAccessibilityDelegate
-
-// Handles the action associated with the trailing button of the |row|.
-- (void)accessibilityTrailingButtonTappedOmniboxPopupRow:(OmniboxPopupRow*)row;
-
-@end
-
-// View used to display an omnibox autocomplete match in the omnibox popup.
-@interface OmniboxPopupRow : UITableViewCell
-
-// A truncate-by-fading version of the textLabel of a UITableViewCell.
-@property(nonatomic, readonly, strong) FadeTruncatingLabel* textTruncatingLabel;
-// A truncate-by-fading version of the detailTextLabel of a UITableViewCell.
-@property(nonatomic, readonly, strong)
-    FadeTruncatingLabel* detailTruncatingLabel;
-// A standard UILabel for answers, which truncates with ellipses to support
-// multi-line text.
-@property(nonatomic, readonly, strong) UILabel* detailAnswerLabel;
-
-// Row number.
-@property(nonatomic, assign) NSUInteger rowNumber;
-
-// Accessibility delegate for this row.
-@property(nonatomic, weak) id<OmniboxPopupRowAccessibilityDelegate> delegate;
-
-@property(nonatomic, readonly, strong) UIImageView* imageView;
-@property(nonatomic, readonly, strong) UIImageView* answerImageView;
-@property(nonatomic, readonly, strong) UIButton* trailingButton;
-@property(nonatomic, assign) CGFloat rowHeight;
-// Whether this row is displaying a TabMatch. If YES, the trailing icon is
-// updated to reflect that.
-@property(nonatomic, assign, getter=isTabMatch) BOOL tabMatch;
-
-// Initialize the row with the given incognito state. The colors and styling are
-// dependent on whether or not the row is displayed in incognito mode.
-- (instancetype)initWithIncognito:(BOOL)incognito;
-
-// Update the match type icon with the supplied image ID and adjust its position
-// based on the current size of the row.
-- (void)updateLeadingImage:(UIImage*)image;
-
-// Callback for the accessibility action associated with the trailing button of
-// this row.
-- (void)accessibilityTrailingButtonTapped;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_OMNIBOX_OMNIBOX_POPUP_ROW_H_
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row.mm
deleted file mode 100644
index 779ab9eb..0000000
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row.mm
+++ /dev/null
@@ -1,195 +0,0 @@
-// Copyright (c) 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row.h"
-
-#include "base/feature_list.h"
-#include "base/logging.h"
-#include "components/omnibox/common/omnibox_features.h"
-#import "ios/chrome/browser/ui/elements/fade_truncating_label.h"
-#import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_accessibility_identifier_constants.h"
-#import "ios/chrome/browser/ui/toolbar/public/toolbar_constants.h"
-#include "ios/chrome/browser/ui/util/rtl_geometry.h"
-#include "ios/chrome/browser/ui/util/ui_util.h"
-#import "ios/chrome/browser/ui/util/uikit_ui_util.h"
-#import "ios/chrome/common/colors/dynamic_color_util.h"
-#import "ios/chrome/common/colors/semantic_color_names.h"
-#include "ios/chrome/grit/ios_theme_resources.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-// Side (w or h) length for the leading image view.
-const CGFloat kImageViewSize = 28.0;
-const CGFloat kImageViewCornerRadius = 7.0;
-const CGFloat kTrailingButtonTrailingMargin = 4;
-const CGFloat kTrailingButtonSize = 48.0;
-const CGFloat kLeadingPaddingIpad = 183;
-const CGFloat kLeadingPaddingIpadCompact = 71;
-}
-
-@interface OmniboxPopupRow () {
-  BOOL _incognito;
-}
-
-// Set the append button normal and highlighted images.
-- (void)updateTrailingButtonImages;
-
-@end
-
-@implementation OmniboxPopupRow
-
-@synthesize imageView = _imageView;
-
-- (instancetype)initWithStyle:(UITableViewCellStyle)style
-              reuseIdentifier:(NSString*)reuseIdentifier {
-  return [self initWithIncognito:NO];
-}
-
-- (instancetype)initWithIncognito:(BOOL)incognito {
-  self = [super initWithStyle:UITableViewCellStyleDefault
-              reuseIdentifier:@"OmniboxPopupRow"];
-  if (self) {
-    _incognito = incognito;
-
-    self.isAccessibilityElement = YES;
-    self.backgroundColor = UIColor.clearColor;
-    self.selectedBackgroundView = [[UIView alloc] initWithFrame:CGRectZero];
-    self.selectedBackgroundView.backgroundColor = color::DarkModeDynamicColor(
-        [UIColor colorNamed:kTableViewRowHighlightColor], _incognito,
-        [UIColor colorNamed:kTableViewRowHighlightDarkColor]);
-
-    _textTruncatingLabel =
-        [[FadeTruncatingLabel alloc] initWithFrame:CGRectZero];
-    _textTruncatingLabel.userInteractionEnabled = NO;
-    [self.contentView addSubview:_textTruncatingLabel];
-
-    _detailTruncatingLabel =
-        [[FadeTruncatingLabel alloc] initWithFrame:CGRectZero];
-    _detailTruncatingLabel.userInteractionEnabled = NO;
-    [self.contentView addSubview:_detailTruncatingLabel];
-
-    // Answers use a UILabel with NSLineBreakByTruncatingTail to produce a
-    // truncation with an ellipse instead of fading on multi-line text.
-    _detailAnswerLabel = [[UILabel alloc] initWithFrame:CGRectZero];
-    _detailAnswerLabel.userInteractionEnabled = NO;
-    _detailAnswerLabel.lineBreakMode = NSLineBreakByTruncatingTail;
-    [self.contentView addSubview:_detailAnswerLabel];
-
-    _trailingButton = [UIButton buttonWithType:UIButtonTypeSystem];
-    [_trailingButton setContentMode:UIViewContentModeRight];
-    [self updateTrailingButtonImages];
-    // TODO(justincohen): Consider using the UITableViewCell's accessory view.
-    // The current implementation is from before using a UITableViewCell.
-    [self.contentView addSubview:_trailingButton];
-
-    // Before UI Refresh, the leading icon is only displayed on iPad. In UI
-    // Refresh, it's only in Regular x Regular size class.
-    // TODO(justincohen): Consider using the UITableViewCell's image view.
-    // The current implementation is from before using a UITableViewCell.
-    _imageView = [[UIImageView alloc] initWithFrame:CGRectZero];
-    _imageView.userInteractionEnabled = NO;
-    _imageView.contentMode = UIViewContentModeCenter;
-
-    _imageView.layer.cornerRadius = kImageViewCornerRadius;
-    _imageView.backgroundColor = UIColor.clearColor;
-    _imageView.tintColor = color::DarkModeDynamicColor(
-        [UIColor colorNamed:@"omnibox_suggestion_icon_color"], _incognito,
-        [UIColor colorNamed:@"omnibox_suggestion_icon_dark_color"]);
-
-    _answerImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
-    _answerImageView.userInteractionEnabled = NO;
-    _answerImageView.contentMode = UIViewContentModeScaleAspectFit;
-    [self.contentView addSubview:_answerImageView];
-  }
-  return self;
-}
-
-- (void)layoutSubviews {
-  [super layoutSubviews];
-  [self layoutAccessoryViews];
-  if ([self showsLeadingIcons]) {
-    [self.contentView addSubview:_imageView];
-  } else {
-    [_imageView removeFromSuperview];
-  }
-}
-
-- (void)layoutAccessoryViews {
-  CGFloat imageViewSize = kImageViewSize;
-  LayoutRect imageViewLayout = LayoutRectMake(
-      ([self showsLeadingIcons] && IsCompactTablet())
-          ? kLeadingPaddingIpadCompact
-          : kLeadingPaddingIpad,
-      CGRectGetWidth(self.contentView.bounds),
-      floor((_rowHeight - imageViewSize) / 2), imageViewSize, imageViewSize);
-  _imageView.frame = LayoutRectGetRect(imageViewLayout);
-
-  LayoutRect trailingAccessoryLayout =
-      LayoutRectMake(CGRectGetWidth(self.contentView.bounds) -
-                         kTrailingButtonSize - kTrailingButtonTrailingMargin,
-                     CGRectGetWidth(self.contentView.bounds),
-                     floor((_rowHeight - kTrailingButtonSize) / 2),
-                     kTrailingButtonSize, kTrailingButtonSize);
-  _trailingButton.frame = LayoutRectGetRect(trailingAccessoryLayout);
-}
-
-- (void)updateLeadingImage:(UIImage*)image {
-  _imageView.image = image;
-
-  // Adjust the vertical position based on the current size of the row.
-  CGFloat imageViewSize = kImageViewSize;
-  CGRect frame = _imageView.frame;
-  frame.origin.y = floor((_rowHeight - imageViewSize) / 2);
-  _imageView.frame = frame;
-}
-
-- (void)setTabMatch:(BOOL)tabMatch {
-  _tabMatch = tabMatch;
-  [self updateTrailingButtonImages];
-}
-
-- (void)updateTrailingButtonImages {
-  UIImage* appendImage = nil;
-  _trailingButton.accessibilityIdentifier = nil;
-  if (self.tabMatch) {
-    appendImage = [UIImage imageNamed:@"omnibox_popup_tab_match"];
-    appendImage = appendImage.imageFlippedForRightToLeftLayoutDirection;
-    _trailingButton.accessibilityIdentifier =
-        kOmniboxPopupRowSwitchTabAccessibilityIdentifier;
-  } else {
-    int appendResourceID = 0;
-    appendResourceID = IDR_IOS_OMNIBOX_KEYBOARD_VIEW_APPEND;
-    appendImage = NativeReversableImage(appendResourceID, YES);
-  }
-  appendImage =
-      [appendImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
-  _trailingButton.tintColor =
-      color::DarkModeDynamicColor([UIColor colorNamed:kBlueColor], _incognito,
-                                  [UIColor colorNamed:kBlueDarkColor]);
-
-  [_trailingButton setImage:appendImage forState:UIControlStateNormal];
-}
-
-- (NSString*)accessibilityLabel {
-  return _textTruncatingLabel.attributedText.string;
-}
-
-- (NSString*)accessibilityValue {
-  return _detailTruncatingLabel.hidden
-             ? _detailAnswerLabel.attributedText.string
-             : _detailTruncatingLabel.attributedText.string;
-}
-
-- (BOOL)showsLeadingIcons {
-    return IsRegularXRegularSizeClass();
-}
-
-- (void)accessibilityTrailingButtonTapped {
-  [self.delegate accessibilityTrailingButtonTappedOmniboxPopupRow:self];
-}
-
-@end
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row_cell_unittest.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row_cell_unittest.mm
index 43fbde8..4f8670b9 100644
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row_cell_unittest.mm
+++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row_cell_unittest.mm
@@ -5,7 +5,6 @@
 #import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row_cell.h"
 
 #import "ios/chrome/browser/ui/omnibox/popup/autocomplete_suggestion.h"
-#import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row.h"
 #include "testing/gtest_mac.h"
 #include "testing/platform_test.h"
 #include "url/gurl.h"
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller_unittest.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller_unittest.mm
deleted file mode 100644
index e2d9c531c..0000000
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_controller_unittest.mm
+++ /dev/null
@@ -1,64 +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.
-
-#import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_legacy_view_controller.h"
-
-#include "components/omnibox/browser/autocomplete_match.h"
-#import "ios/chrome/browser/ui/omnibox/popup/autocomplete_match_formatter.h"
-#import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row.h"
-#include "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-
-class OmniboxPopupViewControllerTest : public PlatformTest {
- protected:
-  void SetUp() override {
-    PlatformTest::SetUp();
-    popup_view_controller_ = [[OmniboxPopupLegacyViewController alloc] init];
-  }
-
-  OmniboxPopupLegacyViewController* popup_view_controller_;
-};
-
-TEST_F(OmniboxPopupViewControllerTest, HasTabMatch) {
-  EXPECT_TRUE([popup_view_controller_
-      conformsToProtocol:@protocol(UITableViewDataSource)]);
-  id<UITableViewDataSource> datasource =
-      (id<UITableViewDataSource>)popup_view_controller_;
-  UITableView* table_view = [[UITableView alloc] init];
-
-  // Check that if the match has a tab match, the cell's trailing button is
-  // visible.
-  AutocompleteMatch match;
-  match.has_tab_match = true;
-  AutocompleteMatchFormatter* formatter =
-      [[AutocompleteMatchFormatter alloc] initWithMatch:match];
-  [popup_view_controller_ updateMatches:@[ formatter ] withAnimation:NO];
-
-  EXPECT_EQ([datasource tableView:table_view numberOfRowsInSection:0], 1);
-  OmniboxPopupRow* cell = static_cast<OmniboxPopupRow*>([datasource
-                  tableView:table_view
-      cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]]);
-
-  EXPECT_FALSE(cell.trailingButton.hidden);
-
-  // Check that it is not the case if the tab match isn't visible.
-  match.has_tab_match = false;
-  formatter = [[AutocompleteMatchFormatter alloc] initWithMatch:match];
-  [popup_view_controller_ updateMatches:@[ formatter ] withAnimation:NO];
-
-  EXPECT_EQ([datasource tableView:table_view numberOfRowsInSection:0], 1);
-  cell = static_cast<OmniboxPopupRow*>([datasource
-                  tableView:table_view
-      cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]]);
-
-  EXPECT_TRUE(cell.trailingButton.hidden);
-}
-
-}  // namespace
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_ios.h b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_ios.h
index 35eaf5d6..4fb1e93 100644
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_ios.h
+++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_ios.h
@@ -11,7 +11,6 @@
 
 #include "base/strings/string16.h"
 #include "components/omnibox/browser/omnibox_popup_view.h"
-#import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_legacy_view_controller.h"
 #import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_mediator.h"
 #include "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_provider.h"
 
diff --git a/ios/chrome/browser/ui/payments/payment_request_coordinator.h b/ios/chrome/browser/ui/payments/payment_request_coordinator.h
index d6019b7..71e3a40d 100644
--- a/ios/chrome/browser/ui/payments/payment_request_coordinator.h
+++ b/ios/chrome/browser/ui/payments/payment_request_coordinator.h
@@ -10,6 +10,7 @@
 #include "base/ios/block_types.h"
 #include "base/strings/string16.h"
 #include "components/autofill/core/browser/payments/full_card_request.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state_forward.h"
 #import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h"
 #import "ios/chrome/browser/ui/payments/address_edit_coordinator.h"
 #import "ios/chrome/browser/ui/payments/contact_info_edit_coordinator.h"
@@ -25,10 +26,6 @@
 class AutofillManager;
 }  // namespace autofill
 
-namespace ios {
-class ChromeBrowserState;
-}  // namespace ios
-
 namespace payments {
 class PaymentDetails;
 class PaymentRequest;
diff --git a/ios/chrome/browser/ui/payments/payment_request_manager.h b/ios/chrome/browser/ui/payments/payment_request_manager.h
index 45aec993..dd09123 100644
--- a/ios/chrome/browser/ui/payments/payment_request_manager.h
+++ b/ios/chrome/browser/ui/payments/payment_request_manager.h
@@ -7,6 +7,8 @@
 
 #import <UIKit/UIKit.h>
 
+#include "ios/chrome/browser/browser_state/chrome_browser_state_forward.h"
+
 // Names identifying the errors used in Payment Request API:
 // https://www.w3.org/TR/payment-request/
 // A complete list of DOMException error names and descriptions can be found at:
@@ -19,10 +21,6 @@
 @protocol ApplicationCommands;
 class LocationBarModel;
 
-namespace ios {
-class ChromeBrowserState;
-}  // namespace ios
-
 namespace web {
 class WebState;
 }  // namespace web
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_action_handler.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_action_handler.mm
index 2bb3031..2ca3a946 100644
--- a/ios/chrome/browser/ui/popup_menu/popup_menu_action_handler.mm
+++ b/ios/chrome/browser/ui/popup_menu/popup_menu_action_handler.mm
@@ -106,6 +106,8 @@
       [self.dispatcher showHelpPage];
       break;
     case PopupMenuActionOpenDownloads:
+      RecordAction(
+          UserMetricsAction("MobileDownloadFolderUIShownFromToolsMenu"));
       [self.dispatcher showDownloadsFolder];
       break;
     case PopupMenuActionTextZoom:
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_coordinator.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_coordinator.mm
index 7328903..ecbf7cb 100644
--- a/ios/chrome/browser/ui/popup_menu/popup_menu_coordinator.mm
+++ b/ios/chrome/browser/ui/popup_menu/popup_menu_coordinator.mm
@@ -133,6 +133,7 @@
 }
 
 - (void)showTabStripTabGridButtonPopup {
+  DCHECK(!base::FeatureList::IsEnabled(kChangeTabSwitcherPosition));
   base::RecordAction(base::UserMetricsAction("MobileTabStripShowTabGridMenu"));
   [self presentPopupOfType:PopupMenuTypeTabStripTabGrid
             fromNamedGuide:kTabStripTabSwitcherGuide];
diff --git a/ios/chrome/browser/ui/tabs/BUILD.gn b/ios/chrome/browser/ui/tabs/BUILD.gn
index 921e5b02..e7c0308 100644
--- a/ios/chrome/browser/ui/tabs/BUILD.gn
+++ b/ios/chrome/browser/ui/tabs/BUILD.gn
@@ -56,6 +56,7 @@
     "//ios/chrome/browser/ui/popup_menu/public",
     "//ios/chrome/browser/ui/tab_grid/grid/resources:grid_cell_close_button",
     "//ios/chrome/browser/ui/tabs/requirements",
+    "//ios/chrome/browser/ui/toolbar/public:feature_flags",
     "//ios/chrome/browser/ui/util",
     "//ios/chrome/browser/web_state_list",
     "//ios/chrome/common",
diff --git a/ios/chrome/browser/ui/tabs/tab_strip_controller.mm b/ios/chrome/browser/ui/tabs/tab_strip_controller.mm
index 4471884..3be3331 100644
--- a/ios/chrome/browser/ui/tabs/tab_strip_controller.mm
+++ b/ios/chrome/browser/ui/tabs/tab_strip_controller.mm
@@ -37,6 +37,7 @@
 #import "ios/chrome/browser/ui/tabs/tab_strip_view.h"
 #import "ios/chrome/browser/ui/tabs/tab_view.h"
 #include "ios/chrome/browser/ui/tabs/target_frame_cache.h"
+#import "ios/chrome/browser/ui/toolbar/public/features.h"
 #import "ios/chrome/browser/ui/ui_feature_flags.h"
 #import "ios/chrome/browser/ui/util/named_guide.h"
 #include "ios/chrome/browser/ui/util/rtl_geometry.h"
@@ -505,7 +506,8 @@
 
     [_tabStripView addSubview:_buttonNewTab];
 
-    [self installTabSwitcherButton];
+    if (!base::FeatureList::IsEnabled(kChangeTabSwitcherPosition))
+      [self installTabSwitcherButton];
 
     // Add tab buttons to tab strip.
     if (_tabModel)
@@ -765,6 +767,9 @@
 // here views use CGAffineTransformMakeScale to support RTL, and NamedGuide
 // doesn't honor transforms. Instead we set the tabSwitcherGuide as necessary.
 - (void)updateTabSwitcherGuide {
+  if (base::FeatureList::IsEnabled(kChangeTabSwitcherPosition))
+    return;
+
   NamedGuide* tabSwitcherGuide =
       [NamedGuide guideWithName:kTabStripTabSwitcherGuide view:self.view];
   if (self.view.hidden) {
@@ -1202,6 +1207,7 @@
 }
 
 - (void)installTabSwitcherButton {
+  DCHECK(!base::FeatureList::IsEnabled(kChangeTabSwitcherPosition));
   DCHECK(!_tabSwitcherButton);
   UIImage* tabSwitcherButtonIcon;
   UIImage* tabSwitcherButtonIconPressed;
@@ -1444,29 +1450,31 @@
 - (void)updateScrollViewFrameForTabSwitcherButton {
   CGRect tabFrame = _tabStripView.frame;
   tabFrame.size.width = _view.bounds.size.width;
-  if (self.useTabStacking) {
-    tabFrame.size.width -= kTabSwitcherButtonWidth;
-    _tabStripView.contentInset = UIEdgeInsetsZero;
-    [_tabSwitcherButtonBackgroundView setHidden:YES];
-  } else {
-    if (!_tabSwitcherButtonBackgroundView) {
-      _tabSwitcherButtonBackgroundView = [[UIImageView alloc] init];
-      const CGFloat tabStripHeight = _view.frame.size.height;
-      const CGRect backgroundViewFrame = CGRectMake(
-          CGRectGetMaxX(_view.frame) - kTabSwitcherButtonBackgroundWidth, 0.0,
-          kTabSwitcherButtonBackgroundWidth, tabStripHeight);
-      [_tabSwitcherButtonBackgroundView setFrame:backgroundViewFrame];
-      [_tabSwitcherButtonBackgroundView
-          setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin];
-      UIImage* backgroundTabSwitcherImage =
-          [UIImage imageNamed:@"tabstrip_toggle_button_gradient"];
-      [_tabSwitcherButtonBackgroundView setImage:backgroundTabSwitcherImage];
-      [_view addSubview:_tabSwitcherButtonBackgroundView];
+  if (!base::FeatureList::IsEnabled(kChangeTabSwitcherPosition)) {
+    if (self.useTabStacking) {
+      tabFrame.size.width -= kTabSwitcherButtonWidth;
+      _tabStripView.contentInset = UIEdgeInsetsZero;
+      [_tabSwitcherButtonBackgroundView setHidden:YES];
+    } else {
+      if (!_tabSwitcherButtonBackgroundView) {
+        _tabSwitcherButtonBackgroundView = [[UIImageView alloc] init];
+        const CGFloat tabStripHeight = _view.frame.size.height;
+        const CGRect backgroundViewFrame = CGRectMake(
+            CGRectGetMaxX(_view.frame) - kTabSwitcherButtonBackgroundWidth, 0.0,
+            kTabSwitcherButtonBackgroundWidth, tabStripHeight);
+        [_tabSwitcherButtonBackgroundView setFrame:backgroundViewFrame];
+        [_tabSwitcherButtonBackgroundView
+            setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin];
+        UIImage* backgroundTabSwitcherImage =
+            [UIImage imageNamed:@"tabstrip_toggle_button_gradient"];
+        [_tabSwitcherButtonBackgroundView setImage:backgroundTabSwitcherImage];
+        [_view addSubview:_tabSwitcherButtonBackgroundView];
+      }
+      [_tabSwitcherButtonBackgroundView setHidden:NO];
+      _tabStripView.contentInset =
+          UIEdgeInsetsMake(0, 0, 0, kTabSwitcherButtonWidth);
+      [_view bringSubviewToFront:_tabSwitcherButton];
     }
-    [_tabSwitcherButtonBackgroundView setHidden:NO];
-    _tabStripView.contentInset =
-        UIEdgeInsetsMake(0, 0, 0, kTabSwitcherButtonWidth);
-    [_view bringSubviewToFront:_tabSwitcherButton];
   }
   [_tabStripView setFrame:tabFrame];
 }
diff --git a/ios/chrome/browser/ui/toolbar/buttons/toolbar_button_visibility_configuration.mm b/ios/chrome/browser/ui/toolbar/buttons/toolbar_button_visibility_configuration.mm
index 6fd91093..ea4d472d 100644
--- a/ios/chrome/browser/ui/toolbar/buttons/toolbar_button_visibility_configuration.mm
+++ b/ios/chrome/browser/ui/toolbar/buttons/toolbar_button_visibility_configuration.mm
@@ -45,8 +45,13 @@
 - (ToolbarComponentVisibility)tabGridButtonVisibility {
   switch (self.type) {
     case PRIMARY:
-      return ToolbarComponentVisibilityCompactWidthCompactHeight |
-             ToolbarComponentVisibilityRegularWidthCompactHeight;
+      if (base::FeatureList::IsEnabled(kChangeTabSwitcherPosition)) {
+        return ToolbarComponentVisibilityAlways &
+               ~ToolbarComponentVisibilitySplit;
+      } else {
+        return ToolbarComponentVisibilityCompactWidthCompactHeight |
+               ToolbarComponentVisibilityRegularWidthCompactHeight;
+      }
     case SECONDARY:
       return ToolbarComponentVisibilitySplit;
   }
diff --git a/ios/chrome/browser/ui/toolbar/primary_toolbar_view.mm b/ios/chrome/browser/ui/toolbar/primary_toolbar_view.mm
index 1d1497b..84207d9b 100644
--- a/ios/chrome/browser/ui/toolbar/primary_toolbar_view.mm
+++ b/ios/chrome/browser/ui/toolbar/primary_toolbar_view.mm
@@ -257,10 +257,16 @@
   self.tabGridButton = [self.buttonFactory tabGridButton];
   self.toolsMenuButton = [self.buttonFactory toolsMenuButton];
 
-  self.trailingStackViewButtons = @[
-    self.bookmarkButton, self.shareButton, self.tabGridButton,
-    self.toolsMenuButton
-  ];
+  if (base::FeatureList::IsEnabled(kChangeTabSwitcherPosition)) {
+    self.trailingStackViewButtons =
+        @[ self.shareButton, self.tabGridButton, self.toolsMenuButton ];
+  } else {
+    self.trailingStackViewButtons = @[
+      self.bookmarkButton, self.shareButton, self.tabGridButton,
+      self.toolsMenuButton
+    ];
+  }
+
   self.trailingStackView = [[UIStackView alloc]
       initWithArrangedSubviews:self.trailingStackViewButtons];
   self.trailingStackView.translatesAutoresizingMaskIntoConstraints = NO;
diff --git a/ios/chrome/browser/ui/toolbar/public/features.h b/ios/chrome/browser/ui/toolbar/public/features.h
index cee15e7..0536e95 100644
--- a/ios/chrome/browser/ui/toolbar/public/features.h
+++ b/ios/chrome/browser/ui/toolbar/public/features.h
@@ -9,6 +9,9 @@
 
 #include "base/feature_list.h"
 
+// Feature to change tab switcher position and remove bookmark button.
+extern const base::Feature kChangeTabSwitcherPosition;
+
 extern const base::Feature kToolbarNewTabButton;
 
 // Enum for the different icons for the search button.
diff --git a/ios/chrome/browser/ui/toolbar/public/features.mm b/ios/chrome/browser/ui/toolbar/public/features.mm
index 65e7ee7..bfa0f88 100644
--- a/ios/chrome/browser/ui/toolbar/public/features.mm
+++ b/ios/chrome/browser/ui/toolbar/public/features.mm
@@ -11,6 +11,9 @@
 #error "This file requires ARC support."
 #endif
 
+const base::Feature kChangeTabSwitcherPosition{
+    "kChangeTabSwitcherPosition", base::FEATURE_DISABLED_BY_DEFAULT};
+
 const base::Feature kToolbarNewTabButton{"ToolbarNewTabButton",
                                          base::FEATURE_DISABLED_BY_DEFAULT};
 
diff --git a/ios/chrome/browser/ui/util/named_guide.mm b/ios/chrome/browser/ui/util/named_guide.mm
index d5d40ae9..587ee6c 100644
--- a/ios/chrome/browser/ui/util/named_guide.mm
+++ b/ios/chrome/browser/ui/util/named_guide.mm
@@ -6,6 +6,7 @@
 
 #include "base/logging.h"
 #import "base/mac/foundation_util.h"
+#import "ios/chrome/browser/ui/toolbar/public/features.h"
 #import "ios/chrome/common/ui_util/constraints_ui_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -143,6 +144,8 @@
 #pragma mark - Public
 
 + (instancetype)guideWithName:(GuideName*)name view:(UIView*)view {
+  DCHECK(name != kTabStripTabSwitcherGuide ||
+         !base::FeatureList::IsEnabled(kChangeTabSwitcherPosition));
   while (view) {
     for (UILayoutGuide* guide in view.layoutGuides) {
       NamedGuide* namedGuide = base::mac::ObjCCast<NamedGuide>(guide);
diff --git a/ios/web/public/ui/crw_web_view_scroll_view_proxy.h b/ios/web/public/ui/crw_web_view_scroll_view_proxy.h
index 7de217e..bfc2e71 100644
--- a/ios/web/public/ui/crw_web_view_scroll_view_proxy.h
+++ b/ios/web/public/ui/crw_web_view_scroll_view_proxy.h
@@ -23,6 +23,8 @@
 // TODO(crbug.com/546152): rename class to CRWContentViewScrollViewProxy.
 @interface CRWWebViewScrollViewProxy : NSObject
 
+@property(nonatomic, readonly, copy) NSArray<__kindof UIView*>* subviews;
+
 // Used by the CRWWebViewProxy to set the UIScrollView to be managed.
 - (void)setScrollView:(UIScrollView*)scrollView;
 
@@ -71,7 +73,6 @@
     UIPanGestureRecognizer* panGestureRecognizer;
 // Returns the scrollview's gesture recognizers.
 @property(weak, nonatomic, readonly) NSArray* gestureRecognizers;
-@property(nonatomic, readonly, copy) NSArray<__kindof UIView*>* subviews;
 
 - (void)addGestureRecognizer:(UIGestureRecognizer*)gestureRecognizer;
 - (void)removeGestureRecognizer:(UIGestureRecognizer*)gestureRecognizer;
diff --git a/ios/web/web_state/ui/crw_web_view_scroll_view_proxy.mm b/ios/web/web_state/ui/crw_web_view_scroll_view_proxy.mm
index c13d89c..311339a1 100644
--- a/ios/web/web_state/ui/crw_web_view_scroll_view_proxy.mm
+++ b/ios/web/web_state/ui/crw_web_view_scroll_view_proxy.mm
@@ -173,14 +173,6 @@
   [self stopObservingScrollView:self.underlyingScrollView];
 }
 
-- (void)addGestureRecognizer:(UIGestureRecognizer*)gestureRecognizer {
-  [self.underlyingScrollView addGestureRecognizer:gestureRecognizer];
-}
-
-- (void)removeGestureRecognizer:(UIGestureRecognizer*)gestureRecognizer {
-  [self.underlyingScrollView removeGestureRecognizer:gestureRecognizer];
-}
-
 - (void)addObserver:(id<CRWWebViewScrollViewProxyObserver>)observer {
   [_observers addObserver:observer];
 }
@@ -232,27 +224,6 @@
   [_observers webViewScrollViewProxyDidSetScrollView:self];
 }
 
-- (CGRect)frame {
-  return self.underlyingScrollView ? [self.underlyingScrollView frame]
-                                   : CGRectZero;
-}
-
-- (BOOL)isScrollEnabled {
-  return [self.underlyingScrollView isScrollEnabled];
-}
-
-- (void)setScrollEnabled:(BOOL)scrollEnabled {
-  [self.underlyingScrollView setScrollEnabled:scrollEnabled];
-}
-
-- (BOOL)bounces {
-  return [self.underlyingScrollView bounces];
-}
-
-- (void)setBounces:(BOOL)bounces {
-  [self.underlyingScrollView setBounces:bounces];
-}
-
 - (BOOL)clipsToBounds {
   if (!self.underlyingScrollView && _storedClipsToBounds) {
     return *_storedClipsToBounds;
@@ -265,75 +236,6 @@
   self.underlyingScrollView.clipsToBounds = clipsToBounds;
 }
 
-- (BOOL)isDecelerating {
-  return [self.underlyingScrollView isDecelerating];
-}
-
-- (BOOL)isDragging {
-  return [self.underlyingScrollView isDragging];
-}
-
-- (BOOL)isTracking {
-  return [self.underlyingScrollView isTracking];
-}
-
-- (BOOL)isZooming {
-  return [self.underlyingScrollView isZooming];
-}
-
-- (CGFloat)zoomScale {
-  return [self.underlyingScrollView zoomScale];
-}
-
-- (void)setContentOffset:(CGPoint)contentOffset {
-  [self.underlyingScrollView setContentOffset:contentOffset];
-}
-
-- (CGPoint)contentOffset {
-  return self.underlyingScrollView ? [self.underlyingScrollView contentOffset]
-                                   : CGPointZero;
-}
-
-- (void)setContentInset:(UIEdgeInsets)contentInset {
-  [self.underlyingScrollView setContentInset:contentInset];
-}
-
-- (UIEdgeInsets)contentInset {
-  return self.underlyingScrollView ? [self.underlyingScrollView contentInset]
-                                   : UIEdgeInsetsZero;
-}
-
-- (void)setScrollIndicatorInsets:(UIEdgeInsets)scrollIndicatorInsets {
-  [self.underlyingScrollView setScrollIndicatorInsets:scrollIndicatorInsets];
-}
-
-- (UIEdgeInsets)scrollIndicatorInsets {
-  return self.underlyingScrollView
-             ? [self.underlyingScrollView scrollIndicatorInsets]
-             : UIEdgeInsetsZero;
-}
-
-- (void)setContentSize:(CGSize)contentSize {
-  [self.underlyingScrollView setContentSize:contentSize];
-}
-
-- (CGSize)contentSize {
-  return self.underlyingScrollView ? [self.underlyingScrollView contentSize]
-                                   : CGSizeZero;
-}
-
-- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated {
-  [self.underlyingScrollView setContentOffset:contentOffset animated:animated];
-}
-
-- (BOOL)scrollsToTop {
-  return [self.underlyingScrollView scrollsToTop];
-}
-
-- (void)setScrollsToTop:(BOOL)scrollsToTop {
-  [self.underlyingScrollView setScrollsToTop:scrollsToTop];
-}
-
 - (UIScrollViewContentInsetAdjustmentBehavior)contentInsetAdjustmentBehavior
     API_AVAILABLE(ios(11.0)) {
   if (self.underlyingScrollView) {
@@ -345,10 +247,6 @@
   }
 }
 
-- (UIEdgeInsets)adjustedContentInset API_AVAILABLE(ios(11.0)) {
-  return [self.underlyingScrollView adjustedContentInset];
-}
-
 - (void)setContentInsetAdjustmentBehavior:
     (UIScrollViewContentInsetAdjustmentBehavior)contentInsetAdjustmentBehavior
     API_AVAILABLE(ios(11.0)) {
@@ -359,14 +257,6 @@
           contentInsetAdjustmentBehavior);
 }
 
-- (UIPanGestureRecognizer*)panGestureRecognizer {
-  return [self.underlyingScrollView panGestureRecognizer];
-}
-
-- (NSArray*)gestureRecognizers {
-  return [self.underlyingScrollView gestureRecognizers];
-}
-
 - (NSArray<__kindof UIView*>*)subviews {
   return self.underlyingScrollView ? [self.underlyingScrollView subviews] : @[];
 }
diff --git a/media/ffmpeg/ffmpeg_common.cc b/media/ffmpeg/ffmpeg_common.cc
index 1f2e692..aa4ea574 100644
--- a/media/ffmpeg/ffmpeg_common.cc
+++ b/media/ffmpeg/ffmpeg_common.cc
@@ -120,6 +120,10 @@
       return kCodecOpus;
     case AV_CODEC_ID_ALAC:
       return kCodecALAC;
+#if BUILDFLAG(ENABLE_PLATFORM_MPEG_H_AUDIO)
+    case AV_CODEC_ID_MPEGH_3D_AUDIO:
+      return kCodecMpegHAudio;
+#endif
     default:
       DVLOG(1) << "Unknown audio CodecID: " << codec_id;
   }
@@ -171,6 +175,10 @@
       return AV_CODEC_ID_PCM_MULAW;
     case kCodecOpus:
       return AV_CODEC_ID_OPUS;
+#if BUILDFLAG(ENABLE_PLATFORM_MPEG_H_AUDIO)
+    case kCodecMpegHAudio:
+      return AV_CODEC_ID_MPEGH_3D_AUDIO;
+#endif
     default:
       DVLOG(1) << "Unknown AudioCodec: " << audio_codec;
   }
@@ -352,6 +360,12 @@
       NOTREACHED();
 #endif
       break;
+#if BUILDFLAG(ENABLE_PLATFORM_MPEG_H_AUDIO)
+    case kCodecMpegHAudio:
+      channel_layout = CHANNEL_LAYOUT_BITSTREAM;
+      sample_format = kSampleFormatMpegHAudio;
+      break;
+#endif
 
     default:
       break;
@@ -391,6 +405,10 @@
   if (codec == kCodecAC3 || codec == kCodecEAC3)
     return true;
 #endif
+#if BUILDFLAG(ENABLE_PLATFORM_MPEG_H_AUDIO)
+  if (codec == kCodecMpegHAudio)
+    return true;
+#endif
 
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
   // TODO(dalecurtis): Just use the profile from the codec context if ffmpeg
diff --git a/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc b/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc
index db2dfae..8debb2ca4 100644
--- a/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc
@@ -682,7 +682,7 @@
   if (image_processor_device_) {
     // Try to get an image size as close as possible to the final one (i.e.
     // coded_size_ may include padding required by the decoder).
-    gl_image_size_ = pic_size;
+    gl_image_size_ = decoder_->GetVisibleRect().size();
     size_t planes_count;
     if (!V4L2ImageProcessorBackend::TryOutputFormat(
             output_format_fourcc_->ToV4L2PixFmt(),
@@ -1484,36 +1484,37 @@
     return;
   }
 
-  // TODO(crbug.com/982172): This must be done in AssignPictureBuffers().
-  // However the size of PictureBuffer might not be adjusted by ARC++. So we
-  // keep this until ARC++ side is fixed.
+  // TODO(crbug.com/982172): ARC++ may adjust the size of the buffer due to
+  // allocator constraints, but the VDA API does not provide a way for it to
+  // communicate the actual buffer size. If we are importing, make sure that the
+  // actual buffer size is coherent with what we expect, and adjust our size if
+  // needed.
   if (output_mode_ == Config::OutputMode::IMPORT) {
-    const int32_t stride = handle.planes[0].stride;
-    const int plane_horiz_bits_per_pixel =
-        VideoFrame::PlaneHorizontalBitsPerPixel(
-            gl_image_format_fourcc_->ToVideoPixelFormat(), 0);
-    if (plane_horiz_bits_per_pixel == 0 ||
-        (stride * 8) % plane_horiz_bits_per_pixel != 0) {
-      VLOGF(1) << "Invalid format " << gl_image_format_fourcc_->ToString()
-               << " or stride " << stride;
-      NOTIFY_ERROR(INVALID_ARGUMENT);
-      return;
+    DCHECK_GT(handle.planes.size(), 0u);
+    const gfx::Size handle_size = v4l2_vda_helpers::NativePixmapSizeFromHandle(
+        handle, *gl_image_format_fourcc_, gl_image_size_);
+
+    // If this is the first picture, then adjust the EGL width.
+    // Otherwise just check that it remains the same.
+    if (state_ == kAwaitingPictureBuffers) {
+      DCHECK_GE(handle_size.width(), gl_image_size_.width());
+      DVLOGF(3) << "Original gl_image_size=" << gl_image_size_.ToString()
+                << ", adjusted buffer size=" << handle_size.ToString();
+      gl_image_size_ = handle_size;
     }
-    int adjusted_coded_width = stride * 8 / plane_horiz_bits_per_pixel;
+    DCHECK_EQ(gl_image_size_, handle_size);
+
+    // For allocate mode, the IP will already have been created in
+    // AssignPictureBuffersTask.
     if (image_processor_device_ && !image_processor_) {
       DCHECK_EQ(kAwaitingPictureBuffers, state_);
       // This is the first buffer import. Create the image processor and change
       // the decoder state. The client may adjust the coded width. We don't have
       // the final coded size in AssignPictureBuffers yet. Use the adjusted
       // coded width to create the image processor.
-      DVLOGF(3) << "Original gl_image_size=" << gl_image_size_.ToString()
-                << ", adjusted coded width=" << adjusted_coded_width;
-      DCHECK_GE(adjusted_coded_width, gl_image_size_.width());
-      gl_image_size_.set_width(adjusted_coded_width);
       if (!CreateImageProcessor())
         return;
     }
-    DCHECK_EQ(gl_image_size_.width(), adjusted_coded_width);
   }
 
   // Put us in kIdle to allow further event processing.
diff --git a/media/gpu/v4l2/v4l2_vda_helpers.cc b/media/gpu/v4l2/v4l2_vda_helpers.cc
index c4d5ba9..12b382f 100644
--- a/media/gpu/v4l2/v4l2_vda_helpers.cc
+++ b/media/gpu/v4l2/v4l2_vda_helpers.cc
@@ -109,5 +109,34 @@
   return image_processor;
 }
 
+gfx::Size NativePixmapSizeFromHandle(const gfx::NativePixmapHandle& handle,
+                                     const Fourcc fourcc,
+                                     const gfx::Size& current_size) {
+  const uint32_t stride = handle.planes[0].stride;
+  const uint32_t horiz_bits_per_pixel =
+      VideoFrame::PlaneHorizontalBitsPerPixel(fourcc.ToVideoPixelFormat(), 0);
+  DCHECK_NE(horiz_bits_per_pixel, 0u);
+  // Stride must fit exactly on a byte boundary (8 bits per byte)
+  DCHECK_EQ((stride * 8) % horiz_bits_per_pixel, 0u);
+
+  // Actual width of buffer is stride (in bits) divided by bits per pixel.
+  int adjusted_coded_width = stride * 8 / horiz_bits_per_pixel;
+  // If the buffer is multi-planar, then the height of the buffer does not
+  // matter as long as it covers the visible area and we can just return
+  // the current height.
+  // For single-planar however, the actual height can be inferred by dividing
+  // the start offset of the second plane by the stride of the first plane,
+  // since the second plane is supposed to start right after the first one.
+  int adjusted_coded_height =
+      handle.planes.size() > 1 && handle.planes[1].offset != 0
+          ? handle.planes[1].offset / adjusted_coded_width
+          : current_size.height();
+
+  DCHECK_GE(adjusted_coded_width, current_size.width());
+  DCHECK_GE(adjusted_coded_height, current_size.height());
+
+  return gfx::Size(adjusted_coded_width, adjusted_coded_height);
+}
+
 }  // namespace v4l2_vda_helpers
 }  // namespace media
diff --git a/media/gpu/v4l2/v4l2_vda_helpers.h b/media/gpu/v4l2/v4l2_vda_helpers.h
index 54607d2..efac751 100644
--- a/media/gpu/v4l2/v4l2_vda_helpers.h
+++ b/media/gpu/v4l2/v4l2_vda_helpers.h
@@ -57,6 +57,14 @@
     scoped_refptr<base::SequencedTaskRunner> client_task_runner,
     ImageProcessor::ErrorCB error_cb);
 
+// When importing a buffer (ARC++ use-case), the buffer's actual size may
+// be different from the requested one. However, the actual size is never
+// provided to us - so we need to compute it from the NativePixmapHandle.
+// Given the |handle| and |fourcc| of the buffer, adjust |current_size| to
+// the actual computed size of the buffer and return the new size.
+gfx::Size NativePixmapSizeFromHandle(const gfx::NativePixmapHandle& handle,
+                                     const Fourcc fourcc,
+                                     const gfx::Size& current_size);
 }  // namespace v4l2_vda_helpers
 }  // namespace media
 
diff --git a/media/gpu/v4l2/v4l2_video_decode_accelerator.cc b/media/gpu/v4l2/v4l2_video_decode_accelerator.cc
index 66c9e66..57f3103 100644
--- a/media/gpu/v4l2/v4l2_video_decode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_video_decode_accelerator.cc
@@ -626,43 +626,37 @@
     return;
   }
 
-  // TODO(crbug.com/982172): This must be done in AssignPictureBuffers().
-  // However the size of PictureBuffer might not be adjusted by ARC++. So we
-  // keep this until ARC++ side is fixed.
+  // TODO(crbug.com/982172): ARC++ may adjust the size of the buffer due to
+  // allocator constraints, but the VDA API does not provide a way for it to
+  // communicate the actual buffer size. If we are importing, make sure that the
+  // actual buffer size is coherent with what we expect, and adjust our size if
+  // needed.
   if (output_mode_ == Config::OutputMode::IMPORT) {
     DCHECK_GT(handle.planes.size(), 0u);
-    const int32_t stride = handle.planes[0].stride;
-    int plane_horiz_bits_per_pixel = VideoFrame::PlaneHorizontalBitsPerPixel(
-        egl_image_format_fourcc_->ToVideoPixelFormat(), 0);
-    if (plane_horiz_bits_per_pixel == 0 ||
-        (stride * 8) % plane_horiz_bits_per_pixel != 0) {
-      VLOGF(1) << "Invalid format " << egl_image_format_fourcc_->ToString()
-               << " or stride " << stride;
-      NOTIFY_ERROR(INVALID_ARGUMENT);
-      return;
-    }
+    const gfx::Size handle_size = v4l2_vda_helpers::NativePixmapSizeFromHandle(
+        handle, *egl_image_format_fourcc_, egl_image_size_);
 
-    int adjusted_coded_width = stride * 8 / plane_horiz_bits_per_pixel;
     // If this is the first picture, then adjust the EGL width.
     // Otherwise just check that it remains the same.
     if (decoder_state_ == kAwaitingPictureBuffers) {
-      DCHECK_GE(adjusted_coded_width, egl_image_size_.width());
-      egl_image_size_.set_width(adjusted_coded_width);
+      DCHECK_GE(handle_size.width(), egl_image_size_.width());
+      DVLOGF(3) << "Original egl_image_size=" << egl_image_size_.ToString()
+                << ", adjusted buffer size=" << handle_size.ToString();
+      egl_image_size_ = handle_size;
     }
-    DCHECK_EQ(egl_image_size_.width(), adjusted_coded_width);
+    DCHECK_EQ(egl_image_size_, handle_size);
 
-    DVLOGF(3) << "Original egl_image_size=" << egl_image_size_.ToString()
-              << ", adjusted coded width=" << adjusted_coded_width;
-  }
-
-  if (image_processor_device_ && !image_processor_) {
-    DCHECK_EQ(kAwaitingPictureBuffers, decoder_state_);
-    // This is the first buffer import. Create the image processor and change
-    // the decoder state. The client may adjust the coded width. We don't have
-    // the final coded size in AssignPictureBuffers yet. Use the adjusted coded
-    // width to create the image processor.
-    if (!CreateImageProcessor())
-      return;
+    // For allocate mode, the IP will already have been created in
+    // AssignPictureBuffersTask.
+    if (image_processor_device_ && !image_processor_) {
+      DCHECK_EQ(kAwaitingPictureBuffers, decoder_state_);
+      // This is the first buffer import. Create the image processor and change
+      // the decoder state. The client may adjust the coded width. We don't have
+      // the final coded size in AssignPictureBuffers yet. Use the adjusted
+      // coded width to create the image processor.
+      if (!CreateImageProcessor())
+        return;
+    }
   }
 
   if (reset_pending_) {
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 12656ad..d47d101 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -1345,6 +1345,7 @@
       "third_party/quiche/src/quic/core/frames/quic_streams_blocked_frame.h",
       "third_party/quiche/src/quic/core/frames/quic_window_update_frame.cc",
       "third_party/quiche/src/quic/core/frames/quic_window_update_frame.h",
+      "third_party/quiche/src/quic/core/handshaker_delegate_interface.h",
       "third_party/quiche/src/quic/core/http/http_constants.h",
       "third_party/quiche/src/quic/core/http/http_decoder.cc",
       "third_party/quiche/src/quic/core/http/http_decoder.h",
@@ -1474,6 +1475,7 @@
       "third_party/quiche/src/quic/core/quic_framer.cc",
       "third_party/quiche/src/quic/core/quic_framer.h",
       "third_party/quiche/src/quic/core/quic_interval.h",
+      "third_party/quiche/src/quic/core/quic_interval_deque.h",
       "third_party/quiche/src/quic/core/quic_interval_set.h",
       "third_party/quiche/src/quic/core/quic_lru_cache.h",
       "third_party/quiche/src/quic/core/quic_mtu_discovery.cc",
@@ -1551,6 +1553,7 @@
       "third_party/quiche/src/quic/platform/api/quic_containers.h",
       "third_party/quiche/src/quic/platform/api/quic_error_code_wrappers.h",
       "third_party/quiche/src/quic/platform/api/quic_estimate_memory_usage.h",
+      "third_party/quiche/src/quic/platform/api/quic_export.h",
       "third_party/quiche/src/quic/platform/api/quic_exported_stats.h",
       "third_party/quiche/src/quic/platform/api/quic_fallthrough.h",
       "third_party/quiche/src/quic/platform/api/quic_file_utils.cc",
@@ -3428,6 +3431,7 @@
     "third_party/quiche/src/quic/test_tools/quic_flow_controller_peer.h",
     "third_party/quiche/src/quic/test_tools/quic_framer_peer.cc",
     "third_party/quiche/src/quic/test_tools/quic_framer_peer.h",
+    "third_party/quiche/src/quic/test_tools/quic_interval_deque_peer.h",
     "third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.cc",
     "third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.h",
     "third_party/quiche/src/quic/test_tools/quic_sent_packet_manager_peer.cc",
diff --git a/net/cookies/canonical_cookie.cc b/net/cookies/canonical_cookie.cc
index 2aaea1a..4bf35ddb 100644
--- a/net/cookies/canonical_cookie.cc
+++ b/net/cookies/canonical_cookie.cc
@@ -348,6 +348,9 @@
     return nullptr;
   }
 
+  if (name.empty() && value.empty())
+    return nullptr;
+
   // This validation step must happen before GetCookieDomainWithString, so it
   // doesn't fail DCHECKs.
   if (!cookie_util::DomainIsHostOnly(url.host()))
diff --git a/net/cookies/canonical_cookie_unittest.cc b/net/cookies/canonical_cookie_unittest.cc
index a6c7d2f..26b3fec 100644
--- a/net/cookies/canonical_cookie_unittest.cc
+++ b/net/cookies/canonical_cookie_unittest.cc
@@ -1804,6 +1804,12 @@
   ASSERT_TRUE(cc);
   EXPECT_EQ("/foo%7F", cc->Path());
 
+  // Empty name and value.
+  EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie(
+      GURL("http://www.foo.com"), "", "", std::string(), "/", base::Time(),
+      base::Time(), base::Time(), false /*secure*/, false /*httponly*/,
+      CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT));
+
   // A __Secure- cookie must be Secure.
   EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie(
       GURL("https://www.foo.com"), "__Secure-A", "B", ".www.foo.com", "/",
@@ -1898,18 +1904,16 @@
   // Check that a file URL with an IPv6 host, and matching IPv6 domain, are
   // valid.
   EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie(
-      GURL("file://[A::]"), std::string(), std::string(), "[A::]", "",
-      base::Time(), base::Time(), base::Time(), false /*secure*/,
-      false /*httponly*/, CookieSameSite::NO_RESTRICTION,
-      COOKIE_PRIORITY_DEFAULT));
+      GURL("file://[A::]"), "A", "B", "[A::]", "", base::Time(), base::Time(),
+      base::Time(), false /*secure*/, false /*httponly*/,
+      CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT));
 
   // On Windows, URLs beginning with two backslashes are considered file
   // URLs. On other platforms, they are invalid.
   auto double_backslash_ipv6_cookie = CanonicalCookie::CreateSanitizedCookie(
-      GURL("\\\\[A::]"), std::string(), std::string(), "[A::]", "",
-      base::Time(), base::Time(), base::Time(), false /*secure*/,
-      false /*httponly*/, CookieSameSite::NO_RESTRICTION,
-      COOKIE_PRIORITY_DEFAULT);
+      GURL("\\\\[A::]"), "A", "B", "[A::]", "", base::Time(), base::Time(),
+      base::Time(), false /*secure*/, false /*httponly*/,
+      CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT);
 #if defined(OS_WIN)
   EXPECT_TRUE(double_backslash_ipv6_cookie);
   EXPECT_TRUE(double_backslash_ipv6_cookie->IsCanonical());
diff --git a/net/cookies/parsed_cookie.cc b/net/cookies/parsed_cookie.cc
index 64e5ea6e..6da2134 100644
--- a/net/cookies/parsed_cookie.cc
+++ b/net/cookies/parsed_cookie.cc
@@ -175,6 +175,11 @@
 bool ParsedCookie::SetName(const std::string& name) {
   if (!name.empty() && !HttpUtil::IsToken(name))
     return false;
+
+  // Fail if we'd be creating a cookie with an empty name and value.
+  if (name.empty() && (pairs_.empty() || pairs_[0].second.empty()))
+    return false;
+
   if (pairs_.empty())
     pairs_.push_back(std::make_pair("", ""));
   pairs_[0].first = name;
@@ -184,6 +189,11 @@
 bool ParsedCookie::SetValue(const std::string& value) {
   if (!IsValidCookieValue(value))
     return false;
+
+  // Fail if we'd be creating a cookie with an empty name and value.
+  if (value.empty() && (pairs_.empty() || pairs_[0].first.empty()))
+    return false;
+
   if (pairs_.empty())
     pairs_.push_back(std::make_pair("", ""));
   pairs_[0].second = value;
diff --git a/net/cookies/parsed_cookie.h b/net/cookies/parsed_cookie.h
index 3dc24ac..7917c68 100644
--- a/net/cookies/parsed_cookie.h
+++ b/net/cookies/parsed_cookie.h
@@ -63,6 +63,9 @@
   // The functions return false in case an error occurred.
   // The cookie needs to be assigned a name/value before setting the other
   // attributes.
+  //
+  // TODO(chlily): Ideally, we can remove these mutators once we remove the
+  // single callsite.
   bool SetName(const std::string& name);
   bool SetValue(const std::string& value);
   bool SetPath(const std::string& path);
diff --git a/net/cookies/parsed_cookie_unittest.cc b/net/cookies/parsed_cookie_unittest.cc
index 72dbc994..27ce53d 100644
--- a/net/cookies/parsed_cookie_unittest.cc
+++ b/net/cookies/parsed_cookie_unittest.cc
@@ -29,6 +29,28 @@
   }
 }
 
+TEST(ParsedCookieTest, TestSetEmptyNameValue) {
+  ParsedCookie empty("");
+  EXPECT_FALSE(empty.IsValid());
+  EXPECT_FALSE(empty.SetName(""));
+  EXPECT_FALSE(empty.SetValue(""));
+  EXPECT_FALSE(empty.IsValid());
+
+  ParsedCookie empty_value("name=");
+  EXPECT_TRUE(empty_value.IsValid());
+  EXPECT_EQ("name", empty_value.Name());
+  EXPECT_FALSE(empty_value.SetName(""));
+  EXPECT_EQ("name", empty_value.Name());
+  EXPECT_TRUE(empty_value.IsValid());
+
+  ParsedCookie empty_name("value");
+  EXPECT_TRUE(empty_name.IsValid());
+  EXPECT_EQ("value", empty_name.Value());
+  EXPECT_FALSE(empty_name.SetValue(""));
+  EXPECT_EQ("value", empty_name.Value());
+  EXPECT_TRUE(empty_value.IsValid());
+}
+
 TEST(ParsedCookieTest, TestQuoted) {
   // These are some quoting cases which the major browsers all
   // handle differently.  I've tested Internet Explorer 6, Opera 9.6,
diff --git a/net/quic/quic_flags_list.h b/net/quic/quic_flags_list.h
index 3db45e0..53409f6 100644
--- a/net/quic/quic_flags_list.h
+++ b/net/quic/quic_flags_list.h
@@ -72,9 +72,6 @@
 // send no more than factor times bytes received.
 QUIC_FLAG(int32_t, FLAGS_quic_anti_amplification_factor, 3)
 
-// Enables 3 new connection options to make PROBE_RTT more aggressive
-QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_bbr_less_probe_rtt, false)
-
 // When true, set the initial congestion control window from connection options
 // in QuicSentPacketManager rather than TcpCubicSenderBytes.
 QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_unified_iw_options, false)
@@ -88,7 +85,7 @@
 
 // Default enables QUIC ack decimation and adds a connection option to disable
 // it.
-QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_ack_decimation, true)
+QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_ack_decimation, false)
 
 // If true, QUIC offload pacing when using USPS as egress method.
 QUIC_FLAG(bool, FLAGS_quic_restart_flag_quic_offload_pacing_to_usps2, false)
@@ -214,22 +211,9 @@
           FLAGS_quic_reloadable_flag_quic_enable_lifo_write_scheduler,
           true)
 
-// If true, enable IETF style probe timeout.
-QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_pto, true)
-
 // The maximum amount of CRYPTO frame data that can be buffered.
 QUIC_FLAG(int32_t, FLAGS_quic_max_buffered_crypto_bytes, 16 * 1024)
 
-// If true, enable IETF loss detection as described in
-// https://tools.ietf.org/html/draft-ietf-quic-recovery-22#section-6.1.
-QUIC_FLAG(bool,
-          FLAGS_quic_reloadable_flag_quic_enable_ietf_loss_detection,
-          true)
-
-// If true, skip packet number before sending the last PTO retransmission.
-QUIC_FLAG(bool,
-          FLAGS_quic_reloadable_flag_quic_skip_packet_number_for_pto,
-          true)
 // If true, enable HTTP/2 default scheduling(round robin).
 QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_rr_write_scheduler, true)
 
@@ -329,7 +313,7 @@
 QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_disable_version_q050, false)
 
 // If true, enable QUIC version Q099.
-QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_version_q099, false)
+QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_version_q099, true)
 
 // If true, enable QUIC version T050.
 QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_version_t050, true)
@@ -356,7 +340,7 @@
 // If true, QUIC BBRv2 will cut inflight_hi gradually upon loss from PROBE_UP.
 QUIC_FLAG(bool,
           FLAGS_quic_reloadable_flag_quic_bbr2_cut_inflight_hi_gradually,
-          false)
+          true)
 
 // If true, the QUIC dispatcher will drop INITIAL packets that are too small.
 QUIC_FLAG(bool,
@@ -381,7 +365,7 @@
 QUIC_FLAG(
     bool,
     FLAGS_quic_reloadable_flag_quic_create_server_handshaker_in_constructor,
-    false)
+    true)
 
 // If true, the frequency of stream frame coalescing will be logged as
 // QuicSession.CoalesceStreamFrameStatus.
diff --git a/third_party/blink/public/mojom/devtools/devtools_agent.mojom b/third_party/blink/public/mojom/devtools/devtools_agent.mojom
index 417749b..2299851 100644
--- a/third_party/blink/public/mojom/devtools/devtools_agent.mojom
+++ b/third_party/blink/public/mojom/devtools/devtools_agent.mojom
@@ -94,10 +94,10 @@
   ReportChildWorkers(bool report, bool wait_for_debugger) => ();
 };
 
-// This interface is implemented in browser and is notified by DevToolsAgent
-// when new child worker is available for future debugging.
+// This interface is implemented in the browser and is notified by
+// DevToolsAgent when a new child worker is available for future debugging.
 interface DevToolsAgentHost {
-  // Informs the host about new child worker and gives its DevToolsAgent
+  // Informs the host about the new child worker and gives its DevToolsAgent
   // for debugging.
   // |devtools_worker_token| is a unique token identifying this worker.
   // |waiting_for_debugger| is true if worker was paused on startup and
diff --git a/third_party/blink/public/mojom/fetch/fetch_api_request.mojom b/third_party/blink/public/mojom/fetch/fetch_api_request.mojom
index 313369b..f598b57b2 100644
--- a/third_party/blink/public/mojom/fetch/fetch_api_request.mojom
+++ b/third_party/blink/public/mojom/fetch/fetch_api_request.mojom
@@ -173,8 +173,7 @@
   bool is_main_resource_load = false;
   RequestContextType request_context_type = RequestContextType.UNSPECIFIED;
   network.mojom.RequestDestination destination = network.mojom.RequestDestination.kEmpty;
-  network.mojom.RequestContextFrameType frame_type =
-    network.mojom.RequestContextFrameType.kNone;
+  RequestContextFrameType frame_type = RequestContextFrameType.kNone;
   url.mojom.Url url;
   string method;
   FetchAPIRequestHeaders headers;
diff --git a/third_party/blink/public/mojom/frame/frame.mojom b/third_party/blink/public/mojom/frame/frame.mojom
index 45c10d4..d06bb4f0 100644
--- a/third_party/blink/public/mojom/frame/frame.mojom
+++ b/third_party/blink/public/mojom/frame/frame.mojom
@@ -7,6 +7,7 @@
 import "cc/mojom/touch_action.mojom";
 import "mojo/public/mojom/base/string16.mojom";
 import "mojo/public/mojom/base/unguessable_token.mojom";
+import "mojo/public/mojom/base/time.mojom";
 import "services/network/public/mojom/content_security_policy.mojom";
 import "skia/public/mojom/skcolor.mojom";
 import "third_party/blink/public/mojom/devtools/console_message.mojom";
@@ -158,6 +159,11 @@
   DidBlockNavigation(url.mojom.Url blocked_url, url.mojom.Url initiator_url,
                        blink.mojom.NavigationBlockedReason reason);
 
+  // Dispatch a load event for this frame in the iframe element of an
+  // out-of-process parent frame. Once handled, the browser process should
+  // call RemoteFrame::DispatchLoadEventForFrameOwner() in the renderer.
+  DispatchLoad();
+
   // Tells the browser to navigate back or forward in session history by
   // the given offset (relative to the current position in session
   // history). |has_user_gesture| tells whether or not this is the consequence
@@ -247,6 +253,16 @@
   // contents. This only happens for frame owners which render their own
   // fallback contents (i.e., <object>).
   RenderFallbackContent();
+
+  // Instructs the frame to invoke the beforeunload event handler.
+  //
+  // The closure callback is invoked to acknowledge the browser that
+  // the beforeunload event is handled. |proceed| matches the return value
+  // of the frame's beforeunload handler: true if the user decided to proceed
+  // with leaving the page.
+  BeforeUnload(bool is_reload)
+      => (bool proceed, mojo_base.mojom.TimeTicks before_unload_start_time,
+          mojo_base.mojom.TimeTicks before_unload_end_time);
 };
 
 // Implemented in Browser, this interface defines frame-specific methods that
diff --git a/third_party/blink/public/mojom/loader/request_context_frame_type.mojom b/third_party/blink/public/mojom/loader/request_context_frame_type.mojom
index 7294e47..a189ec9 100644
--- a/third_party/blink/public/mojom/loader/request_context_frame_type.mojom
+++ b/third_party/blink/public/mojom/loader/request_context_frame_type.mojom
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-module network.mojom;
+module blink.mojom;
 
 // Corresponds to Fetch's "context frame type", the frame type of the requester
 // of the resource fetching. However, it has been removed in spec, see the
diff --git a/third_party/blink/public/mojom/service_worker/service_worker_client.mojom b/third_party/blink/public/mojom/service_worker/service_worker_client.mojom
index 1e638f10..d52ccef 100644
--- a/third_party/blink/public/mojom/service_worker/service_worker_client.mojom
+++ b/third_party/blink/public/mojom/service_worker/service_worker_client.mojom
@@ -46,7 +46,7 @@
   url.mojom.Url url;
 
   // Client#frameType.
-  network.mojom.RequestContextFrameType frame_type = network.mojom.RequestContextFrameType.kNone;
+  RequestContextFrameType frame_type = RequestContextFrameType.kNone;
 
   // Client#id
   string client_uuid;
diff --git a/third_party/blink/public/platform/web_url_request.h b/third_party/blink/public/platform/web_url_request.h
index 193efaa4..b10cf9c 100644
--- a/third_party/blink/public/platform/web_url_request.h
+++ b/third_party/blink/public/platform/web_url_request.h
@@ -46,7 +46,6 @@
 enum class RedirectMode : int32_t;
 enum class ReferrerPolicy : int32_t;
 enum class RequestMode : int32_t;
-enum class RequestContextFrameType : int32_t;
 enum class RequestDestination : int32_t;
 }  // namespace mojom
 }  // namespace network
@@ -60,6 +59,7 @@
 namespace mojom {
 enum class FetchCacheMode : int32_t;
 enum class RequestContextType : int32_t;
+enum class RequestContextFrameType : int32_t;
 }  // namespace mojom
 
 class ResourceRequest;
diff --git a/third_party/blink/public/web/web_local_frame.h b/third_party/blink/public/web/web_local_frame.h
index 83d0923..6ce9fa2 100644
--- a/third_party/blink/public/web/web_local_frame.h
+++ b/third_party/blink/public/web/web_local_frame.h
@@ -156,11 +156,6 @@
   // Runs unload handlers for this frame.
   virtual void DispatchUnloadEvent() = 0;
 
-  // Indicates that the DOM of the initial empty document has been
-  // accessed via javascript. The BeforeUnload event will not be dispatched
-  // if the initial document has not been accessed.
-  virtual bool HasAccessedInitialDocument() = 0;
-
   // Basic properties ---------------------------------------------------
 
   // The urls of the given combination types of favicon (if any) specified by
diff --git a/third_party/blink/public/web/web_local_frame_client.h b/third_party/blink/public/web/web_local_frame_client.h
index 229db134..d464d1c6 100644
--- a/third_party/blink/public/web/web_local_frame_client.h
+++ b/third_party/blink/public/web/web_local_frame_client.h
@@ -459,10 +459,6 @@
   // Only used when the parent frame is remote.
   virtual void ForwardResourceTimingToParent(const WebResourceTimingInfo&) {}
 
-  // Called to dispatch a load event for this frame in the FrameOwner of an
-  // out-of-process parent frame.
-  virtual void DispatchLoad() {}
-
   // Returns the effective connection type when the frame was fetched.
   virtual WebEffectiveConnectionType GetEffectiveConnectionType() {
     return WebEffectiveConnectionType::kTypeUnknown;
diff --git a/third_party/blink/public/web/web_navigation_params.h b/third_party/blink/public/web/web_navigation_params.h
index 8b06ec0..aed8680 100644
--- a/third_party/blink/public/web/web_navigation_params.h
+++ b/third_party/blink/public/web/web_navigation_params.h
@@ -61,8 +61,8 @@
 
   // The frame type. This must not be kNone. See RequestContextFrameType.
   // TODO(dgozman): enforce this is not kNone.
-  network::mojom::RequestContextFrameType frame_type =
-      network::mojom::RequestContextFrameType::kNone;
+  mojom::RequestContextFrameType frame_type =
+      mojom::RequestContextFrameType::kNone;
 
   // The navigation type. See WebNavigationType.
   WebNavigationType navigation_type = kWebNavigationTypeOther;
diff --git a/third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h b/third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h
index 022e5f5c..2f4d94896 100644
--- a/third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h
+++ b/third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h
@@ -27,6 +27,7 @@
 namespace bindings {
 
 class DictionaryBase;
+class UnionBase;
 
 CORE_EXPORT ScriptWrappable* NativeValueTraitsInterfaceNativeValue(
     v8::Isolate* isolate,
@@ -789,6 +790,19 @@
   }
 };
 
+// Union type
+template <typename T>
+struct NativeValueTraits<
+    T,
+    typename std::enable_if_t<std::is_base_of<bindings::UnionBase, T>::value>>
+    : public NativeValueTraitsBase<T*> {
+  static T NativeValue(v8::Isolate* isolate,
+                       v8::Local<v8::Value> value,
+                       ExceptionState& exception_state) {
+    return T::Create(isolate, value, exception_state);
+  }
+};
+
 // Nullable
 template <typename InnerType>
 struct NativeValueTraits<
diff --git a/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h b/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h
index 419739f8..a07836d6 100644
--- a/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h
+++ b/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h
@@ -176,7 +176,6 @@
    public:
     MessagePortArray* message_ports = nullptr;
     const WebBlobInfoArray* blob_info = nullptr;
-    bool read_wasm_from_stream = false;
   };
   v8::Local<v8::Value> Deserialize(v8::Isolate* isolate) {
     return Deserialize(isolate, DeserializeOptions());
diff --git a/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_deserializer.cc b/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_deserializer.cc
index f60eb2f..85bd656a 100644
--- a/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_deserializer.cc
+++ b/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_deserializer.cc
@@ -133,7 +133,6 @@
       transferred_message_ports_(options.message_ports),
       blob_info_array_(options.blob_info) {
   deserializer_.SetSupportsLegacyWireFormat(true);
-  deserializer_.SetExpectInlineWasm(options.read_wasm_from_stream);
 }
 
 v8::Local<v8::Value> V8ScriptValueDeserializer::Deserialize() {
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc b/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc
index 6dc5d6d3..b5bc051 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc
@@ -25,7 +25,9 @@
 
 #include "third_party/blink/renderer/bindings/core/v8/v8_initializer.h"
 
+#include <algorithm>
 #include <memory>
+#include <utility>
 
 #include "base/memory/scoped_refptr.h"
 #include "base/metrics/histogram_macros.h"
@@ -93,7 +95,7 @@
 static void ReportOOMErrorInMainThread(const char* location, bool is_js_heap) {
   DVLOG(1) << "V8 " << (is_js_heap ? "javascript" : "process") << " OOM: ("
            << location << ").";
-  OOM_CRASH();
+  OOM_CRASH(0);
 }
 
 static String ExtractMessageForConsole(v8::Isolate* isolate,
diff --git a/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.cc b/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.cc
index d2b27a02..94719a2f 100644
--- a/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.cc
+++ b/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.cc
@@ -542,7 +542,6 @@
       value->CreateSerializedValue();
   SerializedScriptValue::DeserializeOptions options;
   options.blob_info = &value->BlobInfo();
-  options.read_wasm_from_stream = true;
 
   // deserialize() returns null when serialization fails.  This is sub-optimal
   // because IndexedDB values can be null, so an application cannot distinguish
@@ -758,8 +757,7 @@
 
 ScriptValue DeserializeScriptValue(ScriptState* script_state,
                                    SerializedScriptValue* serialized_value,
-                                   const Vector<WebBlobInfo>* blob_info,
-                                   bool read_wasm_from_stream) {
+                                   const Vector<WebBlobInfo>* blob_info) {
   v8::Isolate* isolate = script_state->GetIsolate();
   v8::HandleScope handle_scope(isolate);
   if (!serialized_value)
@@ -767,7 +765,6 @@
 
   SerializedScriptValue::DeserializeOptions options;
   options.blob_info = blob_info;
-  options.read_wasm_from_stream = read_wasm_from_stream;
   return ScriptValue(isolate, serialized_value->Deserialize(isolate, options));
 }
 
diff --git a/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.h b/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.h
index 7832132..3a44e6c3 100644
--- a/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.h
+++ b/third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.h
@@ -34,8 +34,7 @@
                                                    const IDBKeyPath&);
 ScriptValue DeserializeScriptValue(ScriptState*,
                                    SerializedScriptValue*,
-                                   const Vector<WebBlobInfo>*,
-                                   bool read_wasm_from_stream);
+                                   const Vector<WebBlobInfo>*);
 
 #if DCHECK_IS_ON()
 void AssertPrimaryKeyValidOrInjectable(ScriptState*, const IDBValue*);
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/union.py b/third_party/blink/renderer/bindings/scripts/bind_gen/union.py
index 4921882..d545e67 100644
--- a/third_party/blink/renderer/bindings/scripts/bind_gen/union.py
+++ b/third_party/blink/renderer/bindings/scripts/bind_gen/union.py
@@ -10,6 +10,7 @@
 from .code_node import ListNode
 from .code_node import TextNode
 from .code_node_cxx import CxxClassDefNode
+from .code_node_cxx import CxxFuncDeclNode
 from .code_node_cxx import CxxNamespaceNode
 from .codegen_accumulator import CodeGenAccumulator
 from .codegen_context import CodeGenContext
@@ -24,6 +25,33 @@
 from .path_manager import PathManager
 
 
+def make_union_constructor_defs(cg_context):
+    assert isinstance(cg_context, CodeGenContext)
+
+    class_name = cg_context.class_name
+
+    return ListNode([
+        CxxFuncDeclNode(
+            name=class_name, arg_decls=[], return_type="", default=True),
+        CxxFuncDeclNode(
+            name=class_name,
+            arg_decls=["const ${class_name}&"],
+            return_type="",
+            default=True),
+        CxxFuncDeclNode(
+            name=class_name,
+            arg_decls=["${class_name}&&"],
+            return_type="",
+            default=True),
+        CxxFuncDeclNode(
+            name="~${class_name}",
+            arg_decls=[],
+            return_type="",
+            override=True,
+            default=True),
+    ])
+
+
 def make_union_class_def(cg_context):
     assert isinstance(cg_context, CodeGenContext)
 
@@ -36,12 +64,12 @@
         cg_context.class_name, export=component_export(component))
     class_def.set_base_template_vars(cg_context.template_bindings())
 
-    class_def.top_section.extend([
-        T("DISALLOW_NEW();"),
-    ])
-
-    class_def.public_section.extend([
-        T("void Trace(Visitor*);"),
+    public_section = class_def.public_section
+    public_section.extend([
+        make_union_constructor_defs(cg_context),
+        T(""),
+        CxxFuncDeclNode(
+            name="Trace", arg_decls=["Visitor*"], return_type="void"),
     ])
 
     return class_def
diff --git a/third_party/blink/renderer/core/exported/local_frame_client_impl.cc b/third_party/blink/renderer/core/exported/local_frame_client_impl.cc
index 012abf06..c76c4f91 100644
--- a/third_party/blink/renderer/core/exported/local_frame_client_impl.cc
+++ b/third_party/blink/renderer/core/exported/local_frame_client_impl.cc
@@ -465,7 +465,7 @@
 
 void LocalFrameClientImpl::BeginNavigation(
     const ResourceRequest& request,
-    network::mojom::RequestContextFrameType frame_type,
+    mojom::RequestContextFrameType frame_type,
     Document* origin_document,
     DocumentLoader* document_loader,
     WebNavigationType type,
diff --git a/third_party/blink/renderer/core/exported/local_frame_client_impl.h b/third_party/blink/renderer/core/exported/local_frame_client_impl.h
index eba5fab..e90564e 100644
--- a/third_party/blink/renderer/core/exported/local_frame_client_impl.h
+++ b/third_party/blink/renderer/core/exported/local_frame_client_impl.h
@@ -114,7 +114,7 @@
 
   void BeginNavigation(
       const ResourceRequest&,
-      network::mojom::RequestContextFrameType,
+      mojom::RequestContextFrameType,
       Document* origin_document,
       DocumentLoader*,
       WebNavigationType,
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 bb2c86c..bb741ab 100644
--- a/third_party/blink/renderer/core/exported/web_frame_test.cc
+++ b/third_party/blink/renderer/core/exported/web_frame_test.cc
@@ -12347,10 +12347,6 @@
       EXPECT_TRUE(false) << "didFinishLoad() should not have been called.";
     }
 
-    void DispatchLoad() override {
-      EXPECT_TRUE(false) << "dispatchLoad() should not have been called.";
-    }
-
     bool DidCallFrameDetached() const { return did_call_frame_detached_; }
     bool DidCallDidStopLoading() const { return did_call_did_stop_loading_; }
     bool DidCallDidFinishDocumentLoad() const {
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc
index 34ff617..e1a8430 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -35,6 +35,7 @@
 
 #include "base/auto_reset.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "cc/layers/picture_layer.h"
@@ -3425,6 +3426,12 @@
       if (frame->DomWindow() && frame->DomWindow()->IsLocalDOMWindow()) {
         frame->DomWindow()->ToLocalDOMWindow()->DispatchPersistedPageshowEvent(
             navigation_start);
+        if (frame->IsMainFrame()) {
+          UMA_HISTOGRAM_BOOLEAN(
+              "BackForwardCache.MainFrameHasPageshowListenersOnRestore",
+              frame->DomWindow()->ToLocalDOMWindow()->HasEventListeners(
+                  event_type_names::kPageshow));
+        }
       }
     }
   }
diff --git a/third_party/blink/renderer/core/fetch/fetch_manager.cc b/third_party/blink/renderer/core/fetch/fetch_manager.cc
index c0dbf5f..3f34ad8 100644
--- a/third_party/blink/renderer/core/fetch/fetch_manager.cc
+++ b/third_party/blink/renderer/core/fetch/fetch_manager.cc
@@ -55,6 +55,7 @@
 #include "third_party/blink/renderer/platform/loader/subresource_integrity.h"
 #include "third_party/blink/renderer/platform/network/http_names.h"
 #include "third_party/blink/renderer/platform/network/network_utils.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
@@ -763,7 +764,8 @@
   request.SetSkipServiceWorker(is_isolated_world_);
 
   if (fetch_request_data_->Keepalive()) {
-    if (cors::IsCorsEnabledRequestMode(fetch_request_data_->Mode()) &&
+    if (!RuntimeEnabledFeatures::OutOfBlinkCorsEnabled() &&
+        cors::IsCorsEnabledRequestMode(fetch_request_data_->Mode()) &&
         (!cors::IsCorsSafelistedMethod(request.HttpMethod()) ||
          !cors::ContainsOnlyCorsSafelistedOrForbiddenHeaders(
              request.HttpHeaderFields()))) {
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index 13a7940..2ca4be0 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -2005,6 +2005,21 @@
   owner->RenderFallbackContent(this);
 }
 
+void LocalFrame::BeforeUnload(bool is_reload, BeforeUnloadCallback callback) {
+  base::TimeTicks before_unload_start_time = base::TimeTicks::Now();
+
+  // This will execute the BeforeUnload event in this frame and all of its
+  // local descendant frames, including children of remote frames.  The browser
+  // process will send separate IPCs to dispatch beforeunload in any
+  // out-of-process child frames.
+  bool proceed = Loader().ShouldClose(is_reload);
+
+  DCHECK(!callback.is_null());
+  base::TimeTicks before_unload_end_time = base::TimeTicks::Now();
+  std::move(callback).Run(proceed, before_unload_start_time,
+                          before_unload_end_time);
+}
+
 void LocalFrame::BindToReceiver(
     blink::LocalFrame* frame,
     mojo::PendingAssociatedReceiver<mojom::blink::LocalFrame> receiver) {
diff --git a/third_party/blink/renderer/core/frame/local_frame.h b/third_party/blink/renderer/core/frame/local_frame.h
index e398d8d..f47304d 100644
--- a/third_party/blink/renderer/core/frame/local_frame.h
+++ b/third_party/blink/renderer/core/frame/local_frame.h
@@ -486,6 +486,7 @@
   void SaveImageAt(const gfx::Point& window_point) final;
   void ReportBlinkFeatureUsage(const Vector<mojom::blink::WebFeature>&) final;
   void RenderFallbackContent() final;
+  void BeforeUnload(bool is_reload, BeforeUnloadCallback callback) final;
 
   SystemClipboard* GetSystemClipboard();
 
diff --git a/third_party/blink/renderer/core/frame/local_frame_client.h b/third_party/blink/renderer/core/frame/local_frame_client.h
index 56d7fd9..d43b7a25 100644
--- a/third_party/blink/renderer/core/frame/local_frame_client.h
+++ b/third_party/blink/renderer/core/frame/local_frame_client.h
@@ -149,7 +149,7 @@
 
   virtual void BeginNavigation(
       const ResourceRequest&,
-      network::mojom::RequestContextFrameType,
+      mojom::RequestContextFrameType,
       Document* origin_document,
       DocumentLoader*,
       WebNavigationType,
diff --git a/third_party/blink/renderer/core/frame/remote_frame.cc b/third_party/blink/renderer/core/frame/remote_frame.cc
index 33ca33c6..72dfc0d 100644
--- a/third_party/blink/renderer/core/frame/remote_frame.cc
+++ b/third_party/blink/renderer/core/frame/remote_frame.cc
@@ -82,9 +82,9 @@
   if (!navigation_rate_limiter().CanProceed())
     return;
 
-  frame_request.SetFrameType(
-      IsMainFrame() ? network::mojom::RequestContextFrameType::kTopLevel
-                    : network::mojom::RequestContextFrameType::kNested);
+  frame_request.SetFrameType(IsMainFrame()
+                                 ? mojom::RequestContextFrameType::kTopLevel
+                                 : mojom::RequestContextFrameType::kNested);
 
   const KURL& url = frame_request.GetResourceRequest().Url();
   if (!frame_request.CanDisplay(url)) {
diff --git a/third_party/blink/renderer/core/frame/remote_frame_owner.cc b/third_party/blink/renderer/core/frame/remote_frame_owner.cc
index 129c692..2c121c9 100644
--- a/third_party/blink/renderer/core/frame/remote_frame_owner.cc
+++ b/third_party/blink/renderer/core/frame/remote_frame_owner.cc
@@ -62,9 +62,8 @@
 }
 
 void RemoteFrameOwner::DispatchLoad() {
-  WebLocalFrameImpl* web_frame =
-      WebLocalFrameImpl::FromFrame(To<LocalFrame>(*frame_));
-  web_frame->Client()->DispatchLoad();
+  auto& local_frame_host = To<LocalFrame>(*frame_).GetLocalFrameHostRemote();
+  local_frame_host.DispatchLoad();
 }
 
 void RemoteFrameOwner::RenderFallbackContent(Frame* failed_frame) {
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
index d90e127..48024a9 100644
--- a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
+++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
@@ -761,11 +761,6 @@
   GetFrame()->Loader().DispatchUnloadEvent(nullptr, nullptr);
 }
 
-bool WebLocalFrameImpl::HasAccessedInitialDocument() {
-  DCHECK(GetFrame());
-  return GetFrame()->Loader().HasAccessedInitialDocument();
-}
-
 void WebLocalFrameImpl::ExecuteScript(const WebScriptSource& source) {
   DCHECK(GetFrame());
   v8::HandleScope handle_scope(ToIsolate(GetFrame()));
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.h b/third_party/blink/renderer/core/frame/web_local_frame_impl.h
index 6ec2209..7e13998 100644
--- a/third_party/blink/renderer/core/frame/web_local_frame_impl.h
+++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.h
@@ -112,7 +112,6 @@
   void SetContentCaptureClient(WebContentCaptureClient*) override;
   WebContentCaptureClient* ContentCaptureClient() const override;
   void DispatchUnloadEvent() override;
-  bool HasAccessedInitialDocument() override;
   WebVector<WebIconURL> IconURLs(int icon_types_mask) const override;
   WebDocument GetDocument() const override;
   WebString AssignedName() const override;
diff --git a/third_party/blink/renderer/core/html/canvas/image_element_base.cc b/third_party/blink/renderer/core/html/canvas/image_element_base.cc
index a4fa111..ef14e77 100644
--- a/third_party/blink/renderer/core/html/canvas/image_element_base.cc
+++ b/third_party/blink/renderer/core/html/canvas/image_element_base.cc
@@ -81,31 +81,18 @@
 FloatSize ImageElementBase::ElementSize(
     const FloatSize& default_object_size) const {
   ImageResourceContent* image_content = CachedImage();
-  if (!image_content)
+  if (!image_content || !image_content->HasImage())
     return FloatSize();
-
   Image* image = image_content->GetImage();
   if (image->IsSVGImage())
     return ToSVGImage(image)->ConcreteObjectSize(default_object_size);
-
-  return FloatSize(
-      image_content->IntrinsicSize(LayoutObject::ShouldRespectImageOrientation(
-          GetElement().GetLayoutObject())));
+  return FloatSize(image->Size(LayoutObject::ShouldRespectImageOrientation(
+      GetElement().GetLayoutObject())));
 }
 
 FloatSize ImageElementBase::DefaultDestinationSize(
     const FloatSize& default_object_size) const {
-  ImageResourceContent* image_content = CachedImage();
-  if (!image_content)
-    return FloatSize();
-
-  Image* image = image_content->GetImage();
-  if (image->IsSVGImage())
-    return ToSVGImage(image)->ConcreteObjectSize(default_object_size);
-
-  return FloatSize(
-      image_content->IntrinsicSize(LayoutObject::ShouldRespectImageOrientation(
-          GetElement().GetLayoutObject())));
+  return ElementSize(default_object_size);
 }
 
 bool ImageElementBase::IsAccelerated() const {
diff --git a/third_party/blink/renderer/core/html/forms/file_input_type.cc b/third_party/blink/renderer/core/html/forms/file_input_type.cc
index c207f65ee..d429384c 100644
--- a/third_party/blink/renderer/core/html/forms/file_input_type.cc
+++ b/third_party/blink/renderer/core/html/forms/file_input_type.cc
@@ -520,6 +520,20 @@
   }
 }
 
+String FileInputType::FileStatusText() const {
+  Locale& locale = GetLocale();
+
+  if (file_list_->IsEmpty())
+    return locale.QueryString(IDS_FORM_FILE_NO_FILE_LABEL);
+
+  if (file_list_->length() == 1)
+    return LayoutTheme::GetTheme().DisplayNameForFile(*file_list_->item(0));
+
+  return locale.QueryString(
+      IDS_FORM_FILE_MULTIPLE_UPLOAD,
+      locale.ConvertToLocalizedNumber(String::Number(file_list_->length())));
+}
+
 void FileInputType::UpdateView() {
   if (auto* layout_object = GetElement().GetLayoutObject())
     layout_object->SetShouldDoFullPaintInvalidation();
diff --git a/third_party/blink/renderer/core/html/forms/file_input_type.h b/third_party/blink/renderer/core/html/forms/file_input_type.h
index 3abb82a..6919868 100644
--- a/third_party/blink/renderer/core/html/forms/file_input_type.h
+++ b/third_party/blink/renderer/core/html/forms/file_input_type.h
@@ -93,6 +93,7 @@
   void MultipleAttributeChanged() override;
   String DefaultToolTip(const InputTypeView&) const override;
   void CopyNonAttributeProperties(const HTMLInputElement&) override;
+  String FileStatusText() const override;
   void UpdateView() override;
 
   // KeyboardClickableInputTypeView overrides.
diff --git a/third_party/blink/renderer/core/html/forms/html_input_element.cc b/third_party/blink/renderer/core/html/forms/html_input_element.cc
index 1c559b75..8fa39af 100644
--- a/third_party/blink/renderer/core/html/forms/html_input_element.cc
+++ b/third_party/blink/renderer/core/html/forms/html_input_element.cc
@@ -1785,6 +1785,10 @@
   return input_type_->DefaultToolTip(*input_type_view_);
 }
 
+String HTMLInputElement::FileStatusText() const {
+  return input_type_view_->FileStatusText();
+}
+
 bool HTMLInputElement::ShouldAppearIndeterminate() const {
   return input_type_->ShouldAppearIndeterminate();
 }
diff --git a/third_party/blink/renderer/core/html/forms/html_input_element.h b/third_party/blink/renderer/core/html/forms/html_input_element.h
index d0823e0..bd5669b3 100644
--- a/third_party/blink/renderer/core/html/forms/html_input_element.h
+++ b/third_party/blink/renderer/core/html/forms/html_input_element.h
@@ -265,6 +265,11 @@
 
   String DefaultToolTip() const override;
 
+  // Type=file only: Text not in the button such as "No file chosen". The string
+  // is not truncated by ellipsis.
+  // Return a null string for other types.
+  String FileStatusText() const;
+
   unsigned height() const;
   unsigned width() const;
   void setHeight(unsigned);
diff --git a/third_party/blink/renderer/core/html/forms/html_select_element.cc b/third_party/blink/renderer/core/html/forms/html_select_element.cc
index 0aa0e2f..ed3f037 100644
--- a/third_party/blink/renderer/core/html/forms/html_select_element.cc
+++ b/third_party/blink/renderer/core/html/forms/html_select_element.cc
@@ -2238,12 +2238,52 @@
 }
 
 void HTMLSelectElement::UpdateFromElement() {
+  if (!UsesMenuList())
+    return;
   auto* layout_object = GetLayoutObject();
   if (!layout_object)
     return;
+
+  HTMLOptionElement* option = OptionToBeShown();
+  String text = g_empty_string;
+  option_style_ = nullptr;
+
+  if (IsMultiple()) {
+    unsigned selected_count = 0;
+    HTMLOptionElement* selected_option_element = nullptr;
+    for (auto* const option : GetOptionList()) {
+      if (option->Selected()) {
+        if (++selected_count == 1)
+          selected_option_element = option;
+      }
+    }
+
+    if (selected_count == 1) {
+      text = selected_option_element->TextIndentedToRespectGroupLabel();
+      option_style_ = selected_option_element->GetComputedStyle();
+    } else {
+      Locale& locale = GetLocale();
+      String localized_number_string =
+          locale.ConvertToLocalizedNumber(String::Number(selected_count));
+      text = locale.QueryString(IDS_FORM_SELECT_MENU_LIST_TEXT,
+                                localized_number_string);
+      DCHECK(!option_style_);
+    }
+  } else {
+    if (option) {
+      text = option->TextIndentedToRespectGroupLabel();
+      option_style_ = option->GetComputedStyle();
+    }
+  }
+
+  ToLayoutMenuList(layout_object)->SetText(text.StripWhiteSpace());
   layout_object->UpdateFromElement();
-  if (UsesMenuList())
-    DidUpdateMenuListActiveOption(OptionToBeShown());
+  DidUpdateMenuListActiveOption(option);
+}
+
+const ComputedStyle* HTMLSelectElement::OptionStyle() const {
+  DCHECK(UsesMenuList());
+  return option_style_.get();
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/html/forms/html_select_element.h b/third_party/blink/renderer/core/html/forms/html_select_element.h
index 7967090..775a5e0 100644
--- a/third_party/blink/renderer/core/html/forms/html_select_element.h
+++ b/third_party/blink/renderer/core/html/forms/html_select_element.h
@@ -161,6 +161,9 @@
   void PopupDidHide();
   bool PopupIsVisible() const { return popup_is_visible_; }
   HTMLOptionElement* OptionToBeShown() const;
+  // Style of the selected OPTION. This is nullable, and only for
+  // the menulist mode.
+  const ComputedStyle* OptionStyle() const;
   void ShowPopup();
   void HidePopup();
   PopupMenu* Popup() const { return popup_.Get(); }
@@ -305,6 +308,7 @@
   Member<HTMLOptionElement> active_selection_end_;
   Member<HTMLOptionElement> option_to_scroll_to_;
   Member<HTMLOptionElement> suggested_option_;
+  scoped_refptr<const ComputedStyle> option_style_;
   int ax_menulist_last_active_index_ = -1;
   bool has_updated_menulist_active_option_ = false;
   bool is_multiple_;
diff --git a/third_party/blink/renderer/core/html/forms/input_type_view.cc b/third_party/blink/renderer/core/html/forms/input_type_view.cc
index 139294d..8ac7410 100644
--- a/third_party/blink/renderer/core/html/forms/input_type_view.cc
+++ b/third_party/blink/renderer/core/html/forms/input_type_view.cc
@@ -136,6 +136,10 @@
   return nullptr;
 }
 
+String InputTypeView::FileStatusText() const {
+  return String();
+}
+
 void InputTypeView::AltAttributeChanged() {}
 
 void InputTypeView::SrcAttributeChanged() {}
diff --git a/third_party/blink/renderer/core/html/forms/input_type_view.h b/third_party/blink/renderer/core/html/forms/input_type_view.h
index 78f08414..5d3cf2c 100644
--- a/third_party/blink/renderer/core/html/forms/input_type_view.h
+++ b/third_party/blink/renderer/core/html/forms/input_type_view.h
@@ -114,6 +114,7 @@
   virtual void CreateShadowSubtree();
   virtual void DestroyShadowSubtree();
   virtual HTMLInputElement* UploadButton() const;
+  virtual String FileStatusText() const;
 
   virtual void MinOrMaxAttributeChanged();
   virtual void StepAttributeChanged();
diff --git a/third_party/blink/renderer/core/html/html_image_element.cc b/third_party/blink/renderer/core/html/html_image_element.cc
index 58c8670..daeeca3dc 100644
--- a/third_party/blink/renderer/core/html/html_image_element.cc
+++ b/third_party/blink/renderer/core/html/html_image_element.cc
@@ -658,14 +658,14 @@
 FloatSize HTMLImageElement::DefaultDestinationSize(
     const FloatSize& default_object_size) const {
   ImageResourceContent* image_content = CachedImage();
-  if (!image_content)
+  if (!image_content || !image_content->HasImage())
     return FloatSize();
 
   Image* image = image_content->GetImage();
   if (image->IsSVGImage())
     return ToSVGImage(image)->ConcreteObjectSize(default_object_size);
 
-  LayoutSize size(image_content->IntrinsicSize(
+  LayoutSize size(image->Size(
       LayoutObject::ShouldRespectImageOrientation(GetLayoutObject())));
   if (GetLayoutObject() && GetLayoutObject()->IsLayoutImage() &&
       image->HasIntrinsicSize())
diff --git a/third_party/blink/renderer/core/inspector/devtools_agent.cc b/third_party/blink/renderer/core/inspector/devtools_agent.cc
index baac8ec..e222b71 100644
--- a/third_party/blink/renderer/core/inspector/devtools_agent.cc
+++ b/third_party/blink/renderer/core/inspector/devtools_agent.cc
@@ -20,8 +20,20 @@
 #include "third_party/blink/renderer/core/workers/worker_global_scope.h"
 #include "third_party/blink/renderer/core/workers/worker_thread.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
+#include "third_party/blink/renderer/platform/wtf/cross_thread_copier.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
+namespace WTF {
+
+using StatePtr = mojo::StructPtr<blink::mojom::blink::DevToolsSessionState>;
+template <>
+struct CrossThreadCopier<StatePtr>
+    : public CrossThreadCopierByValuePassThrough<StatePtr> {
+  STATIC_ONLY(CrossThreadCopier);
+};
+
+}  // namespace WTF
+
 namespace blink {
 
 namespace {
@@ -49,6 +61,73 @@
 
 }  // namespace
 
+class DevToolsAgent::IOAgent : public mojom::blink::DevToolsAgent {
+ public:
+  IOAgent(scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
+          scoped_refptr<InspectorTaskRunner> inspector_task_runner,
+          CrossThreadWeakPersistent<::blink::DevToolsAgent> agent,
+          mojo::PendingReceiver<mojom::blink::DevToolsAgent> receiver)
+      : io_task_runner_(io_task_runner),
+        inspector_task_runner_(inspector_task_runner),
+        agent_(std::move(agent)) {
+    // Binds on the IO thread and receive messages there too. Messages are
+    // posted to the worker thread in a way that interrupts V8 execution. This
+    // is necessary so that AttachDevToolsSession can be called on a worker
+    // which has already started and is stuck in JS, e.g. polling using
+    // Atomics.wait() which is a common pattern.
+    PostCrossThreadTask(
+        *io_task_runner_, FROM_HERE,
+        CrossThreadBindOnce(&IOAgent::BindInterface,
+                            CrossThreadUnretained(this), std::move(receiver)));
+  }
+
+  void BindInterface(
+      mojo::PendingReceiver<mojom::blink::DevToolsAgent> receiver) {
+    receiver_.Bind(std::move(receiver), io_task_runner_);
+  }
+
+  void DeleteSoon() { io_task_runner_->DeleteSoon(FROM_HERE, this); }
+
+  ~IOAgent() override = default;
+
+  // mojom::blink::DevToolsAgent implementation.
+  void AttachDevToolsSession(
+      mojo::PendingAssociatedRemote<mojom::blink::DevToolsSessionHost> host,
+      mojo::PendingAssociatedReceiver<mojom::blink::DevToolsSession>
+          main_session,
+      mojo::PendingReceiver<mojom::blink::DevToolsSession> io_session,
+      mojom::blink::DevToolsSessionStatePtr reattach_session_state,
+      bool client_expects_binary_responses) override {
+    DCHECK(receiver_.is_bound());
+    inspector_task_runner_->AppendTask(CrossThreadBindOnce(
+        &::blink::DevToolsAgent::AttachDevToolsSessionImpl, agent_,
+        std::move(host), std::move(main_session), std::move(io_session),
+        std::move(reattach_session_state), client_expects_binary_responses));
+  }
+
+  void InspectElement(const gfx::Point& point) override {
+    // InspectElement on a worker doesn't make sense.
+    NOTREACHED();
+  }
+
+  void ReportChildWorkers(bool report,
+                          bool wait_for_debugger,
+                          base::OnceClosure callback) override {
+    DCHECK(receiver_.is_bound());
+    inspector_task_runner_->AppendTask(CrossThreadBindOnce(
+        &::blink::DevToolsAgent::ReportChildWorkersPostCallbackToIO, agent_,
+        report, wait_for_debugger, CrossThreadBindOnce(std::move(callback))));
+  }
+
+ private:
+  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
+  scoped_refptr<InspectorTaskRunner> inspector_task_runner_;
+  CrossThreadWeakPersistent<::blink::DevToolsAgent> agent_;
+  mojo::Receiver<mojom::blink::DevToolsAgent> receiver_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(IOAgent);
+};
+
 DevToolsAgent::DevToolsAgent(
     Client* client,
     InspectedFrames* inspected_frames,
@@ -76,23 +155,25 @@
   CleanupConnection();
 }
 
-void DevToolsAgent::BindReceiver(
+void DevToolsAgent::BindReceiverForWorker(
     mojo::PendingRemote<mojom::blink::DevToolsAgentHost> host_remote,
     mojo::PendingReceiver<mojom::blink::DevToolsAgent> receiver,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
-  DCHECK(!receiver_.is_bound());
   DCHECK(!associated_receiver_.is_bound());
-  receiver_.Bind(std::move(receiver), std::move(task_runner));
+
   host_remote_.Bind(std::move(host_remote));
   host_remote_.set_disconnect_handler(
       WTF::Bind(&DevToolsAgent::CleanupConnection, WrapWeakPersistent(this)));
+
+  io_agent_ =
+      new IOAgent(io_task_runner_, inspector_task_runner_,
+                  WrapCrossThreadWeakPersistent(this), std::move(receiver));
 }
 
 void DevToolsAgent::BindReceiver(
     mojo::PendingAssociatedRemote<mojom::blink::DevToolsAgentHost> host_remote,
     mojo::PendingAssociatedReceiver<mojom::blink::DevToolsAgent> receiver,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
-  DCHECK(!receiver_.is_bound());
   DCHECK(!associated_receiver_.is_bound());
   associated_receiver_.Bind(std::move(receiver), std::move(task_runner));
   associated_host_remote_.Bind(std::move(host_remote));
@@ -100,13 +181,14 @@
       WTF::Bind(&DevToolsAgent::CleanupConnection, WrapWeakPersistent(this)));
 }
 
-void DevToolsAgent::AttachDevToolsSession(
+void DevToolsAgent::AttachDevToolsSessionImpl(
     mojo::PendingAssociatedRemote<mojom::blink::DevToolsSessionHost> host,
     mojo::PendingAssociatedReceiver<mojom::blink::DevToolsSession>
         session_receiver,
     mojo::PendingReceiver<mojom::blink::DevToolsSession> io_session_receiver,
     mojom::blink::DevToolsSessionStatePtr reattach_session_state,
     bool client_expects_binary_responses) {
+  TRACE_EVENT0("devtools", "Agent::AttachDevToolsSessionImpl");
   client_->DebuggerTaskStarted();
   DevToolsSession* session = MakeGarbageCollected<DevToolsSession>(
       this, std::move(host), std::move(session_receiver),
@@ -116,18 +198,63 @@
   client_->DebuggerTaskFinished();
 }
 
-void DevToolsAgent::InspectElement(const gfx::Point& point) {
+void DevToolsAgent::AttachDevToolsSession(
+    mojo::PendingAssociatedRemote<mojom::blink::DevToolsSessionHost> host,
+    mojo::PendingAssociatedReceiver<mojom::blink::DevToolsSession>
+        session_receiver,
+    mojo::PendingReceiver<mojom::blink::DevToolsSession> io_session_receiver,
+    mojom::blink::DevToolsSessionStatePtr reattach_session_state,
+    bool client_expects_binary_responses) {
+  TRACE_EVENT0("devtools", "Agent::AttachDevToolsSession");
+  if (associated_receiver_.is_bound()) {
+    AttachDevToolsSessionImpl(std::move(host), std::move(session_receiver),
+                              std::move(io_session_receiver),
+                              std::move(reattach_session_state),
+                              client_expects_binary_responses);
+  } else {
+    io_agent_->AttachDevToolsSession(
+        std::move(host), std::move(session_receiver),
+        std::move(io_session_receiver), std::move(reattach_session_state),
+        client_expects_binary_responses);
+  }
+}
+
+void DevToolsAgent::InspectElementImpl(const gfx::Point& point) {
   client_->InspectElement(point);
 }
 
+void DevToolsAgent::InspectElement(const gfx::Point& point) {
+  if (associated_receiver_.is_bound()) {
+    client_->InspectElement(point);
+  } else {
+    // InspectElement on a worker doesn't make sense.
+    NOTREACHED();
+  }
+}
+
 void DevToolsAgent::FlushProtocolNotifications() {
   for (auto& session : sessions_)
     session->FlushProtocolNotifications();
 }
 
-void DevToolsAgent::ReportChildWorkers(bool report,
-                                       bool wait_for_debugger,
-                                       base::OnceClosure callback) {
+void DevToolsAgent::ReportChildWorkersPostCallbackToIO(
+    bool report,
+    bool wait_for_debugger,
+    CrossThreadOnceClosure callback) {
+  TRACE_EVENT0("devtools", "Agent::ReportChildWorkersPostCallbackToIO");
+  ReportChildWorkersImpl(report, wait_for_debugger, base::DoNothing());
+  // This message originally came from the IOAgent for a worker which means the
+  // response needs to be sent on the IO thread as well, so we post the callback
+  // task back there to be run. In the non-IO case, this callback would be run
+  // synchronously at the end of ReportChildWorkersImpl, so the ordering between
+  // ReportChildWorkers and running the callback is preserved.
+  PostCrossThreadTask(*io_task_runner_, FROM_HERE, std::move(callback));
+}
+
+void DevToolsAgent::ReportChildWorkersImpl(bool report,
+                                           bool wait_for_debugger,
+                                           base::OnceClosure callback) {
+  TRACE_EVENT0("devtools", "Agent::ReportChildWorkersImpl");
   report_child_workers_ = report;
   pause_child_workers_on_start_ = wait_for_debugger;
   if (report_child_workers_) {
@@ -138,6 +265,18 @@
   std::move(callback).Run();
 }
 
+void DevToolsAgent::ReportChildWorkers(bool report,
+                                       bool wait_for_debugger,
+                                       base::OnceClosure callback) {
+  TRACE_EVENT0("devtools", "Agent::ReportChildWorkers");
+  if (associated_receiver_.is_bound()) {
+    ReportChildWorkersImpl(report, wait_for_debugger, std::move(callback));
+  } else {
+    io_agent_->ReportChildWorkers(report, wait_for_debugger,
+                                  std::move(callback));
+  }
+}
+
 // static
 std::unique_ptr<WorkerDevToolsParams> DevToolsAgent::WorkerThreadCreated(
     ExecutionContext* parent_context,
@@ -192,7 +331,10 @@
 }
 
 void DevToolsAgent::CleanupConnection() {
-  receiver_.reset();
+  if (io_agent_) {
+    io_agent_->DeleteSoon();
+    io_agent_ = nullptr;
+  }
   associated_receiver_.reset();
   host_remote_.reset();
   associated_host_remote_.reset();
diff --git a/third_party/blink/renderer/core/inspector/devtools_agent.h b/third_party/blink/renderer/core/inspector/devtools_agent.h
index 92b7126c..6dcdbb68 100644
--- a/third_party/blink/renderer/core/inspector/devtools_agent.h
+++ b/third_party/blink/renderer/core/inspector/devtools_agent.h
@@ -59,9 +59,16 @@
 
   void Dispose();
   void FlushProtocolNotifications();
-  void BindReceiver(mojo::PendingRemote<mojom::blink::DevToolsAgentHost>,
-                    mojo::PendingReceiver<mojom::blink::DevToolsAgent>,
-                    scoped_refptr<base::SingleThreadTaskRunner>);
+  // For workers, we use the IO thread similar to DevToolsSession::IOSession to
+  // ensure that we can always interrupt a worker that is stuck in JS. We don't
+  // use an associated channel for workers, meaning we don't have the ordering
+  // constraints related to navigation that the non-worker agents have.
+  void BindReceiverForWorker(
+      mojo::PendingRemote<mojom::blink::DevToolsAgentHost>,
+      mojo::PendingReceiver<mojom::blink::DevToolsAgent>,
+      scoped_refptr<base::SingleThreadTaskRunner>);
+  // Used for non-worker agents. These do not use the IO thread like we do for
+  // workers, and they use associated mojo interfaces.
   void BindReceiver(
       mojo::PendingAssociatedRemote<mojom::blink::DevToolsAgentHost>,
       mojo::PendingAssociatedReceiver<mojom::blink::DevToolsAgent>,
@@ -70,6 +77,7 @@
 
  private:
   friend class DevToolsSession;
+  class IOAgent;
 
   // mojom::blink::DevToolsAgent implementation.
   void AttachDevToolsSession(
@@ -84,6 +92,10 @@
                           bool wait_for_debugger,
                           base::OnceClosure callback) override;
 
+  void ReportChildWorkersPostCallbackToIO(bool report,
+                                          bool wait_for_debugger,
+                                          CrossThreadOnceClosure callback);
+
   struct WorkerData {
     KURL url;
     mojo::PendingRemote<mojom::blink::DevToolsAgent> agent_remote;
@@ -96,8 +108,19 @@
 
   void CleanupConnection();
 
+  void AttachDevToolsSessionImpl(
+      mojo::PendingAssociatedRemote<mojom::blink::DevToolsSessionHost>,
+      mojo::PendingAssociatedReceiver<mojom::blink::DevToolsSession>
+          main_session,
+      mojo::PendingReceiver<mojom::blink::DevToolsSession> io_session,
+      mojom::blink::DevToolsSessionStatePtr reattach_session_state,
+      bool client_expects_binary_responses);
+  void InspectElementImpl(const gfx::Point& point);
+  void ReportChildWorkersImpl(bool report,
+                              bool wait_for_debugger,
+                              base::OnceClosure callback);
+
   Client* client_;
-  mojo::Receiver<mojom::blink::DevToolsAgent> receiver_{this};
   mojo::AssociatedReceiver<mojom::blink::DevToolsAgent> associated_receiver_{
       this};
   mojo::Remote<mojom::blink::DevToolsAgentHost> host_remote_;
@@ -110,6 +133,7 @@
   scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
   HashMap<WorkerThread*, std::unique_ptr<WorkerData>>
       unreported_child_worker_threads_;
+  IOAgent* io_agent_{nullptr};
   bool report_child_workers_ = false;
   bool pause_child_workers_on_start_ = false;
 };
diff --git a/third_party/blink/renderer/core/inspector/devtools_session.cc b/third_party/blink/renderer/core/inspector/devtools_session.cc
index a987f9a6..46d6429 100644
--- a/third_party/blink/renderer/core/inspector/devtools_session.cc
+++ b/third_party/blink/renderer/core/inspector/devtools_session.cc
@@ -39,7 +39,12 @@
          method == "Performance.getMetrics" || method == "Page.crash" ||
          method == "Runtime.terminateExecution" ||
          method == "Debugger.getStackTrace" ||
-         method == "Emulation.setScriptExecutionDisabled";
+         method == "Emulation.setScriptExecutionDisabled" ||
+         // Needed to start/stop the performance timeline.
+         method == "HeapProfiler.enable" || method == "Debugger.disable" ||
+         method == "Debugger.setAsyncCallStackDepth" ||
+         method == "Debugger.enable" ||
+         method == "Debugger.setPauseOnExceptions";
 }
 
 std::vector<uint8_t> Get8BitStringFrom(v8_inspector::StringBuffer* msg) {
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 9dd8ffd..1b68133 100644
--- a/third_party/blink/renderer/core/inspector/v8_inspector_string.cc
+++ b/third_party/blink/renderer/core/inspector/v8_inspector_string.cc
@@ -60,24 +60,6 @@
 }
 
 // static
-void StringUtil::builderAppendQuotedString(StringBuilder& builder,
-                                           const String& str) {
-  builder.Append('"');
-  if (!str.IsEmpty()) {
-    if (str.Is8Bit()) {
-      escapeLatinStringForJSON(
-          reinterpret_cast<const uint8_t*>(str.Characters8()), str.length(),
-          &builder);
-    } else {
-      escapeWideStringForJSON(
-          reinterpret_cast<const uint16_t*>(str.Characters16()), str.length(),
-          &builder);
-    }
-  }
-  builder.Append('"');
-}
-
-// static
 String StringUtil::fromUTF16LE(const uint16_t* data, size_t length) {
   // Chromium doesn't support big endian architectures, so it's OK to cast here.
   return String(reinterpret_cast<const UChar*>(data), length);
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 39b73ccc..06f91f6 100644
--- a/third_party/blink/renderer/core/inspector/v8_inspector_string.h
+++ b/third_party/blink/renderer/core/inspector/v8_inspector_string.h
@@ -73,7 +73,6 @@
   static void builderAppend(StringBuilder& builder, const char* s, size_t len) {
     builder.Append(s, static_cast<wtf_size_t>(len));
   }
-  static void builderAppendQuotedString(StringBuilder&, const String&);
   static void builderReserve(StringBuilder& builder, uint64_t capacity) {
     builder.ReserveCapacity(static_cast<wtf_size_t>(capacity));
   }
diff --git a/third_party/blink/renderer/core/inspector/worker_inspector_controller.cc b/third_party/blink/renderer/core/inspector/worker_inspector_controller.cc
index e5baa33..6491006e 100644
--- a/third_party/blink/renderer/core/inspector/worker_inspector_controller.cc
+++ b/third_party/blink/renderer/core/inspector/worker_inspector_controller.cc
@@ -87,9 +87,10 @@
     agent_ = MakeGarbageCollected<DevToolsAgent>(
         this, inspected_frames_.Get(), probe_sink_.Get(),
         std::move(inspector_task_runner), std::move(io_task_runner));
-    agent_->BindReceiver(std::move(devtools_params->agent_host_remote),
-                         std::move(devtools_params->agent_receiver),
-                         thread->GetTaskRunner(TaskType::kInternalInspector));
+    agent_->BindReceiverForWorker(
+        std::move(devtools_params->agent_host_remote),
+        std::move(devtools_params->agent_receiver),
+        thread->GetTaskRunner(TaskType::kInternalInspector));
   }
   trace_event::AddEnabledStateObserver(this);
   EmitTraceEvent();
diff --git a/third_party/blink/renderer/core/layout/layout_file_upload_control.cc b/third_party/blink/renderer/core/layout/layout_file_upload_control.cc
index 474d769..8fd49e3 100644
--- a/third_party/blink/renderer/core/layout/layout_file_upload_control.cc
+++ b/third_party/blink/renderer/core/layout/layout_file_upload_control.cc
@@ -29,6 +29,7 @@
 #include "third_party/blink/renderer/core/layout/layout_theme.h"
 #include "third_party/blink/renderer/core/paint/file_upload_control_painter.h"
 #include "third_party/blink/renderer/platform/fonts/font.h"
+#include "third_party/blink/renderer/platform/fonts/string_truncator.h"
 #include "third_party/blink/renderer/platform/text/platform_locale.h"
 #include "third_party/blink/renderer/platform/text/text_run.h"
 
@@ -138,11 +139,15 @@
 }
 
 String LayoutFileUploadControl::FileTextValue() const {
+  int width = MaxFilenameWidth();
+  if (width <= 0)
+    return String();
   auto* input = To<HTMLInputElement>(GetNode());
   DCHECK(input->files());
-  return LayoutTheme::GetTheme().FileListNameForWidth(
-      input->GetLocale(), input->files(), StyleRef().GetFont(),
-      MaxFilenameWidth());
+  String text = input->FileStatusText();
+  if (input->files()->length() >= 2)
+    return StringTruncator::RightTruncate(text, width, StyleRef().GetFont());
+  return StringTruncator::CenterTruncate(text, width, StyleRef().GetFont());
 }
 
 PhysicalRect LayoutFileUploadControl::ControlClipRect(
diff --git a/third_party/blink/renderer/core/layout/layout_menu_list.cc b/third_party/blink/renderer/core/layout/layout_menu_list.cc
index 5326ff90..87619a6 100644
--- a/third_party/blink/renderer/core/layout/layout_menu_list.cc
+++ b/third_party/blink/renderer/core/layout/layout_menu_list.cc
@@ -113,9 +113,10 @@
 
 bool LayoutMenuList::HasOptionStyleChanged(
     const ComputedStyle& inner_style) const {
-  return option_style_ &&
-         ((option_style_->Direction() != inner_style.Direction() ||
-           option_style_->GetUnicodeBidi() != inner_style.GetUnicodeBidi()));
+  const ComputedStyle* option_style = SelectElement()->OptionStyle();
+  return option_style &&
+         ((option_style->Direction() != inner_style.Direction() ||
+           option_style->GetUnicodeBidi() != inner_style.GetUnicodeBidi()));
 }
 
 void LayoutMenuList::AdjustInnerStyle(ComputedStyle& inner_style) const {
@@ -155,8 +156,9 @@
   if (HasOptionStyleChanged(inner_style)) {
     inner_block_->SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
         layout_invalidation_reason::kStyleChange);
-    inner_style.SetDirection(option_style_->Direction());
-    inner_style.SetUnicodeBidi(option_style_->GetUnicodeBidi());
+    const ComputedStyle* option_style = SelectElement()->OptionStyle();
+    inner_style.SetDirection(option_style->Direction());
+    inner_style.SetUnicodeBidi(option_style->GetUnicodeBidi());
   }
 }
 
@@ -229,41 +231,6 @@
 }
 
 void LayoutMenuList::UpdateFromElement() {
-  HTMLSelectElement* select = SelectElement();
-  HTMLOptionElement* option = select->OptionToBeShown();
-  String text = g_empty_string;
-  option_style_ = nullptr;
-
-  if (select->IsMultiple()) {
-    unsigned selected_count = 0;
-    HTMLOptionElement* selected_option_element = nullptr;
-    for (auto* const option : select->GetOptionList()) {
-      if (option->Selected()) {
-        if (++selected_count == 1)
-          selected_option_element = option;
-      }
-    }
-
-    if (selected_count == 1) {
-      text = selected_option_element->TextIndentedToRespectGroupLabel();
-      option_style_ = selected_option_element->GetComputedStyle();
-    } else {
-      Locale& locale = select->GetLocale();
-      String localized_number_string =
-          locale.ConvertToLocalizedNumber(String::Number(selected_count));
-      text = locale.QueryString(IDS_FORM_SELECT_MENU_LIST_TEXT,
-                                localized_number_string);
-      DCHECK(!option_style_);
-    }
-  } else {
-    if (option) {
-      text = option->TextIndentedToRespectGroupLabel();
-      option_style_ = option->GetComputedStyle();
-    }
-  }
-
-  SetText(text.StripWhiteSpace());
-
   DCHECK(inner_block_);
   if (HasOptionStyleChanged(inner_block_->StyleRef()))
     UpdateInnerStyle();
diff --git a/third_party/blink/renderer/core/layout/layout_menu_list.h b/third_party/blink/renderer/core/layout/layout_menu_list.h
index c8ed491..9d5a0f1d 100644
--- a/third_party/blink/renderer/core/layout/layout_menu_list.h
+++ b/third_party/blink/renderer/core/layout/layout_menu_list.h
@@ -41,6 +41,7 @@
 
   HTMLSelectElement* SelectElement() const;
   String GetText() const;
+  void SetText(const String&);
 
   const char* GetName() const override { return "LayoutMenuList"; }
 
@@ -96,7 +97,6 @@
   void UpdateInnerStyle();
   void AdjustInnerStyle(ComputedStyle&) const;
   bool HasOptionStyleChanged(const ComputedStyle& inner_style) const;
-  void SetText(const String&);
   void UpdateInnerBlockHeight();
   void UpdateOptionsWidth() const;
   void SetIndexToSelectOnCancel(int list_index);
@@ -109,8 +109,6 @@
   // m_optionsWidth is calculated and cached on demand.
   // updateOptionsWidth() should be called before reading them.
   mutable int options_width_;
-
-  scoped_refptr<const ComputedStyle> option_style_;
 };
 
 DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutMenuList, IsMenuList());
diff --git a/third_party/blink/renderer/core/layout/layout_theme.cc b/third_party/blink/renderer/core/layout/layout_theme.cc
index f30ab22..2115ae3 100644
--- a/third_party/blink/renderer/core/layout/layout_theme.cc
+++ b/third_party/blink/renderer/core/layout/layout_theme.cc
@@ -30,7 +30,7 @@
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/shadow_root.h"
 #include "third_party/blink/renderer/core/editing/frame_selection.h"
-#include "third_party/blink/renderer/core/fileapi/file_list.h"
+#include "third_party/blink/renderer/core/fileapi/file.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/settings.h"
 #include "third_party/blink/renderer/core/html/forms/html_data_list_element.h"
@@ -55,10 +55,8 @@
 #include "third_party/blink/renderer/core/style/computed_style_initial_values.h"
 #include "third_party/blink/renderer/platform/file_metadata.h"
 #include "third_party/blink/renderer/platform/fonts/font_selector.h"
-#include "third_party/blink/renderer/platform/fonts/string_truncator.h"
 #include "third_party/blink/renderer/platform/graphics/touch_action.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
-#include "third_party/blink/renderer/platform/text/platform_locale.h"
 #include "third_party/blink/renderer/platform/web_test_support.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 #include "ui/base/ui_base_features.h"
@@ -856,27 +854,8 @@
                                       : GetTheme().PlatformFocusRingColor();
 }
 
-String LayoutTheme::FileListNameForWidth(Locale& locale,
-                                         const FileList* file_list,
-                                         const Font& font,
-                                         int width) const {
-  if (width <= 0)
-    return String();
-
-  String string;
-  if (file_list->IsEmpty()) {
-    string = locale.QueryString(IDS_FORM_FILE_NO_FILE_LABEL);
-  } else if (file_list->length() == 1) {
-    string = file_list->item(0)->name();
-  } else {
-    return StringTruncator::RightTruncate(
-        locale.QueryString(IDS_FORM_FILE_MULTIPLE_UPLOAD,
-                           locale.ConvertToLocalizedNumber(
-                               String::Number(file_list->length()))),
-        width, font);
-  }
-
-  return StringTruncator::CenterTruncate(string, width, font);
+String LayoutTheme::DisplayNameForFile(const File& file) const {
+  return file.name();
 }
 
 bool LayoutTheme::ShouldOpenPickerWithF4Key() const {
diff --git a/third_party/blink/renderer/core/layout/layout_theme.h b/third_party/blink/renderer/core/layout/layout_theme.h
index 67e8b5c..17f7b365 100644
--- a/third_party/blink/renderer/core/layout/layout_theme.h
+++ b/third_party/blink/renderer/core/layout/layout_theme.h
@@ -43,13 +43,11 @@
 
 class ComputedStyle;
 class Element;
-class FileList;
-class Font;
+class File;
 class FontDescription;
 class HTMLInputElement;
 class IntRect;
 class LengthSize;
-class Locale;
 class LocalFrame;
 class Node;
 class ThemePainter;
@@ -244,10 +242,7 @@
   virtual bool PopsMenuByReturnKey() const { return false; }
   virtual bool PopsMenuByAltDownUpOrF4Key() const { return false; }
 
-  virtual String FileListNameForWidth(Locale&,
-                                      const FileList*,
-                                      const Font&,
-                                      int width) const;
+  virtual String DisplayNameForFile(const File& file) const;
 
   virtual bool ShouldOpenPickerWithF4Key() const;
 
diff --git a/third_party/blink/renderer/core/layout/layout_theme_mac.h b/third_party/blink/renderer/core/layout/layout_theme_mac.h
index 3df1acac..43219d58 100644
--- a/third_party/blink/renderer/core/layout/layout_theme_mac.h
+++ b/third_party/blink/renderer/core/layout/layout_theme_mac.h
@@ -273,10 +273,7 @@
  private:
   const int* ProgressBarHeights() const;
   const int* ProgressBarMargins(NSControlSize) const;
-  String FileListNameForWidth(Locale&,
-                              const FileList*,
-                              const Font&,
-                              int width) const override;
+  String DisplayNameForFile(const File& file) const override;
   String ExtraDefaultStyleSheet() override;
   bool ThemeDrawsFocusRing(const ComputedStyle&) const override;
 
diff --git a/third_party/blink/renderer/core/layout/layout_theme_mac.mm b/third_party/blink/renderer/core/layout/layout_theme_mac.mm
index d8f1abed..ad6097d 100644
--- a/third_party/blink/renderer/core/layout/layout_theme_mac.mm
+++ b/third_party/blink/renderer/core/layout/layout_theme_mac.mm
@@ -31,20 +31,18 @@
 #import "third_party/blink/public/resources/grit/blink_resources.h"
 #import "third_party/blink/public/strings/grit/blink_strings.h"
 #import "third_party/blink/renderer/core/css_value_keywords.h"
-#import "third_party/blink/renderer/core/fileapi/file_list.h"
+#import "third_party/blink/renderer/core/fileapi/file.h"
 #import "third_party/blink/renderer/core/html_names.h"
 #import "third_party/blink/renderer/core/layout/layout_progress.h"
 #import "third_party/blink/renderer/core/layout/layout_theme_default.h"
 #import "third_party/blink/renderer/core/layout/layout_view.h"
 #import "third_party/blink/renderer/core/style/shadow_list.h"
 #import "third_party/blink/renderer/platform/data_resource_helper.h"
-#import "third_party/blink/renderer/platform/fonts/string_truncator.h"
 #import "third_party/blink/renderer/platform/graphics/bitmap_image.h"
 #import "third_party/blink/renderer/platform/mac/block_exceptions.h"
 #import "third_party/blink/renderer/platform/mac/color_mac.h"
 #import "third_party/blink/renderer/platform/mac/web_core_ns_cell_extras.h"
 #import "third_party/blink/renderer/platform/runtime_enabled_features.h"
-#import "third_party/blink/renderer/platform/text/platform_locale.h"
 #import "third_party/blink/renderer/platform/web_test_support.h"
 #include "ui/base/ui_base_features.h"
 
@@ -156,6 +154,11 @@
       WebColorScheme color_scheme) const override;
   Color PlatformSpellingMarkerUnderlineColor() const override;
   Color PlatformGrammarMarkerUnderlineColor() const override;
+  String DisplayNameForFile(const File& file) const override {
+    if (file.GetUserVisibility() == File::kIsUserVisible)
+      return [[NSFileManager defaultManager] displayNameAtPath:file.GetPath()];
+    return file.name();
+  }
 };
 
 // Inflate an IntRect to account for specific padding around margins.
@@ -984,32 +987,10 @@
   return text_field_;
 }
 
-String LayoutThemeMac::FileListNameForWidth(Locale& locale,
-                                            const FileList* file_list,
-                                            const Font& font,
-                                            int width) const {
-  if (width <= 0)
-    return String();
-
-  String str_to_truncate;
-  if (file_list->IsEmpty()) {
-    str_to_truncate = locale.QueryString(IDS_FORM_FILE_NO_FILE_LABEL);
-  } else if (file_list->length() == 1) {
-    File* file = file_list->item(0);
-    if (file->GetUserVisibility() == File::kIsUserVisible)
-      str_to_truncate = [[NSFileManager defaultManager]
-          displayNameAtPath:(file_list->item(0)->GetPath())];
-    else
-      str_to_truncate = file->name();
-  } else {
-    return StringTruncator::RightTruncate(
-        locale.QueryString(IDS_FORM_FILE_MULTIPLE_UPLOAD,
-                           locale.ConvertToLocalizedNumber(
-                               String::Number(file_list->length()))),
-        width, font);
-  }
-
-  return StringTruncator::CenterTruncate(str_to_truncate, width, font);
+String LayoutThemeMac::DisplayNameForFile(const File& file) const {
+  if (file.GetUserVisibility() == File::kIsUserVisible)
+    return [[NSFileManager defaultManager] displayNameAtPath:file.GetPath()];
+  return file.name();
 }
 
 NSView* FlippedView() {
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc
index 357405f0..525bb98 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc
@@ -240,6 +240,24 @@
 }
 
 String NGFragmentItem::DebugName() const {
+  // TODO(yosin): Once |NGPaintFragment| is removed, we should get rid of
+  // following if-statements.
+  // For ease of rebasing, we use same |DebugName()| as |NGPaintFrgment|.
+  if (Type() == NGFragmentItem::kBox) {
+    StringBuilder name;
+    name.Append("NGPhysicalBoxFragment ");
+    name.Append(layout_object_->DebugName());
+    return name.ToString();
+  }
+  if (Type() == NGFragmentItem::kText) {
+    StringBuilder name;
+    name.Append("NGPhysicalTextFragment '");
+    name.Append(Text(*layout_object_->ContainingBlockFlowFragment()->Items()));
+    name.Append('\'');
+    return name.ToString();
+  }
+  if (Type() == NGFragmentItem::kLine)
+    return "NGPhysicalLineBoxFragment";
   return "NGFragmentItem";
 }
 
diff --git a/third_party/blink/renderer/core/layout/scroll_anchor_test.cc b/third_party/blink/renderer/core/layout/scroll_anchor_test.cc
index ae0ac5b..a4b470b 100644
--- a/third_party/blink/renderer/core/layout/scroll_anchor_test.cc
+++ b/third_party/blink/renderer/core/layout/scroll_anchor_test.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/core/layout/scroll_anchor.h"
 
 #include "build/build_config.h"
+#include "third_party/blink/public/common/input/web_mouse_event.h"
 #include "third_party/blink/renderer/core/dom/static_node_list.h"
 #include "third_party/blink/renderer/core/frame/root_frame_viewport.h"
 #include "third_party/blink/renderer/core/frame/visual_viewport.h"
@@ -28,6 +29,11 @@
   ScrollAnchorTest() : ScopedLayoutNGForTest(GetParam()) {}
 
  protected:
+  void SetUp() override {
+    EnableCompositing();
+    RenderingTest::SetUp();
+  }
+
   void Update() {
     // TODO(skobes): Use SimTest instead of RenderingTest and move into
     // Source/web?
@@ -79,6 +85,52 @@
         GetDocument().QuerySelectorAll(AtomicString(serialized.selector));
     EXPECT_EQ(ele_list->length(), 1u);
   }
+
+  Scrollbar* VerticalScrollbarForElement(Element* element) {
+    return ToLayoutBox(element->GetLayoutObject())
+        ->GetScrollableArea()
+        ->VerticalScrollbar();
+  }
+
+  void MouseDownOnVerticalScrollbar(Scrollbar* scrollbar) {
+    DCHECK_EQ(true, scrollbar->GetTheme().AllowsHitTest());
+    int thumb_center = scrollbar->GetTheme().ThumbPosition(*scrollbar) +
+                       scrollbar->GetTheme().ThumbLength(*scrollbar) / 2;
+    scrollbar_drag_point_ =
+        gfx::PointF(scrollbar->GetScrollableArea()
+                        ->ConvertFromScrollbarToContainingEmbeddedContentView(
+                            *scrollbar, IntPoint(0, thumb_center)));
+    scrollbar->MouseDown(blink::WebMouseEvent(
+        blink::WebInputEvent::kMouseDown, *scrollbar_drag_point_,
+        *scrollbar_drag_point_, blink::WebPointerProperties::Button::kLeft, 0,
+        blink::WebInputEvent::kNoModifiers, base::TimeTicks::Now()));
+  }
+
+  void MouseDragVerticalScrollbar(Scrollbar* scrollbar, float scroll_delta_y) {
+    DCHECK(scrollbar_drag_point_);
+    ScrollableArea* scroller = scrollbar->GetScrollableArea();
+    scrollbar_drag_point_->Offset(
+        0, scroll_delta_y *
+               (scrollbar->GetTheme().TrackLength(*scrollbar) -
+                scrollbar->GetTheme().ThumbLength(*scrollbar)) /
+               (scroller->MaximumScrollOffset().Height() -
+                scroller->MinimumScrollOffset().Height()));
+    scrollbar->MouseMoved(blink::WebMouseEvent(
+        blink::WebInputEvent::kMouseMove, *scrollbar_drag_point_,
+        *scrollbar_drag_point_, blink::WebPointerProperties::Button::kLeft, 0,
+        blink::WebInputEvent::kNoModifiers, base::TimeTicks::Now()));
+  }
+
+  void MouseUpOnVerticalScrollbar(Scrollbar* scrollbar) {
+    DCHECK(scrollbar_drag_point_);
+    scrollbar->MouseDown(blink::WebMouseEvent(
+        blink::WebInputEvent::kMouseUp, *scrollbar_drag_point_,
+        *scrollbar_drag_point_, blink::WebPointerProperties::Button::kLeft, 0,
+        blink::WebInputEvent::kNoModifiers, base::TimeTicks::Now()));
+    scrollbar_drag_point_.reset();
+  }
+
+  base::Optional<gfx::PointF> scrollbar_drag_point_;
 };
 
 INSTANTIATE_TEST_SUITE_P(All, ScrollAnchorTest, testing::Bool());
@@ -328,6 +380,51 @@
   EXPECT_EQ(250, scroller->ScrollOffsetInt().Height());
 }
 
+TEST_P(ScrollAnchorTest, AnchorWhileDraggingScrollbar) {
+  // Dragging the scrollbar is inherently inaccurate. Allow many pixels slop in
+  // the scroll position.
+  const int kScrollbarDragAccuracy = 10;
+  USE_NON_OVERLAY_SCROLLBARS();
+  SetBodyInnerHTML(R"HTML(
+    <style>
+        #scroller { overflow: scroll; width: 500px; height: 400px; }
+        div { height: 100px }
+        #block2 { overflow: hidden }
+        #space { height: 1000px; }
+    </style>
+    <div id='scroller'><div id='space'>
+    <div id='block1'>abc</div>
+    <div id='block2'>def</div>
+    </div></div>
+  )HTML");
+  Element* scroller_element = GetDocument().getElementById("scroller");
+  ScrollableArea* scroller = ScrollerForElement(scroller_element);
+
+  Element* block1 = GetDocument().getElementById("block1");
+  Element* block2 = GetDocument().getElementById("block2");
+
+  Scrollbar* scrollbar = VerticalScrollbarForElement(scroller_element);
+  scroller->MouseEnteredScrollbar(*scrollbar);
+  MouseDownOnVerticalScrollbar(scrollbar);
+  MouseDragVerticalScrollbar(scrollbar, 150);
+  EXPECT_NEAR(150, scroller->GetScrollOffset().Height(),
+              kScrollbarDragAccuracy);
+
+  // In this layout pass we will anchor to #block2 which has its own PaintLayer.
+  SetHeight(block1, 200);
+  EXPECT_NEAR(250, scroller->ScrollOffsetInt().Height(),
+              kScrollbarDragAccuracy);
+  EXPECT_EQ(block2->GetLayoutObject(),
+            GetScrollAnchor(scroller).AnchorObject());
+
+  // If we continue dragging the scroller should scroll from the newly anchored
+  // position.
+  MouseDragVerticalScrollbar(scrollbar, 10);
+  EXPECT_NEAR(260, scroller->ScrollOffsetInt().Height(),
+              kScrollbarDragAccuracy);
+  MouseUpOnVerticalScrollbar(scrollbar);
+}
+
 // Verify that a nested scroller with a div that has its own PaintLayer can be
 // removed without causing a crash. This test passes if it doesn't crash.
 TEST_P(ScrollAnchorTest, RemoveScrollerWithLayerInScrollingDiv) {
diff --git a/third_party/blink/renderer/core/loader/empty_clients.cc b/third_party/blink/renderer/core/loader/empty_clients.cc
index c51e40a2..cd6d9b2 100644
--- a/third_party/blink/renderer/core/loader/empty_clients.cc
+++ b/third_party/blink/renderer/core/loader/empty_clients.cc
@@ -90,7 +90,7 @@
 
 void EmptyLocalFrameClient::BeginNavigation(
     const ResourceRequest&,
-    network::mojom::RequestContextFrameType,
+    mojom::RequestContextFrameType,
     Document* origin_document,
     DocumentLoader*,
     WebNavigationType,
diff --git a/third_party/blink/renderer/core/loader/empty_clients.h b/third_party/blink/renderer/core/loader/empty_clients.h
index ca7dab9..77e22ee 100644
--- a/third_party/blink/renderer/core/loader/empty_clients.h
+++ b/third_party/blink/renderer/core/loader/empty_clients.h
@@ -285,7 +285,7 @@
 
   void BeginNavigation(
       const ResourceRequest&,
-      network::mojom::RequestContextFrameType,
+      mojom::RequestContextFrameType,
       Document* origin_document,
       DocumentLoader*,
       WebNavigationType,
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context.cc b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
index be70be7..84725b38 100644
--- a/third_party/blink/renderer/core/loader/frame_fetch_context.cc
+++ b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
@@ -495,7 +495,7 @@
       resource_request,
       &GetResourceFetcherProperties().GetFetchClientSettingsObject(),
       &frame_or_imported_document_->GetDocument(),
-      network::mojom::RequestContextFrameType::kNone);
+      mojom::RequestContextFrameType::kNone);
 }
 
 void FrameFetchContext::AddClientHintsIfNecessary(
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc b/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc
index c07ea3c..4c8591e 100644
--- a/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc
+++ b/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc
@@ -278,7 +278,7 @@
 
  protected:
   void ModifyRequestForCSP(ResourceRequest& resource_request,
-                           network::mojom::RequestContextFrameType frame_type) {
+                           mojom::RequestContextFrameType frame_type) {
     document->GetFrame()->Loader().RecordLatestRequiredCSP();
     document->GetFrame()->Loader().ModifyRequestForCSP(
         resource_request,
@@ -288,12 +288,12 @@
 
   void ExpectUpgrade(const char* input, const char* expected) {
     ExpectUpgrade(input, mojom::RequestContextType::SCRIPT,
-                  network::mojom::RequestContextFrameType::kNone, expected);
+                  mojom::RequestContextFrameType::kNone, expected);
   }
 
   void ExpectUpgrade(const char* input,
                      mojom::RequestContextType request_context,
-                     network::mojom::RequestContextFrameType frame_type,
+                     mojom::RequestContextFrameType frame_type,
                      const char* expected) {
     const KURL input_url(input);
     const KURL expected_url(expected);
@@ -313,7 +313,7 @@
 
   void ExpectUpgradeInsecureRequestHeader(
       const char* input,
-      network::mojom::RequestContextFrameType frame_type,
+      mojom::RequestContextFrameType frame_type,
       bool should_prefer) {
     const KURL input_url(input);
 
@@ -348,14 +348,14 @@
     document->GetSecurityContext().SetInsecureRequestPolicy(policy);
 
     ModifyRequestForCSP(resource_request,
-                        network::mojom::RequestContextFrameType::kNone);
+                        mojom::RequestContextFrameType::kNone);
 
     EXPECT_EQ(expected_value, resource_request.IsAutomaticUpgrade());
   }
 
   void ExpectSetRequiredCSPRequestHeader(
       const char* input,
-      network::mojom::RequestContextFrameType frame_type,
+      mojom::RequestContextFrameType frame_type,
       const AtomicString& expected_required_csp) {
     const KURL input_url(input);
     ResourceRequest resource_request(input_url);
@@ -367,11 +367,10 @@
               resource_request.HttpHeaderField(http_names::kSecRequiredCSP));
   }
 
-  void SetFrameOwnerBasedOnFrameType(
-      network::mojom::RequestContextFrameType frame_type,
-      HTMLIFrameElement* iframe,
-      const AtomicString& potential_value) {
-    if (frame_type != network::mojom::RequestContextFrameType::kNested) {
+  void SetFrameOwnerBasedOnFrameType(mojom::RequestContextFrameType frame_type,
+                                     HTMLIFrameElement* iframe,
+                                     const AtomicString& potential_value) {
+    if (frame_type != mojom::RequestContextFrameType::kNested) {
       document->GetFrame()->SetOwner(nullptr);
       return;
     }
@@ -414,41 +413,33 @@
 
     // We always upgrade for FrameTypeNone.
     ExpectUpgrade(test.original, mojom::RequestContextType::SCRIPT,
-                  network::mojom::RequestContextFrameType::kNone,
-                  test.upgraded);
+                  mojom::RequestContextFrameType::kNone, test.upgraded);
 
     // We never upgrade for FrameTypeNested. This is done on the browser
     // process.
     ExpectUpgrade(test.original, mojom::RequestContextType::SCRIPT,
-                  network::mojom::RequestContextFrameType::kNested,
-                  test.original);
+                  mojom::RequestContextFrameType::kNested, test.original);
 
     // We do not upgrade for FrameTypeTopLevel or FrameTypeAuxiliary...
     ExpectUpgrade(test.original, mojom::RequestContextType::SCRIPT,
-                  network::mojom::RequestContextFrameType::kTopLevel,
-                  test.original);
+                  mojom::RequestContextFrameType::kTopLevel, test.original);
     ExpectUpgrade(test.original, mojom::RequestContextType::SCRIPT,
-                  network::mojom::RequestContextFrameType::kAuxiliary,
-                  test.original);
+                  mojom::RequestContextFrameType::kAuxiliary, test.original);
 
     // unless the request context is RequestContextForm.
     ExpectUpgrade(test.original, mojom::RequestContextType::FORM,
-                  network::mojom::RequestContextFrameType::kTopLevel,
-                  test.upgraded);
+                  mojom::RequestContextFrameType::kTopLevel, test.upgraded);
     ExpectUpgrade(test.original, mojom::RequestContextType::FORM,
-                  network::mojom::RequestContextFrameType::kAuxiliary,
-                  test.upgraded);
+                  mojom::RequestContextFrameType::kAuxiliary, test.upgraded);
 
     // Or unless the host of the resource is in the document's
     // InsecureNavigationsSet:
     document->GetSecurityContext().AddInsecureNavigationUpgrade(
         example_origin->Host().Impl()->GetHash());
     ExpectUpgrade(test.original, mojom::RequestContextType::SCRIPT,
-                  network::mojom::RequestContextFrameType::kTopLevel,
-                  test.upgraded);
+                  mojom::RequestContextFrameType::kTopLevel, test.upgraded);
     ExpectUpgrade(test.original, mojom::RequestContextType::SCRIPT,
-                  network::mojom::RequestContextFrameType::kAuxiliary,
-                  test.upgraded);
+                  mojom::RequestContextFrameType::kAuxiliary, test.upgraded);
   }
 }
 
@@ -511,24 +502,24 @@
 TEST_F(FrameFetchContextModifyRequestTest, SendUpgradeInsecureRequestHeader) {
   struct TestCase {
     const char* to_request;
-    network::mojom::RequestContextFrameType frame_type;
+    mojom::RequestContextFrameType frame_type;
     bool should_prefer;
   } tests[] = {{"http://example.test/page.html",
-                network::mojom::RequestContextFrameType::kAuxiliary, true},
+                mojom::RequestContextFrameType::kAuxiliary, true},
                {"http://example.test/page.html",
-                network::mojom::RequestContextFrameType::kNested, true},
+                mojom::RequestContextFrameType::kNested, true},
                {"http://example.test/page.html",
-                network::mojom::RequestContextFrameType::kNone, false},
+                mojom::RequestContextFrameType::kNone, false},
                {"http://example.test/page.html",
-                network::mojom::RequestContextFrameType::kTopLevel, true},
+                mojom::RequestContextFrameType::kTopLevel, true},
                {"https://example.test/page.html",
-                network::mojom::RequestContextFrameType::kAuxiliary, true},
+                mojom::RequestContextFrameType::kAuxiliary, true},
                {"https://example.test/page.html",
-                network::mojom::RequestContextFrameType::kNested, true},
+                mojom::RequestContextFrameType::kNested, true},
                {"https://example.test/page.html",
-                network::mojom::RequestContextFrameType::kNone, false},
+                mojom::RequestContextFrameType::kNone, false},
                {"https://example.test/page.html",
-                network::mojom::RequestContextFrameType::kTopLevel, true}};
+                mojom::RequestContextFrameType::kTopLevel, true}};
 
   // This should work correctly both when the FrameFetchContext has a Document,
   // and when it doesn't (e.g. during main frame navigations), so run through
@@ -561,15 +552,15 @@
 TEST_F(FrameFetchContextModifyRequestTest, SendRequiredCSPHeader) {
   struct TestCase {
     const char* to_request;
-    network::mojom::RequestContextFrameType frame_type;
-  } tests[] = {{"https://example.test/page.html",
-                network::mojom::RequestContextFrameType::kAuxiliary},
-               {"https://example.test/page.html",
-                network::mojom::RequestContextFrameType::kNested},
-               {"https://example.test/page.html",
-                network::mojom::RequestContextFrameType::kNone},
-               {"https://example.test/page.html",
-                network::mojom::RequestContextFrameType::kTopLevel}};
+    mojom::RequestContextFrameType frame_type;
+  } tests[] = {
+      {"https://example.test/page.html",
+       mojom::RequestContextFrameType::kAuxiliary},
+      {"https://example.test/page.html",
+       mojom::RequestContextFrameType::kNested},
+      {"https://example.test/page.html", mojom::RequestContextFrameType::kNone},
+      {"https://example.test/page.html",
+       mojom::RequestContextFrameType::kTopLevel}};
 
   auto* iframe = MakeGarbageCollected<HTMLIFrameElement>(*document);
   const AtomicString& required_csp = AtomicString("default-src 'none'");
@@ -579,7 +570,7 @@
     SetFrameOwnerBasedOnFrameType(test.frame_type, iframe, required_csp);
     ExpectSetRequiredCSPRequestHeader(
         test.to_request, test.frame_type,
-        test.frame_type == network::mojom::RequestContextFrameType::kNested
+        test.frame_type == mojom::RequestContextFrameType::kNested
             ? required_csp
             : g_null_atom);
 
@@ -587,7 +578,7 @@
                                   another_required_csp);
     ExpectSetRequiredCSPRequestHeader(
         test.to_request, test.frame_type,
-        test.frame_type == network::mojom::RequestContextFrameType::kNested
+        test.frame_type == mojom::RequestContextFrameType::kNested
             ? another_required_csp
             : g_null_atom);
   }
diff --git a/third_party/blink/renderer/core/loader/frame_load_request.h b/third_party/blink/renderer/core/loader/frame_load_request.h
index 7d7ae489..9dba988 100644
--- a/third_party/blink/renderer/core/loader/frame_load_request.h
+++ b/third_party/blink/renderer/core/loader/frame_load_request.h
@@ -55,10 +55,8 @@
 
   Document* OriginDocument() const { return origin_document_.Get(); }
 
-  network::mojom::RequestContextFrameType GetFrameType() const {
-    return frame_type_;
-  }
-  void SetFrameType(network::mojom::RequestContextFrameType frame_type) {
+  mojom::RequestContextFrameType GetFrameType() const { return frame_type_; }
+  void SetFrameType(mojom::RequestContextFrameType frame_type) {
     frame_type_ = frame_type;
   }
 
@@ -165,8 +163,8 @@
   scoped_refptr<base::RefCountedData<mojo::Remote<mojom::blink::BlobURLToken>>>
       blob_url_token_;
   base::TimeTicks input_start_time_;
-  network::mojom::RequestContextFrameType frame_type_ =
-      network::mojom::RequestContextFrameType::kNone;
+  mojom::RequestContextFrameType frame_type_ =
+      mojom::RequestContextFrameType::kNone;
   WebWindowFeatures window_features_;
   bool is_window_open_ = false;
 };
diff --git a/third_party/blink/renderer/core/loader/frame_loader.cc b/third_party/blink/renderer/core/loader/frame_loader.cc
index ecc5038..6da57581 100644
--- a/third_party/blink/renderer/core/loader/frame_loader.cc
+++ b/third_party/blink/renderer/core/loader/frame_loader.cc
@@ -689,8 +689,8 @@
   resource_request.SetRequestDestination(
       DetermineRequestDestinationFromNavigationType(navigation_type));
   request.SetFrameType(frame_->IsMainFrame()
-                           ? network::mojom::RequestContextFrameType::kTopLevel
-                           : network::mojom::RequestContextFrameType::kNested);
+                           ? mojom::RequestContextFrameType::kTopLevel
+                           : mojom::RequestContextFrameType::kNested);
 
   mojo::PendingRemote<mojom::blink::NavigationInitiator> navigation_initiator;
   WebContentSecurityPolicyList initiator_csp;
@@ -1526,7 +1526,7 @@
     ResourceRequest& resource_request,
     const FetchClientSettingsObject* fetch_client_settings_object,
     Document* document_for_logging,
-    network::mojom::RequestContextFrameType frame_type) const {
+    mojom::RequestContextFrameType frame_type) const {
   if (!RequiredCSP().IsEmpty()) {
     DCHECK(
         ContentSecurityPolicy::IsValidCSPAttr(RequiredCSP().GetString(), ""));
@@ -1537,7 +1537,7 @@
   // Tack an 'Upgrade-Insecure-Requests' header to outgoing navigational
   // requests, as described in
   // https://w3c.github.io/webappsec-upgrade-insecure-requests/#feature-detect
-  if (frame_type != network::mojom::RequestContextFrameType::kNone) {
+  if (frame_type != mojom::RequestContextFrameType::kNone) {
     // Early return if the request has already been upgraded.
     if (!resource_request.HttpHeaderField(http_names::kUpgradeInsecureRequests)
              .IsNull()) {
diff --git a/third_party/blink/renderer/core/loader/frame_loader.h b/third_party/blink/renderer/core/loader/frame_loader.h
index 7eb611c..23a0e61 100644
--- a/third_party/blink/renderer/core/loader/frame_loader.h
+++ b/third_party/blink/renderer/core/loader/frame_loader.h
@@ -174,7 +174,7 @@
       ResourceRequest&,
       const FetchClientSettingsObject* fetch_client_settings_object,
       Document* document_for_logging,
-      network::mojom::RequestContextFrameType) const;
+      mojom::RequestContextFrameType) const;
   void ReportLegacyTLSVersion(const KURL& url,
                               bool is_subresource,
                               bool is_ad_resource);
diff --git a/third_party/blink/renderer/core/loader/mixed_content_checker.cc b/third_party/blink/renderer/core/loader/mixed_content_checker.cc
index 717cb2e..d89c305 100644
--- a/third_party/blink/renderer/core/loader/mixed_content_checker.cc
+++ b/third_party/blink/renderer/core/loader/mixed_content_checker.cc
@@ -812,7 +812,7 @@
     ResourceRequest& resource_request,
     const FetchClientSettingsObject* fetch_client_settings_object,
     ExecutionContext* execution_context_for_logging,
-    network::mojom::RequestContextFrameType frame_type,
+    mojom::RequestContextFrameType frame_type,
     WebContentSettingsClient* settings_client) {
   // We always upgrade requests that meet any of the following criteria:
   //  1. Are for subresources.
@@ -854,7 +854,7 @@
   }
 
   // Nested frames are always upgraded on the browser process.
-  if (frame_type == network::mojom::RequestContextFrameType::kNested)
+  if (frame_type == mojom::RequestContextFrameType::kNested)
     return;
 
   // We set the UpgradeIfInsecure flag even if the current request wasn't
@@ -869,7 +869,7 @@
     return;
   }
 
-  if (frame_type == network::mojom::RequestContextFrameType::kNone ||
+  if (frame_type == mojom::RequestContextFrameType::kNone ||
       resource_request.GetRequestContext() == mojom::RequestContextType::FORM ||
       (!url.Host().IsNull() &&
        fetch_client_settings_object->GetUpgradeInsecureNavigationsSet()
diff --git a/third_party/blink/renderer/core/loader/mixed_content_checker.h b/third_party/blink/renderer/core/loader/mixed_content_checker.h
index 43ff269..63e726c 100644
--- a/third_party/blink/renderer/core/loader/mixed_content_checker.h
+++ b/third_party/blink/renderer/core/loader/mixed_content_checker.h
@@ -133,7 +133,7 @@
       ResourceRequest&,
       const FetchClientSettingsObject* fetch_client_settings_object,
       ExecutionContext* execution_context_for_logging,
-      network::mojom::RequestContextFrameType,
+      mojom::RequestContextFrameType,
       WebContentSettingsClient* settings_client);
 
  private:
diff --git a/third_party/blink/renderer/core/loader/resource/image_resource_content.cc b/third_party/blink/renderer/core/loader/resource/image_resource_content.cc
index 0cd852e..50837f2 100644
--- a/third_party/blink/renderer/core/loader/resource/image_resource_content.cc
+++ b/third_party/blink/renderer/core/loader/resource/image_resource_content.cc
@@ -514,7 +514,7 @@
   if (!image_)
     return true;
 
-  uint64_t pixels = IntrinsicSize(kRespectImageOrientation).Area();
+  uint64_t pixels = image_->Size().Area();
   if (!pixels)
     return true;
 
diff --git a/third_party/blink/renderer/core/loader/worker_fetch_context.cc b/third_party/blink/renderer/core/loader/worker_fetch_context.cc
index 247dc0fd..b493b52 100644
--- a/third_party/blink/renderer/core/loader/worker_fetch_context.cc
+++ b/third_party/blink/renderer/core/loader/worker_fetch_context.cc
@@ -243,7 +243,7 @@
   MixedContentChecker::UpgradeInsecureRequest(
       out_request,
       &GetResourceFetcherProperties().GetFetchClientSettingsObject(),
-      global_scope_, network::mojom::RequestContextFrameType::kNone,
+      global_scope_, mojom::RequestContextFrameType::kNone,
       global_scope_->ContentSettingsClient());
   SetFirstPartyCookie(out_request);
   if (!out_request.TopFrameOrigin())
diff --git a/third_party/blink/renderer/core/page/create_window.cc b/third_party/blink/renderer/core/page/create_window.cc
index 7b32f7a..c3e0d56 100644
--- a/third_party/blink/renderer/core/page/create_window.cc
+++ b/third_party/blink/renderer/core/page/create_window.cc
@@ -236,7 +236,7 @@
     return nullptr;
   }
 
-  request.SetFrameType(network::mojom::RequestContextFrameType::kAuxiliary);
+  request.SetFrameType(mojom::RequestContextFrameType::kAuxiliary);
 
   const KURL& url = request.GetResourceRequest().Url();
   if (url.ProtocolIsJavaScript() &&
diff --git a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
index 7caac9d..ea76b3c6 100644
--- a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
+++ b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
@@ -2189,12 +2189,12 @@
   if (graphics_layer == LayerForHorizontalScrollbar()) {
     if (const Scrollbar* scrollbar = scrollable_area->HorizontalScrollbar()) {
       if (cull_rect.Intersects(scrollbar->FrameRect()))
-        scrollbar->Paint(context);
+        scrollbar->Paint(context, IntPoint());
     }
   } else if (graphics_layer == LayerForVerticalScrollbar()) {
     if (const Scrollbar* scrollbar = scrollable_area->VerticalScrollbar()) {
       if (cull_rect.Intersects(scrollbar->FrameRect()))
-        scrollbar->Paint(context);
+        scrollbar->Paint(context, IntPoint());
     }
   } else if (graphics_layer == LayerForScrollCorner()) {
     ScrollableAreaPainter painter(*scrollable_area);
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
index 4045cb0b..6dc734ef 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
@@ -2878,8 +2878,13 @@
   bool is_overlay = scrollbar && scrollbar->IsOverlayScrollbar();
 
   IntRect new_visual_rect;
-  if (scrollbar)
+  if (scrollbar) {
     new_visual_rect = scrollbar->FrameRect();
+    // TODO(crbug.com/1020913): We should not round paint_offset but should
+    // consider subpixel accumulation when painting scrollbars.
+    new_visual_rect.MoveBy(
+        RoundedIntPoint(context.fragment_data->PaintOffset()));
+  }
 
   if (needs_paint_invalidation && graphics_layer) {
     // If the scrollbar needs paint invalidation but didn't change location/size
@@ -2952,8 +2957,10 @@
       box_geometry_has_been_invalidated, context));
 
   IntRect scroll_corner_and_resizer_visual_rect = ScrollCornerAndResizerRect();
+  // TODO(crbug.com/1020913): We should not round paint_offset but should
+  // consider subpixel accumulation when painting scrollbars.
   scroll_corner_and_resizer_visual_rect.MoveBy(
-      RoundedIntPoint(box.FirstFragment().PaintOffset()));
+      RoundedIntPoint(context.fragment_data->PaintOffset()));
   if (ScrollControlNeedsPaintInvalidation(
           scroll_corner_and_resizer_visual_rect,
           scroll_corner_and_resizer_visual_rect_,
diff --git a/third_party/blink/renderer/core/paint/scrollable_area_painter.cc b/third_party/blink/renderer/core/paint/scrollable_area_painter.cc
index ab01fef..778ee1a 100644
--- a/third_party/blink/renderer/core/paint/scrollable_area_painter.cc
+++ b/third_party/blink/renderer/core/paint/scrollable_area_painter.cc
@@ -201,18 +201,16 @@
                                            Scrollbar& scrollbar,
                                            const CullRect& cull_rect,
                                            const IntPoint& paint_offset) {
-  // We create PaintOffsetTranslation for scrollable area, so the rounded
-  // paint offset is always zero.
   // TODO(crbug.com/1020913): We should not round paint_offset but should
   // consider subpixel accumulation when painting scrollbars.
-  DCHECK_EQ(paint_offset, IntPoint());
   IntRect rect = scrollbar.FrameRect();
+  rect.MoveBy(paint_offset);
   if (!cull_rect.Intersects(rect))
     return;
 
   if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
       scrollbar.IsCustomScrollbar()) {
-    scrollbar.Paint(context);
+    scrollbar.Paint(context, paint_offset);
     return;
   }
 
diff --git a/third_party/blink/renderer/core/scroll/scrollable_area.cc b/third_party/blink/renderer/core/scroll/scrollable_area.cc
index a621be8..9a6488e7 100644
--- a/third_party/blink/renderer/core/scroll/scrollable_area.cc
+++ b/third_party/blink/renderer/core/scroll/scrollable_area.cc
@@ -379,9 +379,9 @@
   // invalidated to reflect the new thumb offset, even if the theme did not
   // invalidate any individual part.
   if (Scrollbar* horizontal_scrollbar = this->HorizontalScrollbar())
-    horizontal_scrollbar->OffsetDidChange();
+    horizontal_scrollbar->OffsetDidChange(scroll_type);
   if (Scrollbar* vertical_scrollbar = this->VerticalScrollbar())
-    vertical_scrollbar->OffsetDidChange();
+    vertical_scrollbar->OffsetDidChange(scroll_type);
 
   ScrollOffset delta = GetScrollOffset() - old_offset;
   // TODO(skobes): Should we exit sooner when the offset has not changed?
diff --git a/third_party/blink/renderer/core/scroll/scrollbar.cc b/third_party/blink/renderer/core/scroll/scrollbar.cc
index 6ddd0b5..4e2a37c 100644
--- a/third_party/blink/renderer/core/scroll/scrollbar.cc
+++ b/third_party/blink/renderer/core/scroll/scrollbar.cc
@@ -141,7 +141,7 @@
                                               : max_offset.Height();
 }
 
-void Scrollbar::OffsetDidChange() {
+void Scrollbar::OffsetDidChange(ScrollType scroll_type) {
   DCHECK(scrollable_area_);
 
   float position = ScrollableAreaCurrentPos();
@@ -157,9 +157,13 @@
                                                         position);
   SetNeedsPaintInvalidation(invalid_parts);
 
-  if (pressed_part_ == kThumbPart)
+  // Don't update the pressed position if scroll anchoring takes place as
+  // otherwise the next thumb movement will undo anchoring.
+  if (pressed_part_ == kThumbPart &&
+      scroll_type != ScrollType::kAnchoringScroll) {
     SetPressedPos(pressed_pos_ + GetTheme().ThumbPosition(*this) -
                   old_thumb_position);
+  }
 }
 
 void Scrollbar::DisconnectFromScrollableArea() {
@@ -176,8 +180,9 @@
   SetNeedsPaintInvalidation(kAllParts);
 }
 
-void Scrollbar::Paint(GraphicsContext& context) const {
-  GetTheme().Paint(*this, context);
+void Scrollbar::Paint(GraphicsContext& context,
+                      const IntPoint& paint_offset) const {
+  GetTheme().Paint(*this, context, paint_offset);
 }
 
 void Scrollbar::AutoscrollTimerFired(TimerBase*) {
diff --git a/third_party/blink/renderer/core/scroll/scrollbar.h b/third_party/blink/renderer/core/scroll/scrollbar.h
index 544461b7..4a7bed9 100644
--- a/third_party/blink/renderer/core/scroll/scrollbar.h
+++ b/third_party/blink/renderer/core/scroll/scrollbar.h
@@ -111,7 +111,7 @@
 
   // Called by the ScrollableArea when the scroll offset changes.
   // Will trigger paint invalidation if required.
-  void OffsetDidChange();
+  void OffsetDidChange(ScrollType scroll_type);
 
   virtual void DisconnectFromScrollableArea();
   ScrollableArea* GetScrollableArea() const { return scrollable_area_; }
@@ -124,7 +124,7 @@
   void SetProportion(int visible_size, int total_size);
   void SetPressedPos(int p) { pressed_pos_ = p; }
 
-  void Paint(GraphicsContext&) const;
+  void Paint(GraphicsContext&, const IntPoint& paint_offset) const;
 
   virtual bool IsSolidColor() const;
   virtual bool IsOverlayScrollbar() const;
diff --git a/third_party/blink/renderer/core/scroll/scrollbar_theme.cc b/third_party/blink/renderer/core/scroll/scrollbar_theme.cc
index 1ec12943..2f8f6dc 100644
--- a/third_party/blink/renderer/core/scroll/scrollbar_theme.cc
+++ b/third_party/blink/renderer/core/scroll/scrollbar_theme.cc
@@ -49,12 +49,15 @@
 namespace blink {
 
 void ScrollbarTheme::Paint(const Scrollbar& scrollbar,
-                           GraphicsContext& graphics_context) {
-  PaintTrackButtonsTickmarks(graphics_context, scrollbar, IntPoint());
+                           GraphicsContext& graphics_context,
+                           const IntPoint& paint_offset) {
+  PaintTrackButtonsTickmarks(graphics_context, scrollbar, paint_offset);
 
-  IntRect thumb_rect = ThumbRect(scrollbar);
-  if (HasThumb(scrollbar))
+  if (HasThumb(scrollbar)) {
+    IntRect thumb_rect = ThumbRect(scrollbar);
+    thumb_rect.MoveBy(paint_offset);
     PaintThumbWithOpacity(graphics_context, scrollbar, thumb_rect);
+  }
 }
 
 ScrollbarPart ScrollbarTheme::HitTestRootFramePosition(
diff --git a/third_party/blink/renderer/core/scroll/scrollbar_theme.h b/third_party/blink/renderer/core/scroll/scrollbar_theme.h
index e42faccd..26b1ea8c 100644
--- a/third_party/blink/renderer/core/scroll/scrollbar_theme.h
+++ b/third_party/blink/renderer/core/scroll/scrollbar_theme.h
@@ -54,7 +54,9 @@
   virtual void UpdateEnabledState(const Scrollbar&) {}
 
   // |context|'s current space is the space of the scrollbar's FrameRect().
-  void Paint(const Scrollbar&, GraphicsContext& context);
+  void Paint(const Scrollbar&,
+             GraphicsContext& context,
+             const IntPoint& paint_offset);
 
   ScrollbarPart HitTestRootFramePosition(const Scrollbar&, const IntPoint&);
 
diff --git a/third_party/blink/renderer/core/scroll/scrollbar_theme_overlay_test.cc b/third_party/blink/renderer/core/scroll/scrollbar_theme_overlay_test.cc
index c41d561..2228064 100644
--- a/third_party/blink/renderer/core/scroll/scrollbar_theme_overlay_test.cc
+++ b/third_party/blink/renderer/core/scroll/scrollbar_theme_overlay_test.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/scroll/scrollbar_theme_overlay.h"
 
+#include "third_party/blink/renderer/core/scroll/scroll_types.h"
 #include "third_party/blink/renderer/core/scroll/scrollbar_test_suite.h"
 #include "third_party/blink/renderer/platform/testing/testing_platform_support_with_mock_scheduler.h"
 
@@ -58,8 +59,8 @@
   // should cause a "general" invalidation for non-composited scrollbars.
   // Ensure the horizontal scrollbar is unaffected.
   mock_scrollable_area->UpdateScrollOffset(ScrollOffset(0, 5), kUserScroll);
-  vertical_scrollbar->OffsetDidChange();
-  horizontal_scrollbar->OffsetDidChange();
+  vertical_scrollbar->OffsetDidChange(ScrollType::kUserScroll);
+  horizontal_scrollbar->OffsetDidChange(ScrollType::kUserScroll);
   EXPECT_FALSE(vertical_scrollbar->ThumbNeedsRepaint());
   EXPECT_FALSE(vertical_scrollbar->TrackNeedsRepaint());
   EXPECT_TRUE(mock_scrollable_area->VerticalScrollbarNeedsPaintInvalidation());
@@ -71,8 +72,8 @@
   // Try the horizontal scrollbar.
   mock_scrollable_area->ClearNeedsPaintInvalidationForScrollControls();
   mock_scrollable_area->UpdateScrollOffset(ScrollOffset(5, 5), kUserScroll);
-  horizontal_scrollbar->OffsetDidChange();
-  vertical_scrollbar->OffsetDidChange();
+  horizontal_scrollbar->OffsetDidChange(ScrollType::kUserScroll);
+  vertical_scrollbar->OffsetDidChange(ScrollType::kUserScroll);
   EXPECT_FALSE(vertical_scrollbar->ThumbNeedsRepaint());
   EXPECT_FALSE(vertical_scrollbar->TrackNeedsRepaint());
   EXPECT_FALSE(mock_scrollable_area->VerticalScrollbarNeedsPaintInvalidation());
diff --git a/third_party/blink/renderer/core/testing/DEPS b/third_party/blink/renderer/core/testing/DEPS
index efe470a..61f5ab5 100644
--- a/third_party/blink/renderer/core/testing/DEPS
+++ b/third_party/blink/renderer/core/testing/DEPS
@@ -7,6 +7,7 @@
     "+content/renderer/compositor",
     "+content/test",
     "+gpu/command_buffer/client/gles2_interface.h",
+    "+ui/events/blink/blink_event_util.h"
 ]
 
 specific_include_rules = {
diff --git a/third_party/blink/renderer/core/testing/core_unit_test_helper.cc b/third_party/blink/renderer/core/testing/core_unit_test_helper.cc
index d43b8c6..4d1c5f4 100644
--- a/third_party/blink/renderer/core/testing/core_unit_test_helper.cc
+++ b/third_party/blink/renderer/core/testing/core_unit_test_helper.cc
@@ -6,11 +6,13 @@
 
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
 #include "third_party/blink/renderer/core/html/html_iframe_element.h"
+#include "third_party/blink/renderer/core/input/event_handler.h"
 #include "third_party/blink/renderer/core/page/page.h"
 #include "third_party/blink/renderer/core/scroll/scrollbar_theme.h"
 #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/loader/fetch/memory_cache.h"
+#include "ui/events/blink/blink_event_util.h"
 
 namespace blink {
 
@@ -36,6 +38,27 @@
       ->DidDetachChild();
 }
 
+void RenderingTestChromeClient::InjectGestureScrollEvent(
+    LocalFrame& local_frame,
+    WebGestureDevice device,
+    const gfx::Vector2dF& delta,
+    ScrollGranularity granularity,
+    CompositorElementId scrollable_area_element_id,
+    WebInputEvent::Type injected_type) {
+  // Directly handle injected gesture scroll events. In a real browser, these
+  // would be added to the event queue and handled asynchronously but immediate
+  // handling is sufficient to test scrollbar dragging.
+  std::unique_ptr<WebGestureEvent> gesture_event =
+      ui::GenerateInjectedScrollGesture(injected_type, base::TimeTicks::Now(),
+                                        device, gfx::PointF(0, 0), delta,
+                                        granularity);
+  if (injected_type == WebInputEvent::Type::kGestureScrollBegin) {
+    gesture_event->data.scroll_begin.scrollable_area_element_id =
+        scrollable_area_element_id.GetStableId();
+  }
+  local_frame.GetEventHandler().HandleGestureEvent(*gesture_event);
+}
+
 RenderingTestChromeClient& RenderingTest::GetChromeClient() const {
   DEFINE_STATIC_LOCAL(Persistent<RenderingTestChromeClient>, client,
                       (MakeGarbageCollected<RenderingTestChromeClient>()));
diff --git a/third_party/blink/renderer/core/testing/core_unit_test_helper.h b/third_party/blink/renderer/core/testing/core_unit_test_helper.h
index c2ddac1..c993f27 100644
--- a/third_party/blink/renderer/core/testing/core_unit_test_helper.h
+++ b/third_party/blink/renderer/core/testing/core_unit_test_helper.h
@@ -97,6 +97,13 @@
     return device_emulation_transform_;
   }
 
+  void InjectGestureScrollEvent(LocalFrame& local_frame,
+                                WebGestureDevice device,
+                                const gfx::Vector2dF& delta,
+                                ScrollGranularity granularity,
+                                CompositorElementId scrollable_area_element_id,
+                                WebInputEvent::Type injected_type) override;
+
  private:
   std::unique_ptr<LayerTreeHostEmbedder> layer_tree_;
   TransformationMatrix device_emulation_transform_;
diff --git a/third_party/blink/renderer/core/testing/fake_local_frame_host.cc b/third_party/blink/renderer/core/testing/fake_local_frame_host.cc
index 611df97..2bbd66f 100644
--- a/third_party/blink/renderer/core/testing/fake_local_frame_host.cc
+++ b/third_party/blink/renderer/core/testing/fake_local_frame_host.cc
@@ -77,6 +77,8 @@
     const KURL& initiator_url,
     mojom::NavigationBlockedReason reason) {}
 
+void FakeLocalFrameHost::DispatchLoad() {}
+
 void FakeLocalFrameHost::RenderFallbackContentInParentProcess() {}
 
 void FakeLocalFrameHost::BindFrameHostReceiver(
diff --git a/third_party/blink/renderer/core/testing/fake_local_frame_host.h b/third_party/blink/renderer/core/testing/fake_local_frame_host.h
index 3e789d9..d2fbed58 100644
--- a/third_party/blink/renderer/core/testing/fake_local_frame_host.h
+++ b/third_party/blink/renderer/core/testing/fake_local_frame_host.h
@@ -54,6 +54,7 @@
   void DidBlockNavigation(const KURL& blocked_url,
                           const KURL& initiator_url,
                           mojom::NavigationBlockedReason reason) override;
+  void DispatchLoad() override;
   void GoToEntryAtOffset(int32_t offset, bool has_user_gesture) override;
   void RenderFallbackContentInParentProcess() override;
   void HandleAccessibilityFindInPageResult(
diff --git a/third_party/blink/renderer/core/testing/internals.cc b/third_party/blink/renderer/core/testing/internals.cc
index 49f7c3c8..86da838 100644
--- a/third_party/blink/renderer/core/testing/internals.cc
+++ b/third_party/blink/renderer/core/testing/internals.cc
@@ -2823,30 +2823,6 @@
                                        buffer->ByteLengthAsSizeT());
 }
 
-DOMArrayBuffer* Internals::serializeWithInlineWasm(ScriptValue value) const {
-  v8::Isolate* isolate = value.GetIsolate();
-  ExceptionState exception_state(isolate, ExceptionState::kExecutionContext,
-                                 "Internals", "serializeWithInlineWasm");
-  v8::Local<v8::Value> v8_value = value.V8Value();
-  SerializedScriptValue::SerializeOptions options;
-  options.wasm_policy = SerializedScriptValue::SerializeOptions::kSerialize;
-  scoped_refptr<SerializedScriptValue> obj = SerializedScriptValue::Serialize(
-      isolate, v8_value, options, exception_state);
-  if (exception_state.HadException())
-    return nullptr;
-  return serializeObject(obj);
-}
-
-ScriptValue Internals::deserializeBufferContainingWasm(
-    ScriptState* state,
-    DOMArrayBuffer* buffer) const {
-  DummyExceptionStateForTesting exception_state;
-  SerializedScriptValue::DeserializeOptions options;
-  options.read_wasm_from_stream = true;
-  return ScriptValue::From(state, deserializeBuffer(buffer)->Deserialize(
-                                      state->GetIsolate(), options));
-}
-
 void Internals::forceReload(bool bypass_cache) {
   if (!GetFrame())
     return;
diff --git a/third_party/blink/renderer/core/testing/internals.h b/third_party/blink/renderer/core/testing/internals.h
index 8430aa2f..3fbc6561 100644
--- a/third_party/blink/renderer/core/testing/internals.h
+++ b/third_party/blink/renderer/core/testing/internals.h
@@ -430,10 +430,6 @@
   DOMArrayBuffer* serializeObject(scoped_refptr<SerializedScriptValue>) const;
   scoped_refptr<SerializedScriptValue> deserializeBuffer(DOMArrayBuffer*) const;
 
-  DOMArrayBuffer* serializeWithInlineWasm(ScriptValue) const;
-  ScriptValue deserializeBufferContainingWasm(ScriptState*,
-                                              DOMArrayBuffer*) const;
-
   String getCurrentCursorInfo();
 
   bool cursorUpdatePending() const;
diff --git a/third_party/blink/renderer/core/testing/internals.idl b/third_party/blink/renderer/core/testing/internals.idl
index 18e52658..73054cf8 100644
--- a/third_party/blink/renderer/core/testing/internals.idl
+++ b/third_party/blink/renderer/core/testing/internals.idl
@@ -268,10 +268,6 @@
     SerializedScriptValue deserializeBuffer(ArrayBuffer buffer);
     ArrayBuffer serializeObject(SerializedScriptValue obj);
 
-    [CallWith=ScriptState] any deserializeBufferContainingWasm(ArrayBuffer buffer);
-    ArrayBuffer serializeWithInlineWasm(any obj);
-
-
     void forceReload(boolean endToEnd);
 
     DOMString getImageSourceURL(Element element);
diff --git a/third_party/blink/renderer/core/typed_arrays/array_buffer/array_buffer.h b/third_party/blink/renderer/core/typed_arrays/array_buffer/array_buffer.h
index 72c45c1..650a1c6 100644
--- a/third_party/blink/renderer/core/typed_arrays/array_buffer/array_buffer.h
+++ b/third_party/blink/renderer/core/typed_arrays/array_buffer/array_buffer.h
@@ -126,7 +126,7 @@
   ArrayBufferContents contents(byte_length, 1, ArrayBufferContents::kNotShared,
                                ArrayBufferContents::kDontInitialize);
   if (UNLIKELY(!contents.Data()))
-    OOM_CRASH();
+    OOM_CRASH(byte_length);
   scoped_refptr<ArrayBuffer> buffer = base::AdoptRef(new ArrayBuffer(contents));
   memcpy(buffer->Data(), source, byte_length);
   return buffer;
@@ -157,7 +157,7 @@
   ArrayBufferContents contents(num_elements, element_byte_size,
                                ArrayBufferContents::kNotShared, policy);
   if (UNLIKELY(!contents.Data()))
-    OOM_CRASH();
+    OOM_CRASH(num_elements * element_byte_size);
   return base::AdoptRef(new ArrayBuffer(contents));
 }
 
diff --git a/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.cc b/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.cc
index bbd0fe2..7c230e0d 100644
--- a/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.cc
+++ b/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.cc
@@ -96,7 +96,7 @@
                                ArrayBufferContents::kDontInitialize);
   uint8_t* data = static_cast<uint8_t*>(contents.Data());
   if (UNLIKELY(!data))
-    OOM_CRASH();
+    OOM_CRASH(shared_buffer->size());
 
   for (const auto& span : *shared_buffer) {
     memcpy(data, span.data(), span.size());
@@ -116,7 +116,7 @@
                                ArrayBufferContents::kDontInitialize);
   uint8_t* ptr = static_cast<uint8_t*>(contents.Data());
   if (UNLIKELY(!ptr))
-    OOM_CRASH();
+    OOM_CRASH(size);
 
   for (const auto& span : data) {
     memcpy(ptr, span.data(), span.size());
diff --git a/third_party/blink/renderer/modules/beacon/navigator_beacon.cc b/third_party/blink/renderer/modules/beacon/navigator_beacon.cc
index 1d1d244..88fe37d 100644
--- a/third_party/blink/renderer/modules/beacon/navigator_beacon.cc
+++ b/third_party/blink/renderer/modules/beacon/navigator_beacon.cc
@@ -17,6 +17,7 @@
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
 #include "third_party/blink/renderer/platform/loader/cors/cors.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 
 namespace blink {
 
@@ -99,7 +100,8 @@
         PingLoader::SendBeacon(GetSupplementable()->GetFrame(), url, data_view);
   } else if (data.IsBlob()) {
     Blob* blob = data.GetAsBlob();
-    if (!cors::IsCorsSafelistedContentType(blob->type())) {
+    if (!RuntimeEnabledFeatures::OutOfBlinkCorsEnabled() &&
+        !cors::IsCorsSafelistedContentType(blob->type())) {
       UseCounter::Count(context,
                         WebFeature::kSendBeaconWithNonSimpleContentType);
       if (RuntimeEnabledFeatures::
diff --git a/third_party/blink/renderer/modules/indexeddb/idb_value_wrapping.cc b/third_party/blink/renderer/modules/indexeddb/idb_value_wrapping.cc
index 74b7c5a..12f91ca 100644
--- a/third_party/blink/renderer/modules/indexeddb/idb_value_wrapping.cc
+++ b/third_party/blink/renderer/modules/indexeddb/idb_value_wrapping.cc
@@ -87,12 +87,11 @@
   DCHECK(!done_cloning_) << __func__ << " called after DoneCloning()";
 #endif  // DCHECK_IS_ON()
 
-  bool read_wasm_from_stream = true;
   // It is safe to unconditionally enable WASM module decoding because the
   // relevant checks were already performed in SerializedScriptValue::Serialize,
   // called by the IDBValueWrapper constructor.
   *clone = DeserializeScriptValue(script_state, serialized_value_.get(),
-                                  &blob_info_, read_wasm_from_stream);
+                                  &blob_info_);
 }
 
 // static
diff --git a/third_party/blink/renderer/modules/launch/launch_params.cc b/third_party/blink/renderer/modules/launch/launch_params.cc
index 280f67a..6c0e963 100644
--- a/third_party/blink/renderer/modules/launch/launch_params.cc
+++ b/third_party/blink/renderer/modules/launch/launch_params.cc
@@ -4,9 +4,6 @@
 
 #include "third_party/blink/renderer/modules/launch/launch_params.h"
 
-#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
-#include "third_party/blink/renderer/core/fetch/fetch_request_data.h"
-#include "third_party/blink/renderer/core/fetch/request.h"
 #include "third_party/blink/renderer/modules/native_file_system/native_file_system_handle.h"
 #include "third_party/blink/renderer/platform/heap/visitor.h"
 
@@ -17,22 +14,8 @@
 
 LaunchParams::~LaunchParams() = default;
 
-Request* LaunchParams::request(ScriptState* script_state) {
-  if (!fetch_request_)
-    return nullptr;
-
-  if (!request_) {
-    request_ =
-        Request::Create(script_state, *fetch_request_.get(),
-                        FetchRequestData::ForServiceWorkerFetchEvent::kFalse);
-  }
-
-  return request_;
-}
-
 void LaunchParams::Trace(blink::Visitor* visitor) {
   visitor->Trace(files_);
-  visitor->Trace(request_);
   ScriptWrappable::Trace(visitor);
 }
 
diff --git a/third_party/blink/renderer/modules/launch/launch_params.h b/third_party/blink/renderer/modules/launch/launch_params.h
index 7e958c1..27b5ee6 100644
--- a/third_party/blink/renderer/modules/launch/launch_params.h
+++ b/third_party/blink/renderer/modules/launch/launch_params.h
@@ -5,17 +5,13 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_LAUNCH_LAUNCH_PARAMS_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_LAUNCH_LAUNCH_PARAMS_H_
 
-#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
 #include "third_party/blink/renderer/modules/native_file_system/native_file_system_handle.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/heap/heap_allocator.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 namespace blink {
 
-class Request;
-class ScriptState;
 class Visitor;
 
 class LaunchParams final : public ScriptWrappable {
@@ -27,14 +23,11 @@
 
   // LaunchParams IDL interface.
   const HeapVector<Member<NativeFileSystemHandle>>& files() { return files_; }
-  Request* request(ScriptState* script_state);
 
   void Trace(blink::Visitor*) override;
 
  private:
   HeapVector<Member<NativeFileSystemHandle>> files_;
-  Member<Request> request_;
-  mojom::blink::FetchAPIRequestPtr fetch_request_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/launch/launch_params.idl b/third_party/blink/renderer/modules/launch/launch_params.idl
index 71027b1..2d98f3e 100644
--- a/third_party/blink/renderer/modules/launch/launch_params.idl
+++ b/third_party/blink/renderer/modules/launch/launch_params.idl
@@ -7,7 +7,4 @@
 
 [RuntimeEnabled=FileHandling] interface LaunchParams {
   readonly attribute FrozenArray<FileSystemHandle> files;
-
-  [CallWith=ScriptState]
-  readonly attribute Request request;
 };
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_processor.cc b/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
index af4cd5ae..23ec722 100644
--- a/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
+++ b/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
@@ -980,6 +980,11 @@
   }
 
   for (const auto& video_device : video_devices) {
+    SendLogMessage(base::StringPrintf(
+        "OnStreamGenerated({request_id=%d}, {label=%s}, {device=[id: %s, "
+        "name: %s]}) => (Requesting video device formats)",
+        request_id, label.Utf8().c_str(), video_device.id.c_str(),
+        video_device.name.c_str()));
     String video_device_id(video_device.id.data());
     GetMediaDevicesDispatcher()->GetAllVideoInputDeviceFormats(
         video_device_id,
@@ -1002,6 +1007,11 @@
   if (!IsCurrentRequestInfo(web_request))
     return;
 
+  SendLogMessage(
+      base::StringPrintf("GotAllVideoInputFormatsForDevice({request_id=%d}, "
+                         "{label=%s}, {device=[id: %s]})",
+                         current_request_info_->request_id(),
+                         label.Utf8().c_str(), device_id.Utf8().c_str()));
   current_request_info_->AddNativeVideoFormats(device_id, formats);
   if (current_request_info_->CanStartTracks())
     StartTracks(label);
@@ -1333,7 +1343,9 @@
 
 void UserMediaProcessor::StartTracks(const String& label) {
   DCHECK(!current_request_info_->web_request().IsNull());
-  SendLogMessage("StartTracks({label=" + label.Utf8() + "})");
+  SendLogMessage(base::StringPrintf("StartTracks({request_id=%d}, {label=%s})",
+                                    current_request_info_->request_id(),
+                                    label.Utf8().c_str()));
   if (auto* media_stream_device_observer = GetMediaStreamDeviceObserver()) {
     media_stream_device_observer->AddStream(
         blink::WebString(label),
diff --git a/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.cc b/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.cc
index 63d08f1..cab1ff58 100644
--- a/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.cc
+++ b/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source.cc
@@ -284,10 +284,37 @@
   video_frame->metadata()->SetTimeTicks(
       media::VideoFrameMetadata::DECODE_END_TIME, current_time);
 
+  // RTP_TIMESTAMP, PROCESSING_TIME, and CAPTURE_BEGIN_TIME are all exposed
+  // through the JavaScript callback mechanism video.requestAnimationFrame().
   video_frame->metadata()->SetDouble(
       media::VideoFrameMetadata::RTP_TIMESTAMP,
       static_cast<double>(incoming_frame.timestamp()));
 
+  if (incoming_frame.processing_time()) {
+    video_frame->metadata()->SetTimeDelta(
+        media::VideoFrameMetadata::PROCESSING_TIME,
+        base::TimeDelta::FromMicroseconds(
+            incoming_frame.processing_time()->Elapsed().us()));
+  }
+
+  // Set capture time to arrival of last packet.
+  if (!incoming_frame.packet_infos().empty()) {
+    int64_t last_packet_arrival_ms =
+        std::max_element(
+            incoming_frame.packet_infos().cbegin(),
+            incoming_frame.packet_infos().cend(),
+            [](const webrtc::RtpPacketInfo& a, const webrtc::RtpPacketInfo& b) {
+              return a.receive_time_ms() < b.receive_time_ms();
+            })
+            ->receive_time_ms();
+    const base::TimeTicks capture_time =
+        base::TimeTicks() +
+        base::TimeDelta::FromMilliseconds(last_packet_arrival_ms) + time_diff_;
+
+    video_frame->metadata()->SetTimeTicks(
+        media::VideoFrameMetadata::CAPTURE_BEGIN_TIME, capture_time);
+  }
+
   PostCrossThreadTask(
       *io_task_runner_, FROM_HERE,
       CrossThreadBindOnce(&RemoteVideoSourceDelegate::DoRenderFrameOnIOThread,
diff --git a/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source_test.cc b/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source_test.cc
index 8b96314..02185a2 100644
--- a/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source_test.cc
+++ b/third_party/blink/renderer/modules/peerconnection/media_stream_remote_video_source_test.cc
@@ -24,12 +24,22 @@
 #include "third_party/blink/renderer/platform/testing/io_task_runner_testing_platform_support.h"
 #include "third_party/blink/renderer/platform/webrtc/track_observer.h"
 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
+#include "third_party/webrtc/api/rtp_packet_infos.h"
 #include "third_party/webrtc/api/video/color_space.h"
 #include "third_party/webrtc/api/video/i420_buffer.h"
 #include "ui/gfx/color_space.h"
 
 namespace blink {
 
+namespace {
+// On Linux the clock in WebRTC and Chromium are more or less the same.
+// On Windows they are not the same and the accuracy of the measured time
+// difference is in the range [-1, 1] ms. Since this is compensated for both
+// here and in MediaStreamRemoteVideoSource::RemoteVideoSourceDelegate we need
+// to use the worst case difference between these two measurements.
+float kChromiumWebRtcMaxTimeDiffMs = 2.0f;
+}  // namespace
+
 ACTION_P(RunClosure, closure) {
   closure.Run();
 }
@@ -55,7 +65,9 @@
             blink::MockWebRtcVideoTrack::Create("test", webrtc_video_source_)),
         remote_source_(nullptr),
         number_of_successful_track_starts_(0),
-        number_of_failed_track_starts_(0) {}
+        number_of_failed_track_starts_(0),
+        time_diff_(base::TimeTicks::Now() - base::TimeTicks() -
+                   base::TimeDelta::FromMicroseconds(rtc::TimeMicros())) {}
 
   void SetUp() override {
     scoped_refptr<base::SingleThreadTaskRunner> main_thread =
@@ -139,6 +151,8 @@
     return web_source_;
   }
 
+  const base::TimeDelta& time_diff() const { return time_diff_; }
+
  private:
   void OnTrackStarted(blink::WebPlatformMediaStreamSource* source,
                       blink::mojom::MediaStreamRequestResult result,
@@ -159,6 +173,8 @@
   blink::WebMediaStreamSource web_source_;
   int number_of_successful_track_starts_;
   int number_of_failed_track_starts_;
+  // WebRTC Chromium timestamp diff
+  const base::TimeDelta time_diff_;
 };
 
 TEST_F(MediaStreamRemoteVideoSourceTest, StartTrack) {
@@ -264,6 +280,137 @@
   track->RemoveSink(&sink);
 }
 
+TEST_F(MediaStreamRemoteVideoSourceTest,
+       PopulateRequestAnimationFrameMetadata) {
+  std::unique_ptr<blink::MediaStreamVideoTrack> track(CreateTrack());
+  blink::MockMediaStreamVideoSink sink;
+  track->AddSink(&sink, sink.GetDeliverFrameCB(), false);
+
+  base::RunLoop run_loop;
+  EXPECT_CALL(sink, OnVideoFrame())
+      .WillOnce(RunClosure(run_loop.QuitClosure()));
+  rtc::scoped_refptr<webrtc::I420Buffer> buffer(
+      new rtc::RefCountedObject<webrtc::I420Buffer>(320, 240));
+
+  uint32_t kSsrc = 0;
+  const std::vector<uint32_t> kCsrcs;
+  uint32_t kRtpTimestamp = 123456;
+  float kProcessingTime = 0.014;
+
+  const webrtc::Timestamp kProcessingFinish =
+      webrtc::Timestamp::ms(rtc::TimeMillis());
+  const webrtc::Timestamp kProcessingStart =
+      kProcessingFinish - webrtc::TimeDelta::ms(1.0e3 * kProcessingTime);
+
+  webrtc::RtpPacketInfos::vector_type packet_infos;
+  for (int i = 0; i < 4; ++i) {
+    packet_infos.emplace_back(kSsrc, kCsrcs, kRtpTimestamp, absl::nullopt,
+                              absl::nullopt, kProcessingStart.ms() - 100 + i);
+  }
+  // Capture time should be the same as the last arrival time.
+  base::TimeTicks kExpectedCaptureTime =
+      base::TimeTicks() +
+      base::TimeDelta::FromMilliseconds(kProcessingStart.ms() - 100 + 3) +
+      time_diff();
+
+  webrtc::VideoFrame input_frame =
+      webrtc::VideoFrame::Builder()
+          .set_video_frame_buffer(buffer)
+          .set_timestamp_rtp(kRtpTimestamp)
+          .set_packet_infos(webrtc::RtpPacketInfos(packet_infos))
+          .build();
+
+  input_frame.set_processing_time({kProcessingStart, kProcessingFinish});
+  source()->SinkInterfaceForTesting()->OnFrame(input_frame);
+  run_loop.Run();
+
+  EXPECT_EQ(1, sink.number_of_frames());
+  scoped_refptr<media::VideoFrame> output_frame = sink.last_frame();
+  EXPECT_TRUE(output_frame);
+
+  base::TimeDelta elapsed;
+  EXPECT_TRUE(output_frame->metadata()->GetTimeDelta(
+      media::VideoFrameMetadata::PROCESSING_TIME, &elapsed));
+  EXPECT_FLOAT_EQ(elapsed.InSecondsF(), kProcessingTime);
+
+  base::TimeTicks capture_time;
+  EXPECT_TRUE(output_frame->metadata()->GetTimeTicks(
+      media::VideoFrameMetadata::CAPTURE_BEGIN_TIME, &capture_time));
+  EXPECT_NEAR((capture_time - kExpectedCaptureTime).InMillisecondsF(), 0.0f,
+              kChromiumWebRtcMaxTimeDiffMs);
+
+  double rtp_timestamp;
+  EXPECT_TRUE(output_frame->metadata()->GetDouble(
+      media::VideoFrameMetadata::RTP_TIMESTAMP, &rtp_timestamp));
+  EXPECT_EQ(static_cast<uint32_t>(rtp_timestamp), kRtpTimestamp);
+
+  track->RemoveSink(&sink);
+}
+
+TEST_F(MediaStreamRemoteVideoSourceTest, ReferenceTimeEqualsTimestampUs) {
+  std::unique_ptr<blink::MediaStreamVideoTrack> track(CreateTrack());
+  blink::MockMediaStreamVideoSink sink;
+  track->AddSink(&sink, sink.GetDeliverFrameCB(), false);
+
+  base::RunLoop run_loop;
+  EXPECT_CALL(sink, OnVideoFrame())
+      .WillOnce(RunClosure(run_loop.QuitClosure()));
+  rtc::scoped_refptr<webrtc::I420Buffer> buffer(
+      new rtc::RefCountedObject<webrtc::I420Buffer>(320, 240));
+
+  int64_t kTimestampUs = rtc::TimeMicros();
+  webrtc::VideoFrame input_frame = webrtc::VideoFrame::Builder()
+                                       .set_video_frame_buffer(buffer)
+                                       .set_timestamp_us(kTimestampUs)
+                                       .build();
+
+  source()->SinkInterfaceForTesting()->OnFrame(input_frame);
+  run_loop.Run();
+
+  EXPECT_EQ(1, sink.number_of_frames());
+  scoped_refptr<media::VideoFrame> output_frame = sink.last_frame();
+  EXPECT_TRUE(output_frame);
+
+  base::TimeTicks reference_time;
+  EXPECT_TRUE(output_frame->metadata()->GetTimeTicks(
+      media::VideoFrameMetadata::REFERENCE_TIME, &reference_time));
+  EXPECT_NEAR((reference_time -
+               (base::TimeTicks() +
+                base::TimeDelta::FromMicroseconds(kTimestampUs) + time_diff()))
+                  .InMillisecondsF(),
+              0.0f, kChromiumWebRtcMaxTimeDiffMs);
+  track->RemoveSink(&sink);
+}
+
+// This is a special case that is used to signal "render immediately".
+TEST_F(MediaStreamRemoteVideoSourceTest, NoTimestampUsMeansNoReferenceTime) {
+  std::unique_ptr<blink::MediaStreamVideoTrack> track(CreateTrack());
+  blink::MockMediaStreamVideoSink sink;
+  track->AddSink(&sink, sink.GetDeliverFrameCB(), false);
+
+  base::RunLoop run_loop;
+  EXPECT_CALL(sink, OnVideoFrame())
+      .WillOnce(RunClosure(run_loop.QuitClosure()));
+  rtc::scoped_refptr<webrtc::I420Buffer> buffer(
+      new rtc::RefCountedObject<webrtc::I420Buffer>(320, 240));
+
+  webrtc::VideoFrame input_frame =
+      webrtc::VideoFrame::Builder().set_video_frame_buffer(buffer).build();
+
+  source()->SinkInterfaceForTesting()->OnFrame(input_frame);
+  run_loop.Run();
+
+  EXPECT_EQ(1, sink.number_of_frames());
+  scoped_refptr<media::VideoFrame> output_frame = sink.last_frame();
+  EXPECT_TRUE(output_frame);
+
+  base::TimeTicks reference_time;
+  EXPECT_FALSE(output_frame->metadata()->GetTimeTicks(
+      media::VideoFrameMetadata::REFERENCE_TIME, &reference_time));
+
+  track->RemoveSink(&sink);
+}
+
 class TestEncodedVideoFrame : public webrtc::RecordableEncodedFrame {
  public:
   rtc::scoped_refptr<const webrtc::EncodedImageBufferInterface> encoded_buffer()
diff --git a/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc b/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc
index a4aa7ddf..0659068 100644
--- a/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc
+++ b/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.cc
@@ -119,11 +119,11 @@
   return error_message;
 }
 
-bool IsNavigationRequest(network::mojom::RequestContextFrameType frame_type) {
-  return frame_type != network::mojom::RequestContextFrameType::kNone;
+bool IsNavigationRequest(mojom::RequestContextFrameType frame_type) {
+  return frame_type != mojom::RequestContextFrameType::kNone;
 }
 
-bool IsClientRequest(network::mojom::RequestContextFrameType frame_type,
+bool IsClientRequest(mojom::RequestContextFrameType frame_type,
                      mojom::RequestContextType request_context) {
   return IsNavigationRequest(frame_type) ||
          request_context == mojom::RequestContextType::SHARED_WORKER ||
diff --git a/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.h b/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.h
index f992d55..ad0822c 100644
--- a/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.h
+++ b/third_party/blink/renderer/modules/service_worker/fetch_respond_with_observer.h
@@ -50,7 +50,7 @@
   const KURL request_url_;
   const network::mojom::RequestMode request_mode_;
   const network::mojom::RedirectMode redirect_mode_;
-  const network::mojom::RequestContextFrameType frame_type_;
+  const mojom::RequestContextFrameType frame_type_;
   const mojom::RequestContextType request_context_;
   const network::mojom::blink::CrossOriginEmbedderPolicy requestor_coep_;
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_client.cc b/third_party/blink/renderer/modules/service_worker/service_worker_client.cc
index aba263f6..45cd189 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_client.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_client.cc
@@ -53,13 +53,13 @@
   UseCounter::Count(ExecutionContext::From(script_state),
                     WebFeature::kServiceWorkerClientFrameType);
   switch (frame_type_) {
-    case network::mojom::RequestContextFrameType::kAuxiliary:
+    case mojom::RequestContextFrameType::kAuxiliary:
       return "auxiliary";
-    case network::mojom::RequestContextFrameType::kNested:
+    case mojom::RequestContextFrameType::kNested:
       return "nested";
-    case network::mojom::RequestContextFrameType::kNone:
+    case mojom::RequestContextFrameType::kNone:
       return "none";
-    case network::mojom::RequestContextFrameType::kTopLevel:
+    case mojom::RequestContextFrameType::kTopLevel:
       return "top-level";
   }
 
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_client.h b/third_party/blink/renderer/modules/service_worker/service_worker_client.h
index de96a09..406ed05 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_client.h
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_client.h
@@ -47,7 +47,7 @@
   const String uuid_;
   const String url_;
   const mojom::ServiceWorkerClientType type_;
-  const network::mojom::RequestContextFrameType frame_type_;
+  const mojom::RequestContextFrameType frame_type_;
   const mojom::ServiceWorkerClientLifecycleState lifecycle_state_;
 };
 
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index 0cb01cd6..47ec1566 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -434,6 +434,7 @@
     "bindings/trace_wrapper_v8_reference.h",
     "bindings/trace_wrapper_v8_string.cc",
     "bindings/trace_wrapper_v8_string.h",
+    "bindings/union_base.h",
     "bindings/v0_custom_element_binding.cc",
     "bindings/v0_custom_element_binding.h",
     "bindings/v8_binding.cc",
diff --git a/third_party/blink/renderer/platform/bindings/to_v8.h b/third_party/blink/renderer/platform/bindings/to_v8.h
index 246140e5..86bde05 100644
--- a/third_party/blink/renderer/platform/bindings/to_v8.h
+++ b/third_party/blink/renderer/platform/bindings/to_v8.h
@@ -19,6 +19,7 @@
 #include "third_party/blink/renderer/platform/bindings/dom_data_store.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/bindings/union_base.h"
 #include "third_party/blink/renderer/platform/bindings/v8_binding.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
@@ -85,6 +86,17 @@
                   : v8::Null(isolate).As<v8::Value>();
 }
 
+// Union type
+
+inline v8::Local<v8::Value> ToV8(const bindings::UnionBase& value,
+                                 v8::Local<v8::Object> creation_context,
+                                 v8::Isolate* isolate) {
+  v8::Local<v8::Value> v8_value =
+      value.CreateV8Object(isolate, creation_context);
+  DCHECK(!v8_value.IsEmpty());
+  return v8_value;
+}
+
 // Primitives
 
 inline v8::Local<v8::Value> ToV8(const String& value,
diff --git a/third_party/blink/renderer/platform/bindings/union_base.h b/third_party/blink/renderer/platform/bindings/union_base.h
new file mode 100644
index 0000000..35ce7f815
--- /dev/null
+++ b/third_party/blink/renderer/platform/bindings/union_base.h
@@ -0,0 +1,45 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_UNION_BASE_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_UNION_BASE_H_
+
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
+#include "v8/include/v8.h"
+
+namespace blink {
+
+class Visitor;
+
+namespace bindings {
+
+// This class is the base class for all IDL dictionary implementations.  This
+// is designed to collaborate with NativeValueTraits and ToV8 with supporting
+// type dispatching (SFINAE, etc.).
+class PLATFORM_EXPORT UnionBase {
+  DISALLOW_NEW();
+
+ public:
+  virtual ~UnionBase() = default;
+
+  virtual v8::Local<v8::Value> CreateV8Object(
+      v8::Isolate* isolate,
+      v8::Local<v8::Object> creation_context) const = 0;
+
+  void Trace(Visitor*) {}
+
+ protected:
+  UnionBase() = default;
+  UnionBase(const UnionBase&) = default;
+  UnionBase(UnionBase&&) = default;
+  UnionBase& operator=(const UnionBase&) = default;
+  UnionBase& operator=(UnionBase&&) = default;
+};
+
+}  // namespace bindings
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_UNION_BASE_H_
diff --git a/third_party/blink/renderer/platform/heap/page_memory.cc b/third_party/blink/renderer/platform/heap/page_memory.cc
index c94a586..1fe122b 100644
--- a/third_party/blink/renderer/platform/heap/page_memory.cc
+++ b/third_party/blink/renderer/platform/heap/page_memory.cc
@@ -56,7 +56,8 @@
 // we should probably have a way to distinguish physical memory OOM from
 // virtual address space OOM.
 static NOINLINE void BlinkGCOutOfMemory() {
-  OOM_CRASH();
+  // TODO(lizeb): Add the real allocation size here as well.
+  OOM_CRASH(0);
 }
 
 PageMemoryRegion* PageMemoryRegion::Allocate(size_t size,
diff --git a/third_party/blink/renderer/platform/scheduler/common/thread_cpu_throttler.cc b/third_party/blink/renderer/platform/scheduler/common/thread_cpu_throttler.cc
index 856a09c..c184e22 100644
--- a/third_party/blink/renderer/platform/scheduler/common/thread_cpu_throttler.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/thread_cpu_throttler.cc
@@ -106,9 +106,6 @@
   struct sigaction sa;
   sa.sa_handler = &HandleSignal;
   sigemptyset(&sa.sa_mask);
-  // Block SIGPROF while our handler is running so that the V8 CPU profiler
-  // doesn't try to sample the stack while our signal handler is active.
-  sigaddset(&sa.sa_mask, SIGPROF);
   sa.sa_flags = SA_RESTART;
   signal_handler_installed_ =
       (sigaction(SIGUSR2, &sa, &old_signal_handler_) == 0);
diff --git a/third_party/blink/renderer/platform/text/icu_error.cc b/third_party/blink/renderer/platform/text/icu_error.cc
index 1aad852..ec72aac 100644
--- a/third_party/blink/renderer/platform/text/icu_error.cc
+++ b/third_party/blink/renderer/platform/text/icu_error.cc
@@ -11,7 +11,7 @@
 // Distinguish memory allocation failures from other errors.
 // https://groups.google.com/a/chromium.org/d/msg/platform-architecture-dev/MP0k9WGnCjA/zIBiJtilBwAJ
 static NOINLINE void ICUOutOfMemory() {
-  OOM_CRASH();
+  OOM_CRASH(0);
 }
 
 void ICUError::HandleFailure() {
diff --git a/third_party/blink/renderer/platform/wtf/allocator/partitions.cc b/third_party/blink/renderer/platform/wtf/allocator/partitions.cc
index fc22b7d94..abb17ca 100644
--- a/third_party/blink/renderer/platform/wtf/allocator/partitions.cc
+++ b/third_party/blink/renderer/platform/wtf/allocator/partitions.cc
@@ -149,59 +149,60 @@
   return dumper.TotalActiveBytes();
 }
 
-static NOINLINE void PartitionsOutOfMemoryUsing2G() {
+static NOINLINE void PartitionsOutOfMemoryUsing2G(size_t size) {
   size_t signature = 2UL * 1024 * 1024 * 1024;
   base::debug::Alias(&signature);
-  OOM_CRASH();
+  OOM_CRASH(size);
 }
 
-static NOINLINE void PartitionsOutOfMemoryUsing1G() {
+static NOINLINE void PartitionsOutOfMemoryUsing1G(size_t size) {
   size_t signature = 1UL * 1024 * 1024 * 1024;
   base::debug::Alias(&signature);
-  OOM_CRASH();
+  OOM_CRASH(size);
 }
 
-static NOINLINE void PartitionsOutOfMemoryUsing512M() {
+static NOINLINE void PartitionsOutOfMemoryUsing512M(size_t size) {
   size_t signature = 512 * 1024 * 1024;
   base::debug::Alias(&signature);
-  OOM_CRASH();
+  OOM_CRASH(size);
 }
 
-static NOINLINE void PartitionsOutOfMemoryUsing256M() {
+static NOINLINE void PartitionsOutOfMemoryUsing256M(size_t size) {
   size_t signature = 256 * 1024 * 1024;
   base::debug::Alias(&signature);
-  OOM_CRASH();
+  OOM_CRASH(size);
 }
 
-static NOINLINE void PartitionsOutOfMemoryUsing128M() {
+static NOINLINE void PartitionsOutOfMemoryUsing128M(size_t size) {
   size_t signature = 128 * 1024 * 1024;
   base::debug::Alias(&signature);
-  OOM_CRASH();
+  OOM_CRASH(size);
 }
 
-static NOINLINE void PartitionsOutOfMemoryUsing64M() {
+static NOINLINE void PartitionsOutOfMemoryUsing64M(size_t size) {
   size_t signature = 64 * 1024 * 1024;
   base::debug::Alias(&signature);
-  OOM_CRASH();
+  OOM_CRASH(size);
 }
 
-static NOINLINE void PartitionsOutOfMemoryUsing32M() {
+static NOINLINE void PartitionsOutOfMemoryUsing32M(size_t size) {
   size_t signature = 32 * 1024 * 1024;
   base::debug::Alias(&signature);
-  OOM_CRASH();
+  OOM_CRASH(size);
 }
 
-static NOINLINE void PartitionsOutOfMemoryUsing16M() {
+static NOINLINE void PartitionsOutOfMemoryUsing16M(size_t size) {
   size_t signature = 16 * 1024 * 1024;
   base::debug::Alias(&signature);
-  OOM_CRASH();
+  OOM_CRASH(size);
 }
 
-static NOINLINE void PartitionsOutOfMemoryUsingLessThan16M() {
+static NOINLINE void PartitionsOutOfMemoryUsingLessThan16M(size_t size) {
   size_t signature = 16 * 1024 * 1024 - 1;
   base::debug::Alias(&signature);
-  DLOG(FATAL) << "ParitionAlloc: out of memory with < 16M usage (error:"
+  DLOG(FATAL) << "PartitionAlloc: out of memory with < 16M usage (error:"
               << base::GetAllocPageErrorCode() << ")";
+  OOM_CRASH(size);
 }
 
 // static
@@ -241,28 +242,28 @@
 }
 
 // static
-void Partitions::HandleOutOfMemory() {
+void Partitions::HandleOutOfMemory(size_t size) {
   volatile size_t total_usage = TotalSizeOfCommittedPages();
   uint32_t alloc_page_error_code = base::GetAllocPageErrorCode();
   base::debug::Alias(&alloc_page_error_code);
 
   if (total_usage >= 2UL * 1024 * 1024 * 1024)
-    PartitionsOutOfMemoryUsing2G();
+    PartitionsOutOfMemoryUsing2G(size);
   if (total_usage >= 1UL * 1024 * 1024 * 1024)
-    PartitionsOutOfMemoryUsing1G();
+    PartitionsOutOfMemoryUsing1G(size);
   if (total_usage >= 512 * 1024 * 1024)
-    PartitionsOutOfMemoryUsing512M();
+    PartitionsOutOfMemoryUsing512M(size);
   if (total_usage >= 256 * 1024 * 1024)
-    PartitionsOutOfMemoryUsing256M();
+    PartitionsOutOfMemoryUsing256M(size);
   if (total_usage >= 128 * 1024 * 1024)
-    PartitionsOutOfMemoryUsing128M();
+    PartitionsOutOfMemoryUsing128M(size);
   if (total_usage >= 64 * 1024 * 1024)
-    PartitionsOutOfMemoryUsing64M();
+    PartitionsOutOfMemoryUsing64M(size);
   if (total_usage >= 32 * 1024 * 1024)
-    PartitionsOutOfMemoryUsing32M();
+    PartitionsOutOfMemoryUsing32M(size);
   if (total_usage >= 16 * 1024 * 1024)
-    PartitionsOutOfMemoryUsing16M();
-  PartitionsOutOfMemoryUsingLessThan16M();
+    PartitionsOutOfMemoryUsing16M(size);
+  PartitionsOutOfMemoryUsingLessThan16M(size);
 }
 
 }  // namespace WTF
diff --git a/third_party/blink/renderer/platform/wtf/allocator/partitions.h b/third_party/blink/renderer/platform/wtf/allocator/partitions.h
index 4660baf..4dcc356 100644
--- a/third_party/blink/renderer/platform/wtf/allocator/partitions.h
+++ b/third_party/blink/renderer/platform/wtf/allocator/partitions.h
@@ -91,7 +91,7 @@
   static void* FastZeroedMalloc(size_t n, const char* type_name);
   static void FastFree(void* p);
 
-  static void HandleOutOfMemory();
+  static void HandleOutOfMemory(size_t size);
 
  private:
   ALWAYS_INLINE static base::PartitionRootGeneric* FastMallocPartition() {
diff --git a/third_party/blink/renderer/platform/wtf/cross_thread_copier.h b/third_party/blink/renderer/platform/wtf/cross_thread_copier.h
index 51b1575..1aeaf9b 100644
--- a/third_party/blink/renderer/platform/wtf/cross_thread_copier.h
+++ b/third_party/blink/renderer/platform/wtf/cross_thread_copier.h
@@ -69,6 +69,12 @@
 namespace mojo {
 template <typename Interface>
 class PendingReceiver;
+template <typename Interface>
+class PendingRemote;
+template <typename Interface>
+class PendingAssociatedRemote;
+template <typename Interface>
+class PendingAssociatedReceiver;
 }
 
 namespace WTF {
@@ -80,6 +86,15 @@
   static Type Copy(const T& parameter) { return parameter; }
 };
 
+template <typename T>
+struct CrossThreadCopierByValuePassThrough {
+  STATIC_ONLY(CrossThreadCopierByValuePassThrough);
+  typedef T Type;
+  static Type Copy(T receiver) {
+    return receiver;  // This is in fact a move.
+  }
+};
+
 template <typename T, bool isArithmeticOrEnum>
 struct CrossThreadCopierBase;
 
@@ -273,12 +288,31 @@
 };
 
 template <typename Interface>
-struct CrossThreadCopier<mojo::PendingReceiver<Interface>> {
+struct CrossThreadCopier<mojo::PendingReceiver<Interface>>
+    : public CrossThreadCopierByValuePassThrough<
+          mojo::PendingReceiver<Interface>> {
   STATIC_ONLY(CrossThreadCopier);
-  using Type = mojo::PendingReceiver<Interface>;
-  static Type Copy(Type receiver) {
-    return receiver;  // This is in fact a move.
-  }
+};
+
+template <typename Interface>
+struct CrossThreadCopier<mojo::PendingRemote<Interface>>
+    : public CrossThreadCopierByValuePassThrough<
+          mojo::PendingRemote<Interface>> {
+  STATIC_ONLY(CrossThreadCopier);
+};
+
+template <typename Interface>
+struct CrossThreadCopier<mojo::PendingAssociatedRemote<Interface>>
+    : public CrossThreadCopierByValuePassThrough<
+          mojo::PendingAssociatedRemote<Interface>> {
+  STATIC_ONLY(CrossThreadCopier);
+};
+
+template <typename Interface>
+struct CrossThreadCopier<mojo::PendingAssociatedReceiver<Interface>>
+    : public CrossThreadCopierByValuePassThrough<
+          mojo::PendingAssociatedReceiver<Interface>> {
+  STATIC_ONLY(CrossThreadCopier);
 };
 
 template <>
diff --git a/third_party/blink/web_tests/FlagExpectations/disable-features=OutOfBlinkCors b/third_party/blink/web_tests/FlagExpectations/disable-features=OutOfBlinkCors
index 98d1b61a..6b0f006e 100644
--- a/third_party/blink/web_tests/FlagExpectations/disable-features=OutOfBlinkCors
+++ b/third_party/blink/web_tests/FlagExpectations/disable-features=OutOfBlinkCors
@@ -49,3 +49,13 @@
 crbug.com/870173 virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/fetch-request-xhr.https.html [ Failure ]
 crbug.com/870173 virtual/omt-service-worker-startup/external/wpt/service-workers/service-worker/fetch-request-xhr.https.html [ Failure ]
 crbug.com/870173 virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/fetch-request-xhr.https.html [ Failure ]
+
+# preflight support for fetch keepalive and sendBeacon is only for OOR-CORS.
+crbug.com/835821 external/wpt/beacon/beacon-basic-blob.html [ Failure ]
+crbug.com/835821 external/wpt/beacon/beacon-basic-blobMax.html [ Failure ]
+crbug.com/835821 external/wpt/beacon/beacon-cors.sub.window.html [ Failure ]
+crbug.com/835821 external/wpt/beacon/beacon-navigate.html [ Failure ]
+crbug.com/835821 external/wpt/beacon/beacon-redirect.window.html [ Failure ]
+crbug.com/835821 external/wpt/fetch/api/basic/keepalive.html [ Failure ]
+crbug.com/835821 http/tests/sendbeacon/beacon-blob-with-non-simple-type.html [ Failure ]
+crbug.com/835821 virtual/stable/http/tests/sendbeacon/beacon-blob-with-non-simple-type.html [ Failure ]
diff --git a/third_party/blink/web_tests/FlagExpectations/layout-ng-fragment-item b/third_party/blink/web_tests/FlagExpectations/layout-ng-fragment-item
index ba1e6615..1f51eb7 100644
--- a/third_party/blink/web_tests/FlagExpectations/layout-ng-fragment-item
+++ b/third_party/blink/web_tests/FlagExpectations/layout-ng-fragment-item
@@ -11,36 +11,17 @@
 crbug.com/982194 css3/selectors3/xml/css3-modsel-183.xml [ Failure Pass ]
 crbug.com/982194 css3/selectors3/xml/css3-modsel-3.xml [ Failure Pass ]
 crbug.com/663585 editing/pasteboard/data-transfer-items-image-png.html [ Pass ]
-crbug.com/982194 editing/pasteboard/dragstart-contains-default-content.html [ Failure Pass ]
-crbug.com/982194 editing/selection/anchor-focus2.html [ Failure Pass ]
-crbug.com/982194 editing/selection/anchor-focus3.html [ Failure Pass ]
 crbug.com/982194 editing/selection/android-longtap-not-select-empty.html [ Failure ]
-crbug.com/982194 editing/selection/continuations-with-move-caret-to-boundary.html [ Failure Pass ]
-crbug.com/982194 editing/selection/drag-select-rapidly.html [ Failure Pass ]
-crbug.com/982194 editing/selection/drag-selection-nodes.html [ Failure Pass ]
-crbug.com/982194 editing/selection/first-letter-mouse-select-full-text.html [ Failure Pass ]
-crbug.com/982194 editing/selection/last-empty-inline.html [ Failure Pass ]
 crbug.com/245154 editing/selection/modify_move/move-by-character-brute-force.html [ Pass ]
 crbug.com/24182 editing/selection/modify_move/move-by-word-visually-crash-test-5.html [ Pass ]
-crbug.com/982194 editing/selection/mouse/drag_over_text_transform.html [ Failure Pass ]
-crbug.com/982194 editing/selection/mouse/drag_selects_bidi_image.html [ Failure Pass ]
-crbug.com/982194 editing/selection/mouse/drag_selects_rtl_inline_block.html [ Failure Pass ]
-crbug.com/982194 editing/selection/mouse/extend_by_word_with_base_is_end.html [ Failure Pass ]
-crbug.com/982194 editing/selection/mouse/mouse-selection-horizontal.html [ Failure Pass ]
-crbug.com/982194 editing/selection/mouse/mouse-selection-vertical-lr.html [ Failure Pass ]
-crbug.com/982194 editing/selection/mouse/mouse-selection-vertical-rl.html [ Failure Pass ]
 crbug.com/982194 editing/selection/mouse/select_across_readonly_input.html [ Failure ]
-crbug.com/982194 editing/selection/offset-from-point-complex-scripts.html [ Failure Pass ]
 crbug.com/982194 editing/selection/offset-from-point.html [ Failure ]
 crbug.com/591099 editing/selection/paint-hyphen.html [ Failure ]
 crbug.com/741259 editing/selection/select-bidi-run.html [ Failure ]
-crbug.com/982194 editing/selection/select-line-break-with-opposite-directionality.html [ Failure ]
-crbug.com/982194 editing/selection/select-out-of-floated-contenteditable.html [ Failure ]
-crbug.com/982194 editing/selection/select-out-of-floated-input.html [ Failure ]
-crbug.com/982194 editing/selection/shift-click.html [ Crash Failure ]
-crbug.com/982194 editing/selection/user-select/user-select-all.html [ Failure Pass ]
-crbug.com/982194 editing/selection/vertical-lr-replaced-selection.html [ Failure Pass ]
-crbug.com/982194 editing/shadow/compare-positions-in-nested-shadow.html [ Failure Pass ]
+crbug.com/982194 editing/selection/select-line-break-with-opposite-directionality.html [ Failure Pass ]
+crbug.com/982194 editing/selection/select-out-of-floated-contenteditable.html [ Failure Pass ]
+crbug.com/982194 editing/selection/select-out-of-floated-input.html [ Failure Pass ]
+crbug.com/982194 editing/selection/shift-click.html [ Failure ]
 crbug.com/982194 external/wpt/2dcontext/building-paths/canvas_complexshapes_arcto_001.htm [ Pass ]
 crbug.com/982194 external/wpt/2dcontext/building-paths/canvas_complexshapes_beziercurveto_001.htm [ Pass ]
 crbug.com/626703 external/wpt/acid/acid3/test.html [ Pass ]
@@ -80,7 +61,7 @@
 crbug.com/982194 external/wpt/css/css-writig-modes/sizing-orthog-htb-in-vlr-011.xht [ Failure ]
 crbug.com/982194 external/wpt/css/css-writing-modes/inline-table-alignment-003.xht [ Failure ]
 crbug.com/982194 external/wpt/css/css-writing-modes/inline-table-alignment-005.xht [ Failure ]
-crbug.com/982194 external/wpt/css/cssom-view/elementsFromPoint-simple.html [ Failure ]
+crbug.com/982194 external/wpt/css/cssom-view/elementsFromPoint-simple.html [ Failure Pass ]
 crbug.com/982194 external/wpt/css/cssom-view/offsetTopLeft-trailing-space-inline.html [ Pass ]
 crbug.com/982194 external/wpt/css/csui/text-overflow-002.html [ Failure ]
 crbug.com/982194 external/wpt/css/filter-effects/filtered-inline-applies-to-float.html [ Failure ]
@@ -148,7 +129,7 @@
 crbug.com/982194 external/wpt/pointerevents/extension/pointerevent_touch-action-pan-up-css_touch.html [ Timeout ]
 crbug.com/626703 external/wpt/screen-orientation/onchange-event.html [ Timeout ]
 crbug.com/626703 external/wpt/screen-orientation/orientation-reading.html [ Timeout ]
-crbug.com/982194 external/wpt/uievents/mouse/mouseevent_move_button-manual.html [ Timeout ]
+crbug.com/982194 external/wpt/uievents/mouse/mouseevent_move_button-manual.html [ Pass Timeout ]
 crbug.com/645988 external/wpt/uievents/order-of-events/focus-eventfocus-manual.html [ Crash Failure ]
 crbug.com/645988 external/wpt/uievents/order-of-events/focus-events/focus-manual.html [ Failure ]
 crbug.com/1002514 external/wpt/web-share/share-sharePromise-internal-slot.https.html [ Pass ]
@@ -160,58 +141,48 @@
 crbug.com/982194 external/wpt/webxr/events_referenceSpace_reset_inline.https.html [ Timeout ]
 crbug.com/982194 fast/backgrounds/background-clip-text-multiline-linebreak.html [ Failure ]
 crbug.com/982194 fast/backgrounds/background-clip-text-multiline.html [ Crash ]
-crbug.com/982194 fast/block/float/float-in-float-hit-testing.html [ Failure ]
+crbug.com/982194 fast/block/float/float-in-float-hit-testing.html [ Failure Pass ]
 crbug.com/982194 fast/block/positioning/absolute-in-inline-dynamic.html [ Failure ]
-crbug.com/982194 fast/block/positioning/hittest-on-relative-positioned-children.html [ Failure Pass ]
 crbug.com/982194 fast/block/positioning/rel-positioned-inline-changes-width.html [ Failure ]
 crbug.com/982194 fast/css-generated-content/table-parts-before-and-after.html [ Failure ]
-crbug.com/982194 fast/css/area-computedStyle.html [ Timeout ]
+crbug.com/982194 fast/css/area-computedStyle.html [ Pass Timeout ]
 crbug.com/982194 fast/css/first-line-hover-001.html [ Failure ]
 crbug.com/982194 fast/css/getComputedStyle/computed-style-percentage-top-with-position-inline.html [ Failure ]
 crbug.com/835484 fast/css/outline-narrowLine.html [ Failure ]
 crbug.com/982194 fast/css/pseudo-element-hit-test.html [ Crash ]
-crbug.com/982194 fast/dnd/link-dragging-draggable-div-with-dragged-link.html [ Timeout ]
-crbug.com/982194 fast/dnd/link-dragging-draggable-div-with-link.html [ Timeout ]
-crbug.com/982194 fast/dnd/link-dragging-draggable-link.html [ Timeout ]
-crbug.com/982194 fast/dnd/link-dragging-non-draggable-link.html [ Timeout ]
-crbug.com/982194 fast/dom/Document/CaretRangeFromPoint/basic.html [ Failure Pass ]
-crbug.com/982194 fast/dom/Document/CaretRangeFromPoint/caretRangeFromPoint-in-strict-mode-wtih-checkbox.html [ Failure Pass ]
+crbug.com/982194 fast/dnd/link-dragging-draggable-div-with-dragged-link.html [ Pass Timeout ]
+crbug.com/982194 fast/dnd/link-dragging-draggable-div-with-link.html [ Pass Timeout ]
+crbug.com/982194 fast/dnd/link-dragging-draggable-link.html [ Pass Timeout ]
+crbug.com/982194 fast/dnd/link-dragging-non-draggable-link.html [ Pass Timeout ]
 crbug.com/982194 fast/dom/Document/CaretRangeFromPoint/caretRangeFromPoint-in-user-select-none.html [ Failure ]
-crbug.com/982194 fast/dom/Document/CaretRangeFromPoint/caretRangeFromPoint-in-zoom-and-scroll.html [ Failure Pass ]
 crbug.com/982194 fast/dom/Document/CaretRangeFromPoint/caretRangeFromPoint-with-before-style.html [ Failure ]
 crbug.com/982194 fast/dom/Document/CaretRangeFromPoint/caretRangeFromPoint-with-first-letter-style.html [ Failure ]
-crbug.com/982194 fast/dom/Document/CaretRangeFromPoint/hittest-empty-line.html [ Failure Pass ]
-crbug.com/982194 fast/dom/Document/CaretRangeFromPoint/hittest-outside-image.html [ Failure Pass ]
 crbug.com/982194 fast/dom/Document/CaretRangeFromPoint/replace-element.html [ Failure ]
-crbug.com/982194 fast/dom/elementsFromPoint/elementsFromPoint-simple.html [ Failure ]
+crbug.com/982194 fast/dom/elementsFromPoint/elementsFromPoint-simple.html [ Failure Pass ]
 crbug.com/982194 fast/dom/nodesFromRect/nodesFromRect-child-frame-content.html [ Failure ]
 crbug.com/982194 fast/dom/nodesFromRect/nodesFromRect-culled-inlines-between-silblings-bidi.html [ Failure ]
 crbug.com/982194 fast/dom/nodesFromRect/nodesFromRect-embedded-frame-content.html [ Failure ]
 crbug.com/874695 fast/events/autoscroll-iframe-no-scrolling.html [ Pass ]
-crbug.com/982194 fast/events/autoscroll-should-not-stop-on-keypress.html [ Failure Pass ]
 crbug.com/663847 fast/events/context-no-deselect.html [ Failure ]
 crbug.com/982194 fast/events/drag-in-frames.html [ Failure ]
 crbug.com/346473 fast/events/drag-on-mouse-move-cancelled.html [ Failure ]
 crbug.com/982194 fast/events/event-on-culled-inline-with-pseudo.html [ Failure ]
 crbug.com/874695 fast/events/frame-detached-in-mousedown.html [ Pass ]
-crbug.com/982194 fast/events/pointerevents/mouse-node-remove.html [ Failure ]
-crbug.com/982194 fast/events/pointerevents/mouse-pointer-capture-transition-events.html [ Failure ]
-crbug.com/982194 fast/events/pointerevents/mouse-pointer-capture.html [ Failure ]
+crbug.com/982194 fast/events/pointerevents/mouse-node-remove.html [ Failure Pass ]
+crbug.com/982194 fast/events/pointerevents/mouse-pointer-capture-transition-events.html [ Failure Pass ]
+crbug.com/982194 fast/events/pointerevents/mouse-pointer-capture.html [ Failure Pass ]
 crbug.com/722212 fast/events/pointerevents/mouse-pointer-event-properties.html [ Failure ]
-crbug.com/982194 fast/events/pointerevents/mouse-pointer-transition-events.html [ Failure ]
-crbug.com/982194 fast/events/pointerevents/mouse-pointer-updown-events.html [ Failure ]
+crbug.com/982194 fast/events/pointerevents/mouse-pointer-transition-events.html [ Failure Pass ]
+crbug.com/982194 fast/events/pointerevents/mouse-pointer-updown-events.html [ Failure Pass ]
 crbug.com/874695 fast/events/pointerevents/pointerevent_touch-adjustment_click_target.html [ Pass ]
-crbug.com/982194 fast/events/pointerevents/touch-capture.html [ Failure ]
-crbug.com/982194 fast/events/pointerevents/touch-pointer-events.html [ Failure ]
+crbug.com/982194 fast/events/pointerevents/touch-capture.html [ Failure Pass ]
+crbug.com/982194 fast/events/pointerevents/touch-pointer-events.html [ Failure Pass ]
 crbug.com/874695 fast/events/popup-blocking-timers4.html [ Pass ]
-crbug.com/982194 fast/events/selectstart-by-single-click-with-shift.html [ Failure Pass ]
 crbug.com/591099 fast/events/touch/compositor-touch-hit-rects.html [ Failure ]
-crbug.com/982194 fast/events/touch/gesture/gesture-tap-mouse-events-between-frames.html [ Failure ]
-crbug.com/982194 fast/events/touch/gesture/gesture-tap-mouse-events.html [ Failure ]
+crbug.com/982194 fast/events/touch/gesture/gesture-tap-mouse-events-between-frames.html [ Failure Pass ]
+crbug.com/982194 fast/events/touch/gesture/gesture-tap-mouse-events.html [ Failure Pass ]
 crbug.com/874695 fast/forms/color/color-suggestion-picker-one-row-appearance.html [ Pass ]
 crbug.com/874695 fast/forms/color/color-suggestion-picker-two-row-appearance.html [ Pass ]
-crbug.com/982194 fast/forms/label/label-selection-by-dragging.html [ Failure Pass ]
-crbug.com/982194 fast/forms/label/label-selection-by-textSelection-and-click.html [ Failure Pass ]
 crbug.com/874695 fast/forms/number/number-spinbutton-gets-disabled-or-readonly.html [ Pass ]
 crbug.com/982194 fast/html/draggable-controls.html [ Failure ]
 crbug.com/982194 fast/inline/inline-offsetLeft-relpos.html [ Failure ]
@@ -244,7 +215,7 @@
 crbug.com/451577 crbug.com/924308 http/tests/devtools/console/console-format-es6-2.js [ Crash Failure Pass Timeout ]
 crbug.com/451577 crbug.com/916975 http/tests/devtools/console/console-repeat-count.js [ Crash Failure Pass Timeout ]
 crbug.com/451577 http/tests/devtools/console/console-search.js [ Pass ]
-crbug.com/967526 http/tests/devtools/console/console-uncaught-promise.js [ Failure Pass ]
+crbug.com/967526 http/tests/devtools/console/console-uncaught-promise.js [ Pass ]
 crbug.com/982194 http/tests/devtools/coverage/decorations-after-script-formatter.js [ Timeout ]
 crbug.com/678482 http/tests/devtools/debugger/fetch-breakpoints.js [ Timeout ]
 crbug.com/846997 http/tests/devtools/editor/text-editor-ctrl-d-1.js [ Timeout ]
@@ -282,7 +253,7 @@
 crbug.com/982194 http/tests/devtools/network/network-cookies-pane.js [ Failure ]
 crbug.com/679833 crbug.com/762529 http/tests/devtools/network/network-datareceived.js [ Crash Failure Timeout ]
 crbug.com/759632 http/tests/devtools/network/network-datasaver-warning.js [ Failure ]
-crbug.com/945629 http/tests/devtools/network/network-filters.js [ Timeout ]
+crbug.com/945629 http/tests/devtools/network/network-filters.js [ Pass Timeout ]
 crbug.com/817167 crbug.com/874695 http/tests/devtools/oopif/oopif-cookies-refresh.js [ Crash Failure Pass Timeout ]
 crbug.com/818076 http/tests/devtools/oopif/oopif-elements-navigate-in.js [ Pass ]
 crbug.com/874695 http/tests/devtools/persistence/persistence-mimetype-on-rename.js [ Pass ]
@@ -444,8 +415,7 @@
 crbug.com/718155 virtual/android/fullscreen/full-screen-iframe-not-allowed.html [ Failure ]
 crbug.com/982194 virtual/audio-service/http/tests/media/video-frame-size-change.html [ Failure Pass ]
 crbug.com/874695 crbug.com/936165 virtual/audio-service/media/autoplay-muted.html [ Crash Pass Timeout ]
-crbug.com/982194 accessibility/aom-relation-list-properties.html [ Crash ]
-crbug.com/982194 accessibility/selection-affinity.html [ Failure Pass ]
+crbug.com/982194 accessibility/aom-relation-list-properties.html [ Crash Pass ]
 crbug.com/982194 compositing/gestures/gesture-tapHighlight-invisible-inline-squashing.html [ Failure ]
 crbug.com/982194 compositing/gestures/gesture-tapHighlight-invisible-inline.html [ Failure ]
 crbug.com/982194 compositing/gestures/gesture-tapHighlight-simple-nested.html [ Failure ]
@@ -1037,7 +1007,7 @@
 crbug.com/982194 external/wpt/media-source/mediasource-getvideoplaybackquality.html [ Pass ]
 crbug.com/982194 external/wpt/mediacapture-record/MediaRecorder-destroy-script-execution.html [ Pass ]
 crbug.com/982194 external/wpt/native-file-system/sandboxed_FileSystemBaseHandle-postMessage-MessagePort.tentative.https.window.html [ Timeout ]
-crbug.com/982194 external/wpt/native-file-system/sandboxed_FileSystemBaseHandle-postMessage.tentative.https.window.html [ Timeout ]
+crbug.com/982194 external/wpt/native-file-system/sandboxed_FileSystemBaseHandle-postMessage.tentative.https.window.html [ Pass Timeout ]
 crbug.com/982194 external/wpt/payment-method-basic-card/apply_the_modifiers.html [ Timeout ]
 crbug.com/982194 external/wpt/payment-method-basic-card/steps_for_selecting_the_payment_handler.html [ Timeout ]
 crbug.com/982194 external/wpt/quirks/text-decoration-doesnt-propagate-into-tables/quirks.html [ Failure ]
@@ -1076,7 +1046,7 @@
 crbug.com/982194 external/wpt/webvtt/rendering/cues-with-video/processing-model/bidi/u06E9_no_strong_dir.html [ Failure ]
 crbug.com/982194 external/wpt/webvtt/rendering/cues-with-video/processing-model/bidi/vertical_lr.html [ Failure ]
 crbug.com/982194 external/wpt/webvtt/rendering/cues-with-video/processing-model/bidi/vertical_rl.html [ Failure ]
-crbug.com/982194 external/wpt/webvtt/rendering/cues-with-video/processing-model/cue_too_long.html [ Failure Pass ]
+crbug.com/982194 external/wpt/webvtt/rendering/cues-with-video/processing-model/cue_too_long.html [ Failure ]
 crbug.com/982194 external/wpt/webvtt/rendering/cues-with-video/processing-model/dom_override_cue_align_position_line_size_while_paused.html [ Failure ]
 crbug.com/982194 external/wpt/webvtt/rendering/cues-with-video/processing-model/dom_override_cue_line.html [ Failure ]
 crbug.com/982194 external/wpt/webvtt/rendering/cues-with-video/processing-model/dom_override_cue_text.html [ Failure ]
@@ -1244,8 +1214,8 @@
 crbug.com/982194 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/default_styles/underline_object_default_font-style.html [ Failure ]
 crbug.com/982194 external/wpt/webvtt/rendering/cues-with-video/processing-model/size_50.html [ Failure ]
 crbug.com/982194 fast/backgrounds/quirks-mode-line-box-backgrounds.html [ Failure ]
-crbug.com/982194 fast/block/float/hittest-float-in-anchor.html [ Failure ]
-crbug.com/982194 fast/block/float/overlapping-floats-paint-hittest-order-1.html [ Failure ]
+crbug.com/982194 fast/block/float/hittest-float-in-anchor.html [ Failure Pass ]
+crbug.com/982194 fast/block/float/overlapping-floats-paint-hittest-order-1.html [ Failure Pass ]
 crbug.com/982194 fast/block/positioning/058.html [ Failure ]
 crbug.com/982194 fast/block/positioning/absolute-in-inline-ltr-2.html [ Failure ]
 crbug.com/982194 fast/block/positioning/absolute-in-inline-ltr-3.html [ Failure ]
@@ -1275,7 +1245,6 @@
 crbug.com/982194 fast/events/touch/compositor-touch-hit-rects-list-translate.html [ Failure ]
 crbug.com/982194 fast/forms/calendar-picker/calendar-picker-appearance-zoom125.html [ Failure ]
 crbug.com/982194 fast/forms/date/date-appearance-basic.html [ Failure ]
-crbug.com/982194 fast/forms/text/input-readonly-autoscroll.html [ Failure Pass ]
 crbug.com/982194 fast/forms/time/time-appearance-basic.html [ Failure ]
 crbug.com/982194 fast/hidpi/clip-text-in-hidpi.html [ Failure ]
 crbug.com/982194 fast/history/visited-link-hover-emphasis-color.html [ Failure ]
@@ -1308,19 +1277,19 @@
 crbug.com/982194 http/tests/devtools/editor/text-editor-reveal-line.js [ Pass Timeout ]
 crbug.com/982194 http/tests/devtools/elements/edit/edit-dom-actions-1.js [ Pass Timeout ]
 crbug.com/982194 http/tests/devtools/elements/edit/edit-dom-actions-2.js [ Pass Timeout ]
-crbug.com/982194 http/tests/devtools/elements/highlight/highlight-dom-updates.js [ Pass Timeout ]
+crbug.com/982194 http/tests/devtools/elements/highlight/highlight-dom-updates.js [ Timeout ]
 crbug.com/982194 http/tests/devtools/elements/styles-1/disable-property-workingcopy-update.js [ Timeout ]
 crbug.com/982194 http/tests/devtools/elements/styles-4/styles-update-from-js.js [ Timeout ]
 crbug.com/982194 http/tests/devtools/elements/styles/selector-line-sourcemap-header.js [ Pass Timeout ]
 crbug.com/982194 http/tests/devtools/indexeddb/database-refresh-view.js [ Pass ]
-crbug.com/982194 http/tests/devtools/network/network-search.js [ Timeout ]
+crbug.com/982194 http/tests/devtools/network/network-search.js [ Pass Timeout ]
 crbug.com/982194 http/tests/devtools/oopif/oopif-navigator.js [ Timeout ]
 crbug.com/982194 http/tests/devtools/oopif/oopif-storage.js [ Pass Timeout ]
 crbug.com/982194 http/tests/devtools/profiler/heap-snapshot-location.js [ Pass ]
 crbug.com/982194 http/tests/devtools/resource-tree/resource-tree-crafted-frame-add.js [ Pass ]
 crbug.com/982194 http/tests/devtools/resource-tree/resource-tree-frame-in-crafted-frame.js [ Pass ]
-crbug.com/982194 http/tests/devtools/resource-tree/resource-tree-frame-navigate.js [ Pass ]
-crbug.com/982194 http/tests/devtools/resource-tree/resource-tree-htmlimports.js [ Pass ]
+crbug.com/982194 http/tests/devtools/resource-tree/resource-tree-frame-navigate.js [ Pass Timeout ]
+crbug.com/982194 http/tests/devtools/resource-tree/resource-tree-htmlimports.js [ Pass Timeout ]
 crbug.com/982194 http/tests/devtools/service-workers/service-worker-agents.js [ Pass ]
 crbug.com/982194 http/tests/devtools/service-workers/service-workers-force-update-on-page-load.js [ Pass ]
 crbug.com/982194 http/tests/devtools/service-workers/service-workers-redundant.js [ Pass ]
@@ -1339,17 +1308,17 @@
 crbug.com/982194 jquery/manipulation.html [ Pass Timeout ]
 crbug.com/982194 jquery/offset.html [ Pass ]
 crbug.com/982194 jquery/traversing.html [ Pass ]
-crbug.com/982194 media/video-canvas-draw.html [ Failure Pass ]
+crbug.com/982194 media/video-canvas-draw.html [ Failure ]
 crbug.com/982194 overflow/overflow-inline-003.html [ Failure ]
 crbug.com/982194 paint/background/background-clip-text-inline.html [ Failure ]
 crbug.com/982194 paint/invalidation/compositing/float-under-composited-inline.html [ Failure ]
 crbug.com/982194 paint/invalidation/flexbox/scrollbars-changed.html [ Failure ]
-crbug.com/982194 paint/invalidation/forms/slider-thumb-float.html [ Failure ]
+crbug.com/982194 paint/invalidation/forms/slider-thumb-float.html [ Failure Pass ]
 crbug.com/982194 paint/invalidation/multi-layout-one-frame.html [ Failure ]
 crbug.com/982194 paint/invalidation/outline/focus-layers.html [ Failure ]
 crbug.com/982194 paint/invalidation/position/absolute-position-moved.html [ Failure ]
 crbug.com/982194 paint/invalidation/selection/selection-repaint.html [ Failure ]
-crbug.com/982194 paint/invalidation/svg/scroll-hit-test.xhtml [ Failure ]
+crbug.com/982194 paint/invalidation/svg/scroll-hit-test.xhtml [ Crash Failure ]
 crbug.com/982194 paint/invalidation/text-decoration-invalidation.html [ Failure ]
 crbug.com/982194 paint/selection/text-selection-inline-block-rtl.html [ Failure ]
 crbug.com/982194 paint/selection/text-selection-inline-block.html [ Failure ]
@@ -1368,14 +1337,17 @@
 crbug.com/982194 virtual/audio-service/media/picture-in-picture/v2/request-picture-in-picture.html [ Failure Pass ]
 crbug.com/874695 virtual/audio-service/media/remoteplayback/prompt-twice-throws.html [ Pass ]
 crbug.com/982194 virtual/audio-service/media/stable/video-object-fit-stable.html [ Pass ]
-crbug.com/982194 virtual/audio-service/media/video-canvas-draw.html [ Failure ]
+crbug.com/982194 virtual/audio-service/media/video-canvas-draw.html [ Failure Pass ]
 crbug.com/982194 virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/udate-bytecheck.https.html [ Timeout ]
 crbug.com/982194 virtual/cascade/external/wpt/css/css-paint-api/background-image-alpha.https.html [ Pass ]
 crbug.com/982194 virtual/cascade/external/wpt/css/css-scoping/slotted-with-pseudo-element.html [ Failure ]
 crbug.com/982194 virtual/cascade/fast/forms/calendar-picker/calendar-picker-appearance-zoom125.html [ Failure ]
 crbug.com/982194 virtual/cascade/fast/forms/date/date-appearance-basic.html [ Failure ]
 crbug.com/982194 virtual/composite-after-paint/paint/background/background-clip-text-inline.html [ Failure ]
+crbug.com/982194 virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/date/date-appearance-basic.html [ Failure ]
+crbug.com/982194 virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/datetimelocal/datetimelocal-appearance-basic.html [ Failure ]
 crbug.com/982194 virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/file/file-appearance-basic.html [ Failure ]
+crbug.com/982194 virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/week/week-appearance-basic.html [ Failure ]
 crbug.com/982194 virtual/controls-refresh/calendar-picker/date-picker-appearance-zoom150.html [ Failure ]
 crbug.com/982194 virtual/controls-refresh/color-scheme/date/date-appearance-basic.html [ Failure ]
 crbug.com/982194 virtual/controls-refresh/color-scheme/datetimelocal/datetimelocal-appearance-basic.html [ Failure ]
@@ -1392,8 +1364,6 @@
 crbug.com/982194 virtual/forced-high-contrast-colors/external/wpt/forced-colors-mode/forced-colors-mode-14.html [ Failure ]
 crbug.com/982194 virtual/forced-high-contrast-colors/fast/css/forced-colors-mode/forced-colors-mode-15.html [ Failure ]
 crbug.com/982194 virtual/form-controls-refresh-disabled/fast/forms/date/date-appearance-basic.html [ Failure ]
-crbug.com/982194 virtual/form-controls-refresh-disabled/fast/forms/label/label-selection-by-dragging.html [ Failure Pass ]
-crbug.com/982194 virtual/form-controls-refresh-disabled/fast/forms/label/label-selection-by-textSelection-and-click.html [ Failure Pass ]
 crbug.com/982194 virtual/form-controls-refresh-disabled/fast/forms/suggestion-picker/date-suggestion-picker-appearance.html [ Failure ]
 crbug.com/982194 virtual/form-controls-refresh-disabled/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-locale-hebrew.html [ Failure ]
 crbug.com/982194 virtual/form-controls-refresh-disabled/fast/forms/suggestion-picker/datetimelocal-suggestion-picker-appearance-rtl.html [ Failure ]
@@ -1405,7 +1375,6 @@
 crbug.com/982194 virtual/form-controls-refresh-disabled/fast/forms/suggestion-picker/time-suggestion-picker-appearance-with-scroll-bar.html [ Failure ]
 crbug.com/982194 virtual/form-controls-refresh-disabled/fast/forms/suggestion-picker/time-suggestion-picker-appearance.html [ Failure ]
 crbug.com/982194 virtual/form-controls-refresh-disabled/fast/forms/suggestion-picker/week-suggestion-picker-appearance.html [ Failure ]
-crbug.com/982194 virtual/form-controls-refresh-disabled/fast/forms/text/input-readonly-autoscroll.html [ Failure Pass ]
 crbug.com/956736 virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map.html [ Failure ]
 crbug.com/982194 virtual/gpu/fast/canvas/OffscreenCanvas-zero-size-readback.html [ Crash ]
 crbug.com/982194 virtual/gpu/fast/canvas/canvas-arc-circumference.html [ Failure ]
@@ -1732,27 +1701,25 @@
 crbug.com/982194 virtual/layout_ng_flex_box/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-min-width-auto-002c.html [ Failure ]
 crbug.com/982194 virtual/layout_ng_flex_box/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-paint-ordering-002.xhtml [ Failure ]
 crbug.com/982194 virtual/lazyload-image/http/tests/lazyload/style-dimension.html [ Pass ]
-crbug.com/982194 virtual/mouseevent_fractional/fast/events/autoscroll-should-not-stop-on-keypress.html [ Failure Pass ]
 crbug.com/779170 virtual/mouseevent_fractional/fast/events/clientXY-in-zoom-and-scroll.html [ Pass ]
 crbug.com/663847 virtual/mouseevent_fractional/fast/events/context-no-deselect.html [ Failure ]
 crbug.com/982194 virtual/mouseevent_fractional/fast/events/drag-in-frames.html [ Failure ]
 crbug.com/346473 virtual/mouseevent_fractional/fast/events/drag-on-mouse-move-cancelled.html [ Failure ]
 crbug.com/982194 virtual/mouseevent_fractional/fast/events/event-on-culled-inline-with-pseudo.html [ Failure ]
 crbug.com/982194 virtual/mouseevent_fractional/fast/events/mouse-relative-position.html [ Failure ]
-crbug.com/982194 virtual/mouseevent_fractional/fast/events/pointerevents/mouse-node-remove.html [ Failure ]
-crbug.com/982194 virtual/mouseevent_fractional/fast/events/pointerevents/mouse-pointer-capture-transition-events.html [ Failure ]
-crbug.com/982194 virtual/mouseevent_fractional/fast/events/pointerevents/mouse-pointer-capture.html [ Failure ]
+crbug.com/982194 virtual/mouseevent_fractional/fast/events/pointerevents/mouse-node-remove.html [ Failure Pass ]
+crbug.com/982194 virtual/mouseevent_fractional/fast/events/pointerevents/mouse-pointer-capture-transition-events.html [ Failure Pass ]
+crbug.com/982194 virtual/mouseevent_fractional/fast/events/pointerevents/mouse-pointer-capture.html [ Failure Pass ]
 crbug.com/722212 virtual/mouseevent_fractional/fast/events/pointerevents/mouse-pointer-event-properties.html [ Failure ]
-crbug.com/982194 virtual/mouseevent_fractional/fast/events/pointerevents/mouse-pointer-transition-events.html [ Failure ]
-crbug.com/982194 virtual/mouseevent_fractional/fast/events/pointerevents/mouse-pointer-updown-events.html [ Failure ]
-crbug.com/982194 virtual/mouseevent_fractional/fast/events/pointerevents/touch-capture.html [ Failure ]
-crbug.com/982194 virtual/mouseevent_fractional/fast/events/pointerevents/touch-pointer-events.html [ Failure ]
-crbug.com/982194 virtual/mouseevent_fractional/fast/events/selectstart-by-single-click-with-shift.html [ Failure Pass ]
+crbug.com/982194 virtual/mouseevent_fractional/fast/events/pointerevents/mouse-pointer-transition-events.html [ Failure Pass ]
+crbug.com/982194 virtual/mouseevent_fractional/fast/events/pointerevents/mouse-pointer-updown-events.html [ Failure Pass ]
+crbug.com/982194 virtual/mouseevent_fractional/fast/events/pointerevents/touch-capture.html [ Failure Pass ]
+crbug.com/982194 virtual/mouseevent_fractional/fast/events/pointerevents/touch-pointer-events.html [ Failure Pass ]
 crbug.com/982194 virtual/mouseevent_fractional/fast/events/touch/compositor-touch-hit-rects-list-translate.html [ Failure ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/touch/compositor-touch-hit-rects.html [ Failure ]
-crbug.com/874695 virtual/mouseevent_fractional/fast/events/touch/gesture/gesture-click.html [ Pass Timeout ]
-crbug.com/982194 virtual/mouseevent_fractional/fast/events/touch/gesture/gesture-tap-mouse-events-between-frames.html [ Failure ]
-crbug.com/982194 virtual/mouseevent_fractional/fast/events/touch/gesture/gesture-tap-mouse-events.html [ Failure ]
+crbug.com/874695 virtual/mouseevent_fractional/fast/events/touch/gesture/gesture-click.html [ Pass ]
+crbug.com/982194 virtual/mouseevent_fractional/fast/events/touch/gesture/gesture-tap-mouse-events-between-frames.html [ Failure Pass ]
+crbug.com/982194 virtual/mouseevent_fractional/fast/events/touch/gesture/gesture-tap-mouse-events.html [ Failure Pass ]
 crbug.com/874695 virtual/mouseevent_fractional/fast/events/touch/touch-slider-no-js-touch-listener.html [ Pass ]
 crbug.com/779170 virtual/mouseevent_fractional/fast/events/zoom-dblclick.html [ Failure ]
 crbug.com/982194 virtual/not-site-per-process/http/tests/devtools/debugger/fetch-breakpoints.js [ Timeout ]
@@ -1775,8 +1742,8 @@
 crbug.com/982194 virtual/scalefactor200/fast/hidpi/static/pointerevents/pointerevent_touch-adjustment_click_target.html [ Pass ]
 crbug.com/982194 virtual/scalefactor200/fast/hidpi/static/validation-bubble-appearance-hidpi.html [ Failure ]
 crbug.com/982194 virtual/scalefactor200withoutzoom/external/wpt/largest-contentful-paint/first-paint-equals-lcp-text.html [ Failure Pass ]
-crbug.com/982194 virtual/scroll_customization/fast/events/touch/gesture/gesture-tap-mouse-events-between-frames.html [ Failure ]
-crbug.com/982194 virtual/scroll_customization/fast/events/touch/gesture/gesture-tap-mouse-events.html [ Failure ]
+crbug.com/982194 virtual/scroll_customization/fast/events/touch/gesture/gesture-tap-mouse-events-between-frames.html [ Failure Pass ]
+crbug.com/982194 virtual/scroll_customization/fast/events/touch/gesture/gesture-tap-mouse-events.html [ Failure Pass ]
 crbug.com/982194 virtual/speech-with-unified-autoplay/external/wpt/speech-api/SpeechSynthesis-speak-without-activation-fails.tentative.html [ Pass ]
 crbug.com/982194 virtual/stable/media/stable/video-object-fit-stable.html [ Failure Pass ]
 crbug.com/874695 virtual/sxg-with-network-service/http/tests/devtools/sxg/sxg-disable-cache.js [ Pass ]
@@ -1792,7 +1759,7 @@
 crbug.com/982194 virtual/threaded/external/wpt/feature-policy/experimental-features/lazyload/loading-frame-default-eager-disabled-tentative.sub.html [ Pass ]
 crbug.com/982194 virtual/threaded/fast/scroll-snap/snaps-after-scrollbar-scrolling.html [ Timeout ]
 crbug.com/874695 virtual/threaded/http/tests/devtools/tracing/console-timeline.js [ Pass ]
-crbug.com/982194 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-event-causes.js [ Failure ]
+crbug.com/982194 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-event-causes.js [ Failure Pass ]
 crbug.com/982194 virtual/threaded/http/tests/devtools/tracing/timeline-paint/paint-profiler-update.js [ Pass ]
 crbug.com/982194 virtual/threaded/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.js [ Pass ]
 crbug.com/982194 virtual/threaded/http/tests/devtools/tracing/timeline-worker-events.js [ Failure Pass ]
@@ -1800,16 +1767,11 @@
 crbug.com/982194 virtual/unified-autoplay/external/wpt/feature-policy/experimental-features/lazyload/loading-frame-default-eager-disabled-tentative.sub.html [ Pass ]
 crbug.com/982194 virtual/web-components-v0-disabled/external/wpt/html/semantics/document-metadata/the-link-element/stylesheet-change-href.html [ Failure Pass ]
 crbug.com/982194 virtual/web-components-v0-disabled/external/wpt/html/semantics/scripting-1/the-script-element/css-module/utf8.tentative.html [ Pass ]
-crbug.com/982194 virtual/web-components-v0-disabled/fast/dom/Document/CaretRangeFromPoint/basic.html [ Failure Pass ]
-crbug.com/982194 virtual/web-components-v0-disabled/fast/dom/Document/CaretRangeFromPoint/caretRangeFromPoint-in-strict-mode-wtih-checkbox.html [ Failure Pass ]
 crbug.com/982194 virtual/web-components-v0-disabled/fast/dom/Document/CaretRangeFromPoint/caretRangeFromPoint-in-user-select-none.html [ Failure ]
-crbug.com/982194 virtual/web-components-v0-disabled/fast/dom/Document/CaretRangeFromPoint/caretRangeFromPoint-in-zoom-and-scroll.html [ Failure Pass ]
 crbug.com/982194 virtual/web-components-v0-disabled/fast/dom/Document/CaretRangeFromPoint/caretRangeFromPoint-with-before-style.html [ Failure ]
 crbug.com/982194 virtual/web-components-v0-disabled/fast/dom/Document/CaretRangeFromPoint/caretRangeFromPoint-with-first-letter-style.html [ Failure ]
-crbug.com/982194 virtual/web-components-v0-disabled/fast/dom/Document/CaretRangeFromPoint/hittest-empty-line.html [ Failure Pass ]
-crbug.com/982194 virtual/web-components-v0-disabled/fast/dom/Document/CaretRangeFromPoint/hittest-outside-image.html [ Failure Pass ]
 crbug.com/982194 virtual/web-components-v0-disabled/fast/dom/Document/CaretRangeFromPoint/replace-element.html [ Failure ]
-crbug.com/982194 virtual/web-components-v0-disabled/fast/dom/elementsFromPoint/elementsFromPoint-simple.html [ Failure ]
+crbug.com/982194 virtual/web-components-v0-disabled/fast/dom/elementsFromPoint/elementsFromPoint-simple.html [ Failure Pass ]
 crbug.com/982194 virtual/web-components-v0-disabled/fast/dom/nodesFromRect/nodesFromRect-child-frame-content.html [ Failure ]
 crbug.com/982194 virtual/web-components-v0-disabled/fast/dom/nodesFromRect/nodesFromRect-culled-inlines-between-silblings-bidi.html [ Failure ]
 crbug.com/982194 virtual/web-components-v0-disabled/fast/dom/nodesFromRect/nodesFromRect-embedded-frame-content.html [ Failure ]
diff --git a/third_party/blink/web_tests/SlowTests b/third_party/blink/web_tests/SlowTests
index 34f2d63..6268d37 100644
--- a/third_party/blink/web_tests/SlowTests
+++ b/third_party/blink/web_tests/SlowTests
@@ -675,3 +675,7 @@
 
 crbug.com/1040054 http/tests/devtools/cache-storage/cache-data.js [ Slow ]
 crbug.com/1040450 http/tests/devtools/persistence/persistence-external-change-breakpoints.js [ Slow ]
+
+# Reaching the stack size limit makes for a consistently slow test with
+# occasional timeouts on Win7
+crbug.com/937546 [ Win7 ] http/tests/security/xss-DENIED-cross-origin-stack-overflow.html [ Slow ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 70a3b6a8..b20593a 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -3980,7 +3980,6 @@
 crbug.com/1031667 external/wpt/css/css-pseudo/marker-content-007.tentative.html [ Failure ]
 crbug.com/1031667 external/wpt/css/css-pseudo/marker-content-008.tentative.html [ Failure ]
 crbug.com/1031667 external/wpt/css/css-pseudo/marker-content-009.tentative.html [ Failure ]
-crbug.com/457718 external/wpt/css/css-pseudo/marker-content-010.html [ Failure ]
 crbug.com/1031667 external/wpt/css/css-pseudo/marker-content-011.tentative.html [ Failure ]
 crbug.com/457718 external/wpt/css/css-pseudo/marker-font-variant-numeric-normal.html [ Failure ]
 crbug.com/457718 external/wpt/css/css-pseudo/marker-list-style-position.html [ Failure ]
@@ -5737,9 +5736,6 @@
 # Sheriff 2019-06-13
 crbug.com/973692 [ Mac ] external/wpt/css/css-text/parsing/hyphens-computed.html [ Failure ]
 crbug.com/973726 [ Mac ] fast/css/large-list-of-rules-crash.html [ Pass Timeout ]
-crbug.com/937546 [ Win7 ] http/tests/security/xss-DENIED-cross-origin-stack-overflow.html [ Pass Timeout ]
-
-# Sheriff 2019-06-14
 
 # Sheriff 2019-06-20
 crbug.com/976045 fast/scrolling/unscrollable-layer-subpixel-size-with-negative-overflow.html [ Pass Failure ]
@@ -6307,3 +6303,7 @@
 # Sheriff 2020-01-20
 crbug.com/1043357 http/tests/credentialmanager/credentialscontainer-get-with-virtual-authenticator.html [ Pass Timeout Failure ]
 crbug.com/1043774 [ Linux ] virtual/web-components-v0-disabled/external/wpt/html/dom/reflection-grouping.html [ Pass Failure ]
+
+# Sheriff 2020-01-22
+crbug.com/1044567 [ Mac10.10 ] media/video-colorspace-yuv420.html [ Pass Failure ]
+crbug.com/1044567 [ Mac10.10 ] virtual/audio-service/media/video-colorspace-yuv420.html [ Pass Failure ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_7.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_7.json
index b1ced03..9ededab 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_7.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_7.json
@@ -88049,6 +88049,30 @@
      {}
     ]
    ],
+   "css/css-transforms/transform-translate-background-001.html": [
+    [
+     "css/css-transforms/transform-translate-background-001.html",
+     [
+      [
+       "/css/css-transforms/transform-translate-background-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-transforms/transform-translate-background-002.html": [
+    [
+     "css/css-transforms/transform-translate-background-002.html",
+     [
+      [
+       "/css/css-transforms/transform-translate-background-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-transforms/transform-translatex-001.html": [
     [
      "css/css-transforms/transform-translatex-001.html",
@@ -123219,6 +123243,18 @@
      {}
     ]
    ],
+   "svg/extensibility/foreignObject/foreign-object-scale-scroll.html": [
+    [
+     "svg/extensibility/foreignObject/foreign-object-scale-scroll.html",
+     [
+      [
+       "/svg/extensibility/foreignObject/foreign-object-scale-scroll-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "svg/extensibility/foreignObject/foreign-object-size.html": [
     [
      "svg/extensibility/foreignObject/foreign-object-size.html",
@@ -128548,6 +128584,9 @@
    "2dcontext/imagebitmap/common.sub.js": [
     []
    ],
+   "2dcontext/imagebitmap/createImageBitmap-worker.js": [
+    []
+   ],
    "2dcontext/imagebitmap/no-coop-coep.https.window-expected.txt": [
     []
    ],
@@ -129619,27 +129658,12 @@
    "beacon/OWNERS": [
     []
    ],
-   "beacon/beacon-basic-blob-expected.txt": [
-    []
-   ],
-   "beacon/beacon-basic-blobMax-expected.txt": [
-    []
-   ],
    "beacon/beacon-common.sub.js": [
     []
    ],
-   "beacon/beacon-cors.sub.window-expected.txt": [
-    []
-   ],
-   "beacon/beacon-navigate-expected.txt": [
-    []
-   ],
    "beacon/beacon-readablestream.window-expected.txt": [
     []
    ],
-   "beacon/beacon-redirect.window-expected.txt": [
-    []
-   ],
    "beacon/headers/header-content-type-expected.txt": [
     []
    ],
@@ -149998,6 +150022,9 @@
    "css/css-transforms/transform-transformed-tr-percent-height-child-ref.html": [
     []
    ],
+   "css/css-transforms/transform-translate-background-001-ref.html": [
+    []
+   ],
    "css/css-transforms/transform-translate-ref.html": [
     []
    ],
@@ -177154,6 +177181,9 @@
    "svg/extensibility/foreignObject/foreign-object-paints-before-rect-ref.html": [
     []
    ],
+   "svg/extensibility/foreignObject/foreign-object-scale-scroll-ref.html": [
+    []
+   ],
    "svg/extensibility/foreignObject/foreign-object-size-ref.html": [
     []
    ],
@@ -189474,6 +189504,12 @@
      {}
     ]
    ],
+   "2dcontext/imagebitmap/createImageBitmap-in-worker-transfer.html": [
+    [
+     "2dcontext/imagebitmap/createImageBitmap-in-worker-transfer.html",
+     {}
+    ]
+   ],
    "2dcontext/imagebitmap/createImageBitmap-invalid-args.html": [
     [
      "2dcontext/imagebitmap/createImageBitmap-invalid-args.html",
@@ -271224,8 +271260,13 @@
        [
         "script",
         "script-tests/FileSystemBaseHandle-postMessage.js"
+       ],
+       [
+        "timeout",
+        "long"
        ]
-      ]
+      ],
+      "timeout": "long"
      }
     ]
    ],
@@ -343762,6 +343803,10 @@
    "bbc920f1e303ff45e22c4396d098decafffac87b",
    "testharness"
   ],
+  "2dcontext/imagebitmap/createImageBitmap-in-worker-transfer.html": [
+   "727a8a4978db6ea62451d8af642a91d57b0aaed6",
+   "testharness"
+  ],
   "2dcontext/imagebitmap/createImageBitmap-invalid-args.html": [
    "c200ce36f98658ef0dae6f654f892105a7e7aca1",
    "testharness"
@@ -343782,6 +343827,10 @@
    "708f97097c16e9074cc3cbf54dad0ee75df7967c",
    "testharness"
   ],
+  "2dcontext/imagebitmap/createImageBitmap-worker.js": [
+   "67a0904e479323e4a159937f49919580109fbc61",
+   "support"
+  ],
   "2dcontext/imagebitmap/no-coop-coep.https.window-expected.txt": [
    "a0f5b55f298a18350f51c8d0c3e0be8f3f87a3f5",
    "support"
@@ -349126,18 +349175,10 @@
    "c82b6c02247630966ddd2c05b0db1c9321350d20",
    "support"
   ],
-  "beacon/beacon-basic-blob-expected.txt": [
-   "00fd0eb95320c48e621103c3b9c382c8a92cce46",
-   "support"
-  ],
   "beacon/beacon-basic-blob.html": [
    "805ea63be252b1087aedffbc20beaa765aedbc9a",
    "testharness"
   ],
-  "beacon/beacon-basic-blobMax-expected.txt": [
-   "66c55f65847bf4e118f1c17d2dcb352f0d44c512",
-   "support"
-  ],
   "beacon/beacon-basic-blobMax.html": [
    "e18b163d6300cdb3f58ea03e1a912bac5043627a",
    "testharness"
@@ -349170,10 +349211,6 @@
    "ae2f169f272e9efbbea3b7464ea77c34fe65c6e1",
    "support"
   ],
-  "beacon/beacon-cors.sub.window-expected.txt": [
-   "7d9f711e6f208f710f2756fb043afa62c6b4368a",
-   "support"
-  ],
   "beacon/beacon-cors.sub.window.js": [
    "4a8e4dfbc6570e58ae7d57e409d4fbbc72a47964",
    "testharness"
@@ -349182,10 +349219,6 @@
    "f2c5e95a276c257387e1cd85c2bcb70090d1132c",
    "testharness"
   ],
-  "beacon/beacon-navigate-expected.txt": [
-   "36c8b1023a0b7a6ce2f2e9589002ff3412330721",
-   "support"
-  ],
   "beacon/beacon-navigate.html": [
    "5df13905978dad65dea1f42606317897061d4aa4",
    "testharness"
@@ -349198,10 +349231,6 @@
    "fc7f81f884bdf47b6eb76f6d9b237bc38556efa4",
    "testharness"
   ],
-  "beacon/beacon-redirect.window-expected.txt": [
-   "e38d0c22b1fe901679f6b4dadd8bcd47d1bfe1da",
-   "support"
-  ],
   "beacon/beacon-redirect.window.js": [
    "3a8aef3c742b68348fa2c27303e297e8386768b3",
    "testharness"
@@ -356379,11 +356408,11 @@
    "testharness"
   ],
   "cookies/samesite/window-open-reload.https.html": [
-   "9c30bd5ca6760c23803fcf951cd772d8a8b39a1d",
+   "ee2091b1373a1da7068722c2557332e3a7f60b05",
    "testharness"
   ],
   "cookies/samesite/window-open.https.html": [
-   "fe2318acc43d857e0a7890d77b95a80f5b060863",
+   "d685eb47fd07872116caa22d2b8ca23774f26a81",
    "testharness"
   ],
   "cookies/secure/set-from-dom.https.sub.html": [
@@ -419766,6 +419795,18 @@
    "22c7008a672378beee17ae9f6f7528f78af58099",
    "reftest"
   ],
+  "css/css-transforms/transform-translate-background-001-ref.html": [
+   "f0b53d492a008c3d79200f725be7c4f527616b0c",
+   "support"
+  ],
+  "css/css-transforms/transform-translate-background-001.html": [
+   "72011e37bce073ce79bc65ad75dcaf4f55cce55a",
+   "reftest"
+  ],
+  "css/css-transforms/transform-translate-background-002.html": [
+   "b1be52774007c1f7886c18fd18f2acea279ef554",
+   "reftest"
+  ],
   "css/css-transforms/transform-translate-ref.html": [
    "1a781a06145aa3f6c192976b36dbb47672666ae7",
    "support"
@@ -451827,7 +451868,7 @@
    "testharness"
   ],
   "fetch/api/basic/keepalive.html": [
-   "5316410004a7880ff4d24234d4508680c29a6720",
+   "447ef2ddfecd7a62c4bf9f3d19af4e31e9fe68bc",
    "testharness"
   ],
   "fetch/api/basic/mediasource.window.js": [
@@ -452599,7 +452640,7 @@
    "support"
   ],
   "fetch/api/resources/keepalive-iframe.html": [
-   "742309ab4d238404b3ad66f8160c24fd5d16ef66",
+   "47de0da7790618224f70171c12dc8fd04436c0e3",
    "support"
   ],
   "fetch/api/resources/method.py": [
@@ -452627,7 +452668,7 @@
    "support"
   ],
   "fetch/api/resources/stash-put.py": [
-   "dd84ff1fc852cfc143231f717366c61b12e3c30c",
+   "36527b98b71785809cd6a490196dd9112fef9181",
    "support"
   ],
   "fetch/api/resources/stash-take.py": [
@@ -484695,7 +484736,7 @@
    "manual"
   ],
   "native-file-system/native_FileSystemBaseHandle-postMessage-manual.https.tentative.html": [
-   "266238c4acc269b4a29b0f849f1807172ce3dd72",
+   "e04be7df5fc7bdb00c1737c35174ee368370c43d",
    "manual"
   ],
   "native-file-system/native_FileSystemDirectoryHandle-getDirectory-manual.https.tentative-expected.txt": [
@@ -484811,7 +484852,7 @@
    "testharness"
   ],
   "native-file-system/sandboxed_FileSystemBaseHandle-postMessage.tentative.https.window.js": [
-   "e010f6599e890f0eeaffd01a4bae962a8aa8b950",
+   "f7d5776e19e50865f298877a08e0b0a463073d6c",
    "testharness"
   ],
   "native-file-system/sandboxed_FileSystemDirectoryHandle-getDirectory.tentative.https.any.js": [
@@ -510007,7 +510048,7 @@
    "support"
   ],
   "service-workers/service-worker/clients-matchall-client-types.https.html": [
-   "7dfd5ed1b87327303b94b531d51cf6cc18a20919",
+   "54f182b6202cd67cc63e159e7e2d4294fdf975ff",
    "testharness"
   ],
   "service-workers/service-worker/clients-matchall-exact-controller.https.html": [
@@ -515222,6 +515263,14 @@
    "5757d07a0999cde2b5ca8ddeb6307d632772de5f",
    "reftest"
   ],
+  "svg/extensibility/foreignObject/foreign-object-scale-scroll-ref.html": [
+   "a2217fed5d059cc819034ad7101bd4ff19856ca3",
+   "support"
+  ],
+  "svg/extensibility/foreignObject/foreign-object-scale-scroll.html": [
+   "72ce40dc5c04a647bb81dcf88020ec762c3408e1",
+   "reftest"
+  ],
   "svg/extensibility/foreignObject/foreign-object-size-ref.html": [
    "e0b17a2c4a287ee6fe339b23cc9df94de54c0bfb",
    "support"
@@ -522107,7 +522156,7 @@
    "support"
   ],
   "tools/wptrunner/wptrunner/manifestexpected.py": [
-   "65b53f0ab97b581b2b71277bd8f260f79a1afb12",
+   "335b0da5c907f649a4bec803ebc25ed7ff54faf8",
    "support"
   ],
   "tools/wptrunner/wptrunner/manifestinclude.py": [
@@ -536883,7 +536932,7 @@
    "support"
   ],
   "webxr/resources/webxr_util.js": [
-   "5f66dc9573d37630d588265f20e5b57a8175766f",
+   "dbe1585929f50089bb3e26a981b9c12b30e9fa1f",
    "support"
   ],
   "webxr/webGLCanvasContext_create_xrcompatible.https.html": [
@@ -537035,7 +537084,7 @@
    "testharness"
   ],
   "webxr/xrSession_features_deviceSupport.https.html": [
-   "d8858bd4be689bf8e4f3a3795e13fad2a2057019",
+   "1ee63bae047bd196233f5e4253baec94b6a576a9",
    "testharness"
   ],
   "webxr/xrSession_input_events_end.https.html": [
@@ -537075,7 +537124,7 @@
    "testharness"
   ],
   "webxr/xrSession_viewer_availability.https.html": [
-   "c509e5f1a2a992b9329fd55e591e37fcea2b6e91",
+   "f28a07ad8bd0f8529b791048840bf60495186a7e",
    "testharness"
   ],
   "webxr/xrSession_viewer_referenceSpace.https.html": [
@@ -538331,7 +538380,7 @@
    "support"
   ],
   "workers/modules/dedicated-worker-import-blob-url.any.js": [
-   "f51a821d1813df81187e8c78d6251f9f29cf45eb",
+   "e5d79add73661e6a814fe77ccd783f651c56319c",
    "testharness"
   ],
   "workers/modules/dedicated-worker-import-csp.html": [
@@ -538343,7 +538392,7 @@
    "testharness"
   ],
   "workers/modules/dedicated-worker-import-failure.html": [
-   "439bea888b2bac65f5de50d47c12639fd49168a4",
+   "5e8b152195a354022943ae9404bb4473d3cd0c0d",
    "testharness"
   ],
   "workers/modules/dedicated-worker-import-meta-expected.txt": [
@@ -538351,7 +538400,7 @@
    "support"
   ],
   "workers/modules/dedicated-worker-import-meta.html": [
-   "9292b0f6d8ef8f543cbdc060b64cf2826bac1ac4",
+   "4ed56e279f7d558ca5d75c6cbe969ba41b2d52dd",
    "testharness"
   ],
   "workers/modules/dedicated-worker-import-referrer.html": [
@@ -538359,7 +538408,7 @@
    "testharness"
   ],
   "workers/modules/dedicated-worker-import.any.js": [
-   "308c5e74c157da005257fd03fa9bc714c6d0eee7",
+   "d5bb6cccbe21a3050f57dc8b3378e3e04fb7b03c",
    "testharness"
   ],
   "workers/modules/dedicated-worker-options-credentials.html": [
@@ -538507,7 +538556,7 @@
    "support"
   ],
   "workers/modules/shared-worker-import-blob-url.any.js": [
-   "d9e9e34c394bc171cd497c8527b4806dfc32c595",
+   "f56c1a5525f8c46e5d06f6549b3f355c4ccb4a0a",
    "testharness"
   ],
   "workers/modules/shared-worker-import-failure.html": [
@@ -538515,7 +538564,7 @@
    "testharness"
   ],
   "workers/modules/shared-worker-import.any.js": [
-   "450d4ad422b8da33d515da9b41557f488aff8bff",
+   "15dfdde067a347b024c078578f24a5c63ae53fdd",
    "testharness"
   ],
   "workers/modules/shared-worker-options-type.html": [
diff --git a/third_party/blink/web_tests/external/wpt/2dcontext/imagebitmap/createImageBitmap-in-worker-transfer.html b/third_party/blink/web_tests/external/wpt/2dcontext/imagebitmap/createImageBitmap-in-worker-transfer.html
new file mode 100644
index 0000000..727a8a49
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/2dcontext/imagebitmap/createImageBitmap-in-worker-transfer.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>createImageBitmap in worker and transfer</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+promise_test(function(t) {
+    return new Promise(function(resolve, reject) {
+        var worker = new Worker("createImageBitmap-worker.js");
+        worker.addEventListener("message", function(evt) {
+            var bitmap = evt.data;
+            assert_equals(bitmap.width, 20);
+            assert_equals(bitmap.height, 20);
+            resolve();
+        });
+        worker.postMessage('test');
+    });
+}, 'Transfer ImageBitmap created in worker');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/2dcontext/imagebitmap/createImageBitmap-worker.js b/third_party/blink/web_tests/external/wpt/2dcontext/imagebitmap/createImageBitmap-worker.js
new file mode 100644
index 0000000..67a0904
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/2dcontext/imagebitmap/createImageBitmap-worker.js
@@ -0,0 +1,17 @@
+function makeBlob() {
+    return new Promise(function(resolve, reject) {
+        var xhr = new XMLHttpRequest();
+        xhr.open("GET", '/images/pattern.png');
+        xhr.responseType = 'blob';
+        xhr.send();
+        xhr.onload = function() {
+            resolve(xhr.response);
+        };
+    });
+}
+
+addEventListener("message", () => {
+    makeBlob().then(createImageBitmap).then(bitmap => {
+        postMessage(bitmap, [bitmap]);
+    });
+});
diff --git a/third_party/blink/web_tests/external/wpt/beacon/beacon-basic-blob-expected.txt b/third_party/blink/web_tests/external/wpt/beacon/beacon-basic-blob-expected.txt
deleted file mode 100644
index 00fd0eb9..0000000
--- a/third_party/blink/web_tests/external/wpt/beacon/beacon-basic-blob-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-This is a testharness.js-based test.
-FAIL Verify 'navigator.sendbeacon()' successfully sends for variant: EmptyBlob Failed to execute 'sendBeacon' on 'Navigator': sendBeacon() with a Blob whose type is not any of the CORS-safelisted values for the Content-Type request header is disabled temporarily. See http://crbug.com/490015 for details.
-FAIL Verify 'navigator.sendbeacon()' successfully sends for variant: SmallBlob Failed to execute 'sendBeacon' on 'Navigator': sendBeacon() with a Blob whose type is not any of the CORS-safelisted values for the Content-Type request header is disabled temporarily. See http://crbug.com/490015 for details.
-FAIL Verify 'navigator.sendbeacon()' successfully sends for variant: MediumBlob Failed to execute 'sendBeacon' on 'Navigator': sendBeacon() with a Blob whose type is not any of the CORS-safelisted values for the Content-Type request header is disabled temporarily. See http://crbug.com/490015 for details.
-FAIL Verify 'navigator.sendbeacon()' successfully sends for variant: LargeBlob Failed to execute 'sendBeacon' on 'Navigator': sendBeacon() with a Blob whose type is not any of the CORS-safelisted values for the Content-Type request header is disabled temporarily. See http://crbug.com/490015 for details.
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/beacon/beacon-basic-blobMax-expected.txt b/third_party/blink/web_tests/external/wpt/beacon/beacon-basic-blobMax-expected.txt
deleted file mode 100644
index 66c55f6..0000000
--- a/third_party/blink/web_tests/external/wpt/beacon/beacon-basic-blobMax-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Verify 'navigator.sendbeacon()' successfully sends for variant: MaxBlob Failed to execute 'sendBeacon' on 'Navigator': sendBeacon() with a Blob whose type is not any of the CORS-safelisted values for the Content-Type request header is disabled temporarily. See http://crbug.com/490015 for details.
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/beacon/beacon-cors.sub.window-expected.txt b/third_party/blink/web_tests/external/wpt/beacon/beacon-cors.sub.window-expected.txt
deleted file mode 100644
index 7d9f711..0000000
--- a/third_party/blink/web_tests/external/wpt/beacon/beacon-cors.sub.window-expected.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-This is a testharness.js-based test.
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: NoData-CORS-ALLOW
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: NullData-CORS-ALLOW
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: UndefinedData-CORS-ALLOW
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: SmallString-CORS-ALLOW
-FAIL Verify 'navigator.sendbeacon()' successfully sends for variant: SmallBlob-CORS-ALLOW Failed to execute 'sendBeacon' on 'Navigator': sendBeacon() with a Blob whose type is not any of the CORS-safelisted values for the Content-Type request header is disabled temporarily. See http://crbug.com/490015 for details.
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: SmallBufferSource-CORS-ALLOW
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: SmallFormData-CORS-ALLOW
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: SmallSafeContentTypeEncoded-CORS-ALLOW
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: SmallSafeContentTypeForm-CORS-ALLOW
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: SmallSafeContentTypeText-CORS-ALLOW
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: NoData-CORS-FORBID
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: NullData-CORS-FORBID
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: UndefinedData-CORS-FORBID
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: SmallString-CORS-FORBID
-FAIL Verify 'navigator.sendbeacon()' successfully sends for variant: SmallBlob-CORS-FORBID Failed to execute 'sendBeacon' on 'Navigator': sendBeacon() with a Blob whose type is not any of the CORS-safelisted values for the Content-Type request header is disabled temporarily. See http://crbug.com/490015 for details.
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: SmallBufferSource-CORS-FORBID
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: SmallFormData-CORS-FORBID
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: SmallSafeContentTypeEncoded-CORS-FORBID
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: SmallSafeContentTypeForm-CORS-FORBID
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: SmallSafeContentTypeText-CORS-FORBID
-FAIL Verify 'navigator.sendbeacon()' successfully sends for variant: SmallCORSContentTypeText-PREFLIGHT-ALLOW Failed to execute 'sendBeacon' on 'Navigator': sendBeacon() with a Blob whose type is not any of the CORS-safelisted values for the Content-Type request header is disabled temporarily. See http://crbug.com/490015 for details.
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/beacon/beacon-navigate-expected.txt b/third_party/blink/web_tests/external/wpt/beacon/beacon-navigate-expected.txt
deleted file mode 100644
index 36c8b10..0000000
--- a/third_party/blink/web_tests/external/wpt/beacon/beacon-navigate-expected.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-This is a testharness.js-based test.
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: NoData-NAVIGATE
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: NullData-NAVIGATE
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: UndefinedData-NAVIGATE
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: SmallString-NAVIGATE
-FAIL Verify 'navigator.sendbeacon()' successfully sends for variant: SmallBlob-NAVIGATE Failed to execute 'sendBeacon' on 'Navigator': sendBeacon() with a Blob whose type is not any of the CORS-safelisted values for the Content-Type request header is disabled temporarily. See http://crbug.com/490015 for details.
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: SmallBufferSource-NAVIGATE
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: SmallFormData-NAVIGATE
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: SmallSafeContentTypeEncoded-NAVIGATE
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: SmallSafeContentTypeForm-NAVIGATE
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: SmallSafeContentTypeText-NAVIGATE
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/beacon/beacon-redirect.window-expected.txt b/third_party/blink/web_tests/external/wpt/beacon/beacon-redirect.window-expected.txt
deleted file mode 100644
index e38d0c2..0000000
--- a/third_party/blink/web_tests/external/wpt/beacon/beacon-redirect.window-expected.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-This is a testharness.js-based test.
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: NoData-307
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: NullData-307
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: UndefinedData-307
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: SmallString-307
-FAIL Verify 'navigator.sendbeacon()' successfully sends for variant: SmallBlob-307 Failed to execute 'sendBeacon' on 'Navigator': sendBeacon() with a Blob whose type is not any of the CORS-safelisted values for the Content-Type request header is disabled temporarily. See http://crbug.com/490015 for details.
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: SmallBufferSource-307
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: SmallFormData-307
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: SmallSafeContentTypeEncoded-307
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: SmallSafeContentTypeForm-307
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: SmallSafeContentTypeText-307
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: NoData-308
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: NullData-308
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: UndefinedData-308
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: SmallString-308
-FAIL Verify 'navigator.sendbeacon()' successfully sends for variant: SmallBlob-308 Failed to execute 'sendBeacon' on 'Navigator': sendBeacon() with a Blob whose type is not any of the CORS-safelisted values for the Content-Type request header is disabled temporarily. See http://crbug.com/490015 for details.
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: SmallBufferSource-308
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: SmallFormData-308
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: SmallSafeContentTypeEncoded-308
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: SmallSafeContentTypeForm-308
-PASS Verify 'navigator.sendbeacon()' successfully sends for variant: SmallSafeContentTypeText-308
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/cookies/samesite/window-open-reload.https.html b/third_party/blink/web_tests/external/wpt/cookies/samesite/window-open-reload.https.html
index 9c30bd5..ee2091b 100644
--- a/third_party/blink/web_tests/external/wpt/cookies/samesite/window-open-reload.https.html
+++ b/third_party/blink/web_tests/external/wpt/cookies/samesite/window-open-reload.https.html
@@ -34,7 +34,7 @@
             window.addEventListener("message", msgHandler);
 
             if (!w)
-              reject("Popup could not be opened (did you whitelist the test site in your popup blocker?).");
+              reject("Popup could not be opened (did you allow the test site in your popup blocker?).");
           });
         });
     }, title);
diff --git a/third_party/blink/web_tests/external/wpt/cookies/samesite/window-open.https.html b/third_party/blink/web_tests/external/wpt/cookies/samesite/window-open.https.html
index fe2318a..d685eb4 100644
--- a/third_party/blink/web_tests/external/wpt/cookies/samesite/window-open.https.html
+++ b/third_party/blink/web_tests/external/wpt/cookies/samesite/window-open.https.html
@@ -28,7 +28,7 @@
             window.addEventListener("message", msgHandler);
 
             if (!w)
-              reject("Popup could not be opened (did you whitelist the test site in your popup blocker?).");
+              reject("Popup could not be opened (did you allow the test site in your popup blocker?).");
           });
         });
     }, title);
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/basic/keepalive.html b/third_party/blink/web_tests/external/wpt/fetch/api/basic/keepalive.html
index 5316410..447ef2d 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/basic/keepalive.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/basic/keepalive.html
@@ -7,25 +7,85 @@
 <script src="/common/get-host-info.sub.js"></script>
 <body>
 <script>
+function getUrl(origin1, origin2, withHeaders) {
+  const frameOrigin = host_info.HTTP_NOTSAMESITE_ORIGIN;
+  return `${frameOrigin}/fetch/api/resources/keepalive-iframe.html?` +
+    `origin1=${origin1}&` +
+    `origin2=${origin2}&` +
+    (withHeaders ? `with-headers` : ``);
+}
+
+async function getToken() {
+  return new Promise((resolve) => {
+    window.addEventListener('message', (event) => {
+      resolve(event.data);
+    }, {once: true});
+  });
+}
+
+async function queryToken(token) {
+  const response = await fetch(`../resources/stash-take.py?key=${token}`);
+  const json = await response.json();
+  return json;
+}
+
+// In order to parallelize the work, we are going to have an async_test
+// for the rest of the work. Note that we want the serialized behavior
+// for the steps so far, so we don't want to make the entire test case
+// an async_test.
+function checkToken(testName, token) {
+  async_test((test) => {
+    new Promise((resolve) => test.step_timeout(resolve, 1000)).then(() => {
+      return queryToken(token);
+    }).then((result) => {
+      assert_equals(result, 'on');
+    }).then(() => {
+      test.done();
+    }).catch(test.step_func((e) => {
+      assert_unreached(e);
+    }));
+  }, testName);
+}
+
 const host_info = get_host_info();
 promise_test(async (test) => {
   const iframe = document.createElement('iframe');
-  iframe.src = host_info.HTTP_REMOTE_ORIGIN +
-    '/fetch/api/resources/keepalive-iframe.html';
+  iframe.src = getUrl('', '', false);
   document.body.appendChild(iframe);
-  const uuid_promise = new Promise((resolve) => {
-    window.addEventListener('message', (event) => {
-      resolve(event.data);
-    });
-  });
+  const tokenPromise = getToken();
   await (new Promise((resolve) => iframe.addEventListener('load', resolve)));
-  const uuid = await uuid_promise;
+  const token = await tokenPromise;
   iframe.remove();
-  await (new Promise((resolve) => test.step_timeout(resolve, 1000)));
-  const response = await fetch(`../resources/stash-take.py?key=${uuid}`);
-  const json = await response.json();
-  assert_equals(json, 'on');
-});
+
+  checkToken('same-origin', token);
+}, 'same-origin; setting up');
+
+promise_test(async (test) => {
+  const iframe = document.createElement('iframe');
+  iframe.src = getUrl(host_info.HTTP_REMOTE_ORIGIN,
+                      host_info.HTTP_REMOTE_ORIGIN_WITH_DIFFERENT_PORT, false);
+  document.body.appendChild(iframe);
+  const tokenPromise = getToken();
+  await (new Promise((resolve) => iframe.addEventListener('load', resolve)));
+  const token = await tokenPromise;
+  iframe.remove();
+
+  checkToken('cross-origin redirect', token);
+}, 'cross-origin redirect; setting up');
+
+promise_test(async (test) => {
+  const iframe = document.createElement('iframe');
+  iframe.src = getUrl(host_info.HTTP_REMOTE_ORIGIN,
+                      host_info.HTTP_REMOTE_ORIGIN_WITH_DIFFERENT_PORT, true);
+  document.body.appendChild(iframe);
+  const tokenPromise = getToken();
+  await (new Promise((resolve) => iframe.addEventListener('load', resolve)));
+  const token = await tokenPromise;
+  iframe.remove();
+
+  checkToken('cross-origin redirect with preflight', token);
+}, 'cross-origin redirect with preflight; setting up');
+
 </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/resources/keepalive-iframe.html b/third_party/blink/web_tests/external/wpt/fetch/api/resources/keepalive-iframe.html
index 742309ab..47de0da 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/resources/keepalive-iframe.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/resources/keepalive-iframe.html
@@ -2,16 +2,24 @@
 <html>
 <meta charset="utf-8">
 <script src="/common/utils.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
 <script>
-const uuid = token();
-const URL =
-    `../resources/redirect.py?` +
-    `delay=100&` +
-    `location=../resources/stash-put.py?key=${uuid}%26value=on`;
+const SEARCH_PARAMS = new URL(location.href).searchParams;
+const ORIGIN1 = SEARCH_PARAMS.get('origin1') || '';
+const ORIGIN2 = SEARCH_PARAMS.get('origin2') || '';
+const WITH_HEADERS = !!SEARCH_PARAMS.has('with-headers');
+const TOKEN = token();
+
+const url =
+    `${ORIGIN1}/fetch/api/resources/redirect.py?` +
+    `delay=500&` +
+    `allow_headers=foo&` +
+    `location=${ORIGIN2}/fetch/api/resources/stash-put.py?key=${TOKEN}%26value=on`;
 
 addEventListener('load', () => {
-  let p = fetch(URL, {keepalive: true});
-  window.parent.postMessage(uuid, '*');
+  const headers = WITH_HEADERS ? {'foo': 'bar'} : undefined;
+  let p = fetch(url, {keepalive: true, headers});
+  window.parent.postMessage(TOKEN, '*');
 });
 </script>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/resources/stash-put.py b/third_party/blink/web_tests/external/wpt/fetch/api/resources/stash-put.py
index dd84ff1..36527b98 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/resources/stash-put.py
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/resources/stash-put.py
@@ -1,4 +1,11 @@
 def main(request, response):
+    if request.method == 'OPTIONS':
+        # CORS preflight
+        response.headers.set('Access-Control-Allow-Origin', '*')
+        response.headers.set('Access-Control-Allow-Methods', '*')
+        response.headers.set('Access-Control-Allow-Headers', '*')
+        return 'done'
+
     url_dir = '/'.join(request.url_parts.path.split('/')[:-1]) + '/'
     key = request.GET.first("key")
     value = request.GET.first("value")
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/clients-matchall-client-types.https.html b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/clients-matchall-client-types.https.html
index 7dfd5ed1..54f182b 100644
--- a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/clients-matchall-client-types.https.html
+++ b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/clients-matchall-client-types.https.html
@@ -4,117 +4,89 @@
 <script src="/resources/testharnessreport.js"></script>
 <script src="resources/test-helpers.sub.js"></script>
 <script>
-var scope = 'resources/clients-matchall-client-types';
-var iframe_url = scope + '-iframe.html';
-var shared_worker_url = scope + '-shared-worker.js';
-var dedicated_worker_url = scope + '-dedicated-worker.js';
+const scope = 'resources/clients-matchall-client-types';
+const iframe_url = scope + '-iframe.html';
+const shared_worker_url = scope + '-shared-worker.js';
+const dedicated_worker_url = scope + '-dedicated-worker.js';
 
 /* visibilityState, focused, url, type, frameType */
-var expected_only_window = [
+const expected_only_window = [
     ['visible', true, new URL(iframe_url, location).href, 'window', 'nested']
 ];
-var expected_only_shared_worker = [
+const expected_only_shared_worker = [
     [undefined, undefined, new URL(shared_worker_url, location).href, 'sharedworker', 'none']
 ];
-var expected_only_dedicated_worker = [
+const expected_only_dedicated_worker = [
     [undefined, undefined, new URL(dedicated_worker_url, location).href, 'worker', 'none']
 ];
 
 // These are explicitly sorted by URL in the service worker script.
-var expected_all_clients = [
+const expected_all_clients = [
     expected_only_dedicated_worker[0],
     expected_only_window[0],
     expected_only_shared_worker[0],
 ];
 
-function test_matchall(frame, expected, query_options) {
+async function test_matchall(frame, expected, query_options) {
   // Make sure the frame gets focus.
   frame.focus();
-  return new Promise(function(resolve, reject) {
-    var channel = new MessageChannel();
-    channel.port1.onmessage = function(e) { resolve(e.data); };
+  const data = await new Promise(resolve => {
+    const channel = new MessageChannel();
+    channel.port1.onmessage = e => resolve(e.data);
     frame.contentWindow.navigator.serviceWorker.controller.postMessage(
         {port:channel.port2, options:query_options},
         [channel.port2]);
-  }).then(function(data) {
-    if (typeof data === 'string') {
-      throw new Error(data);
-    }
-
-    assert_equals(data.length, expected.length, 'result count');
-
-    for (var i = 0; i < data.length; ++i) {
-      assert_array_equals(data[i], expected[i]);
-    }
   });
+
+  if (typeof data === 'string') {
+    throw new Error(data);
+  }
+
+  assert_equals(data.length, expected.length, 'result count');
+
+  for (let i = 0; i < data.length; ++i) {
+    assert_array_equals(data[i], expected[i]);
+  }
 }
 
-promise_test(function(t) {
-    var frame;
-    return service_worker_unregister_and_register(
-        t, 'resources/clients-matchall-worker.js', scope)
-      .then(function(registration) {
-          t.add_cleanup(function() {
-              return service_worker_unregister(t, scope);
-            });
+promise_test(async t => {
+  const registration = await service_worker_unregister_and_register(
+      t, 'resources/clients-matchall-worker.js', scope);
+  t.add_cleanup(_ => registration.unregister());
+  await wait_for_state(t, registration.installing, 'activated');
+  const frame = await with_iframe(iframe_url);
+  t.add_cleanup(_ => frame.remove());
+  await test_matchall(frame, expected_only_window, {});
+  await test_matchall(frame, expected_only_window, {type:'window'});
+}, 'Verify matchAll() with window client type');
 
-          return wait_for_state(t, registration.installing, 'activated');
-        })
-      .then(function() { return with_iframe(iframe_url); })
-      .then(function(f) {
-          frame = f;
-          t.add_cleanup(function() { frame.remove(); });
-          return test_matchall(frame, expected_only_window, {});
-        })
-      .then(function() {
-          return test_matchall(frame, expected_only_window, {type:'window'});
-        });
-  }, 'Verify matchAll() with window client type');
+promise_test(async t => {
+  const registration = await service_worker_unregister_and_register(
+      t, 'resources/clients-matchall-worker.js', scope);
+  t.add_cleanup(_ => registration.unregister());
+  await wait_for_state(t, registration.installing, 'activated');
+  const frame = await with_iframe(iframe_url);
+  t.add_cleanup(_ => frame.remove());
 
-promise_test(function(t) {
-    var frame;
-    return service_worker_unregister_and_register(
-        t, 'resources/clients-matchall-worker.js', scope)
-      .then(function(registration) {
-          t.add_cleanup(function() {
-              return service_worker_unregister(t, scope);
-            });
+  // Set up worker clients.
+  const shared_worker = await new Promise((resolve, reject) => {
+    const w = new SharedWorker(shared_worker_url);
+    w.onerror = e => reject(e.message);
+    w.port.onmessage = _ => resolve(w);
+  });
+  const dedicated_worker = await new Promise((resolve, reject) => {
+    const w = new Worker(dedicated_worker_url);
+    w.onerror = e => reject(e.message);
+    w.onmessage = _ => resolve(w);
+    w.postMessage('Start');
+  });
 
-          return wait_for_state(t, registration.installing, 'activated');
-        })
-      .then(function() { return with_iframe(iframe_url); })
-      .then(function(f) {
-          frame = f;
-          t.add_cleanup(function() { frame.remove(); });
-          return new Promise(function(resolve, reject) {
-              var w = new SharedWorker(shared_worker_url);
-              w.port.onmessage = resolve;
-            });
-        })
-      .then(function() {
-          return new Promise(function(resolve, reject) {
-              var w = new Worker(dedicated_worker_url);
-              w.onmessage = resolve;
-              w.postMessage('Start');
-            });
-        })
-      .then(function() {
-          return test_matchall(frame, expected_only_window, {});
-        })
-      .then(function() {
-          return test_matchall(frame, expected_only_window, {type:'window'});
-        })
-      .then(function() {
-          return test_matchall(frame, expected_only_shared_worker,
-                               {type:'sharedworker'});
-        })
-      .then(function() {
-          return test_matchall(frame, expected_only_dedicated_worker,
-                               {type:'worker'});
-        })
-      .then(function() {
-          return test_matchall(frame, expected_all_clients, {type:'all'});
-        });
+  await test_matchall(frame, expected_only_window, {});
+  await test_matchall(frame, expected_only_window, {type:'window'});
+  await test_matchall(frame, expected_only_shared_worker,
+                      {type:'sharedworker'});
+  await test_matchall(frame, expected_only_dedicated_worker, {type:'worker'});
+  await test_matchall(frame, expected_all_clients, {type:'all'});
 }, 'Verify matchAll() with {window, sharedworker, worker} client types');
 
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/svg/extensibility/foreignObject/foreign-object-scale-scroll-ref.html b/third_party/blink/web_tests/external/wpt/svg/extensibility/foreignObject/foreign-object-scale-scroll-ref.html
new file mode 100644
index 0000000..a2217fe
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/svg/extensibility/foreignObject/foreign-object-scale-scroll-ref.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<svg width="400" height="400">
+  <foreignObject x="200" y="200" width="200" height="200">
+    <div style="width: 100px; height: 100px; transform: scale(2); transform-origin: 0 0; overflow: scroll">
+      <div style="width: 1000px; height: 1000px; background: blue"></div>
+    </div>
+  </foreignObject>
+</svg>
diff --git a/third_party/blink/web_tests/external/wpt/svg/extensibility/foreignObject/foreign-object-scale-scroll.html b/third_party/blink/web_tests/external/wpt/svg/extensibility/foreignObject/foreign-object-scale-scroll.html
new file mode 100644
index 0000000..72ce40dc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/svg/extensibility/foreignObject/foreign-object-scale-scroll.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<title>foreignObject with scale transform and overflow:scroll</title>
+<link rel="help" href="https://svgwg.org/svg2-draft/single-page.html#embedded-ForeignObjectElement"/>
+<link rel="match" href="foreign-object-scale-scroll-ref.html">
+<svg width="400" height="400">
+  <foreignObject x="100" y="100" transform="scale(2)" width="100" height="100" style="overflow: scroll">
+    <div style="width: 1000px; height: 1000px; background: blue"></div>
+  </foreignObject>
+</svg>
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/manifestexpected.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/manifestexpected.py
index 65b53f0..335b0da5 100644
--- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/manifestexpected.py
+++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/manifestexpected.py
@@ -1,7 +1,8 @@
 import os
-from six.moves.urllib.parse import urljoin
 from collections import deque
-from six import text_type
+from six import string_types, text_type
+from six.moves.urllib.parse import urljoin
+
 
 from .wptmanifest.backends import static
 from .wptmanifest.backends.base import ManifestItem
@@ -47,7 +48,7 @@
     """List property"""
     try:
         list_prop = node.get(name)
-        if isinstance(list_prop, basestring):
+        if isinstance(list_prop, string_types):
             return [list_prop]
         return list(list_prop)
     except KeyError:
diff --git a/third_party/blink/web_tests/external/wpt/webxr/resources/webxr_util.js b/third_party/blink/web_tests/external/wpt/webxr/resources/webxr_util.js
index 5f66dc9..dbe1585 100644
--- a/third_party/blink/web_tests/external/wpt/webxr/resources/webxr_util.js
+++ b/third_party/blink/web_tests/external/wpt/webxr/resources/webxr_util.js
@@ -101,6 +101,18 @@
       properties);
 }
 
+
+// This function wraps the provided function in a
+// simulateUserActivation() call, and resolves the promise with the
+// result of func(), or an error if one is thrown
+function promise_simulate_user_activation(func) {
+  return new Promise((resolve, reject) => {
+    navigator.xr.test.simulateUserActivation(() => {
+      try { let a = func(); resolve(a); } catch(e) { reject(e); }
+    });
+  });
+}
+
 // This functions calls a callback with each API object as specified
 // by https://immersive-web.github.io/webxr/spec/latest/, allowing
 // checks to be made on all ojects.
diff --git a/third_party/blink/web_tests/external/wpt/webxr/xrSession_features_deviceSupport.https.html b/third_party/blink/web_tests/external/wpt/webxr/xrSession_features_deviceSupport.https.html
index d8858bd..1ee63ba 100644
--- a/third_party/blink/web_tests/external/wpt/webxr/xrSession_features_deviceSupport.https.html
+++ b/third_party/blink/web_tests/external/wpt/webxr/xrSession_features_deviceSupport.https.html
@@ -21,6 +21,7 @@
     "local-floor"]
   };
 
+
   xr_promise_test(testName,
     (t) => {
     function session_resolves(sessionMode, sessionInit) {
@@ -31,34 +32,28 @@
     }
 
     return navigator.xr.test.simulateDeviceConnection(fakeDeviceInitParams)
-      .then((controller) => new Promise((resolve, reject) => {
-        navigator.xr.test.simulateUserActivation(() => {
+      .then((controller) =>
+        promise_simulate_user_activation(() => {
           // Attempting to request required features that aren't supported by
           // the device should reject.
-          promise_rejects(t, "NotSupportedError",
+
+          return promise_rejects(t, "NotSupportedError",
             navigator.xr.requestSession("immersive-vr", {
               requiredFeatures: ['bounded-floor']
             }))
-          .then(() => {
+        }).then(() => promise_simulate_user_activation(() => {
             // Attempting to request with an unsupported feature as optional
             // should succeed
             return session_resolves("immersive-vr", {
               optionalFeatures: ['bounded-floor']
             });
+        })).then(() => promise_simulate_user_activation(() => {
+          // Attempting to request with supported features only should succeed.
+          return session_resolves("immersive-vr", {
+            requiredFeatures: ['local', 'local-floor']
           })
-          .then(() => {
-            // Attempting to request with supported features only should succeed.
-            return session_resolves("immersive-vr", {
-              requiredFeatures: ['local', 'local-floor']
-            })
-          .then(() => {
-            resolve();
-          }).catch((err) => {
-            reject(err);
-          });;
-          });
-        });
-      }));
+        }))
+      );
   });
 
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/webxr/xrSession_viewer_availability.https.html b/third_party/blink/web_tests/external/wpt/webxr/xrSession_viewer_availability.https.html
index c509e5f..f28a07a 100644
--- a/third_party/blink/web_tests/external/wpt/webxr/xrSession_viewer_availability.https.html
+++ b/third_party/blink/web_tests/external/wpt/webxr/xrSession_viewer_availability.https.html
@@ -24,14 +24,6 @@
         .then(session => session.end()));
     }
 
-    function simulate_user_activation(func) {
-      return new Promise((resolve, reject) => {
-        navigator.xr.test.simulateUserActivation(() => {
-          try { resolve(func()); } catch(e) { reject(e); }
-        });
-      });
-    }
-
     return session_resolves('inline', {
       // RequestSession with 'viewer' as a required featre should succeed, even
       // without user activation.
@@ -62,14 +54,14 @@
         optionalFeatures: ['local']
       });
     })
-    .then(() => simulate_user_activation(() => {
+    .then(() => promise_simulate_user_activation(() => {
       // RequestSession with unsupported optional features should succeed.
       return session_resolves('inline', {
         requiredFeatures: ['viewer'],
         optionalFeatures: ['local']
       })
     }))
-    .then(() => simulate_user_activation(() => {
+    .then(() => promise_simulate_user_activation(() => {
       // Request with unsupported required features should reject.
       return session_rejects("NotSupportedError", 'inline', {
           requiredFeatures: ['local']
diff --git a/third_party/blink/web_tests/external/wpt/workers/modules/dedicated-worker-import-blob-url.any.js b/third_party/blink/web_tests/external/wpt/workers/modules/dedicated-worker-import-blob-url.any.js
index f51a821d..e5d79ad 100644
--- a/third_party/blink/web_tests/external/wpt/workers/modules/dedicated-worker-import-blob-url.any.js
+++ b/third_party/blink/web_tests/external/wpt/workers/modules/dedicated-worker-import-blob-url.any.js
@@ -13,7 +13,11 @@
     worker.postMessage('Send message for tests from main script.');
     const msgEvent = await new Promise((resolve, reject) => {
       worker.onmessage = resolve;
-      worker.onerror = (error) => reject(error && error.message);
+      worker.onerror = error => {
+        const msg = error instanceof ErrorEvent ? error.message
+                                                : 'unknown error';
+        reject(msg);
+      };
     });
     assert_array_equals(msgEvent.data, testCase.expectation);
   }, testCase.description);
diff --git a/third_party/blink/web_tests/external/wpt/workers/modules/dedicated-worker-import-failure.html b/third_party/blink/web_tests/external/wpt/workers/modules/dedicated-worker-import-failure.html
index 439bea8..5e8b152 100644
--- a/third_party/blink/web_tests/external/wpt/workers/modules/dedicated-worker-import-failure.html
+++ b/third_party/blink/web_tests/external/wpt/workers/modules/dedicated-worker-import-failure.html
@@ -38,7 +38,11 @@
   worker.postMessage(scriptURL);
   const msg_event = await new Promise((resolve, reject) => {
     worker.onmessage = resolve;
-    worker.onerror = (error) => reject(error && error.message);
+    worker.onerror = error => {
+      const msg = error instanceof ErrorEvent ? error.message
+                                              : 'unknown error';
+      reject(msg);
+    };
   });
   assert_equals(msg_event.data, 'TypeError');
 }, 'Dynamic import for non-existent script should throw an exception.');
diff --git a/third_party/blink/web_tests/external/wpt/workers/modules/dedicated-worker-import-meta.html b/third_party/blink/web_tests/external/wpt/workers/modules/dedicated-worker-import-meta.html
index 9292b0f..4ed56e2 100644
--- a/third_party/blink/web_tests/external/wpt/workers/modules/dedicated-worker-import-meta.html
+++ b/third_party/blink/web_tests/external/wpt/workers/modules/dedicated-worker-import-meta.html
@@ -9,7 +9,11 @@
   const worker = new Worker(script_url, { type: 'module' });
   return new Promise((resolve, reject) => {
         worker.onmessage = resolve;
-        worker.onerror = (error) => reject(error && error.message);
+        worker.onerror = error => {
+          const msg = error instanceof ErrorEvent ? error.message
+                                                  : 'unknown error';
+          reject(msg);
+        };
       })
       .then(msg_event => assert_true(msg_event.data.endsWith(script_url)));
 }, 'Test import.meta.url on the top-level module script.');
@@ -21,7 +25,11 @@
   worker.postMessage('./' + script_url);
   return new Promise((resolve, reject) => {
         worker.onmessage = resolve;
-        worker.onerror = (error) => reject(error && error.message);
+        worker.onerror = error => {
+          const msg = error instanceof ErrorEvent ? error.message
+                                                  : 'unknown error';
+          reject(msg);
+        };
       })
       .then(msg_event => assert_true(msg_event.data.endsWith(script_url)));
 }, 'Test import.meta.url on the imported module script.');
@@ -34,7 +42,11 @@
 
   return new Promise((resolve, reject) => {
         worker.onmessage = resolve;
-        worker.onerror = (error) => reject(error && error.message);
+        worker.onerror = error => {
+          const msg = error instanceof ErrorEvent ? error.message
+                                                  : 'unknown error';
+          reject(msg);
+        };
       })
       .then(msg_event => assert_true(msg_event.data.endsWith(script_url)))
       .then(() => {
diff --git a/third_party/blink/web_tests/external/wpt/workers/modules/dedicated-worker-import.any.js b/third_party/blink/web_tests/external/wpt/workers/modules/dedicated-worker-import.any.js
index 308c5e74..d5bb6cc 100644
--- a/third_party/blink/web_tests/external/wpt/workers/modules/dedicated-worker-import.any.js
+++ b/third_party/blink/web_tests/external/wpt/workers/modules/dedicated-worker-import.any.js
@@ -9,7 +9,11 @@
     worker.postMessage('Send message for tests from main script.');
     const msgEvent = await new Promise((resolve, reject) => {
       worker.onmessage = resolve;
-      worker.onerror = (error) => reject(error && error.message);
+      worker.onerror = error => {
+        const msg = error instanceof ErrorEvent ? error.message
+                                                : 'unknown error';
+        reject(msg);
+      };
     });
     assert_array_equals(msgEvent.data, testCase.expectation);
   }, testCase.description);
diff --git a/third_party/blink/web_tests/external/wpt/workers/modules/shared-worker-import-blob-url.any.js b/third_party/blink/web_tests/external/wpt/workers/modules/shared-worker-import-blob-url.any.js
index d9e9e34..f56c1a5 100644
--- a/third_party/blink/web_tests/external/wpt/workers/modules/shared-worker-import-blob-url.any.js
+++ b/third_party/blink/web_tests/external/wpt/workers/modules/shared-worker-import-blob-url.any.js
@@ -14,7 +14,11 @@
     worker.port.postMessage('Send message for tests from main script.');
     const msgEvent = await new Promise((resolve, reject) => {
       worker.port.onmessage = resolve;
-      worker.onerror = (error) => reject(error && error.message);
+      worker.onerror = error => {
+        const msg = error instanceof ErrorEvent ? error.message
+                                                : 'unknown error';
+        reject(msg);
+      };
     });
     assert_array_equals(msgEvent.data, testCase.expectation);
   }, testCase.description);
diff --git a/third_party/blink/web_tests/external/wpt/workers/modules/shared-worker-import.any.js b/third_party/blink/web_tests/external/wpt/workers/modules/shared-worker-import.any.js
index 450d4ad..15dfdde 100644
--- a/third_party/blink/web_tests/external/wpt/workers/modules/shared-worker-import.any.js
+++ b/third_party/blink/web_tests/external/wpt/workers/modules/shared-worker-import.any.js
@@ -10,7 +10,11 @@
     worker.port.postMessage('Send message for tests from main script.');
     const msgEvent = await new Promise((resolve, reject) => {
       worker.port.onmessage = resolve;
-      worker.onerror = (error) => reject(error && error.message);
+      worker.onerror = error => {
+        const msg = error instanceof ErrorEvent ? error.message
+                                                : 'unknown error';
+        reject(msg);
+      };
     });
     assert_array_equals(msgEvent.data, testCase.expectation);
   }, testCase.description);
diff --git a/third_party/blink/web_tests/http/tests/devtools/application-panel/storage-view-reports-quota-expected.txt b/third_party/blink/web_tests/http/tests/devtools/application-panel/storage-view-reports-quota-expected.txt
index 4ff40ac..99f1c96 100644
--- a/third_party/blink/web_tests/http/tests/devtools/application-panel/storage-view-reports-quota-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/application-panel/storage-view-reports-quota-expected.txt
@@ -7,10 +7,10 @@
 Total: 0 B
 
 Running: Now with data
--- KB used out of -- storage quota. 
+-- kB used out of -- storage quota. 
 Usage breakdown:
-IndexedDB: --.- KB
-Total: --.- KB
+IndexedDB: --.- kB
+Total: --.- kB
 
 Running: Clear again with ActionDelegate
 -- B used out of -- storage quota. 
diff --git a/third_party/blink/web_tests/http/tests/devtools/application-panel/storage-view-reports-quota.js b/third_party/blink/web_tests/http/tests/devtools/application-panel/storage-view-reports-quota.js
index 58da155..b53663f 100644
--- a/third_party/blink/web_tests/http/tests/devtools/application-panel/storage-view-reports-quota.js
+++ b/third_party/blink/web_tests/http/tests/devtools/application-panel/storage-view-reports-quota.js
@@ -39,7 +39,7 @@
     // Quota will vary between setups, rather strip it altogether
     var clean = view._quotaRow.innerHTML.replace(/\&nbsp;/g, ' ');
     // Clean usage value because it's platform-dependent.
-    var quotaStripped = clean.replace(/[\d.]+ (K?B used out of) \d+ .?B([^\d]*)/, '-- $1 --$2');
+    var quotaStripped = clean.replace(/[\d.]+ (k?B used out of) \d+ .?B([^\d]*)/, '-- $1 --$2');
     TestRunner.addResult(quotaStripped);
 
     TestRunner.addResult('Usage breakdown:');
@@ -53,7 +53,7 @@
           typeUsage = children[j].textContent + typeUsage;
         if (children[j].classList.contains('pie-chart-size')) {
           // Clean usage value because it's platform-dependent.
-          var cleanedValue = children[j].textContent.replace(/\d+.\d\sKB/, '--.- KB');
+          var cleanedValue = children[j].textContent.replace(/\d+.\d\skB/, '--.- kB');
           typeUsage = typeUsage + cleanedValue;
         }
       }
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/edit-value-url-with-color.js b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/edit-value-url-with-color.js
index 1740ebb..970e9c22 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/edit-value-url-with-color.js
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/styles-1/edit-value-url-with-color.js
@@ -23,7 +23,7 @@
   var maxIndex = 11;
   var idIndex = 1;
 
-  Common.Color.detectColorFormat = function() {
+  Common.Color.detectColorFormat = Common.Settings.detectColorFormat = function() {
     return Common.Color.Format.RGB;
   };
 
diff --git a/third_party/blink/web_tests/http/tests/fetch/chromium/keepalive-preflight.html b/third_party/blink/web_tests/http/tests/fetch/chromium/keepalive-preflight.html
deleted file mode 100644
index 2da14ff..0000000
--- a/third_party/blink/web_tests/http/tests/fetch/chromium/keepalive-preflight.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!doctype html>
-<html>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script>
-promise_test((t) => {
-    const method = 'X';
-    const keepalive = true;
-    return promise_rejects(t, TypeError(), fetch('/', {method, keepalive}),
-        'keepalive with non-simple request');
-  }, 'keepalive: we do not support non-simple requests at this time');
-</script>
-</html>
diff --git a/third_party/blink/web_tests/http/tests/sendbeacon/beacon-blob-with-non-simple-type.html b/third_party/blink/web_tests/http/tests/sendbeacon/beacon-blob-with-non-simple-type.html
index 04fad8f..c80801c 100644
--- a/third_party/blink/web_tests/http/tests/sendbeacon/beacon-blob-with-non-simple-type.html
+++ b/third_party/blink/web_tests/http/tests/sendbeacon/beacon-blob-with-non-simple-type.html
@@ -3,12 +3,7 @@
 <script src="/js-test-resources/testharnessreport.js"></script>
 <script>
 test(() => {
-  assert_throws(
-      'SecurityError',
-      () => {
-        navigator.sendBeacon("/",
-                             new Blob(["X"], {type: "image/png"}));
-      });
+  assert_true(navigator.sendBeacon("/", new Blob(["X"], {type: "image/png"})));
 }, "navigator.sendBeacon() to a cross-origin target with a Blob body with " +
-    "non-simple type should throw.");
+   "non-simple type should not throw.");
 </script>
diff --git a/third_party/blink/web_tests/http/tests/wasm/wasm_downgrade_test.html b/third_party/blink/web_tests/http/tests/wasm/wasm_downgrade_test.html
deleted file mode 100644
index 6169c55d..0000000
--- a/third_party/blink/web_tests/http/tests/wasm/wasm_downgrade_test.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<!DOCTYPE html>
-<script src="../../../resources/testharness.js"></script>
-<script src="../../../resources/testharnessreport.js"></script>
-<script src="../resources/get-host-info.js"></script>
-<script src="resources/load_wasm.js"></script>
-<script src="wasm_downgrade_test.js"></script>
-<script>
-  promise_test(TestIncompatibleDowngrade, "incompatible downgrade");
-</script>
diff --git a/third_party/blink/web_tests/http/tests/wasm/wasm_downgrade_test.js b/third_party/blink/web_tests/http/tests/wasm/wasm_downgrade_test.js
deleted file mode 100644
index a66e4f8..0000000
--- a/third_party/blink/web_tests/http/tests/wasm/wasm_downgrade_test.js
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-function ascii(a) { return a.charCodeAt(0); }
-
-function findStartOfWasmHeader(byteView) {
-  for (var i = 0; i < byteView.length - 2; ++i) {
-    if (byteView[i] === ascii('a') &&
-        byteView[i+1] === ascii('s') &&
-        byteView[i+2] === ascii('m')) {
-      return i;
-    }
-  }
-  return -1;
-}
-
-function TestIncompatibleDowngrade() {
-  return createWasmModule()
-    .then((mod) => {
-      var buffer = internals.serializeWithInlineWasm(mod);
-      var byteView = new Uint8Array(buffer);
-      // The serialized payload starts with some serialization header, followed
-      // by the wasm wire bytes. Those should start with the characters
-      // 'a' 's' 'm'.
-      // Find the start of that sequence and invalidate the wire bytes by
-      // clearing the first byte.
-      var startOfWasmHeader = findStartOfWasmHeader(byteView);
-      assert_greater_than(startOfWasmHeader, 0,
-                          "The wire format should contain a wasm header.");
-      byteView[startOfWasmHeader] = 0;
-      // Also invalidate the serialized blob. That follows the wire bytes.
-      // Start from the end and clear the first non-null byte.
-      var invalidalidated = false;
-      for (var i = byteView.length - 1; i >= startOfWasmHeader + 3; --i) {
-        if (byteView[i] != 0) {
-          byteView[i] = 0;
-          invalidated = true;
-          break;
-        }
-      }
-      assert_true(invalidated,
-                  "the serialized blob should contain some non-null bytes.");
-
-      var deserialized = internals.deserializeBufferContainingWasm(byteView.buffer);
-      assert_equals(deserialized, null);
-    });
-}
diff --git a/third_party/blink/web_tests/inspector-protocol/cpu-profiler/record-cpu-profile-with-cpu-throttling-expected.txt b/third_party/blink/web_tests/inspector-protocol/cpu-profiler/record-cpu-profile-with-cpu-throttling-expected.txt
deleted file mode 100644
index 6b0e284ed..0000000
--- a/third_party/blink/web_tests/inspector-protocol/cpu-profiler/record-cpu-profile-with-cpu-throttling-expected.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Test that the profiler can record a profile with cpu throttling enabled.
-
diff --git a/third_party/blink/web_tests/inspector-protocol/cpu-profiler/record-cpu-profile-with-cpu-throttling.js b/third_party/blink/web_tests/inspector-protocol/cpu-profiler/record-cpu-profile-with-cpu-throttling.js
deleted file mode 100644
index bf6df29..0000000
--- a/third_party/blink/web_tests/inspector-protocol/cpu-profiler/record-cpu-profile-with-cpu-throttling.js
+++ /dev/null
@@ -1,20 +0,0 @@
-(async function(testRunner) {
-  const {page, session, dp} = await testRunner.startBlank(
-      'Test that the profiler can record a profile with cpu throttling enabled.');
-
-  await dp.Emulation.setCPUThrottlingRate({rate: 4});
-  await dp.Profiler.enable();
-  await dp.Profiler.start();
-
-  await session.evaluate(`
-    let count = 0;
-    for (let i = 0; i < 1e7; i++) {
-      count += i;
-    }
-    window.count = count;
-  `);
-
-  await dp.Profiler.stop();
-
-  testRunner.completeTest();
-})
diff --git a/third_party/closure_compiler/externs/chrome.js b/third_party/closure_compiler/externs/chrome.js
index d8472ca..6559fbeb 100644
--- a/third_party/closure_compiler/externs/chrome.js
+++ b/third_party/closure_compiler/externs/chrome.js
@@ -385,9 +385,17 @@
 
 
 /** @type {string|undefined} */
+MessageSender.prototype.nativeApplication;
+
+
+/** @type {string|undefined} */
 MessageSender.prototype.tlsChannelId;
 
 
+/** @type {string|undefined} */
+MessageSender.prototype.origin;
+
+
 /**
  * @enum {string}
  * @see https://developer.chrome.com/extensions/tabs#type-MutedInfoReason
diff --git a/third_party/closure_compiler/externs/chrome_extensions.js b/third_party/closure_compiler/externs/chrome_extensions.js
index 8026fab..c0fb4e1 100644
--- a/third_party/closure_compiler/externs/chrome_extensions.js
+++ b/third_party/closure_compiler/externs/chrome_extensions.js
@@ -2340,6 +2340,62 @@
 chrome.enterprise.reportingPrivate.getDeviceId = function(callback) {};
 
 /**
+ * Returns a random secret stored in a platform specific storage.
+ * @param {(function(!ArrayBuffer): void)=} callback Called with the result.
+ */
+chrome.enterprise.reportingPrivate.getPersistentSecret = function(callback) {};
+
+/**
+ * Returns byte string associated with the data item stored in a platform
+ * specific storage.
+ * @param {!string} item Item name (can have containers separated by '/').
+ * @param {(function(!ArrayBuffer): void)=} callback Called back with the
+ *     response.
+ */
+chrome.enterprise.reportingPrivate.getDeviceData = function(item, callback) {};
+
+/**
+ * Stores byte string associated with the data item in a platform
+ * specific storage.
+ * @param {!string} item Item name (can have containers separated by '/').
+ * @param {!ArrayBuffer} data Byte string to associate with the data item.
+ * @param {(function(): void)=} callback Called back with the response.
+ */
+chrome.enterprise.reportingPrivate.setDeviceData = function(
+    item, data, callback) {};
+
+/**
+ * Represents a device info property type.
+ * @enum {string}
+ */
+chrome.enterprise.reportingPrivate.SettingValue = {
+  UNKNOWN: '',
+  DISABLED: '',
+  ENABLED: '',
+};
+
+/**
+ * Type of the object returned by getDeviceInfo.
+ * @typedef {?{
+ *   osName: string,
+ *   osVersion: string,
+ *   deviceHostName: string,
+ *   deviceModel: string,
+ *   serialNumber: string,
+ *   screenLockSecured: chrome.enterprise.reportingPrivate.SettingValue,
+ *   diskEncrypted: chrome.enterprise.reportingPrivate.SettingValue,
+ * }}
+ */
+chrome.enterprise.reportingPrivate.DeviceInfo;
+
+/**
+ * Returns the device information object.
+ * @param {(function(!chrome.enterprise.reportingPrivate.DeviceInfo): void)=}
+ *     callback Called back with the response.
+ */
+chrome.enterprise.reportingPrivate.getDeviceInfo = function(callback) {};
+
+/**
  * @see https://developer.chrome.com/extensions/extension.html
  * @const
  */
@@ -2517,6 +2573,10 @@
 chrome.runtime.Manifest.prototype.version;
 
 
+/** @type {string|undefined} */
+chrome.runtime.Manifest.prototype.version_name;
+
+
 /** @type {number|undefined} */
 chrome.runtime.Manifest.prototype.manifest_version;
 
@@ -4040,7 +4100,7 @@
 /**
  * @param {function(!Array<!ExtensionInfo>): void=} opt_callback Optional
  *     callback function.
- * @return {!Array<!ExtensionInfo>}
+ * @return {undefined}
  */
 chrome.management.getAll = function(opt_callback) {};
 
@@ -7730,6 +7790,10 @@
 
 
 /** @type {boolean|undefined} */
+ChromeKeyboardEvent.prototype.altgrKey;
+
+
+/** @type {boolean|undefined} */
 ChromeKeyboardEvent.prototype.ctrlKey;
 
 
@@ -10565,6 +10629,24 @@
 
 
 /**
+ * Commits the text currently being composed without moving the selected text
+ * range. This is a no-op if the context is incorrect.
+ * @param {{
+ *  contextID: number
+ * }} parameters Parameters for the finishComposingText API call.
+ * @param {function(): void=} callback Called when the operation completes.
+ */
+chrome.inputMethodPrivate.finishComposingText = function(
+    parameters, callback) {};
+
+
+/**
+ * Resets the current engine to its initial state. Fires an OnReset event.
+ */
+chrome.inputMethodPrivate.reset = function() {};
+
+
+/**
  * @const
  * @see https://goo.gl/7dvJFW
  */
diff --git a/third_party/inspector_protocol/README.chromium b/third_party/inspector_protocol/README.chromium
index e6a0e3d..7c36d45 100644
--- a/third_party/inspector_protocol/README.chromium
+++ b/third_party/inspector_protocol/README.chromium
@@ -2,7 +2,7 @@
 Short Name: inspector_protocol
 URL: https://chromium.googlesource.com/deps/inspector_protocol/
 Version: 0
-Revision: ac6919eb836521a96cc18931f0bf270d8c1b53a1
+Revision: 6361d066985aafcb5c7d7b4066da0a0ecaa5866d
 License: BSD
 License File: LICENSE
 Security Critical: yes
diff --git a/third_party/inspector_protocol/lib/Values_cpp.template b/third_party/inspector_protocol/lib/Values_cpp.template
index 4e27edd..91cd471 100644
--- a/third_party/inspector_protocol/lib/Values_cpp.template
+++ b/third_party/inspector_protocol/lib/Values_cpp.template
@@ -13,55 +13,6 @@
 {% endfor %}
 
 namespace {
-
-const char* const nullValueString = "null";
-const char* const trueValueString = "true";
-const char* const falseValueString = "false";
-
-inline bool escapeChar(uint16_t c, StringBuilder* dst)
-{
-    switch (c) {
-    case '\b': StringUtil::builderAppend(*dst, "\\b"); break;
-    case '\f': StringUtil::builderAppend(*dst, "\\f"); break;
-    case '\n': StringUtil::builderAppend(*dst, "\\n"); break;
-    case '\r': StringUtil::builderAppend(*dst, "\\r"); break;
-    case '\t': StringUtil::builderAppend(*dst, "\\t"); break;
-    case '\\': StringUtil::builderAppend(*dst, "\\\\"); break;
-    case '"': StringUtil::builderAppend(*dst, "\\\""); break;
-    default:
-        return false;
-    }
-    return true;
-}
-
-const char hexDigits[17] = "0123456789ABCDEF";
-
-void appendUnsignedAsHex(uint16_t number, StringBuilder* dst)
-{
-    StringUtil::builderAppend(*dst, "\\u");
-    for (size_t i = 0; i < 4; ++i) {
-        uint16_t c = hexDigits[(number & 0xF000) >> 12];
-        StringUtil::builderAppend(*dst, c);
-        number <<= 4;
-    }
-}
-
-template <typename Char>
-void escapeStringForJSONInternal(const Char* str, unsigned len,
-                                 StringBuilder* dst)
-{
-    for (unsigned i = 0; i < len; ++i) {
-        Char c = str[i];
-        if (escapeChar(c, dst))
-            continue;
-        if (c < 32 || c > 126) {
-            appendUnsignedAsHex(c, dst);
-        } else {
-            StringUtil::builderAppend(*dst, c);
-        }
-    }
-}
-
 // When parsing CBOR, we limit recursion depth for objects and arrays
 // to this constant.
 static constexpr int kStackLimitValues = 1000;
@@ -275,12 +226,6 @@
     return false;
 }
 
-void Value::writeJSON(StringBuilder* output) const
-{
-    DCHECK(m_type == TypeNull);
-    StringUtil::builderAppend(*output, nullValueString, 4);
-}
-
 void Value::AppendSerialized(std::vector<uint8_t>* bytes) const {
     DCHECK(m_type == TypeNull);
     bytes->push_back(cbor::EncodeNull());
@@ -291,14 +236,6 @@
     return Value::null();
 }
 
-String Value::toJSONString() const
-{
-    StringBuilder result;
-    StringUtil::builderReserve(result, 512);
-    writeJSON(&result);
-    return StringUtil::builderToString(result);
-}
-
 bool FundamentalValue::asBoolean(bool* output) const
 {
     if (type() != TypeBoolean)
@@ -328,25 +265,6 @@
     return true;
 }
 
-void FundamentalValue::writeJSON(StringBuilder* output) const
-{
-    DCHECK(type() == TypeBoolean || type() == TypeInteger || type() == TypeDouble);
-    if (type() == TypeBoolean) {
-        if (m_boolValue)
-            StringUtil::builderAppend(*output, trueValueString, 4);
-        else
-            StringUtil::builderAppend(*output, falseValueString, 5);
-    } else if (type() == TypeDouble) {
-        if (!std::isfinite(m_doubleValue)) {
-            StringUtil::builderAppend(*output, nullValueString, 4);
-            return;
-        }
-        StringUtil::builderAppend(*output, StringUtil::fromDouble(m_doubleValue));
-    } else if (type() == TypeInteger) {
-        StringUtil::builderAppend(*output, StringUtil::fromInteger(m_integerValue));
-    }
-}
-
 void FundamentalValue::AppendSerialized(std::vector<uint8_t>* bytes) const {
     switch (type()) {
     case TypeDouble:
@@ -381,12 +299,6 @@
     return true;
 }
 
-void StringValue::writeJSON(StringBuilder* output) const
-{
-    DCHECK(type() == TypeString);
-    StringUtil::builderAppendQuotedString(*output, m_stringValue);
-}
-
 namespace {
 // This routine distinguishes between the current encoding for a given
 // string |s|, and calls encoding routines that will
@@ -431,12 +343,6 @@
     return true;
 }
 
-void BinaryValue::writeJSON(StringBuilder* output) const
-{
-    DCHECK(type() == TypeBinary);
-    StringUtil::builderAppendQuotedString(*output, m_binaryValue.toBase64());
-}
-
 void BinaryValue::AppendSerialized(std::vector<uint8_t>* bytes) const {
     cbor::EncodeBinary(span<uint8_t>(m_binaryValue.data(),
                                      m_binaryValue.size()), bytes);
@@ -570,21 +476,6 @@
     m_order.erase(std::remove(m_order.begin(), m_order.end(), name), m_order.end());
 }
 
-void DictionaryValue::writeJSON(StringBuilder* output) const
-{
-    StringUtil::builderAppend(*output, '{');
-    for (size_t i = 0; i < m_order.size(); ++i) {
-        Dictionary::const_iterator it = m_data.find(m_order[i]);
-        CHECK(it != m_data.end());
-        if (i)
-            StringUtil::builderAppend(*output, ',');
-        StringUtil::builderAppendQuotedString(*output, it->first);
-        StringUtil::builderAppend(*output, ':');
-        it->second->writeJSON(output);
-    }
-    StringUtil::builderAppend(*output, '}');
-}
-
 void DictionaryValue::AppendSerialized(std::vector<uint8_t>* bytes) const {
     cbor::EnvelopeEncoder encoder;
     encoder.EncodeStart(bytes);
@@ -621,19 +512,6 @@
 {
 }
 
-void ListValue::writeJSON(StringBuilder* output) const
-{
-    StringUtil::builderAppend(*output, '[');
-    bool first = true;
-    for (const std::unique_ptr<protocol::Value>& value : m_data) {
-        if (!first)
-            StringUtil::builderAppend(*output, ',');
-        value->writeJSON(output);
-        first = false;
-    }
-    StringUtil::builderAppend(*output, ']');
-}
-
 void ListValue::AppendSerialized(std::vector<uint8_t>* bytes) const {
     cbor::EnvelopeEncoder encoder;
     encoder.EncodeStart(bytes);
@@ -670,16 +548,6 @@
     return m_data[index].get();
 }
 
-void escapeLatinStringForJSON(const uint8_t* str, unsigned len, StringBuilder* dst)
-{
-    escapeStringForJSONInternal<uint8_t>(str, len, dst);
-}
-
-void escapeWideStringForJSON(const uint16_t* str, unsigned len, StringBuilder* dst)
-{
-    escapeStringForJSONInternal<uint16_t>(str, len, dst);
-}
-
 {% for namespace in config.protocol.namespace %}
 } // namespace {{namespace}}
 {% endfor %}
diff --git a/third_party/inspector_protocol/lib/Values_h.template b/third_party/inspector_protocol/lib/Values_h.template
index cdcea063..41d326e 100644
--- a/third_party/inspector_protocol/lib/Values_h.template
+++ b/third_party/inspector_protocol/lib/Values_h.template
@@ -52,10 +52,8 @@
     virtual bool asString(String* output) const;
     virtual bool asBinary(Binary* output) const;
 
-    virtual void writeJSON(StringBuilder* output) const;
     virtual void AppendSerialized(std::vector<uint8_t>* bytes) const override;
     virtual std::unique_ptr<Value> clone() const;
-    String toJSONString() const;
 
 protected:
     Value() : m_type(TypeNull) { }
@@ -88,7 +86,6 @@
     bool asBoolean(bool* output) const override;
     bool asDouble(double* output) const override;
     bool asInteger(int* output) const override;
-    void writeJSON(StringBuilder* output) const override;
     void AppendSerialized(std::vector<uint8_t>* bytes) const override;
     std::unique_ptr<Value> clone() const override;
 
@@ -117,7 +114,6 @@
     }
 
     bool asString(String* output) const override;
-    void writeJSON(StringBuilder* output) const override;
     void AppendSerialized(std::vector<uint8_t>* bytes) const override;
     std::unique_ptr<Value> clone() const override;
 
@@ -136,7 +132,6 @@
     }
 
     bool asBinary(Binary* output) const override;
-    void writeJSON(StringBuilder* output) const override;
     void AppendSerialized(std::vector<uint8_t>* bytes) const override;
     std::unique_ptr<Value> clone() const override;
 
@@ -166,7 +161,6 @@
         return std::unique_ptr<DictionaryValue>(DictionaryValue::cast(value.release()));
     }
 
-    void writeJSON(StringBuilder* output) const override;
     void AppendSerialized(std::vector<uint8_t>* bytes) const override;
     std::unique_ptr<Value> clone() const override;
 
@@ -235,7 +229,6 @@
 
     ~ListValue() override;
 
-    void writeJSON(StringBuilder* output) const override;
     void AppendSerialized(std::vector<uint8_t>* bytes) const override;
     std::unique_ptr<Value> clone() const override;
 
@@ -250,9 +243,6 @@
     std::vector<std::unique_ptr<Value>> m_data;
 };
 
-void escapeLatinStringForJSON(const uint8_t* str, unsigned len, StringBuilder* dst);
-void escapeWideStringForJSON(const uint16_t* str, unsigned len, StringBuilder* dst);
-
 {% for namespace in config.protocol.namespace %}
 } // namespace {{namespace}}
 {% endfor %}
diff --git a/third_party/inspector_protocol/lib/base_string_adapter_cc.template b/third_party/inspector_protocol/lib/base_string_adapter_cc.template
index bfbb2a29..edd3da99 100644
--- a/third_party/inspector_protocol/lib/base_string_adapter_cc.template
+++ b/third_party/inspector_protocol/lib/base_string_adapter_cc.template
@@ -145,16 +145,6 @@
   string_.append(characters, length);
 }
 
-// static
-void StringUtil::builderAppendQuotedString(StringBuilder& builder,
-                                           const String& str) {
-  builder.append('"');
-  base::string16 str16 = base::UTF8ToUTF16(str);
-  escapeWideStringForJSON(reinterpret_cast<const uint16_t*>(&str16[0]),
-                          str16.length(), &builder);
-  builder.append('"');
-}
-
 std::string StringBuilder::toString() {
   return string_;
 }
diff --git a/third_party/inspector_protocol/lib/base_string_adapter_h.template b/third_party/inspector_protocol/lib/base_string_adapter_h.template
index 26f9858..32bd7ea2 100644
--- a/third_party/inspector_protocol/lib/base_string_adapter_h.template
+++ b/third_party/inspector_protocol/lib/base_string_adapter_h.template
@@ -84,8 +84,6 @@
   static void builderAppend(StringBuilder& builder, const char* s, size_t len) {
     builder.append(s, len);
   }
-  static void builderAppendQuotedString(StringBuilder& builder,
-                                        const String& str);
   static void builderReserve(StringBuilder& builder, unsigned capacity) {
     builder.reserveCapacity(capacity);
   }
diff --git a/third_party/inspector_protocol/templates/Exported_h.template b/third_party/inspector_protocol/templates/Exported_h.template
index 2475f635..6481eef5 100644
--- a/third_party/inspector_protocol/templates/Exported_h.template
+++ b/third_party/inspector_protocol/templates/Exported_h.template
@@ -20,8 +20,6 @@
 #define {{"_".join(config.protocol.namespace)}}_exported_api_h
 class {{config.exported.export_macro}} Exported {
 public:
-    virtual {{config.exported.string_out}} toJSONString() const = 0;
-
     virtual void AppendSerialized(std::vector<uint8_t>* out) const = 0;
 
     virtual ~Exported() { }
diff --git a/third_party/inspector_protocol/templates/Imported_h.template b/third_party/inspector_protocol/templates/Imported_h.template
index fc57764..b549388 100644
--- a/third_party/inspector_protocol/templates/Imported_h.template
+++ b/third_party/inspector_protocol/templates/Imported_h.template
@@ -29,12 +29,6 @@
         return std::unique_ptr<ImportedValue>(new ImportedValue(value));
     }
 
-    void writeJSON(StringBuilder* output) const override {
-        auto json = m_exported->toJSONString();
-        String local_json = ({{config.imported.from_imported_string % "std::move(json)"}});
-        StringUtil::builderAppend(*output, local_json);
-    }
-
     void AppendSerialized(std::vector<uint8_t>* output) const override {
         m_exported->AppendSerialized(output);
     }
diff --git a/third_party/inspector_protocol/templates/TypeBuilder_cpp.template b/third_party/inspector_protocol/templates/TypeBuilder_cpp.template
index 36e6e8a..eabafba 100644
--- a/third_party/inspector_protocol/templates/TypeBuilder_cpp.template
+++ b/third_party/inspector_protocol/templates/TypeBuilder_cpp.template
@@ -114,12 +114,6 @@
 }
     {% if protocol.is_exported(domain.domain, type.id) %}
 
-{{config.exported.string_out}} {{type.id}}::toJSONString() const
-{
-    String json = toValue()->toJSONString();
-    return {{config.exported.to_string_out % "json"}};
-}
-
 // static
 std::unique_ptr<API::{{type.id}}> API::{{type.id}}::fromBinary(const uint8_t* data, size_t length)
 {
diff --git a/third_party/inspector_protocol/templates/TypeBuilder_h.template b/third_party/inspector_protocol/templates/TypeBuilder_h.template
index 740d0a0..08615f8 100644
--- a/third_party/inspector_protocol/templates/TypeBuilder_h.template
+++ b/third_party/inspector_protocol/templates/TypeBuilder_h.template
@@ -101,11 +101,7 @@
 
     std::unique_ptr<protocol::DictionaryValue> toValue() const;
     void AppendSerialized(std::vector<uint8_t>* out) const override;
-    String toJSON() const { return toValue()->toJSONString(); }
     std::unique_ptr<{{type.id}}> clone() const;
-    {% if protocol.is_exported(domain.domain, type.id) %}
-    {{config.exported.string_out}} toJSONString() const override;
-    {% endif %}
 
     template<int STATE>
     class {{type.id}}Builder {
diff --git a/tools/cygprofile_win/BUILD.gn b/tools/cygprofile_win/BUILD.gn
index 9694a3c..99b23c5 100644
--- a/tools/cygprofile_win/BUILD.gn
+++ b/tools/cygprofile_win/BUILD.gn
@@ -3,9 +3,7 @@
 # found in the LICENSE file.
 
 static_library("cygprofile_win") {
-  sources = [
-    "cygprofile.cc",
-  ]
+  sources = [ "cygprofile.cc" ]
 
   # Don't instrument this library.
   configs -= [ "//build/config/win:default_cygprofile_instrumentation" ]
diff --git a/tools/dump_process_memory/BUILD.gn b/tools/dump_process_memory/BUILD.gn
index 4c1a241..0a6c0e5 100644
--- a/tools/dump_process_memory/BUILD.gn
+++ b/tools/dump_process_memory/BUILD.gn
@@ -3,16 +3,10 @@
 # found in the LICENSE file.
 
 executable("dump_process") {
-  sources = [
-    "dump_process.cc",
-  ]
-  deps = [
-    "//base",
-  ]
+  sources = [ "dump_process.cc" ]
+  deps = [ "//base" ]
 }
 
 group("all") {
-  deps = [
-    ":dump_process",
-  ]
+  deps = [ ":dump_process" ]
 }
diff --git a/tools/grit/BUILD.gn b/tools/grit/BUILD.gn
index d48a778..1cd3c75 100644
--- a/tools/grit/BUILD.gn
+++ b/tools/grit/BUILD.gn
@@ -12,15 +12,11 @@
   depfile = "$target_out_dir/grit_sources.d"
   script = "stamp_grit_sources.py"
 
-  inputs = [
-    "grit.py",
-  ]
+  inputs = [ "grit.py" ]
 
   # Note that we can't call this "grit_sources.stamp" because that file is
   # implicitly created by GN for script actions.
-  outputs = [
-    "$target_out_dir/grit_sources.script.stamp",
-  ]
+  outputs = [ "$target_out_dir/grit_sources.script.stamp" ]
 
   args = [
     rebase_path("//tools/grit", root_build_dir),
@@ -47,8 +43,6 @@
     bundle_root_dir = "$target_out_dir/$target_name"
     bundle_executable_dir = bundle_root_dir
 
-    public_deps = [
-      "//third_party/brotli:brotli($host_toolchain)",
-    ]
+    public_deps = [ "//third_party/brotli:brotli($host_toolchain)" ]
   }
 }
diff --git a/tools/grit/grit_rule.gni b/tools/grit/grit_rule.gni
index d1f7596..530ee17 100644
--- a/tools/grit/grit_rule.gni
+++ b/tools/grit/grit_rule.gni
@@ -271,12 +271,8 @@
     script = "//tools/grit/grit.py"
     depfile = "$target_gen_dir/$target_name.d"
 
-    inputs = [
-      invoker.source,
-    ]
-    deps = [
-      "//tools/grit:grit_sources",
-    ]
+    inputs = [ invoker.source ]
+    deps = [ "//tools/grit:grit_sources" ]
     outputs = [ "${depfile}.stamp" ] + _grit_outputs + _pak_info_outputs
 
     _grit_flags = grit_defines
@@ -455,13 +451,9 @@
     # grit above rather than this library. This target needs to depend on the
     # action publicly so other scripts can take the outputs from the grit
     # script as inputs.
-    public_deps = [
-      ":$_grit_custom_target",
-    ]
+    public_deps = [ ":$_grit_custom_target" ]
 
-    deps = [
-      "//base",
-    ]
+    deps = [ "//base" ]
 
     if (defined(invoker.public_configs)) {
       public_configs += invoker.public_configs
diff --git a/tools/grit/repack.gni b/tools/grit/repack.gni
index ef06311..ef104ba 100644
--- a/tools/grit/repack.gni
+++ b/tools/grit/repack.gni
@@ -54,9 +54,7 @@
     script = "//tools/grit/pak_util.py"
 
     inputs = invoker.sources
-    outputs = [
-      invoker.output,
-    ]
+    outputs = [ invoker.output ]
 
     args = [ "repack" ]
     if (defined(invoker.repack_whitelist)) {
@@ -80,20 +78,12 @@
                                "visibility",
                              ])
 
-      public_deps = [
-        ":$_repack_target_name",
-      ]
-      sources = [
-        invoker.output,
-      ]
+      public_deps = [ ":$_repack_target_name" ]
+      sources = [ invoker.output ]
       if (defined(invoker.bundle_output)) {
-        outputs = [
-          invoker.bundle_output,
-        ]
+        outputs = [ invoker.bundle_output ]
       } else {
-        outputs = [
-          "{{bundle_resources_dir}}/{{source_file_part}}",
-        ]
+        outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ]
       }
     }
   }
diff --git a/tools/ipc_fuzzer/fuzzer/BUILD.gn b/tools/ipc_fuzzer/fuzzer/BUILD.gn
index d00e411..a80cbb0 100644
--- a/tools/ipc_fuzzer/fuzzer/BUILD.gn
+++ b/tools/ipc_fuzzer/fuzzer/BUILD.gn
@@ -22,9 +22,7 @@
     "//base/util/type_safety",
     "//tools/ipc_fuzzer/message_lib:ipc_message_lib",
   ]
-  public_deps = [
-    "//ipc",
-  ]
+  public_deps = [ "//ipc" ]
   if (is_asan && is_chromeos) {
     # Compiling fuzzer.cc with ASan takes too long, see
     # http://crbug.com/360158.
diff --git a/tools/ipc_fuzzer/get_accessible_interfaces/BUILD.gn b/tools/ipc_fuzzer/get_accessible_interfaces/BUILD.gn
index 125ec3e..fd2f591 100644
--- a/tools/ipc_fuzzer/get_accessible_interfaces/BUILD.gn
+++ b/tools/ipc_fuzzer/get_accessible_interfaces/BUILD.gn
@@ -1,7 +1,5 @@
 executable("get_accessible_interfaces") {
-  sources = [
-    "get_accessible_interfaces.cc",
-  ]
+  sources = [ "get_accessible_interfaces.cc" ]
 
   deps = [
     "//base",
diff --git a/tools/ipc_fuzzer/message_dump/BUILD.gn b/tools/ipc_fuzzer/message_dump/BUILD.gn
index a5ed38b..e431cf1 100644
--- a/tools/ipc_fuzzer/message_dump/BUILD.gn
+++ b/tools/ipc_fuzzer/message_dump/BUILD.gn
@@ -5,10 +5,6 @@
 loadable_module("ipc_message_dump") {
   testonly = true
   configs += [ "//tools/ipc_fuzzer:ipc_fuzzer_tool_config" ]
-  deps = [
-    "//tools/ipc_fuzzer/message_lib:ipc_message_lib",
-  ]
-  sources = [
-    "message_dump.cc",
-  ]
+  deps = [ "//tools/ipc_fuzzer/message_lib:ipc_message_lib" ]
+  sources = [ "message_dump.cc" ]
 }
diff --git a/tools/ipc_fuzzer/message_tools/BUILD.gn b/tools/ipc_fuzzer/message_tools/BUILD.gn
index d5032f9..d984be9 100644
--- a/tools/ipc_fuzzer/message_tools/BUILD.gn
+++ b/tools/ipc_fuzzer/message_tools/BUILD.gn
@@ -9,9 +9,7 @@
     "//third_party/re2",
     "//tools/ipc_fuzzer/message_lib:ipc_message_lib",
   ]
-  sources = [
-    "message_util.cc",
-  ]
+  sources = [ "message_util.cc" ]
 }
 
 executable("ipc_message_list") {
@@ -22,7 +20,5 @@
     "//components/nacl/common:buildflags",
     "//tools/ipc_fuzzer/message_lib:ipc_message_lib",
   ]
-  sources = [
-    "message_list.cc",
-  ]
+  sources = [ "message_list.cc" ]
 }
diff --git a/tools/json_schema_compiler/BUILD.gn b/tools/json_schema_compiler/BUILD.gn
index f92f937cc..e71557b 100644
--- a/tools/json_schema_compiler/BUILD.gn
+++ b/tools/json_schema_compiler/BUILD.gn
@@ -8,7 +8,5 @@
     "util.cc",
     "util.h",
   ]
-  deps = [
-    "//base",
-  ]
+  deps = [ "//base" ]
 }
diff --git a/tools/json_schema_compiler/test/BUILD.gn b/tools/json_schema_compiler/test/BUILD.gn
index 88d762d..f220961 100644
--- a/tools/json_schema_compiler/test/BUILD.gn
+++ b/tools/json_schema_compiler/test/BUILD.gn
@@ -36,9 +36,7 @@
 
   root_namespace = "test::api::%(namespace)s"
 
-  deps = [
-    "//extensions/buildflags",
-  ]
+  deps = [ "//extensions/buildflags" ]
 }
 
 json_features("features_compiler_test") {
@@ -73,9 +71,7 @@
   # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
   configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
 
-  public_deps = [
-    ":features_compiler_test",
-  ]
+  public_deps = [ ":features_compiler_test" ]
 
   deps = [
     ":generated_types",
diff --git a/tools/media_engagement_preload/BUILD.gn b/tools/media_engagement_preload/BUILD.gn
index 6c8dee9..d1edcd734 100644
--- a/tools/media_engagement_preload/BUILD.gn
+++ b/tools/media_engagement_preload/BUILD.gn
@@ -53,7 +53,6 @@
 copy("generator") {
   sources = generator_sources
 
-  outputs = [
-    "$root_out_dir/{{source_root_relative_dir}}/{{source_file_part}}",
-  ]
+  outputs =
+      [ "$root_out_dir/{{source_root_relative_dir}}/{{source_file_part}}" ]
 }
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index cf74508..b6a17dc 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -12315,6 +12315,22 @@
   <description>User was presented with the Download file UI.</description>
 </action>
 
+<action name="MobileDownloadFolderUIShownFromDownloadManager">
+  <owner>ewannpv@chromium.org</owner>
+  <owner>gambard@chromium.org</owner>
+  <description>
+    User pressed &quot;Open in Downloads&quot; button from the download manager.
+  </description>
+</action>
+
+<action name="MobileDownloadFolderUIShownFromToolsMenu">
+  <owner>ewannpv@chromium.org</owner>
+  <owner>gambard@chromium.org</owner>
+  <description>
+    User pressed &quot;Downloads&quot; button from the tools menu.
+  </description>
+</action>
+
 <action name="MobileDownloadRetryDownload">
   <owner>eugenebut@chromium.org</owner>
   <description>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index f2b82d8..b39289c 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -50768,6 +50768,7 @@
   <int value="5" label="User cancelled setup while importing Plugin VM image"/>
   <int value="6" label="Error while downloading Plugin VM DLC"/>
   <int value="7" label="User cancelled setup while downloading Plugin VM DLC"/>
+  <int value="8" label="Plugin VM was already installed"/>
 </enum>
 
 <enum name="PNaClOptionsOptLevelEnum">
@@ -57771,6 +57772,35 @@
   <int value="6" label="PRIVACY_SECURITY_KEYS"/>
   <int value="7" label="PRIVACY_SITE_SETTINGS"/>
   <int value="8" label="PRIVACY_CLEAR_BROWSING_DATA"/>
+  <int value="9" label="PRIVACY_SAFE_BROWSING"/>
+  <int value="10" label="PRIVACY_PASSWORD_CHECK"/>
+  <int value="11" label="PRIVACY_IMPROVE_SECUITRY"/>
+  <int value="12" label="PRIVACY_SITE_SETTINGS_COOKIES"/>
+  <int value="13" label="PRIVACY_SITE_SETTINGS_LOCATION"/>
+  <int value="14" label="PRIVACY_SITE_SETTINGS_CAMERA"/>
+  <int value="15" label="PRIVACY_SITE_SETTINGS_MICROPHONE"/>
+  <int value="16" label="PRIVACY_SITE_SETTINGS_SENSORS"/>
+  <int value="17" label="PRIVACY_SITE_SETTINGS_NOTIFICATIONS"/>
+  <int value="18" label="PRIVACY_SITE_SETTINGS_JAVASCRIPT"/>
+  <int value="19" label="PRIVACY_SITE_SETTINGS_FLASH"/>
+  <int value="20" label="PRIVACY_SITE_SETTINGS_IMAGES"/>
+  <int value="21" label="PRIVACY_SITE_SETTINGS_POPUPS"/>
+  <int value="22" label="PRIVACY_SITE_SETTINGS_ADS"/>
+  <int value="23" label="PRIVACY_SITE_SETTINGS_BACKGROUND_SYNC"/>
+  <int value="24" label="PRIVACY_SITE_SETTINGS_SOUND"/>
+  <int value="25" label="PRIVACY_SITE_SETTINGS_AUTOMATIC_DOWNLOADS"/>
+  <int value="26" label="PRIVACY_SITE_SETTINGS_UNSANDBOXED_PLUGINS"/>
+  <int value="27" label="PRIVACY_SITE_SETTINGS_HANDLERS"/>
+  <int value="28" label="PRIVACY_SITE_SETTINGS_MIDI_DEVICES"/>
+  <int value="29" label="PRIVACY_SITE_SETTINGS_ZOOM_LEVELS"/>
+  <int value="30" label="PRIVACY_SITE_SETTINGS_USB_DEVICES"/>
+  <int value="31" label="PRIVACY_SITE_SETTINGS_SERIAL_PORTS"/>
+  <int value="32" label="PRIVACY_SITE_SETTINGS_NATIVE_FILE_SYSTEM_WRITE"/>
+  <int value="33" label="PRIVACY_SITE_SETTINGS_PDF_DOCUMENTS"/>
+  <int value="34" label="PRIVACY_SITE_SETTINGS_PROTECTED_CONTENT"/>
+  <int value="35" label="PRIVACY_SITE_SETTINGS_CLIPBOARD"/>
+  <int value="36" label="PRIVACY_SITE_SETTINGS_PAYMENT_HANDLER"/>
+  <int value="37" label="PRIVACY_SITE_SETTINGS_MIXEDSCRIPT"/>
 </enum>
 
 <enum name="SettingsResetPromptConfigError">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index a7bf5da1..f4d60da 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -14845,6 +14845,18 @@
   </summary>
 </histogram>
 
+<histogram name="BackForwardCache.MainFrameHasPageshowListenersOnRestore"
+    enum="BooleanPresent" expires_after="M82">
+  <owner>altimin@chromium.org</owner>
+  <owner>hajimehoshi@chromium.org</owner>
+  <owner>bfcache-dev@chromium.org</owner>
+  <summary>
+    Records whether a page restored from the back-forward cache has pageshow
+    handlers installed in its main frame. Recorded when the renderer resumes
+    page when restoring it from the back-forward cache.
+  </summary>
+</histogram>
+
 <histogram base="true" name="BackgroundFetch.EventDispatchFailure.Dispatch"
     enum="ServiceWorkerStatusCode">
 <!-- Name completed by histogram_suffixes name="BackgroundFetchEvents" -->
@@ -67437,8 +67449,9 @@
 </histogram>
 
 <histogram name="Media.AudioInputCbErrorMac" units="OSStatus"
-    expires_after="2020-02-02">
+    expires_after="2021-01-21">
   <owner>henrika@chromium.org</owner>
+  <owner>webrtc-audio@google.com</owner>
   <summary>
     Error codes that AudioUnitRender() returns in AUAudioInputStream on Mac.
   </summary>
@@ -137005,7 +137018,7 @@
 </histogram>
 
 <histogram name="Search.ContextualSearchQuickActions.Category"
-    enum="ContextualSearchQuickActionCategory" expires_after="M81">
+    enum="ContextualSearchQuickActionCategory" expires_after="2021-01-15">
   <owner>donnd@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/structured/BUILD.gn b/tools/metrics/structured/BUILD.gn
index 1c647bf8..c04675f 100644
--- a/tools/metrics/structured/BUILD.gn
+++ b/tools/metrics/structured/BUILD.gn
@@ -9,9 +9,7 @@
     "//tools/metrics/structured/events_template.py",
     "//tools/metrics/structured/gen_events.py",
   ]
-  sources = [
-    "//tools/metrics/structured/structured.xml",
-  ]
+  sources = [ "//tools/metrics/structured/structured.xml" ]
 
   outdir = "$target_gen_dir"
 
diff --git a/tools/perf/contrib/vr_benchmarks/BUILD.gn b/tools/perf/contrib/vr_benchmarks/BUILD.gn
index 51644e0..5213df73 100644
--- a/tools/perf/contrib/vr_benchmarks/BUILD.gn
+++ b/tools/perf/contrib/vr_benchmarks/BUILD.gn
@@ -25,13 +25,9 @@
     "//chrome/test/data/xr/webvr_info/samples/",
     "//third_party/webxr_test_pages/webxr-samples/",
   ]
-  data_deps = [
-    "//testing:run_perf_test",
-  ]
+  data_deps = [ "//testing:run_perf_test" ]
 
-  deps = [
-    "//tools/perf:perf",
-  ]
+  deps = [ "//tools/perf:perf" ]
 
   if (is_android) {
     data += [
@@ -71,9 +67,7 @@
     "//chrome/browser/resources/vr/assets/VERSION",
     "//chrome/browser/resources/vr/assets/vr_assets_component_files.json",
   ]
-  outputs = [
-    "$target_gen_dir/vr_assets_profile",
-  ]
+  outputs = [ "$target_gen_dir/vr_assets_profile" ]
   args = [
     "--output",
     rebase_path(target_gen_dir, root_build_dir),
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml
index 6e4b0fb..522e59f 100644
--- a/tools/traffic_annotation/summary/annotations.xml
+++ b/tools/traffic_annotation/summary/annotations.xml
@@ -136,6 +136,7 @@
  <item id="history_ui_favicon_request_handler_get_favicon" hash_code="17562717" type="0" content_hash_code="64054629" os_list="linux,windows" file_path="components/favicon/core/history_ui_favicon_request_handler_impl.cc"/>
  <item id="http_server_error_response" hash_code="32197336" type="0" content_hash_code="61082230" os_list="linux,windows" file_path="net/server/http_server.cc"/>
  <item id="https_server_previews_navigation" hash_code="35725390" type="0" content_hash_code="84423109" os_list="linux,windows" file_path="chrome/browser/previews/previews_lite_page_redirect_serving_url_loader.cc"/>
+ <item id="ice_config_fetcher" hash_code="137093034" type="0" content_hash_code="60051202" os_list="linux,windows" file_path="chrome/browser/sharing/webrtc/ice_config_fetcher.cc"/>
  <item id="icon_cacher" hash_code="103133150" type="0" content_hash_code="116368348" os_list="linux,windows" file_path="components/ntp_tiles/icon_cacher_impl.cc"/>
  <item id="icon_catcher_get_large_icon" hash_code="44494884" type="0" content_hash_code="98262037" os_list="linux,windows" file_path="components/ntp_tiles/icon_cacher_impl.cc"/>
  <item id="image_annotation" hash_code="107881858" type="0" content_hash_code="96203979" os_list="linux,windows" file_path="services/image_annotation/annotator.cc"/>
diff --git a/tools/win/chromeexts/BUILD.gn b/tools/win/chromeexts/BUILD.gn
index 39d188b..2e5819b 100644
--- a/tools/win/chromeexts/BUILD.gn
+++ b/tools/win/chromeexts/BUILD.gn
@@ -12,7 +12,5 @@
     "commands/hwnd_command.h",
   ]
 
-  deps = [
-    "//base",
-  ]
+  deps = [ "//base" ]
 }
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 b5c84a4a..9b05b827 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
@@ -173,7 +173,6 @@
    */
   onQuickViewKeyDown_(event) {
     if (this.quickView_.isOpened()) {
-      let index;
       switch (event.key) {
         case ' ':
         case 'Escape':
@@ -294,15 +293,6 @@
   }
 
   /**
-   * @param {!FileEntry} entry
-   * @return {!Promise<!FileTasks>}
-   * @private
-   */
-  getAvailableTasks_(entry) {
-    return this.taskController_.getEntryFileTasks(entry);
-  }
-
-  /**
    * Update quick view using current entries.
    *
    * @return {!Promise} Promise fulfilled after quick view is updated.
@@ -328,7 +318,7 @@
     return Promise
         .all([
           this.metadataModel_.get([entry], ['thumbnailUrl']),
-          this.getAvailableTasks_(entry)
+          this.taskController_.getEntryFileTasks(entry)
         ])
         .then(values => {
           const items = (/**@type{Array<MetadataItem>}*/ (values[0]));
@@ -373,7 +363,10 @@
         browsable: params.browsable || false,
       });
 
-      this.tasks_ = fileTasks;
+      if (params.hasTask) {
+        this.tasks_ = fileTasks;
+      }
+
     });
   }
 
diff --git a/ui/file_manager/image_loader/image_loader.js b/ui/file_manager/image_loader/image_loader.js
index 1540aec..0ed1dc9 100644
--- a/ui/file_manager/image_loader/image_loader.js
+++ b/ui/file_manager/image_loader/image_loader.js
@@ -65,10 +65,10 @@
  * @const
  * @type {Array<string>}
  */
-ImageLoader.ALLOWED_CLIENTS = [
-  'hhaomjibdihmijegdhdafkllkbggdgoj',  // File Manager's extension id.
-  'nlkncpkkdoccmpiclbokaimcnedabhhm',  // Gallery's extension id.
-  'jcgeabjmjgoblfofpppfkcoakmfobdko',  // Video Player's extension id.
+ImageLoader.ALLOWED_CLIENT_ORIGINS = [
+  'chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj',  // File Manager
+  'chrome-extension://nlkncpkkdoccmpiclbokaimcnedabhhm',  // Gallery
+  'chrome-extension://jcgeabjmjgoblfofpppfkcoakmfobdko',  // Video Player
 ];
 
 /**
@@ -80,10 +80,10 @@
  */
 ImageLoader.prototype.onIncomingRequest_ = function(
     request_data, sender, sendResponse) {
-  if (!sender.id || !request_data) {
+  if (!sender.origin || !request_data) {
     return;
   }
-  if (ImageLoader.ALLOWED_CLIENTS.indexOf(sender.id) === -1) {
+  if (ImageLoader.ALLOWED_CLIENT_ORIGINS.indexOf(sender.origin) === -1) {
     return;
   }
 
@@ -108,14 +108,14 @@
   } else {
     request.orientation = new ImageOrientation(1, 0, 0, 1);
   }
-  return this.onMessage_(sender.id, request, failSafeSendResponse);
+  return this.onMessage_(sender.origin, request, failSafeSendResponse);
 };
 
 /**
  * Handles a request. Depending on type of the request, starts or stops
  * an image task.
  *
- * @param {string} senderId Sender's extension id.
+ * @param {string} senderOrigin Sender's extension origin.
  * @param {!LoadImageRequest} request Pre-processed request.
  * @param {function(!LoadImageResponse)} callback Callback to be called to
  *     return response.
@@ -123,8 +123,8 @@
  *     callback is called.
  * @private
  */
-ImageLoader.prototype.onMessage_ = function(senderId, request, callback) {
-  const requestId = senderId + ':' + request.taskId;
+ImageLoader.prototype.onMessage_ = function(senderOrigin, request, callback) {
+  const requestId = senderOrigin + ':' + request.taskId;
   if (request.cancel) {
     // Cancel a task.
     this.scheduler_.remove(requestId);
diff --git a/ui/gl/direct_composition_surface_win.cc b/ui/gl/direct_composition_surface_win.cc
index da62ecd..4830e68b 100644
--- a/ui/gl/direct_composition_surface_win.cc
+++ b/ui/gl/direct_composition_surface_win.cc
@@ -30,6 +30,8 @@
 
 namespace gl {
 namespace {
+// Whether the overlay caps are valid or not.
+bool g_overlay_caps_valid = false;
 // Indicates support for either NV12 or YUY2 hardware overlays.
 bool g_supports_overlays = false;
 
@@ -51,11 +53,19 @@
                    DXGI_OVERLAY_SUPPORT_FLAG_SCALING));
 }
 
-void InitializeHardwareOverlaySupport() {
-  static bool overlay_support_initialized = false;
-  if (overlay_support_initialized)
+void UpdateHardwareOverlaySupport() {
+  if (g_overlay_caps_valid)
     return;
-  overlay_support_initialized = true;
+  g_overlay_caps_valid = true;
+
+  bool prev_supports_overlays = g_supports_overlays;
+  DXGI_FORMAT prev_overlay_format_used = g_overlay_format_used;
+  // Reset all caps in case of early exit.
+  g_supports_overlays = false;
+  g_overlay_format_used = DXGI_FORMAT_NV12;
+  g_nv12_overlay_support_flags = 0;
+  g_yuy2_overlay_support_flags = 0;
+  g_overlay_monitor_size = gfx::Size();
 
   // Check for DirectComposition support first to prevent likely crashes.
   if (!DirectCompositionSurfaceWin::IsDirectCompositionSupported())
@@ -92,6 +102,8 @@
     return;
   }
 
+  bool supports_overlays = false;
+  DXGI_FORMAT overlay_format_used = DXGI_FORMAT_NV12;
   unsigned int i = 0;
   while (true) {
     Microsoft::WRL::ComPtr<IDXGIOutput> output;
@@ -128,17 +140,17 @@
         // performing an extra scaling Blt before calling the driver. Even when
         // scaled overlays aren't actually supported, presentation using the
         // overlay path should be relatively efficient.
-        g_overlay_format_used = DXGI_FORMAT_NV12;
-        g_supports_overlays = true;
+        overlay_format_used = DXGI_FORMAT_NV12;
+        supports_overlays = true;
       }
     }
-    if (!g_supports_overlays &&
+    if (!supports_overlays &&
         FlagsSupportsOverlays(g_yuy2_overlay_support_flags)) {
       // If NV12 isn't supported, fallback to YUY2 if it's supported.
-      g_overlay_format_used = DXGI_FORMAT_YUY2;
-      g_supports_overlays = true;
+      overlay_format_used = DXGI_FORMAT_YUY2;
+      supports_overlays = true;
     }
-    if (g_supports_overlays) {
+    if (supports_overlays) {
       DXGI_OUTPUT_DESC monitor_desc = {};
       if (SUCCEEDED(output3->GetDesc(&monitor_desc))) {
         g_overlay_monitor_size =
@@ -151,15 +163,23 @@
     // https://docs.microsoft.com/en-us/windows-hardware/drivers/display/multiplane-overlay-hardware-requirements
     // TODO(sunnyps): If the above is true, then we can only look at first
     // output instead of iterating over all outputs.
-    if (g_supports_overlays)
+    if (supports_overlays)
       break;
   }
-  if (g_supports_overlays) {
-    base::UmaHistogramSparse("GPU.DirectComposition.OverlayFormatUsed3",
-                             g_overlay_format_used);
+
+  g_supports_overlays = supports_overlays;
+  g_overlay_format_used = overlay_format_used;
+
+  if (supports_overlays != prev_supports_overlays ||
+      overlay_format_used != prev_overlay_format_used) {
+    // Record the new histograms
+    if (supports_overlays) {
+      base::UmaHistogramSparse("GPU.DirectComposition.OverlayFormatUsed3",
+                               overlay_format_used);
+    }
+    UMA_HISTOGRAM_BOOLEAN("GPU.DirectComposition.OverlaysSupported",
+                          supports_overlays);
   }
-  UMA_HISTOGRAM_BOOLEAN("GPU.DirectComposition.OverlaysSupported",
-                        g_supports_overlays);
 }
 
 bool SupportsPresentationFeedback() {
@@ -267,7 +287,7 @@
 bool DirectCompositionSurfaceWin::AreOverlaysSupported() {
   // Always initialize and record overlay support information irrespective of
   // command line flags.
-  InitializeHardwareOverlaySupport();
+  UpdateHardwareOverlaySupport();
 
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   // Enable flag should be checked before the disable flag, so we could
@@ -284,7 +304,7 @@
 bool DirectCompositionSurfaceWin::IsDecodeSwapChainSupported() {
   if (base::FeatureList::IsEnabled(
           features::kDirectCompositionUseNV12DecodeSwapChain)) {
-    InitializeHardwareOverlaySupport();
+    UpdateHardwareOverlaySupport();
     return GetOverlayFormatUsed() == DXGI_FORMAT_NV12;
   }
   return false;
@@ -296,8 +316,13 @@
 }
 
 // static
+void DirectCompositionSurfaceWin::InvalidateOverlayCaps() {
+  g_overlay_caps_valid = false;
+}
+
+// static
 bool DirectCompositionSurfaceWin::AreScaledOverlaysSupported() {
-  InitializeHardwareOverlaySupport();
+  UpdateHardwareOverlaySupport();
   if (g_overlay_format_used == DXGI_FORMAT_NV12)
     return !!(g_nv12_overlay_support_flags & DXGI_OVERLAY_SUPPORT_FLAG_SCALING);
   DCHECK_EQ(DXGI_FORMAT_YUY2, g_overlay_format_used);
@@ -306,7 +331,7 @@
 
 // static
 UINT DirectCompositionSurfaceWin::GetOverlaySupportFlags(DXGI_FORMAT format) {
-  InitializeHardwareOverlaySupport();
+  UpdateHardwareOverlaySupport();
   if (format == DXGI_FORMAT_NV12)
     return g_nv12_overlay_support_flags;
   DCHECK_EQ(DXGI_FORMAT_YUY2, format);
@@ -326,7 +351,7 @@
 // static
 void DirectCompositionSurfaceWin::SetScaledOverlaysSupportedForTesting(
     bool supported) {
-  InitializeHardwareOverlaySupport();
+  UpdateHardwareOverlaySupport();
   if (supported) {
     g_nv12_overlay_support_flags |= DXGI_OVERLAY_SUPPORT_FLAG_SCALING;
     g_yuy2_overlay_support_flags |= DXGI_OVERLAY_SUPPORT_FLAG_SCALING;
@@ -341,7 +366,7 @@
 void DirectCompositionSurfaceWin::SetOverlayFormatUsedForTesting(
     DXGI_FORMAT format) {
   DCHECK(format == DXGI_FORMAT_NV12 || format == DXGI_FORMAT_YUY2);
-  InitializeHardwareOverlaySupport();
+  UpdateHardwareOverlaySupport();
   g_overlay_format_used = format;
   DCHECK_EQ(format, GetOverlayFormatUsed());
 }
diff --git a/ui/gl/direct_composition_surface_win.h b/ui/gl/direct_composition_surface_win.h
index ba89b881..a869a7ed 100644
--- a/ui/gl/direct_composition_surface_win.h
+++ b/ui/gl/direct_composition_surface_win.h
@@ -60,6 +60,9 @@
   // current GPU process' lifetime.
   static void DisableOverlays();
 
+  // Indicate the overlay caps are invalid.
+  static void InvalidateOverlayCaps();
+
   // Returns true if scaled hardware overlays are supported.
   static bool AreScaledOverlaysSupported();
 
diff --git a/ui/login/display_manager.js b/ui/login/display_manager.js
index 5e03c81..2276609 100644
--- a/ui/login/display_manager.js
+++ b/ui/login/display_manager.js
@@ -27,7 +27,6 @@
 /** @const */ var SCREEN_TPM_ERROR = 'tpm-error-message';
 /** @const */ var SCREEN_PASSWORD_CHANGED = 'password-changed';
 /** @const */ var SCREEN_APP_LAUNCH_SPLASH = 'app-launch-splash';
-/** @const */ var SCREEN_ARC_KIOSK_SPLASH = 'arc-kiosk-splash';
 /** @const */ var SCREEN_CONFIRM_PASSWORD = 'confirm-password';
 /** @const */ var SCREEN_FATAL_ERROR = 'fatal-error';
 /** @const */ var SCREEN_KIOSK_ENABLE = 'kiosk-enable';
@@ -450,8 +449,6 @@
       } else if (name == ACCELERATOR_APP_LAUNCH_BAILOUT) {
         if (currentStepId == SCREEN_APP_LAUNCH_SPLASH)
           chrome.send('cancelAppLaunch');
-        if (currentStepId == SCREEN_ARC_KIOSK_SPLASH)
-          chrome.send('cancelArcKioskLaunch');
       } else if (name == ACCELERATOR_APP_LAUNCH_NETWORK_CONFIG) {
         if (currentStepId == SCREEN_APP_LAUNCH_SPLASH)
           chrome.send('networkConfigRequest');
@@ -689,8 +686,7 @@
       // screen.
       // TODO: remove this special case when a better fix is found for the race
       // condition. This if statement was introduced to fix http://b/113786350.
-      if ((this.currentScreen.id == SCREEN_APP_LAUNCH_SPLASH ||
-           this.currentScreen.id == SCREEN_ARC_KIOSK_SPLASH) &&
+      if (this.currentScreen.id == SCREEN_APP_LAUNCH_SPLASH &&
           screen.id == SCREEN_GAIA_SIGNIN) {
         console.log(
             this.currentScreen.id +
diff --git a/ui/login/display_manager_types.js b/ui/login/display_manager_types.js
index 4c023aae5..52d4bff 100644
--- a/ui/login/display_manager_types.js
+++ b/ui/login/display_manager_types.js
@@ -73,7 +73,6 @@
   LOCK: 'lock',
   USER_ADDING: 'user-adding',
   APP_LAUNCH_SPLASH: 'app-launch-splash',
-  ARC_KIOSK_SPLASH: 'arc-kiosk-splash',
   DESKTOP_USER_MANAGER: 'login-add-user',
   GAIA_SIGNIN: 'gaia-signin'
 };
diff --git a/ui/views/bubble/bubble_dialog_delegate_view.cc b/ui/views/bubble/bubble_dialog_delegate_view.cc
index de7320f..dddce3e 100644
--- a/ui/views/bubble/bubble_dialog_delegate_view.cc
+++ b/ui/views/bubble/bubble_dialog_delegate_view.cc
@@ -91,8 +91,6 @@
                               : Widget::InitParams::WindowOpacity::kOpaque;
   bubble_params.accept_events = bubble->accept_events();
   bubble_params.remove_standard_frame = true;
-  bubble_params.layer_type = bubble->GetLayerType();
-
   // Use a window default shadow if the bubble doesn't provides its own.
   if (bubble->GetShadow() == BubbleBorder::NO_ASSETS)
     bubble_params.shadow_type = Widget::InitParams::ShadowType::kDefault;
@@ -342,10 +340,6 @@
     Widget::InitParams* params,
     Widget* widget) const {}
 
-ui::LayerType BubbleDialogDelegateView::GetLayerType() const {
-  return ui::LAYER_TEXTURED;
-}
-
 void BubbleDialogDelegateView::UseCompactMargins() {
   set_margins(gfx::Insets(6));
 }
diff --git a/ui/views/bubble/bubble_dialog_delegate_view.h b/ui/views/bubble/bubble_dialog_delegate_view.h
index ea8d72f..d63281d9 100644
--- a/ui/views/bubble/bubble_dialog_delegate_view.h
+++ b/ui/views/bubble/bubble_dialog_delegate_view.h
@@ -137,9 +137,6 @@
   virtual void OnBeforeBubbleWidgetInit(Widget::InitParams* params,
                                         Widget* widget) const;
 
-  // The layer type of the bubble widget.
-  virtual ui::LayerType GetLayerType() const;
-
   // Sets the content margins to a default picked for smaller bubbles.
   void UseCompactMargins();
 
diff --git a/ui/webui/resources/cr_components/chromeos/smb_shares/add_smb_share_dialog.js b/ui/webui/resources/cr_components/chromeos/smb_shares/add_smb_share_dialog.js
index 56c44e1..54ac8aff 100644
--- a/ui/webui/resources/cr_components/chromeos/smb_shares/add_smb_share_dialog.js
+++ b/ui/webui/resources/cr_components/chromeos/smb_shares/add_smb_share_dialog.js
@@ -106,6 +106,7 @@
             SmbAuthMethod.KERBEROS :
             SmbAuthMethod.CREDENTIALS;
       },
+      observer: 'onAuthenticationMethodChanged_',
     },
 
     /** @private */
@@ -173,6 +174,15 @@
   },
 
   /**
+   * @param {string} newValue
+   * @param {string} oldValue
+   * @private
+   */
+  onAuthenticationMethodChanged_(newValue, oldValue) {
+    this.resetErrorState_();
+  },
+
+  /**
    * @return {boolean}
    * @private
    */
@@ -223,8 +233,13 @@
     switch (result) {
       // Credential Error
       case SmbMountResult.AUTHENTICATION_FAILED:
-        this.setCredentialError_(
-            loadTimeData.getString('smbShareAddedAuthFailedMessage'));
+        if (this.authenticationMethod_ === SmbAuthMethod.KERBEROS) {
+          this.setGeneralError_(
+              loadTimeData.getString('smbShareAddedAuthFailedMessage'));
+        } else {
+          this.setCredentialError_(
+              loadTimeData.getString('smbShareAddedAuthFailedMessage'));
+        }
         break;
 
       // Path Errors
diff --git a/url/BUILD.gn b/url/BUILD.gn
index 4aad0b6..0974b55 100644
--- a/url/BUILD.gn
+++ b/url/BUILD.gn
@@ -98,9 +98,7 @@
 
 if (is_android) {
   static_library("origin_android") {
-    sources = [
-      "android/origin_android.cc",
-    ]
+    sources = [ "android/origin_android.cc" ]
 
     deps = [
       ":url",
@@ -111,18 +109,12 @@
   }
 
   android_library("url_java") {
-    sources = [
-      "android/java/src/org/chromium/url/IDNStringUtil.java",
-    ]
-    deps = [
-      "//base:base_java",
-    ]
+    sources = [ "android/java/src/org/chromium/url/IDNStringUtil.java" ]
+    deps = [ "//base:base_java" ]
   }
 
   android_library("origin_java") {
-    sources = [
-      "android/java/src/org/chromium/url/Origin.java",
-    ]
+    sources = [ "android/java/src/org/chromium/url/Origin.java" ]
     deps = [
       "//base:base_java",
       "//url/mojom:url_mojom_origin_java",
@@ -208,9 +200,7 @@
 }
 
 fuzzer_test("gurl_fuzzer") {
-  sources = [
-    "gurl_fuzzer.cc",
-  ]
+  sources = [ "gurl_fuzzer.cc" ]
   deps = [
     ":url",
     "//base",
diff --git a/url/ipc/BUILD.gn b/url/ipc/BUILD.gn
index 52968a19..9b3d9db 100644
--- a/url/ipc/BUILD.gn
+++ b/url/ipc/BUILD.gn
@@ -17,17 +17,13 @@
     "//ipc",
     "//url",
   ]
-  deps = [
-    "//base",
-  ]
+  deps = [ "//base" ]
 }
 
 # IPC unit tests aren't build on iOS.
 if (!is_ios) {
   test("url_ipc_unittests") {
-    sources = [
-      "url_param_traits_unittest.cc",
-    ]
+    sources = [ "url_param_traits_unittest.cc" ]
 
     deps = [
       ":url_ipc",
diff --git a/url/mojom/BUILD.gn b/url/mojom/BUILD.gn
index e60a2a90..f809122c 100644
--- a/url/mojom/BUILD.gn
+++ b/url/mojom/BUILD.gn
@@ -6,16 +6,12 @@
 
 mojom("url_mojom_gurl") {
   generate_java = true
-  sources = [
-    "url.mojom",
-  ]
+  sources = [ "url.mojom" ]
 }
 
 mojom("url_mojom_origin") {
   generate_java = true
-  sources = [
-    "origin.mojom",
-  ]
+  sources = [ "origin.mojom" ]
 
   public_deps = [
     ":url_mojom_gurl",
@@ -26,9 +22,7 @@
 }
 
 mojom("test_url_mojom_gurl") {
-  sources = [
-    "url_test.mojom",
-  ]
+  sources = [ "url_test.mojom" ]
 
   public_deps = [
     ":url_mojom_gurl",
diff --git a/weblayer/browser/java/BUILD.gn b/weblayer/browser/java/BUILD.gn
index 4a48070..9c6d9c2 100644
--- a/weblayer/browser/java/BUILD.gn
+++ b/weblayer/browser/java/BUILD.gn
@@ -42,7 +42,6 @@
     "org/chromium/weblayer_private/FragmentWindowAndroid.java",
     "org/chromium/weblayer_private/FullscreenCallbackProxy.java",
     "org/chromium/weblayer_private/LocaleChangedBroadcastReceiver.java",
-    "org/chromium/weblayer_private/MinidumpUploader.java",
     "org/chromium/weblayer_private/NavigationControllerImpl.java",
     "org/chromium/weblayer_private/NavigationImpl.java",
     "org/chromium/weblayer_private/NewTabCallbackProxy.java",
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/CrashReporterControllerImpl.java b/weblayer/browser/java/org/chromium/weblayer_private/CrashReporterControllerImpl.java
index ed43222..1f147c0 100644
--- a/weblayer/browser/java/org/chromium/weblayer_private/CrashReporterControllerImpl.java
+++ b/weblayer/browser/java/org/chromium/weblayer_private/CrashReporterControllerImpl.java
@@ -18,6 +18,7 @@
 import org.chromium.base.task.AsyncTask;
 import org.chromium.components.crash.browser.ChildProcessCrashObserver;
 import org.chromium.components.minidump_uploader.CrashFileManager;
+import org.chromium.components.minidump_uploader.MinidumpUploader;
 import org.chromium.weblayer_private.interfaces.ICrashReporterController;
 import org.chromium.weblayer_private.interfaces.ICrashReporterControllerClient;
 import org.chromium.weblayer_private.interfaces.StrictModeWorkaround;
@@ -80,16 +81,16 @@
         AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
             File minidumpFile = getCrashFileManager().getCrashFileWithLocalId(localId);
             MinidumpUploader.Result result = new MinidumpUploader().upload(minidumpFile);
-            if (result.mSuccess) {
+            if (result.isSuccess()) {
                 CrashFileManager.markUploadSuccess(minidumpFile);
             } else {
                 CrashFileManager.tryIncrementAttemptNumber(minidumpFile);
             }
             try {
-                if (result.mSuccess) {
-                    mClient.onCrashUploadSucceeded(localId, result.mResult);
+                if (result.isSuccess()) {
+                    mClient.onCrashUploadSucceeded(localId, result.message());
                 } else {
-                    mClient.onCrashUploadFailed(localId, result.mResult);
+                    mClient.onCrashUploadFailed(localId, result.message());
                 }
             } catch (RemoteException e) {
                 throw new AndroidRuntimeException(e);