diff --git a/DEPS b/DEPS
index b9f9f00..ea93e86 100644
--- a/DEPS
+++ b/DEPS
@@ -189,7 +189,7 @@
   'checkout_reclient': False,
 
   # reclient CIPD package version
-  'reclient_version': 're_client_version:0.22.0.d95c8de',
+  'reclient_version': 're_client_version:0.23.0.edbb281',
 
   'android_git': 'https://android.googlesource.com',
   'aomedia_git': 'https://aomedia.googlesource.com',
@@ -204,11 +204,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': 'be54c66cdd08df96b5170c574d535730eeec4b2f',
+  'skia_revision': '2603c1fb145f5caa6fefe1532c185f515fff2f5e',
   # 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': '380d3d23acddd8b6eb5521fbf5cf30b9ff8ac301',
+  'v8_revision': '9c91874d93f2ca4e7df23a7abdb80bb888afb20b',
   # 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.
@@ -224,7 +224,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': '47754ac7c8421c93a54aa0a000656a7bc7212305',
+  'pdfium_revision': '0314adedee93768b6bc696e60f0630114abad77d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -283,7 +283,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': 'e7b220d512b2debe4621adcd571685f3ec4df7e5',
+  'devtools_frontend_revision': 'eacb47ae08da075f10f8e0a3987026c751fa6a6a',
   # 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.
@@ -930,7 +930,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'c2c576e9404d0a8fd14649f79fff13ea0d46b4e1',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '2f8ba755627741ed16e0cbc253dc37dd8897652a',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -1285,7 +1285,7 @@
     Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + '3dd5b80bc4f172dd82925bb259cb7c82348409c5',
 
   'src/third_party/openscreen/src':
-    Var('chromium_git') + '/openscreen' + '@' + 'a8a4c73136eb1dc451201e17d9d3c5cddd35718f',
+    Var('chromium_git') + '/openscreen' + '@' + '67a0bf042c8eb7791b39c87140d5733c0a21abf0',
 
   'src/third_party/openxr/src': {
     'url': Var('chromium_git') + '/external/github.com/KhronosGroup/OpenXR-SDK' + '@' + '97cfe495bb7a3853266b646d1c79e169387f9c7a',
@@ -1302,7 +1302,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'c600d9d76c9f4dacf63073cc0971779cef567fa2',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '6dfe3a2da9327700dbd4434c6c91ac2f6330fe19',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1610,7 +1610,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@70f6de137da5c577a576ea0bf0fb847b53504dca',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@7614260bb57f95cf58eef4958364da2c66b348bf',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index 43e37c5..047171c 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -3527,10 +3527,10 @@
       <message name="IDS_ASH_PCIE_PERIPHERAL_NOTIFICATION_GUEST_MODE_NOT_SUPPORTED" desc="Notification body text that explains to the user that their peripheral is not supported in Guest mode due to security reasons.">
         Peripheral not supported in Guest mode for security reasons
       </message>
-      <message name="IDS_ASH_PCIE_PERIPHERAL_NOTIFICATION_DEVICE_BLOCKED_TITLE" translateable="false" desc="Notification title that indicates to the user that their peripheral is not supported due to security reasons.">
+      <message name="IDS_ASH_PCIE_PERIPHERAL_NOTIFICATION_DEVICE_BLOCKED_TITLE" desc="Notification title that indicates to the user that their peripheral is not supported due to security reasons.">
         Peripheral not supported for security reasons
       </message>
-      <message name="IDS_ASH_PCIE_PERIPHERAL_NOTIFICATION_DEVICE_BLOCKED_BODY" translateable="false" desc="Notification body text that explains to the user that their peripheral is not supported because it is not part of the approved peripherals list.">
+      <message name="IDS_ASH_PCIE_PERIPHERAL_NOTIFICATION_DEVICE_BLOCKED_BODY" desc="Notification body text that explains to the user that their peripheral is not supported because it is not part of the approved peripherals list.">
         Only approved Thunderbolt devices are compatible with your Chromebook
       </message>
     </messages>
diff --git a/ash/ash_strings_grd/IDS_ASH_PCIE_PERIPHERAL_NOTIFICATION_DEVICE_BLOCKED_BODY.png.sha1 b/ash/ash_strings_grd/IDS_ASH_PCIE_PERIPHERAL_NOTIFICATION_DEVICE_BLOCKED_BODY.png.sha1
new file mode 100644
index 0000000..9c50474
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_PCIE_PERIPHERAL_NOTIFICATION_DEVICE_BLOCKED_BODY.png.sha1
@@ -0,0 +1 @@
+2294cb31f4b82463d9e6fc07b9447246a2aeb5f4
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_PCIE_PERIPHERAL_NOTIFICATION_DEVICE_BLOCKED_TITLE.png.sha1 b/ash/ash_strings_grd/IDS_ASH_PCIE_PERIPHERAL_NOTIFICATION_DEVICE_BLOCKED_TITLE.png.sha1
new file mode 100644
index 0000000..9c50474
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_PCIE_PERIPHERAL_NOTIFICATION_DEVICE_BLOCKED_TITLE.png.sha1
@@ -0,0 +1 @@
+2294cb31f4b82463d9e6fc07b9447246a2aeb5f4
\ No newline at end of file
diff --git a/ash/components/audio/cras_audio_handler.cc b/ash/components/audio/cras_audio_handler.cc
index 9aeb961..793981c 100644
--- a/ash/components/audio/cras_audio_handler.cc
+++ b/ash/components/audio/cras_audio_handler.cc
@@ -955,14 +955,12 @@
   // Mute the output during HDMI re-discovering grace period.
   if (hdmi_rediscovering_ && !IsHDMIPrimaryOutputDevice()) {
     VLOG(1) << "Mute the output during HDMI re-discovering grace period";
-    output_mute_on_ = true;
+    SetOutputMuteInternal(true);
   } else {
-    output_mute_on_ = audio_pref_handler_->GetMuteValue(*device);
+    SetOutputMuteInternal(audio_pref_handler_->GetMuteValue(*device));
   }
   output_volume_ = audio_pref_handler_->GetOutputVolumeValue(device);
 
-  SetOutputMuteInternal(output_mute_on_);
-
   if (initializing_audio_state_) {
     // During power up, InitializeAudioState() could be called twice, first
     // by CrasAudioHandler constructor, then by cras server restarting signal,
diff --git a/ash/strings/ash_strings_gu.xtb b/ash/strings/ash_strings_gu.xtb
index 7356c5e..492effa 100644
--- a/ash/strings/ash_strings_gu.xtb
+++ b/ash/strings/ash_strings_gu.xtb
@@ -873,7 +873,7 @@
 <translation id="8425213833346101688">બદલો</translation>
 <translation id="8426708595819210923">ગુડ ઇવનિંગ <ph name="GIVEN_NAME" />,</translation>
 <translation id="8427213022735114808">કોઈપણ ટેક્સ્ટ ફીલ્ડમાં અવાજ ટાઇપ કરવાને મંજૂરી આપવા માટે, શ્રુતલેખન Googleને તમારો અવાજ મોકલે છે.</translation>
-<translation id="8428213095426709021">સેટિંગ્સ</translation>
+<translation id="8428213095426709021">સેટિંગ</translation>
 <translation id="8433186206711564395">નેટવર્ક સેટિંગ્સ</translation>
 <translation id="8433977262951327081">શેલ્ફમાં મેનૂ પરપોટો ઇનપુટ વિકલ્પો બતાવવાનો શૉર્ટકટ બદલાયો છે. કૃપા કરીને <ph name="OLD_SHORTCUT" />ને બદલે <ph name="NEW_SHORTCUT" />નો ઉપયોગ કરો.</translation>
 <translation id="8444246603146515890">ડેસ્ક <ph name="DESK_TITILE" /> સક્રિય કર્યું</translation>
diff --git a/ash/wm/full_restore/full_restore_controller.cc b/ash/wm/full_restore/full_restore_controller.cc
index da437e0..bb8f0e4 100644
--- a/ash/wm/full_restore/full_restore_controller.cc
+++ b/ash/wm/full_restore/full_restore_controller.cc
@@ -177,8 +177,13 @@
     // storage size.
     window_info.visible_on_all_workspaces = true;
   }
-  window_info.restore_bounds = window_state->GetRestoreBoundsInScreen();
-  window_info.current_bounds = window->GetBoundsInScreen();
+  // If there are restore bounds, use those as current bounds. On restore, for
+  // states with restore bounds (maximized, minimized, snapped, etc), they will
+  // take the current bounds as their restore bounds and have the current bounds
+  // determined by the system.
+  window_info.current_bounds = window_state->HasRestoreBounds()
+                                   ? window_state->GetRestoreBoundsInScreen()
+                                   : window->GetBoundsInScreen();
   window_info.window_state_type = window_state->GetStateType();
   window_info.display_id =
       display::Screen::GetScreen()->GetDisplayNearestWindow(window).id();
diff --git a/base/android/java/src/org/chromium/base/PathUtils.java b/base/android/java/src/org/chromium/base/PathUtils.java
index 556a6ce7..28c6e546 100644
--- a/base/android/java/src/org/chromium/base/PathUtils.java
+++ b/base/android/java/src/org/chromium/base/PathUtils.java
@@ -19,6 +19,9 @@
 
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.MainDex;
+import org.chromium.base.compat.ApiHelperForM;
+import org.chromium.base.compat.ApiHelperForQ;
+import org.chromium.base.compat.ApiHelperForR;
 import org.chromium.base.task.AsyncTask;
 
 import java.io.File;
@@ -248,13 +251,13 @@
     public static @NonNull String[] getExternalDownloadVolumesNames() {
         ArrayList<File> files = new ArrayList<>();
         Set<String> volumes =
-                MediaStore.getExternalVolumeNames(ContextUtils.getApplicationContext());
+                ApiHelperForQ.getExternalVolumeNames(ContextUtils.getApplicationContext());
         for (String vol : volumes) {
             if (!TextUtils.isEmpty(vol) && !vol.contains(MediaStore.VOLUME_EXTERNAL_PRIMARY)) {
-                File volumeDir = ContextUtils.getApplicationContext()
-                                         .getSystemService(StorageManager.class)
-                                         .getStorageVolume(MediaStore.Files.getContentUri(vol))
-                                         .getDirectory();
+                StorageManager manager = ApiHelperForM.getSystemService(
+                        ContextUtils.getApplicationContext(), StorageManager.class);
+                File volumeDir =
+                        ApiHelperForR.getVolumeDir(manager, MediaStore.Files.getContentUri(vol));
                 assert volumeDir.isDirectory();
                 assert volumeDir.exists();
 
diff --git a/base/android/java/src/org/chromium/base/RadioUtils.java b/base/android/java/src/org/chromium/base/RadioUtils.java
index ee9f990..c1dc722 100644
--- a/base/android/java/src/org/chromium/base/RadioUtils.java
+++ b/base/android/java/src/org/chromium/base/RadioUtils.java
@@ -18,6 +18,8 @@
 
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
+import org.chromium.base.compat.ApiHelperForM;
+import org.chromium.base.compat.ApiHelperForP;
 
 /**
  * Exposes radio related information about the current device.
@@ -78,7 +80,7 @@
         ConnectivityManager connectivityManager =
                 (ConnectivityManager) ContextUtils.getApplicationContext().getSystemService(
                         Context.CONNECTIVITY_SERVICE);
-        Network network = connectivityManager.getActiveNetwork();
+        Network network = ApiHelperForM.getActiveNetwork(connectivityManager);
         if (network == null) return false;
         NetworkCapabilities networkCapabilities =
                 connectivityManager.getNetworkCapabilities(network);
@@ -99,7 +101,7 @@
                         Context.TELEPHONY_SERVICE);
         int level = -1;
         try {
-            SignalStrength signalStrength = telephonyManager.getSignalStrength();
+            SignalStrength signalStrength = ApiHelperForP.getSignalStrength(telephonyManager);
             if (signalStrength != null) {
                 level = signalStrength.getLevel();
             }
diff --git a/base/android/java/src/org/chromium/base/compat/ApiHelperForM.java b/base/android/java/src/org/chromium/base/compat/ApiHelperForM.java
index 5a5f9211..439a686 100644
--- a/base/android/java/src/org/chromium/base/compat/ApiHelperForM.java
+++ b/base/android/java/src/org/chromium/base/compat/ApiHelperForM.java
@@ -6,15 +6,24 @@
 
 import android.annotation.TargetApi;
 import android.app.Activity;
+import android.app.AlarmManager;
+import android.app.Notification;
 import android.app.PendingIntent;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Icon;
 import android.net.ConnectivityManager;
 import android.net.Network;
 import android.net.NetworkInfo;
+import android.os.BatteryManager;
 import android.os.Build;
+import android.os.PowerManager;
 import android.os.Process;
 import android.os.UserManager;
 import android.security.NetworkSecurityPolicy;
 import android.view.ActionMode;
+import android.view.Display;
+import android.view.MotionEvent;
 import android.view.ViewConfiguration;
 import android.webkit.WebView;
 import android.webkit.WebViewClient;
@@ -122,4 +131,77 @@
     public static int getPendingIntentImmutableFlag() {
         return PendingIntent.FLAG_IMMUTABLE;
     }
+
+    /** See {@link ConnectivityManager#reportNetworkConnectivity(Network, boolean)}. */
+    public static void reportNetworkConnectivity(
+            ConnectivityManager connectivityManager, Network network, boolean hasConnectivity) {
+        connectivityManager.reportNetworkConnectivity(network, hasConnectivity);
+    }
+
+    /** See {@link MotionEvent#getActionButton() }. */
+    public static int getActionButton(MotionEvent event) {
+        return event.getActionButton();
+    }
+
+    /** See {@link AlarmManager#setExactAndAllowWhileIdle(int, long, PendingIntent) }.  */
+    public static void setAlarmManagerExactAndAllowWhileIdle(AlarmManager alarmManager, int type,
+            long triggerAtMillis, PendingIntent pendingIntent) {
+        alarmManager.setExactAndAllowWhileIdle(type, triggerAtMillis, pendingIntent);
+    }
+
+    /** See {@link Display#getSupportedModes() }. */
+    public static Display.Mode[] getDisplaySupportedModes(Display display) {
+        return display.getSupportedModes();
+    }
+
+    /** See {@link Display#getMode() }. */
+    public static Display.Mode getDisplayMode(Display display) {
+        return display.getMode();
+    }
+
+    /** See {@link Display.Mode#getPhysicalWidth() }. */
+    public static int getModePhysicalWidth(Display.Mode mode) {
+        return mode.getPhysicalWidth();
+    }
+
+    /** See {@link Display.Mode#getPhysicalHeight() }. */
+    public static int getModePhysicalHeight(Display.Mode mode) {
+        return mode.getPhysicalHeight();
+    }
+
+    /** See {@link BatteryManager#isCharging() }. */
+    public static boolean isCharging(BatteryManager batteryManager) {
+        return batteryManager.isCharging();
+    }
+
+    /** See {@link Icon#createWithBitmap(Bitmap) }. */
+    public static Icon createIconWithBitmap(Bitmap bitmap) {
+        return Icon.createWithBitmap(bitmap);
+    }
+
+    /** See {@link PowerManager#isDeviceIdleMode() }. */
+    public static boolean isDeviceIdleMode(PowerManager powerManager) {
+        return powerManager.isDeviceIdleMode();
+    }
+
+    /** See {@link Notification.Builder#setSmallIcon(Icon)}. */
+    public static Notification.Builder setSmallIcon(Notification.Builder builder, Icon icon) {
+        return builder.setSmallIcon(icon);
+    }
+
+    /** See {@link Icon#createWithResource(Context, int)}. */
+    public static Icon createIconWithResource(Context context, int resId) {
+        return Icon.createWithResource(context, resId);
+    }
+
+    /** See {@link Context#getSystemService(Class<T>)}. */
+    public static <T> T getSystemService(Context context, Class<T> serviceClass) {
+        return context.getSystemService(serviceClass);
+    }
+
+    /** See {@link Notification.Action.Builder#Builder(Icon, CharSequence, PendingIntent)}. */
+    public static Notification.Action.Builder newNotificationActionBuilder(
+            Icon icon, CharSequence title, PendingIntent intent) {
+        return new Notification.Action.Builder(icon, title, intent);
+    }
 }
diff --git a/base/android/java/src/org/chromium/base/compat/ApiHelperForN.java b/base/android/java/src/org/chromium/base/compat/ApiHelperForN.java
index 8a7dee1..949f3a3 100644
--- a/base/android/java/src/org/chromium/base/compat/ApiHelperForN.java
+++ b/base/android/java/src/org/chromium/base/compat/ApiHelperForN.java
@@ -6,6 +6,7 @@
 
 import android.annotation.TargetApi;
 import android.app.Activity;
+import android.app.Notification;
 import android.app.job.JobInfo;
 import android.app.job.JobScheduler;
 import android.content.ClipData;
@@ -23,6 +24,7 @@
 import android.webkit.WebResourceRequest;
 import android.webkit.WebView;
 import android.webkit.WebViewClient;
+import android.widget.RemoteViews;
 
 import org.chromium.base.annotations.VerifiesOnN;
 
@@ -91,4 +93,16 @@
     public static long getStartUptimeMillis() {
         return Process.getStartUptimeMillis();
     }
+
+    /** See {@link Notification.Builder#setCustomContentView(RemoteViews)}. */
+    public static Notification.Builder setCustomContentView(
+            Notification.Builder builder, RemoteViews views) {
+        return builder.setCustomContentView(views);
+    }
+
+    /** See {@link Notification.Builder#setCustomBigContentView(RemoteViews)}. */
+    public static Notification.Builder setCustomBigContentView(
+            Notification.Builder builder, RemoteViews view) {
+        return builder.setCustomBigContentView(view);
+    }
 }
diff --git a/base/android/java/src/org/chromium/base/compat/ApiHelperForO.java b/base/android/java/src/org/chromium/base/compat/ApiHelperForO.java
index f855829..e3462c99 100644
--- a/base/android/java/src/org/chromium/base/compat/ApiHelperForO.java
+++ b/base/android/java/src/org/chromium/base/compat/ApiHelperForO.java
@@ -4,14 +4,20 @@
 
 package org.chromium.base.compat;
 
+import android.animation.ValueAnimator;
 import android.annotation.TargetApi;
 import android.app.Activity;
+import android.app.Notification;
 import android.content.ClipDescription;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
+import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.NetworkRequest;
 import android.os.Build;
+import android.os.Handler;
 import android.view.Display;
 import android.view.View;
 import android.view.Window;
@@ -95,4 +101,39 @@
             afm.notifyValueChanged(view);
         }
     }
+
+    /**
+     * See {@link ConnectivityManager#registerNetworkCallback(NetworkRequest,
+     * ConnectivityManager.NetworkCallback, Handler) }.
+     */
+    public static void registerNetworkCallback(ConnectivityManager connectivityManager,
+            NetworkRequest networkRequest, NetworkCallback networkCallback, Handler handler) {
+        connectivityManager.registerNetworkCallback(networkRequest, networkCallback, handler);
+    }
+
+    /** See {@link ValueAnimator#areAnimatorsEnabled()}. */
+    public static boolean areAnimatorsEnabled() {
+        return ValueAnimator.areAnimatorsEnabled();
+    }
+
+    /** See {@link Notification.Builder#setChannelId(String)}. */
+    public static Notification.Builder setChannelId(
+            Notification.Builder builder, String channelId) {
+        return builder.setChannelId(channelId);
+    }
+
+    /**
+     * See {@link
+     * ConnectivityManager#registerDefaultNetworkCallback(ConnectivityManager.NetworkCallback,
+     * Handler) }.
+     */
+    public static void registerDefaultNetworkCallback(ConnectivityManager connectivityManager,
+            NetworkCallback networkCallback, Handler handler) {
+        connectivityManager.registerDefaultNetworkCallback(networkCallback, handler);
+    }
+
+    /** See {@link Notification#getChannelId()}. */
+    public static String getNotificationChannelId(Notification notification) {
+        return notification.getChannelId();
+    }
 }
diff --git a/base/android/java/src/org/chromium/base/compat/ApiHelperForP.java b/base/android/java/src/org/chromium/base/compat/ApiHelperForP.java
index c4b41cf..f07481a0 100644
--- a/base/android/java/src/org/chromium/base/compat/ApiHelperForP.java
+++ b/base/android/java/src/org/chromium/base/compat/ApiHelperForP.java
@@ -9,6 +9,8 @@
 import android.location.LocationManager;
 import android.net.LinkProperties;
 import android.os.Build;
+import android.telephony.SignalStrength;
+import android.telephony.TelephonyManager;
 
 import org.chromium.base.annotations.VerifiesOnP;
 
@@ -41,4 +43,9 @@
     public static boolean isLocationEnabled(LocationManager locationManager) {
         return locationManager.isLocationEnabled();
     }
+
+    /** See {@link TelephonyManager#getSignalStrength() }. */
+    public static SignalStrength getSignalStrength(TelephonyManager telephonyManager) {
+        return telephonyManager.getSignalStrength();
+    }
 }
diff --git a/base/android/java/src/org/chromium/base/compat/ApiHelperForQ.java b/base/android/java/src/org/chromium/base/compat/ApiHelperForQ.java
index e7df4f5..169bec99 100644
--- a/base/android/java/src/org/chromium/base/compat/ApiHelperForQ.java
+++ b/base/android/java/src/org/chromium/base/compat/ApiHelperForQ.java
@@ -6,18 +6,29 @@
 
 import android.annotation.SuppressLint;
 import android.annotation.TargetApi;
+import android.app.Notification;
+import android.app.Service;
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.hardware.biometrics.BiometricManager;
+import android.net.Uri;
 import android.os.Build;
+import android.os.FileUtils;
+import android.provider.MediaStore;
 import android.telephony.CellInfo;
 import android.telephony.TelephonyManager;
+import android.view.MotionEvent;
 
 import org.chromium.base.Callback;
 import org.chromium.base.annotations.VerifiesOnQ;
 import org.chromium.base.task.AsyncTask;
 
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.util.List;
+import java.util.Set;
 import java.util.concurrent.Executor;
 
 /**
@@ -52,4 +63,40 @@
             Context context, ServiceConnection connection, int group, int importance) {
         context.updateServiceGroup(connection, group, importance);
     }
+
+    /** See {@link MotionEvent#getClassification() }. */
+    public static int getClassification(MotionEvent event) {
+        return event.getClassification();
+    }
+
+    /** See {@link Context#getSystemService(Class<T>) }. */
+    public static BiometricManager getBiometricManagerSystemService(Context context) {
+        return context.getSystemService(BiometricManager.class);
+    }
+
+    /** See {@link Service#startForegroung(int, Notification, int) }. */
+    public static void startForeground(
+            Service service, int id, Notification notification, int foregroundServiceType) {
+        service.startForeground(id, notification, foregroundServiceType);
+    }
+
+    /** See {@link FileUtils#copy(InputStream, OutputStream) }. */
+    public static long copy(InputStream in, OutputStream out) throws IOException {
+        return FileUtils.copy(in, out);
+    }
+
+    /** See {@link MediaStore#setIncludePending(Uri) }. */
+    public static Uri setIncludePending(Uri uri) {
+        return MediaStore.setIncludePending(uri);
+    }
+
+    /** See {@link MediaStore#getExternalVolumeNames(Context) }. */
+    public static Set<String> getExternalVolumeNames(Context context) {
+        return MediaStore.getExternalVolumeNames(context);
+    }
+
+    /** See {@link BiometricManager#canAuthenticate() }. */
+    public static int canAuthenticate(BiometricManager manager) {
+        return manager.canAuthenticate();
+    }
 }
diff --git a/base/android/java/src/org/chromium/base/compat/ApiHelperForR.java b/base/android/java/src/org/chromium/base/compat/ApiHelperForR.java
index d3c2d6c..e685773 100644
--- a/base/android/java/src/org/chromium/base/compat/ApiHelperForR.java
+++ b/base/android/java/src/org/chromium/base/compat/ApiHelperForR.java
@@ -6,11 +6,15 @@
 
 import android.annotation.TargetApi;
 import android.content.Context;
+import android.net.Uri;
 import android.os.Build;
+import android.os.storage.StorageManager;
 import android.view.Display;
 
 import org.chromium.base.annotations.VerifiesOnR;
 
+import java.io.File;
+
 /**
  * Utility class to use new APIs that were added in Q (API level 29). These need to exist in a
  * separate class so that Android framework can successfully verify classes without
@@ -24,4 +28,12 @@
     public static Display getDisplay(Context context) throws UnsupportedOperationException {
         return context.getDisplay();
     }
+
+    /**
+     * See {@link StorageManager#getStorageVolume(Uri)}.
+     * See {@link File#getDirectory()}.
+     */
+    public static File getVolumeDir(StorageManager manager, Uri uri) {
+        return manager.getStorageVolume(uri).getDirectory();
+    }
 }
diff --git a/base/test/launcher/test_launcher.cc b/base/test/launcher/test_launcher.cc
index 65e4b04..4ef0615 100644
--- a/base/test/launcher/test_launcher.cc
+++ b/base/test/launcher/test_launcher.cc
@@ -997,8 +997,9 @@
   options.flags = launcher_delegate_->GetLaunchOptions();
 
   ChildProcessResults process_results = DoLaunchChildTestProcess(
-      new_command_line, child_temp_dir, launcher_delegate_->GetTimeout(),
-      options, redirect_stdio_, launcher_delegate_);
+      new_command_line, child_temp_dir,
+      launcher_delegate_->GetTimeout() * test_names.size(), options,
+      redirect_stdio_, launcher_delegate_);
 
   // Invoke ProcessTestResults on the original thread, not
   // on a worker pool thread.
diff --git a/base/tracing/protos/chrome_track_event.proto b/base/tracing/protos/chrome_track_event.proto
index d1d128a0..5a8939e 100644
--- a/base/tracing/protos/chrome_track_event.proto
+++ b/base/tracing/protos/chrome_track_event.proto
@@ -59,9 +59,75 @@
   optional uint32 message_id = 1;
 }
 
+// An enumeration specifying the reason of the RenderFrame deletion.
+// This is copied from content/common/frame.mojom.
+enum FrameDeleteIntention {
+  // The frame being deleted isn't a (speculative) main frame.
+  FRAME_DELETE_INTENTION_NOT_MAIN_FRAME = 0;
+
+  // The frame being deleted is a speculative main frame, and it is being
+  // deleted as part of the shutdown for that WebContents. The entire RenderView
+  // etc will be destroyed by a separate IPC sent later.
+  FRAME_DELETE_INTENTION_SPECULATIVE_MAIN_FRAME_FOR_SHUTDOWN = 1;
+
+  // The frame being deleted is a speculative main frame, and it is being
+  // deleted because the speculative navigation was cancelled. This is not part
+  // of shutdown.
+  FRAME_DELETE_INTENTION_SPECULATIVE_MAIN_FRAME_FOR_NAVIGATION_CANCELLED = 2;
+}
+
+message RenderFrameImplDeletion {
+  // The intent for the deletion.
+  optional FrameDeleteIntention intent = 1;
+
+  // Whether the frame that's about to be deleted has a pending navigation
+  // commit.
+  optional bool has_pending_commit = 2;
+
+  // Whether the frame that's about to be deleted has a pending cross-document
+  // navigation commit.
+  optional bool has_pending_cross_document_commit = 3;
+
+  // The FrameTreeNode ID of the frame that's about to be deleted.
+  optional uint64 frame_tree_node_id = 4;
+}
+
+enum ShouldSwapBrowsingInstance {
+  // No BrowsingInstance swap.
+  SHOULD_SWAP_BROWSING_INSTANCE_NO = 0;
+
+  // Forced BrowsingInstance swap.
+  SHOULD_SWAP_BROWSING_INSTANCE_YES_FORCE_SWAP = 1;
+
+  // Proactive BrowsingInstance swap for cross-site navigation.
+  SHOULD_SWAP_BROWSING_INSTANCE_YES_CROSS_SITE_PROACTIVE_SWAP = 2;
+
+  // Proactive BrowsingInstance swap for same-site navigation.
+  SHOULD_SWAP_BROWSING_INSTANCE_YES_SAME_SITE_PROACTIVE_SWAP = 3;
+}
+
+message ShouldSwapBrowsingInstancesResult {
+  // The FrameTreeNode ID.
+  optional uint64 frame_tree_node_id = 1;
+
+  // Whether a navigation will do a BrowsingInstance swap or not.
+  optional ShouldSwapBrowsingInstance result = 2;
+}
+
+message FrameTreeNodeInfo {
+  // The FrameTreeNode ID.
+  optional uint64 frame_tree_node_id = 1;
+
+  // Whether the frame is a main frame or not.
+  optional bool is_main_frame = 2;
+
+  // Whether there's a speculative RenderFrameHost or not.
+  optional bool has_speculative_render_frame_host = 3;
+}
+
 message ChromeTrackEvent {
   // Extension range for Chrome: 1000-1999
-  // Next ID: 1008
+  // Next ID: 1011
   extend TrackEvent {
     optional ChromeAppState chrome_app_state = 1000;
 
@@ -80,5 +146,12 @@
     optional ChromeTaskGraphRunner chrome_task_graph_runner = 1006;
 
     optional ChromeMessagePumpForUI chrome_message_pump_for_ui = 1007;
+
+    optional RenderFrameImplDeletion render_frame_impl_deletion = 1008;
+
+    optional ShouldSwapBrowsingInstancesResult
+        should_swap_browsing_instances_result = 1009;
+
+    optional FrameTreeNodeInfo frame_tree_node_info = 1010;
   }
 }
diff --git a/build/config/clang/BUILD.gn b/build/config/clang/BUILD.gn
index 21739874..180e2e62 100644
--- a/build/config/clang/BUILD.gn
+++ b/build/config/clang/BUILD.gn
@@ -15,6 +15,10 @@
       "-add-plugin",
       "-Xclang",
       "find-bad-constructs",
+      "-Xclang",
+      "-plugin-arg-find-bad-constructs",
+      "-Xclang",
+      "checked-ptr-as-trivial-member",
     ]
 
     if (is_linux || is_chromeos || is_android || is_fuchsia) {
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index cd5c9267..20c3af9 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-3.20210310.2.1
+3.20210311.0.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index cd5c9267..20c3af9 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-3.20210310.2.1
+3.20210311.0.1
diff --git a/chrome/VERSION b/chrome/VERSION
index 5ba0e791..f578845 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=91
 MINOR=0
-BUILD=4443
+BUILD=4444
 PATCH=0
diff --git a/chrome/android/features/tab_ui/java/strings/translations/android_chrome_tab_ui_strings_de.xtb b/chrome/android/features/tab_ui/java/strings/translations/android_chrome_tab_ui_strings_de.xtb
index 2381672..3508d7c5 100644
--- a/chrome/android/features/tab_ui/java/strings/translations/android_chrome_tab_ui_strings_de.xtb
+++ b/chrome/android/features/tab_ui/java/strings/translations/android_chrome_tab_ui_strings_de.xtb
@@ -21,6 +21,7 @@
 <translation id="3291470810748040983">Sie erhalten eine Benachrichtigung, wenn auf einem offenen Tab ein günstigerer Preis verfügbar ist</translation>
 <translation id="3328308545011660196">Vorschlag: <ph name="NUMBER_OF_TABS" /> Tabs scheinen zusammenzugehören. Sollen sie gruppiert werden?</translation>
 <translation id="3819916404117584598">{TABS_COUNT,plural, =1{<ph name="TABS_COUNT_ONE" /> Tab minimieren}other{Tabgruppe "<ph name="TITLE_OF_GROUP" />" mit <ph name="TABS_COUNT_MANY" /> Tabs minimieren}}</translation>
+<translation id="3882834874697329510">Falls Sie benachrichtigt werden möchten, wenn auf einem offenen Tab ein günstigerer Preis verfügbar ist, aktivieren Sie Benachrichtigungen in den Einstellungen.</translation>
 <translation id="3940195383040445971">Preise auf Tabs beobachten</translation>
 <translation id="3996880007329611795">Benachrichtigungen erhalten</translation>
 <translation id="4133493477912226187"><ph name="NUMBER_OF_TABS" /> Tabs scheinen zusammenzugehören. Sollen sie gruppiert werden?</translation>
diff --git a/chrome/android/features/tab_ui/java/strings/translations/android_chrome_tab_ui_strings_pa.xtb b/chrome/android/features/tab_ui/java/strings/translations/android_chrome_tab_ui_strings_pa.xtb
index a1b9ac2..7fc4bde 100644
--- a/chrome/android/features/tab_ui/java/strings/translations/android_chrome_tab_ui_strings_pa.xtb
+++ b/chrome/android/features/tab_ui/java/strings/translations/android_chrome_tab_ui_strings_pa.xtb
@@ -21,6 +21,7 @@
 <translation id="3291470810748040983">ਖੁੱਲ੍ਹੀ ਟੈਬ ਵਿੱਚ ਕੀਮਤ ਘੱਟ ਹੋਣ 'ਤੇ ਤੁਹਾਨੂੰ ਸੁਚੇਤਨਾ ਪ੍ਰਾਪਤ ਹੋਵੇਗੀ</translation>
 <translation id="3328308545011660196">ਸੁਝਾਅ: <ph name="NUMBER_OF_TABS" /> ਟੈਬਾਂ ਸੰਬੰਧਿਤ ਲੱਗਦੀਆਂ ਹਨ। ਕੀ ਉਹਨਾਂ ਨੂੰ ਗਰੁੱਪਬੱਧ ਕਰਨਾ ਹੈ?</translation>
 <translation id="3819916404117584598">{TABS_COUNT,plural, =1{<ph name="TABS_COUNT_ONE" /> ਟੈਬ ਨੂੰ ਸਮੇਟੋ।}one{<ph name="TABS_COUNT_MANY" /> ਟੈਬ ਵਾਲੇ <ph name="TITLE_OF_GROUP" /> ਟੈਬ ਗਰੁੱਪ ਨੂੰ ਸਮੇਟੋ।}other{<ph name="TABS_COUNT_MANY" /> ਟੈਬਾਂ ਵਾਲੇ <ph name="TITLE_OF_GROUP" /> ਟੈਬ ਗਰੁੱਪ ਨੂੰ ਸਮੇਟੋ।}}</translation>
+<translation id="3882834874697329510">ਖੁੱਲ੍ਹੀ ਟੈਬ ਵਿੱਚ ਕੀਮਤ ਘੱਟ ਹੋਣ 'ਤੇ ਸੁਚੇਤਨਾ ਪ੍ਰਾਪਤ ਕਰਨ ਲਈ, ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਸੂਚਨਾਵਾਂ ਨੂੰ ਚਾਲੂ ਕਰੋ।</translation>
 <translation id="3940195383040445971">ਟੈਬਾਂ ਵਿੱਚ ਕੀਮਤਾਂ 'ਤੇ ਨਜ਼ਰ ਰੱਖੋ</translation>
 <translation id="3996880007329611795">ਸੂਚਨਾ ਪ੍ਰਾਪਤ ਕਰੋ</translation>
 <translation id="4133493477912226187"><ph name="NUMBER_OF_TABS" /> ਟੈਬਾਂ ਸੰਬੰਧਿਤ ਲੱਗਦੀਆਂ ਹਨ। ਕੀ ਉਹਨਾਂ ਨੂੰ ਗਰੁੱਪਬੱਧ ਕਰਨਾ ਹੈ?</translation>
diff --git a/chrome/android/features/tab_ui/java/strings/translations/android_chrome_tab_ui_strings_uk.xtb b/chrome/android/features/tab_ui/java/strings/translations/android_chrome_tab_ui_strings_uk.xtb
index d24c6f81..1e73b838 100644
--- a/chrome/android/features/tab_ui/java/strings/translations/android_chrome_tab_ui_strings_uk.xtb
+++ b/chrome/android/features/tab_ui/java/strings/translations/android_chrome_tab_ui_strings_uk.xtb
@@ -21,7 +21,7 @@
 <translation id="3291470810748040983">Коли на відкритій вкладці знизиться ціна, ви отримаєте сповіщення</translation>
 <translation id="3328308545011660196">Підказка: схоже, ви відкрили кілька пов'язаних вкладок (<ph name="NUMBER_OF_TABS" />). Додати їх у групу?</translation>
 <translation id="3819916404117584598">{TABS_COUNT,plural, =1{Згорнути <ph name="TABS_COUNT_ONE" /> вкладку}one{Згорнути групу "<ph name="TITLE_OF_GROUP" />" з <ph name="TABS_COUNT_MANY" /> вкладкою}few{Згорнути групу "<ph name="TITLE_OF_GROUP" />" з <ph name="TABS_COUNT_MANY" /> вкладками}many{Згорнути групу "<ph name="TITLE_OF_GROUP" />" з <ph name="TABS_COUNT_MANY" /> вкладками}other{Згорнути групу "<ph name="TITLE_OF_GROUP" />" з <ph name="TABS_COUNT_MANY" /> вкладки}}</translation>
-<translation id="3882834874697329510">Щоб отримувати сповіщення, коли на відкритій вкладці знижується ціна, перейдіть у налаштування й увімкніть їх.</translation>
+<translation id="3882834874697329510">Увімкніть їх у налаштуваннях, щоб дізнаватися, коли на відкритій вкладці знижуватиметься ціна.</translation>
 <translation id="3940195383040445971">Відстежувати ціни на вкладках</translation>
 <translation id="3996880007329611795">Отримувати сповіщення</translation>
 <translation id="4133493477912226187">Схоже, ви відкрили кілька пов'язаних вкладок (<ph name="NUMBER_OF_TABS" />). Додати їх у групу?</translation>
diff --git a/chrome/android/features/tab_ui/java/strings/translations/android_chrome_tab_ui_strings_zh-CN.xtb b/chrome/android/features/tab_ui/java/strings/translations/android_chrome_tab_ui_strings_zh-CN.xtb
index 69f6cc22..97563bf7 100644
--- a/chrome/android/features/tab_ui/java/strings/translations/android_chrome_tab_ui_strings_zh-CN.xtb
+++ b/chrome/android/features/tab_ui/java/strings/translations/android_chrome_tab_ui_strings_zh-CN.xtb
@@ -21,6 +21,7 @@
 <translation id="3291470810748040983">当某个已打开的标签页中有商品降价时,您会收到提醒</translation>
 <translation id="3328308545011660196">建议:有 <ph name="NUMBER_OF_TABS" /> 个标签页似乎彼此相关。为它们建组?</translation>
 <translation id="3819916404117584598">{TABS_COUNT,plural, =1{收起 <ph name="TABS_COUNT_ONE" /> 个标签页。}other{收起包含 <ph name="TABS_COUNT_MANY" /> 个标签页的“<ph name="TITLE_OF_GROUP" />”标签页组。}}</translation>
+<translation id="3882834874697329510">如果想在某个已打开的标签页中有商品降价时收到提醒,请在“设置”中开启通知功能。</translation>
 <translation id="3940195383040445971">跟踪标签页上的价格</translation>
 <translation id="3996880007329611795">接收通知</translation>
 <translation id="4133493477912226187">有 <ph name="NUMBER_OF_TABS" /> 个标签页似乎彼此相关。为它们建组?</translation>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AutofillOfferNotificationInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AutofillOfferNotificationInfoBar.java
index 96206a9..32089d6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AutofillOfferNotificationInfoBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AutofillOfferNotificationInfoBar.java
@@ -19,6 +19,7 @@
 import org.chromium.components.infobars.InfoBarLayout;
 import org.chromium.ui.UiUtils;
 import org.chromium.ui.text.NoUnderlineClickableSpan;
+import org.chromium.url.GURL;
 
 /**
  * Infobar to be displayed when an offer is available for the current merchant website.
@@ -26,14 +27,14 @@
 public class AutofillOfferNotificationInfoBar extends ConfirmInfoBar {
     private final long mNativeAutofillOfferNotificationInfoBar;
     private String mCreditCardIdentifierString;
-    private String mOfferDeepLinkUrl;
+    private GURL mOfferDeepLinkUrl;
     private String mTitleText;
     private int mHeaderIconDrawableId;
     private int mNetworkIconDrawableId = -1;
 
     private AutofillOfferNotificationInfoBar(long nativeAutofillOfferNotificationInfoBar,
             int headerIconDrawableId, String title, String positiveButtonLabel,
-            String offerDeepLinkUrl) {
+            GURL offerDeepLinkUrl) {
         // No icon is specified here; it is rather added in |createContent|. This hides the
         // ImageView that normally shows the icon and gets rid of the left padding of the infobar
         // content.
@@ -48,7 +49,7 @@
     @CalledByNative
     private static AutofillOfferNotificationInfoBar create(
             long nativeAutofillOfferNotificationInfoBar, int headerIconDrawableId, String title,
-            String positiveButtonLabel, String offerDeepLinkUrl) {
+            String positiveButtonLabel, GURL offerDeepLinkUrl) {
         return new AutofillOfferNotificationInfoBar(nativeAutofillOfferNotificationInfoBar,
                 headerIconDrawableId, title, positiveButtonLabel, offerDeepLinkUrl);
     }
@@ -79,7 +80,7 @@
                 indexForCardIdentifierString + mCreditCardIdentifierString.length(),
                 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
 
-        if (!TextUtils.isEmpty(mOfferDeepLinkUrl)) {
+        if (mOfferDeepLinkUrl.isValid()) {
             String linkText =
                     getContext().getString(R.string.autofill_offers_reminder_deep_link_text);
             NoUnderlineClickableSpan noUnderlineClickableSpan = new NoUnderlineClickableSpan(
@@ -99,6 +100,6 @@
     @NativeMethods
     interface Natives {
         void onOfferDeepLinkClicked(long nativeAutofillOfferNotificationInfoBar,
-                AutofillOfferNotificationInfoBar caller, String url);
+                AutofillOfferNotificationInfoBar caller, GURL url);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilderBase.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilderBase.java
index 2c2d6ea..6620fb4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilderBase.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilderBase.java
@@ -24,6 +24,7 @@
 import androidx.core.app.NotificationCompat;
 import androidx.core.graphics.drawable.IconCompat;
 
+import org.chromium.base.compat.ApiHelperForM;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.components.browser_ui.notifications.NotificationMetadata;
 import org.chromium.components.browser_ui.notifications.NotificationWrapper;
@@ -503,7 +504,7 @@
             // The Icon class was added in Android M.
             Bitmap publicIcon = mSmallIconBitmapForStatusBar.copy(
                     mSmallIconBitmapForStatusBar.getConfig(), true);
-            builder.setSmallIcon(Icon.createWithBitmap(publicIcon));
+            builder.setSmallIcon(ApiHelperForM.createIconWithBitmap(publicIcon));
         } else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M && mOrigin != null) {
             // Only set the large icon for L & M because on N(+?) it would add an extra icon on
             // the right hand side, which looks odd without a notification title.
@@ -539,7 +540,7 @@
             NotificationWrapperBuilder builder, int iconId, @Nullable Bitmap iconBitmap) {
         if (iconBitmap != null) {
             assert deviceSupportsBitmapStatusBarIcons();
-            builder.setSmallIcon(Icon.createWithBitmap(iconBitmap));
+            builder.setSmallIcon(ApiHelperForM.createIconWithBitmap(iconBitmap));
         } else {
             builder.setSmallIcon(iconId);
         }
@@ -639,8 +640,8 @@
     private static Notification.Action.Builder getActionBuilderStandard(Action action) {
         PendingIntent intent = action.intent.getPendingIntent();
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && action.iconBitmap != null) {
-            Icon icon = Icon.createWithBitmap(action.iconBitmap);
-            return new Notification.Action.Builder(icon, action.title, intent);
+            Icon icon = ApiHelperForM.createIconWithBitmap(action.iconBitmap);
+            return ApiHelperForM.newNotificationActionBuilder(icon, action.title, intent);
         }
         return new Notification.Action.Builder(action.iconId, action.title, intent);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationServiceImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationServiceImpl.java
index 58f28a1..3c06d16 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationServiceImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationServiceImpl.java
@@ -37,10 +37,12 @@
     public static class Receiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
-            int actionIndex = intent.getIntExtra(
-                    NotificationConstants.EXTRA_NOTIFICATION_INFO_ACTION_INDEX, -1);
-            boolean isActionButton = actionIndex != -1;
-            WebPlatformNotificationMetrics.getInstance().onNotificationClicked(isActionButton);
+            if (NotificationConstants.ACTION_CLICK_NOTIFICATION.equals(intent.getAction())) {
+                int actionIndex = intent.getIntExtra(
+                        NotificationConstants.EXTRA_NOTIFICATION_INFO_ACTION_INDEX, -1);
+                boolean isActionButton = actionIndex != -1;
+                WebPlatformNotificationMetrics.getInstance().onNotificationClicked(isActionButton);
+            }
 
             Log.i(TAG, "Received a notification intent in the NotificationService's receiver.");
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java
index bb24576a..b21a2bd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java
@@ -6,17 +6,18 @@
 
 import android.annotation.TargetApi;
 import android.app.Notification;
-import android.app.NotificationChannel;
 import android.app.NotificationManager;
 import android.os.Build;
 import android.text.format.DateUtils;
 
 import androidx.annotation.IntDef;
 import androidx.annotation.Nullable;
+import androidx.core.app.NotificationChannelCompat;
 import androidx.core.app.NotificationManagerCompat;
 
 import org.chromium.base.ContextUtils;
 import org.chromium.base.MathUtils;
+import org.chromium.base.compat.ApiHelperForO;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.browser.notifications.channels.ChromeChannelDefinitions;
@@ -176,7 +177,7 @@
         if (type == SystemNotificationType.UNKNOWN || notification == null) return;
 
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-            logNotificationShown(type, notification.getChannelId());
+            logNotificationShown(type, ApiHelperForO.getNotificationChannelId(notification));
         } else {
             logNotificationShown(type, null);
         }
@@ -300,11 +301,10 @@
 
     @TargetApi(26)
     private boolean isChannelBlocked(@ChromeChannelDefinitions.ChannelId String channelId) {
-        // Use non-compat notification manager as compat does not have getNotificationChannel (yet).
-        NotificationManager notificationManager =
-                ContextUtils.getApplicationContext().getSystemService(NotificationManager.class);
-        NotificationChannel channel = notificationManager.getNotificationChannel(channelId);
-        return channel != null && channel.getImportance() == NotificationManager.IMPORTANCE_NONE;
+        NotificationChannelCompat channel =
+                mNotificationManager.getNotificationChannelCompat(channelId);
+        return channel != null
+                && channel.getImportance() == NotificationManagerCompat.IMPORTANCE_NONE;
     }
 
     private void saveLastShownNotification(@SystemNotificationType int type) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/WebPlatformNotificationMetrics.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/WebPlatformNotificationMetrics.java
index 1f711da..b8c7729 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/WebPlatformNotificationMetrics.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/WebPlatformNotificationMetrics.java
@@ -22,8 +22,8 @@
  * counts.
  */
 public class WebPlatformNotificationMetrics {
-    private static final String METRIC_PREFIX = "Notifications.WebPlatform.";
-    private static final int ATTRIBUTION_THRESHOLD_MS = 5000;
+    private static final String METRIC_PREFIX = "Notifications.WebPlatformV2.";
+    private static final int ATTRIBUTION_THRESHOLD_MS = 10_000;
     private static final long INVALID_TIME = -1;
     private static WebPlatformNotificationMetrics sInstance;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/BiometricAuthenticatorBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/BiometricAuthenticatorBridge.java
index 11dce24c..558e5b1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/BiometricAuthenticatorBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/BiometricAuthenticatorBridge.java
@@ -16,6 +16,7 @@
 import androidx.core.hardware.fingerprint.FingerprintManagerCompat;
 
 import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.compat.ApiHelperForQ;
 import org.chromium.ui.base.WindowAndroid;
 
 class BiometricAuthenticatorBridge {
@@ -33,8 +34,9 @@
     @CalledByNative
     public @BiometricsAvailability int canAuthenticate() {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
-            BiometricManager biometricManager = mContext.getSystemService(BiometricManager.class);
-            switch (biometricManager.canAuthenticate()) {
+            BiometricManager biometricManager =
+                    ApiHelperForQ.getBiometricManagerSystemService(mContext);
+            switch (ApiHelperForQ.canAuthenticate(biometricManager)) {
                 case BIOMETRIC_SUCCESS:
                     return BiometricsAvailability.AVAILABLE;
                 case BIOMETRIC_ERROR_NO_HARDWARE:
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninActivityLauncherImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninActivityLauncherImpl.java
index 0413320..a066f26d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninActivityLauncherImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninActivityLauncherImpl.java
@@ -21,8 +21,8 @@
  * SigninActivityLauncher creates the proper intent and then launches the
  * SigninActivity in different scenarios.
  */
-public class SigninActivityLauncherImpl implements SigninActivityLauncher {
-    private static SigninActivityLauncherImpl sLauncher;
+public final class SigninActivityLauncherImpl implements SigninActivityLauncher {
+    private static SigninActivityLauncher sLauncher;
 
     /**
      * Singleton instance getter
@@ -35,7 +35,7 @@
     }
 
     @VisibleForTesting
-    public static void setLauncherForTest(@Nullable SigninActivityLauncherImpl launcher) {
+    public static void setLauncherForTest(@Nullable SigninActivityLauncher launcher) {
         sLauncher = launcher;
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedSigninPromoTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedSigninPromoTest.java
index 24a11483..266e005 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedSigninPromoTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedSigninPromoTest.java
@@ -36,6 +36,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.signin.SigninActivityLauncherImpl;
+import org.chromium.chrome.browser.signin.ui.SigninActivityLauncher;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.chrome.test.batch.BlankCTATabInitialStateRule;
@@ -70,14 +71,14 @@
     public final RuleChain chain =
             RuleChain.outerRule(mAccountManagerTestRule).around(mBookmarkTestRule);
 
-    private final SigninActivityLauncherImpl mMockSigninActivityLauncherImpl =
-            mock(SigninActivityLauncherImpl.class);
+    private final SigninActivityLauncher mMockSigninActivityLauncher =
+            mock(SigninActivityLauncher.class);
 
     @Before
     public void setUp() {
         BookmarkPromoHeader.forcePromoStateForTests(
                 BookmarkPromoHeader.PromoState.PROMO_SIGNIN_PERSONALIZED);
-        SigninActivityLauncherImpl.setLauncherForTest(mMockSigninActivityLauncherImpl);
+        SigninActivityLauncherImpl.setLauncherForTest(mMockSigninActivityLauncher);
     }
 
     @After
@@ -96,7 +97,7 @@
                 mAccountManagerTestRule.addAccount(AccountManagerTestRule.TEST_ACCOUNT_EMAIL);
         showBookmarkManagerAndCheckSigninPromoIsDisplayed();
         onView(withId(R.id.signin_promo_signin_button)).perform(click());
-        verify(mMockSigninActivityLauncherImpl)
+        verify(mMockSigninActivityLauncher)
                 .launchActivityForPromoDefaultFlow(any(Activity.class),
                         eq(SigninAccessPoint.BOOKMARK_MANAGER), eq(accountInfo.getEmail()));
     }
@@ -111,7 +112,7 @@
                 mAccountManagerTestRule.addAccount(AccountManagerTestRule.TEST_ACCOUNT_EMAIL);
         showBookmarkManagerAndCheckSigninPromoIsDisplayed();
         onView(withId(R.id.signin_promo_choose_account_button)).perform(click());
-        verify(mMockSigninActivityLauncherImpl)
+        verify(mMockSigninActivityLauncher)
                 .launchActivityForPromoChooseAccountFlow(any(Activity.class),
                         eq(SigninAccessPoint.BOOKMARK_MANAGER), eq(accountInfo.getEmail()));
     }
@@ -124,7 +125,7 @@
                 .launchActivityForPromoAddAccountFlow(any(Context.class), anyInt());
         showBookmarkManagerAndCheckSigninPromoIsDisplayed();
         onView(withId(R.id.signin_promo_signin_button)).perform(click());
-        verify(mMockSigninActivityLauncherImpl)
+        verify(mMockSigninActivityLauncher)
                 .launchActivityForPromoAddAccountFlow(
                         any(Activity.class), eq(SigninAccessPoint.BOOKMARK_MANAGER));
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/settings/MainSettingsFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/settings/MainSettingsFragmentTest.java
index f9ac9fd..2b8506a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/settings/MainSettingsFragmentTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/settings/MainSettingsFragmentTest.java
@@ -63,6 +63,7 @@
 import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.chrome.browser.search_engines.settings.SearchEngineSettings;
 import org.chromium.chrome.browser.signin.SigninActivityLauncherImpl;
+import org.chromium.chrome.browser.signin.ui.SigninActivityLauncher;
 import org.chromium.chrome.browser.sync.ProfileSyncService;
 import org.chromium.chrome.browser.sync.SyncTestRule;
 import org.chromium.chrome.browser.sync.settings.SignInPreference;
@@ -125,7 +126,7 @@
     private PasswordCheck mPasswordCheck;
 
     @Mock
-    private SigninActivityLauncherImpl mMockSigninActivityLauncherImpl;
+    private SigninActivityLauncher mMockSigninActivityLauncher;
 
     private @Nullable TemplateUrlService mActualTemplateUrlService;
 
@@ -136,7 +137,7 @@
         MockitoAnnotations.initMocks(this);
         InstrumentationRegistry.getInstrumentation().setInTouchMode(true);
         PasswordCheckFactory.setPasswordCheckForTesting(mPasswordCheck);
-        SigninActivityLauncherImpl.setLauncherForTest(mMockSigninActivityLauncherImpl);
+        SigninActivityLauncherImpl.setLauncherForTest(mMockSigninActivityLauncher);
         DeveloperSettings.setIsEnabledForTests(true);
         NightModeUtils.setNightModeSupportedForTesting(true);
     }
@@ -324,7 +325,7 @@
         launchSettingsActivity();
 
         onView(withText(R.string.sync_category_title)).perform(click());
-        verify(mMockSigninActivityLauncherImpl)
+        verify(mMockSigninActivityLauncher)
                 .launchActivityForPromoDefaultFlow(any(Activity.class),
                         eq(SigninAccessPoint.SETTINGS), eq(accountInfo.getEmail()));
     }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/notifications/WebPlatformNotificationMetricsTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/notifications/WebPlatformNotificationMetricsTest.java
index 7bc79d6..9fabc0d 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/notifications/WebPlatformNotificationMetricsTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/notifications/WebPlatformNotificationMetricsTest.java
@@ -58,8 +58,8 @@
     public void recordsClick() {
         mMetrics.onNotificationClicked(mActionButtonClicked);
 
-        assertActionRecorded(mActionButtonClicked ? "Notifications.WebPlatform.ActionButton.Click"
-                                                  : "Notifications.WebPlatform.Body.Click");
+        assertActionRecorded(mActionButtonClicked ? "Notifications.WebPlatformV2.ActionButton.Click"
+                                                  : "Notifications.WebPlatformV2.Body.Click");
         assertNumActions(1);
     }
 
@@ -69,8 +69,8 @@
         mMetrics.onTabFocused();
 
         assertActionRecorded(mActionButtonClicked
-                        ? "Notifications.WebPlatform.ActionButton.FocusActivity"
-                        : "Notifications.WebPlatform.Body.FocusActivity");
+                        ? "Notifications.WebPlatformV2.ActionButton.FocusActivity"
+                        : "Notifications.WebPlatformV2.Body.FocusActivity");
         assertNumActions(2); // Click + FocusActivity.
     }
 
@@ -81,8 +81,8 @@
         mMetrics.onTabFocused();
 
         assertActionRecorded(mActionButtonClicked
-                        ? "Notifications.WebPlatform.ActionButton.NewActivity"
-                        : "Notifications.WebPlatform.Body.NewActivity");
+                        ? "Notifications.WebPlatformV2.ActionButton.NewActivity"
+                        : "Notifications.WebPlatformV2.Body.NewActivity");
         assertNumActions(2); // Click + NewActivity.
     }
 
@@ -91,8 +91,8 @@
         mMetrics.onNotificationClicked(mActionButtonClicked);
         mMetrics.onNotificationClosed();
 
-        assertActionRecorded(mActionButtonClicked ? "Notifications.WebPlatform.ActionButton.Close"
-                                                  : "Notifications.WebPlatform.Body.Close");
+        assertActionRecorded(mActionButtonClicked ? "Notifications.WebPlatformV2.ActionButton.Close"
+                                                  : "Notifications.WebPlatformV2.Body.Close");
         assertNumActions(2); // Click + Close.
     }
 
@@ -101,14 +101,14 @@
         mMetrics.onNotificationClicked(mActionButtonClicked);
         mMetrics.onNotificationClosed();
 
-        assertActionRecorded(mActionButtonClicked ? "Notifications.WebPlatform.ActionButton.Close"
-                                                  : "Notifications.WebPlatform.Body.Close");
+        assertActionRecorded(mActionButtonClicked ? "Notifications.WebPlatformV2.ActionButton.Close"
+                                                  : "Notifications.WebPlatformV2.Body.Close");
 
         mMetrics.onTabFocused();
 
         assertActionRecorded(mActionButtonClicked
-                        ? "Notifications.WebPlatform.ActionButton.FocusActivity"
-                        : "Notifications.WebPlatform.Body.FocusActivity");
+                        ? "Notifications.WebPlatformV2.ActionButton.FocusActivity"
+                        : "Notifications.WebPlatformV2.Body.FocusActivity");
         assertNumActions(3); // Click + Close + FocusActivity.
     }
 
@@ -154,7 +154,7 @@
     public void timeLimitOnClose() {
         mMetrics.onNotificationClicked(mActionButtonClicked);
 
-        when(mClock.getTime()).thenReturn(7000L);
+        when(mClock.getTime()).thenReturn(12_000L);
         mMetrics.onNotificationClosed();
 
         assertNumActions(1); // Click.
@@ -164,7 +164,7 @@
     public void timeLimitOnFocus() {
         mMetrics.onNotificationClicked(mActionButtonClicked);
 
-        when(mClock.getTime()).thenReturn(7000L);
+        when(mClock.getTime()).thenReturn(12_000L);
         mMetrics.onTabFocused();
 
         assertNumActions(1); // Click.
@@ -178,8 +178,8 @@
         mMetrics.onTabFocused();
 
         assertDurationRecorded(mActionButtonClicked
-                        ? "Notifications.WebPlatform.ActionButton.TimeToActivity"
-                        : "Notifications.WebPlatform.Body.TimeToActivity",
+                        ? "Notifications.WebPlatformV2.ActionButton.TimeToActivity"
+                        : "Notifications.WebPlatformV2.Body.TimeToActivity",
                 2000);
     }
 
@@ -191,8 +191,8 @@
         mMetrics.onNotificationClosed();
 
         assertDurationRecorded(mActionButtonClicked
-                        ? "Notifications.WebPlatform.ActionButton.TimeToClose"
-                        : "Notifications.WebPlatform.Body.TimeToClose",
+                        ? "Notifications.WebPlatformV2.ActionButton.TimeToClose"
+                        : "Notifications.WebPlatformV2.Body.TimeToClose",
                 3000);
     }
 
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 04ab689e..b5b024d 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -5311,6 +5311,9 @@
   <message name="IDS_ACCOUNT_MANAGER_WELCOME_BUTTON" desc="Label for the button to view accounts on the Chrome OS Account Manager Welcome screen.">
     View accounts
   </message>
+  <message name="IDS_ACCOUNT_MANAGER_DIALOG_TITLE" desc="Title for the Chrome OS 'Add account' dialog.">
+    Sign in to add a Google account
+  </message>
   <message name="IDS_ACCOUNT_MANAGER_DIALOG_WELCOME_TITLE" desc="Title for the Welcome screen in Chrome OS 'Add account' dialog.">
     Add another Google Account for <ph name="USER_NAME">$1<ex>John</ex></ph>
   </message>
@@ -5707,6 +5710,11 @@
     Autocorrect undo dialog is shown for <ph name="TYPED_WORD">$1<ex>hllo</ex></ph> corrected to <ph name="CORRECTED_WORD">$2<ex>hello</ex></ph>.  Press up arrow to access, escape to ignore.
   </message>
 
+  <!-- Strings for emoji picker-->
+  <message name="IDS_ACCNAME_EMOJI_PICKER" desc="The accessible name for the emoji picker.">
+    Emoji Picker
+  </message>
+
   <!-- Strings for Custom Tab UI -->
   <message name="IDS_CUSTOM_TABS_ACTION_MENU_ACCESSIBLE_NAME" desc="Accessible name for the overflow menu of the Chrome Custom Tab toolbar.">
     Action menu button
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ACCNAME_EMOJI_PICKER.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_ACCNAME_EMOJI_PICKER.png.sha1
new file mode 100644
index 0000000..841d40d
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_ACCNAME_EMOJI_PICKER.png.sha1
@@ -0,0 +1 @@
+3667c98c330115757df405333f234b739c3ee780
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ACCOUNT_MANAGER_DIALOG_TITLE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_ACCOUNT_MANAGER_DIALOG_TITLE.png.sha1
new file mode 100644
index 0000000..c13c25b
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_ACCOUNT_MANAGER_DIALOG_TITLE.png.sha1
@@ -0,0 +1 @@
+42c4175fd806b251e3476911f60a6f3753770f73
\ No newline at end of file
diff --git a/chrome/app/nearby_share_strings.grdp b/chrome/app/nearby_share_strings.grdp
index b513a699..57a6a7c2 100644
--- a/chrome/app/nearby_share_strings.grdp
+++ b/chrome/app/nearby_share_strings.grdp
@@ -347,4 +347,10 @@
   <message name="IDS_NEARBY_NOTIFICATION_SOURCE" desc="Text shown as the source of a Nearby Share notification.">
     Nearby Share
   </message>
+  <message name="IDS_NEARBY_NOTIFICATION_RECEIVER_CANCELLED" desc="Text shown as the title of a notification when the receiver device cancels the Nearby Share tranfer.">
+    <ph name="DEVICE_NAME">$1<ex>Ted's Pixel 2</ex></ph> did not accept the file
+  </message>
+  <message name="IDS_NEARBY_NOTIFICATION_SENDER_CANCELLED" desc="Text shown as the title of a notification when the sender device cancels the Nearby Share tranfer.">
+    <ph name="DEVICE_NAME">$1<ex>Ted's Pixel 2</ex></ph> cancelled the transfer
+  </message>
 </grit-part>
diff --git a/chrome/app/nearby_share_strings_grdp/IDS_NEARBY_NOTIFICATION_RECEIVER_CANCELLED.png.sha1 b/chrome/app/nearby_share_strings_grdp/IDS_NEARBY_NOTIFICATION_RECEIVER_CANCELLED.png.sha1
new file mode 100644
index 0000000..0cbc83e6
--- /dev/null
+++ b/chrome/app/nearby_share_strings_grdp/IDS_NEARBY_NOTIFICATION_RECEIVER_CANCELLED.png.sha1
@@ -0,0 +1 @@
+992d7afcc0f79311e9c85b5c32fb33557fa6e943
\ No newline at end of file
diff --git a/chrome/app/nearby_share_strings_grdp/IDS_NEARBY_NOTIFICATION_SENDER_CANCELLED.png.sha1 b/chrome/app/nearby_share_strings_grdp/IDS_NEARBY_NOTIFICATION_SENDER_CANCELLED.png.sha1
new file mode 100644
index 0000000..ae8f124
--- /dev/null
+++ b/chrome/app/nearby_share_strings_grdp/IDS_NEARBY_NOTIFICATION_SENDER_CANCELLED.png.sha1
@@ -0,0 +1 @@
+56f16e6a2e2a10cdaf1b2c440d5a8a0b59254cef
\ No newline at end of file
diff --git a/chrome/app/resources/generated_resources_ar.xtb b/chrome/app/resources/generated_resources_ar.xtb
index 614dc82..413b3c2 100644
--- a/chrome/app/resources/generated_resources_ar.xtb
+++ b/chrome/app/resources/generated_resources_ar.xtb
@@ -2408,7 +2408,7 @@
 <translation id="3677911431265050325">طلب موقع إلكتروني متوافق مع الأجهزة الجوَالة</translation>
 <translation id="3677959414150797585">يتضمن المحتوى المُقترح التطبيقات وصفحات الويب والمزيد. لا يتم إرسال إحصاءات لتحسين المحتوى المُقترح إلا إذا اختَرت مشاركة بيانات الاستخدام.</translation>
 <translation id="3678156199662914018">الإضافة: <ph name="EXTENSION_NAME" /></translation>
-<translation id="3678188444105291936">لن تظهر في سجل المتصفّح الصفحات التي تعرضها في هذه النافذة، ولن تترك آثارًا أخرى، كملفات تعريف الارتباط، في الكمبيوتر بعد الخروج من وضع الضيف، ولن يتم الاحتفاظ بالملفات التي تنزِّلها والإشارات المرجعية التي تنشئها.</translation>
+<translation id="3678188444105291936">لن تظهر في سجل المتصفّح الصفحات التي تعرضها في هذه النافذة، ولن تترك آثارًا أخرى في الكمبيوتر، كملفات تعريف الارتباط، بعد الخروج من وضع الضيف، ولن يتم الاحتفاظ بالملفات التي تنزِّلها والإشارات المرجعية التي تنشئها.</translation>
 <translation id="3680683624079082902">صوت "تحويل النص إلى كلام"</translation>
 <translation id="3681311097828166361">شكرًا على تعليقاتك. أنت غير متصل الآن، وسيتم إرسال تقريرك لاحقًا.</translation>
 <translation id="3682824389861648626">الحد الأدنى للحركات</translation>
@@ -2642,7 +2642,7 @@
 <translation id="3916445069167113093">هذا النوع من الملفات قد يلحق الضرر بالكمبيوتر. هل تريد الاحتفاظ بـ <ph name="FILE_NAME" /> على أيّ حال؟</translation>
 <translation id="3918972485393593704">‏إبلاغ Google بالتفاصيل</translation>
 <translation id="3919145445993746351">للحصول على الإضافات على جميع أجهزة الكمبيوتر، يُرجى تفعيل المزامنة</translation>
-<translation id="3919798653937160644">لن تظهر في سجلّ المتصفّح الصفحات التي تعرضها في هذه النافذة، ولن تترك أي آثار أخرى، مثل ملفات تعريف الارتباط، في الكمبيوتر بعد إغلاق جميع النوافذ المفتوحة في وضع الضيف، ومع ذلك، سيتم الاحتفاظ بأي ملفات يتم تنزيلها.</translation>
+<translation id="3919798653937160644">لن تظهر في سجلّ المتصفّح الصفحات التي تعرضها في هذه النافذة، ولن تترك أي آثار أخرى في الكمبيوتر، مثل ملفات تعريف الارتباط، بعد إغلاق جميع النوافذ المفتوحة في وضع الضيف، علمًا أنه سيتم الاحتفاظ بأي ملفات يتم تنزيلها.</translation>
 <translation id="3920504717067627103">سياسات الشهادة</translation>
 <translation id="392089482157167418">‏تفعيل ChromeVox (التعليقات المنطوقة)</translation>
 <translation id="3920909973552939961">المواقع الإلكترونية التي لا يُسمح لها بتثبيت معالجات الدفع</translation>
@@ -3706,7 +3706,7 @@
 <translation id="5187826826541650604"><ph name="KEY_NAME" /> (<ph name="DEVICE" />)</translation>
 <translation id="5190187232518914472">‏استرجِع ذكرياتك المفضّلة. ولإضافة أي ألبومات أو تعديلها، انتقِل إلى <ph name="LINK_BEGIN" />صور Google<ph name="LINK_END" />.</translation>
 <translation id="5190926251776387065">تفعيل المنفذ</translation>
-<translation id="5191094172448199359">أرقام التعريف الشخصية التي أدخلتها غير متطابقة</translation>
+<translation id="5191094172448199359">رقما التعريف الشخصيان اللذان أدخلتهما غير متطابقَين</translation>
 <translation id="5191251636205085390">يمكنك التعرّف على تقنيات جديدة تهدف إلى استبدال ملفات تعريف الارتباط التابعة لجهات خارجية وكيفية التحكُّم في تلك التقنيات.</translation>
 <translation id="51918995459521422">يريد <ph name="ORIGIN" /> تنزيل ملفات متعددة.</translation>
 <translation id="5192062846343383368">‏فتح تطبيق Family Link للاطّلاع على إعدادات الإشراف</translation>
@@ -5091,7 +5091,7 @@
 <translation id="6793723358811598107">سبق وتم تخصيص مفتاح "<ph name="CURRENTKEY" />" للإجراء "<ph name="ACTION" />". يُرجى الضغط على أي مفتاح للخروج.</translation>
 <translation id="6795884519221689054">باندا</translation>
 <translation id="6797493596609571643">عفوًا، حدث خطأ ما.</translation>
-<translation id="6798420440063423019">تم قفل مفتاح الأمان بسبب إدخال رقم التعريف الشخصي غير الصحيح عدّة مرات. عليك إعادة ضبط مفتاح الأمان.</translation>
+<translation id="6798420440063423019">تم قفل مفتاح الأمان بسبب إدخال رقم تعريف شخصي غير صحيح عدّة مرات. عليك إعادة ضبط مفتاح الأمان.</translation>
 <translation id="6798578729981748444">‏لإنهاء الاستيراد، أغلق جميع نوافذ Firefox.</translation>
 <translation id="6798780071646309401">‏مفتاح caps lock قيد التفعيل</translation>
 <translation id="6798954102094737107">المكوّن الإضافي: <ph name="PLUGIN_NAME" /></translation>
diff --git a/chrome/app/resources/generated_resources_ca.xtb b/chrome/app/resources/generated_resources_ca.xtb
index 3116eb2..bd2d817 100644
--- a/chrome/app/resources/generated_resources_ca.xtb
+++ b/chrome/app/resources/generated_resources_ca.xtb
@@ -4439,7 +4439,7 @@
 <translation id="6043994281159824495">Tanca la sessió ara</translation>
 <translation id="6044805581023976844"><ph name="APP_NAME" /> està compartint una pestanya de Chrome i àudio amb <ph name="TAB_NAME" />.</translation>
 <translation id="6045114302329202345">Botó TrackPoint principal</translation>
-<translation id="6047632800149092791">La sincronització no funciona. Prova de tancar la sessió i tornar a iniciar-la.</translation>
+<translation id="6047632800149092791">La sincronització no funciona. Tanca la sessió i torna-la a iniciar.</translation>
 <translation id="6049004884579590341">Mantén premut |<ph name="ACCELERATOR" />| per sortir del mode de pantalla completa</translation>
 <translation id="6051354611314852653">El sistema no ha pogut autoritzar l'accés a l'API per a aquest dispositiu.</translation>
 <translation id="6052976518993719690">Entitat emissora de certificats SSL</translation>
@@ -4532,7 +4532,7 @@
 <translation id="6143186082490678276">Obtén ajuda</translation>
 <translation id="6143366292569327983">Tria l'idioma de la pàgina des del qual vulguis traduir</translation>
 <translation id="6144938890088808325">Contribuïu a millorar els dispositius Chromebook</translation>
-<translation id="6146409560350811147">La sincronització no funciona. Prova de tornar a iniciar la sessió.</translation>
+<translation id="6146409560350811147">La sincronització no funciona. Torna a iniciar la sessió.</translation>
 <translation id="6147020289383635445">La previsualització d'impressió ha fallat.</translation>
 <translation id="6148576794665275391">Obre ara</translation>
 <translation id="6149015141270619212">No es pot connectar a Internet</translation>
diff --git a/chrome/app/resources/generated_resources_de.xtb b/chrome/app/resources/generated_resources_de.xtb
index b2f3c1b..34d2ba8 100644
--- a/chrome/app/resources/generated_resources_de.xtb
+++ b/chrome/app/resources/generated_resources_de.xtb
@@ -572,6 +572,7 @@
 <translation id="1627408615528139100">Bereits heruntergeladen</translation>
 <translation id="1628948239858170093">Datei vor dem Öffnen scannen?</translation>
 <translation id="1629314197035607094">Passwort abgelaufen</translation>
+<translation id="1629521517399325891">Das Nutzerzertifikat ist nicht für die Netzwerkauthentifizierung verfügbar.</translation>
 <translation id="163072119192489970">Dürfen den Datenversand und ‑empfang abschließen</translation>
 <translation id="1630768113285622200">Neu starten und fortfahren</translation>
 <translation id="1632082166874334883">In Ihrem Google-Konto gespeichertes Passwort</translation>
@@ -1176,6 +1177,7 @@
 <translation id="2300383962156589922"><ph name="APP_NAME" /> anpassen und verwalten</translation>
 <translation id="2301382460326681002">Stammverzeichnis der Erweiterung ist ungültig.</translation>
 <translation id="23030561267973084">"<ph name="EXTENSION_NAME" />" hat zusätzliche Berechtigungen angefordert.</translation>
+<translation id="230529452743010958">Wir zeigen Ihnen diesen Eintrag auf der Grundlage Ihrer bisherigen Nutzung von Google-Diensten. Auf <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /> können Sie Ihre Daten einsehen, sie löschen und Ihre Einstellungen ändern.</translation>
 <translation id="23055578400314116">Wählen Sie einen Nutzernamen aus</translation>
 <translation id="2307462900900812319">Netzwerk konfigurieren</translation>
 <translation id="230927227160767054">Diese Seite möchte einen Service-Handler installieren.</translation>
@@ -1401,6 +1403,7 @@
 <translation id="2541706104884128042">Neue Schlafenszeit festgelegt</translation>
 <translation id="2542050502251273923">Hiermit wird das Fehlerbehebungslevel des Netzwerkverbindungsmanagers und anderer Services mithilfe von ff_debug festgelegt.</translation>
 <translation id="2544292303401268586">Der Administrator möchte Ihr Gerät neu starten, um Apps zu aktualisieren. Dies kann einige Minuten dauern.</translation>
+<translation id="2544352060595557290">Dieser Tab</translation>
 <translation id="2544853746127077729">Ablehnung des Authentifizierungszertifikats durch das Netzwerk</translation>
 <translation id="2546283357679194313">Cookies und Websitedaten</translation>
 <translation id="2548347166720081527"><ph name="PERMISSION" /> zugelassen</translation>
@@ -1566,6 +1569,7 @@
 <translation id="2734760316755174687">Websites unter <ph name="SITE_GROUP_NAME" /> werden ebenfalls zurückgesetzt.</translation>
 <translation id="2735712963799620190">Zeitplan</translation>
 <translation id="2737363922397526254">Minimieren...</translation>
+<translation id="2737916598897808047"><ph name="APP_NAME" /> möchte den Inhalt Ihres Bildschirms mit <ph name="TARGET_NAME" /> teilen.</translation>
 <translation id="2738771556149464852">Nicht nach</translation>
 <translation id="2739191690716947896">Fehlerbehebung</translation>
 <translation id="2739240477418971307">Einstellungen für Zugänglichkeit ändern</translation>
@@ -2394,6 +2398,7 @@
 <translation id="3677911431265050325">Mobile Version anfordern</translation>
 <translation id="3677959414150797585">Das kann u. a. Apps und Webseiten einschließen. Statistiken zur Verbesserung von Vorschlägen werden nur gesendet, wenn Sie der Freigabe von Nutzungsdaten zugestimmt haben.</translation>
 <translation id="3678156199662914018">Erweiterung: <ph name="EXTENSION_NAME" /></translation>
+<translation id="3678188444105291936">In diesem Fenster aufgerufene Seiten erscheinen nicht im Browserverlauf und hinterlassen auch keine anderweitigen Spuren wie Cookies auf dem Computer, nachdem Sie sich abgemeldet haben. Ihre Lesezeichen und Ihre heruntergeladenen Dateien bleiben nicht erhalten.</translation>
 <translation id="3680683624079082902">Stimme der Sprachausgabe</translation>
 <translation id="3681311097828166361">Vielen Dank für Ihr Feedback. Sie sind jetzt offline und Ihr Bericht wird später versendet.</translation>
 <translation id="3682824389861648626">Grenzwert für Mausbewegungen</translation>
@@ -2595,6 +2600,7 @@
 <translation id="3884152383786131369">Für Webinhalte in mehreren Sprachen wird die erste unterstützte Sprache aus dieser Liste verwendet. Diese Einstellungen werden mit den Browsereinstellungen synchronisiert. <ph name="BEGIN_LINK_LEARN_MORE" />Weitere Informationen<ph name="END_LINK_LEARN_MORE" /></translation>
 <translation id="3886446263141354045">Deine Anfrage zum Zugriff auf diese Website wurde an <ph name="NAME" /> gesendet</translation>
 <translation id="3888550877729210209">Notizerstellung mit <ph name="LOCK_SCREEN_APP_NAME" /></translation>
+<translation id="3888586133700543064">Diese Informationen helfen uns, Ihr Problem mit Assistant besser zu verstehen. Sie werden bis zu 90 Tage gespeichert und der Zugriff ist auf die zuständigen Entwickler- und Feedbackteams beschränkt.</translation>
 <translation id="3890064827463908288">Chrome-Synchronisierung aktivieren, um WLAN-Synchronisation zu verwenden</translation>
 <translation id="3892414795099177503">OpenVPN/L2TP hinzufügen…</translation>
 <translation id="3893536212201235195">Einstellungen für Eingabehilfen lesen und ändern</translation>
@@ -2626,6 +2632,7 @@
 <translation id="3916445069167113093">Dateien dieses Typs können Schäden an Ihrem Computer verursachen. Möchten Sie <ph name="FILE_NAME" /> trotzdem behalten?</translation>
 <translation id="3918972485393593704">Details an Google senden</translation>
 <translation id="3919145445993746351">Wenn Ihre Erweiterungen auf allen Computern verfügbar sein sollen, aktivieren Sie die Synchronisierung</translation>
+<translation id="3919798653937160644">In diesem Fenster aufgerufene Seiten erscheinen nicht im Browserverlauf und hinterlassen auch keine anderweitigen Spuren wie Cookies auf dem Computer, nachdem Sie alle geöffneten Gastmodus-Fenster geschlossen haben. Heruntergeladene Dateien bleiben jedoch erhalten.</translation>
 <translation id="3920504717067627103">Zertifikatrichtlinien</translation>
 <translation id="392089482157167418">ChromeVox aktivieren (gesprochenes Feedback)</translation>
 <translation id="3920909973552939961">Dürfen keine Zahlungs-Handler installieren</translation>
@@ -2961,6 +2968,7 @@
 <translation id="4332976768901252016">Jugendschutzeinstellungen einrichten</translation>
 <translation id="4333854382783149454">PKCS #1 SHA-1 mit RSA-Verschlüsselung</translation>
 <translation id="4336434711095810371">Alle Daten löschen</translation>
+<translation id="4340125850502689798">Ungültiger Nutzername</translation>
 <translation id="4340515029017875942"><ph name="ORIGIN" /> möchte mit der App "<ph name="EXTENSION_NAME" />" kommunizieren.</translation>
 <translation id="4341577178275615435">Mit dem Tastaturkürzel F7 kann die Tastaturnavigation aktiviert oder deaktiviert werden</translation>
 <translation id="434198521554309404">Schnell. Sicher. Mühelos.</translation>
@@ -3574,6 +3582,7 @@
 <translation id="5057110919553308744">Wenn die Erweiterung angeklickt wird</translation>
 <translation id="5057403786441168405">Hier können Sie Ihre angemeldeten Konten verwalten. Websites, Apps und Erweiterungen in Chrome und Google Play können diese Konten verwenden, um Ihnen – je nach den jeweiligen Berechtigungen – personalisierte Inhalte anzuzeigen. <ph name="LINK_BEGIN" />Weitere Informationen<ph name="LINK_END" /></translation>
 <translation id="5059241099014281248">Anmeldung beschränken</translation>
+<translation id="5059526285558225588">Auswählen, was geteilt werden soll</translation>
 <translation id="5060332552815861872">Es ist 1 Drucker verfügbar, der gespeichert werden kann.</translation>
 <translation id="5061347216700970798">{NUM_BOOKMARKS,plural, =1{Dieser Ordner enthält ein Lesezeichen. Möchten Sie ihn wirklich löschen?}other{Dieser Ordner enthält # Lesezeichen. Möchten Sie ihn wirklich löschen?}}</translation>
 <translation id="5062930723426326933">Fehler bei der Anmeldung. Bitte stellen Sie eine Internetverbindung her und versuchen Sie es erneut.</translation>
@@ -3690,6 +3699,7 @@
 <translation id="5187826826541650604"><ph name="KEY_NAME" /> (<ph name="DEVICE" />)</translation>
 <translation id="5190187232518914472">Die schönsten Erinnerungen immer vor Augen. Wenn Sie Alben hinzufügen oder bearbeiten möchten, gehen Sie zu <ph name="LINK_BEGIN" />Google Fotos<ph name="LINK_END" />.</translation>
 <translation id="5190926251776387065">Port aktivieren</translation>
+<translation id="5191094172448199359">Die eingegebenen PINs stimmen nicht überein</translation>
 <translation id="5191251636205085390">Weitere Informationen zu neuen Technologien als Ersatz für Drittanbieter-Cookies und ihrer Nutzung</translation>
 <translation id="51918995459521422"><ph name="ORIGIN" /> möchte mehrere Dateien herunterladen</translation>
 <translation id="5192062846343383368">Die Einstellungen für die Elternaufsicht lassen sich in der Family Link App anpassen</translation>
@@ -3702,6 +3712,7 @@
 <translation id="5204673965307125349">Bitte führen einen Powerwash auf dem Gerät durch und versuchen Sie es noch einmal.</translation>
 <translation id="5204967432542742771">Passwort eingeben</translation>
 <translation id="5205484256512407285">Nie mobile Daten benutzen, um Daten zu übertragen</translation>
+<translation id="520568280985468584">Das Netzwerk wurde hinzugefügt. Es kann einige Minuten dauern, bis das Mobilfunknetz aktiv wird.</translation>
 <translation id="5206215183583316675">"<ph name="CERTIFICATE_NAME" />" löschen?</translation>
 <translation id="520621735928254154">Fehler beim Importieren des Zertifikats</translation>
 <translation id="5206787458656075734">{COUNT,plural, =1{Das gehackte Passwort wurde erfolgreich geändert. Sie haben # weiteres gehacktes Passwort. Chrome empfiehlt, dieses Passwort jetzt zu prüfen.}other{Das gehackte Passwort wurde erfolgreich geändert. Sie haben # weitere gehackte Passwörter. Chrome empfiehlt, diese Passwörter jetzt zu prüfen.}}</translation>
@@ -4336,6 +4347,7 @@
 <translation id="5935656526031444304">Safe Browsing verwalten</translation>
 <translation id="5938002010494270685">Sicherheitsupdate verfügbar</translation>
 <translation id="5939518447894949180">Zurücksetzen</translation>
+<translation id="5939719276406088041">Verknüpfung konnte nicht erstellt werden</translation>
 <translation id="5941153596444580863">Person hinzufügen...</translation>
 <translation id="5941343993301164315">Melden Sie sich in <ph name="TOKEN_NAME" /> an.</translation>
 <translation id="5941711191222866238">Minimieren</translation>
@@ -4423,6 +4435,7 @@
 <translation id="6043994281159824495">Jetzt abmelden</translation>
 <translation id="6044805581023976844"><ph name="APP_NAME" /> teilt einen Chrome-Tab und Audio mit <ph name="TAB_NAME" />.</translation>
 <translation id="6045114302329202345">Primäre TrackPoint-Taste</translation>
+<translation id="6047632800149092791">Synchronisierung funktioniert nicht. Melden Sie sich ab und dann wieder an.</translation>
 <translation id="6049004884579590341">|<ph name="ACCELERATOR" />| gedrückt halten, um den Vollbildmodus zu beenden</translation>
 <translation id="6051354611314852653">Hoppla! Das System konnte das Gerät nicht für den API-Zugriff autorisieren.</translation>
 <translation id="6052976518993719690">SSL-Zertifizierungsstelle</translation>
@@ -4515,6 +4528,7 @@
 <translation id="6143186082490678276">Hilfe</translation>
 <translation id="6143366292569327983">Wählen Sie die Ausgangssprache aus</translation>
 <translation id="6144938890088808325">Bei der Verbesserung von Chromebooks helfen</translation>
+<translation id="6146409560350811147">Synchronisierung funktioniert nicht. Versuchen Sie es noch einmal.</translation>
 <translation id="6147020289383635445">Druckvorschau fehlgeschlagen</translation>
 <translation id="6148576794665275391">Jetzt öffnen</translation>
 <translation id="6149015141270619212">Internetverbindung kann nicht hergestellt werden</translation>
@@ -4582,6 +4596,7 @@
 <translation id="6232017090690406397">Akku</translation>
 <translation id="6232116551750539448">Verbindung mit <ph name="NAME" /> wurde unterbrochen.</translation>
 <translation id="6233154960150021497">Standardmäßig Spracheingabe anstatt Tastatur verwenden</translation>
+<translation id="6234108445915742946">Neue Nutzungsbedingungen für Chrome ab dem 31. März</translation>
 <translation id="6234474535228214774">Installation ausstehend</translation>
 <translation id="6237474966939441970">Notizen-App für Eingabestift</translation>
 <translation id="6237816943013845465">Ermöglicht die Anpassung der Bildschirmauflösung</translation>
@@ -4880,6 +4895,7 @@
 <translation id="656293578423618167">Der Dateipfad oder Dateiname ist zu lang. Verwenden Sie bitte einen kürzeren Namen oder einen anderen Speicherort.</translation>
 <translation id="6563469144985748109">Der Administrator hat die Berechtigung noch nicht erteilt</translation>
 <translation id="6569934958368283244">Andere Personen</translation>
+<translation id="6573497332121198392">Verknüpfung kann nicht entfernt werden</translation>
 <translation id="657402800789773160">&amp;Diese Seite neu laden</translation>
 <translation id="6577284282025554716">Download abgebrochen: <ph name="FILE_NAME" /></translation>
 <translation id="657866106756413002">Netzwerkzustand – Übersicht</translation>
@@ -4887,6 +4903,7 @@
 <translation id="6579705087617859690"><ph name="WINDOW_TITLE" /> – Desktopinhalte geteilt</translation>
 <translation id="6580203076670148210">Scangeschwindigkeit</translation>
 <translation id="6582080224869403177">Setzen Sie Ihr <ph name="DEVICE_TYPE" /> zurück, um das Sicherheitsupdate durchzuführen.</translation>
+<translation id="6582274660680936615">Der Gastmodus ist aktiviert</translation>
 <translation id="6584878029876017575">Microsoft-Lebensdauersignatur</translation>
 <translation id="6586099239452884121">Gastmodus</translation>
 <translation id="6586451623538375658">Primäre Maustaste tauschen</translation>
@@ -5056,6 +5073,7 @@
 <translation id="6782468519961184511">Dein Administrator lässt keine zusätzlichen Google-Konten zu</translation>
 <translation id="6785518634832172390">PIN darf maximal 12 Zeichen lang sein</translation>
 <translation id="6786747875388722282">Erweiterungen</translation>
+<translation id="6787097042755590313">Anderer Tab</translation>
 <translation id="6787839852456839824">Tastenkombinationen</translation>
 <translation id="6788210894632713004">Entpackte Erweiterung</translation>
 <translation id="6789592661892473991">Horizontal teilen</translation>
@@ -5066,6 +5084,7 @@
 <translation id="6793723358811598107">„<ph name="CURRENTKEY" />“ wurde bereits der Aktion „<ph name="ACTION" />“ zugewiesen. Drücken Sie zum Beenden eine beliebige Taste.</translation>
 <translation id="6795884519221689054">Panda</translation>
 <translation id="6797493596609571643">Hoppla, ein Fehler ist aufgetreten.</translation>
+<translation id="6798420440063423019">Der Sicherheitsschlüssel wurde gesperrt, weil zu oft die falsche PIN eingegeben wurde. Sie müssen den Sicherheitsschlüssel zurücksetzen.</translation>
 <translation id="6798578729981748444">Schließen Sie alle Firefox-Fenster, um den Import abzuschließen.</translation>
 <translation id="6798780071646309401">Feststelltaste an</translation>
 <translation id="6798954102094737107">Plug-in: <ph name="PLUGIN_NAME" /></translation>
@@ -5411,6 +5430,7 @@
 <translation id="7180865173735832675">Anpassen</translation>
 <translation id="7182791023900310535">Passwort verschieben</translation>
 <translation id="7186088072322679094">In Symbolleiste behalten</translation>
+<translation id="7186303001964993981"><ph name="ORIGIN" /> kann diesen Ordner nicht öffnen, weil er Systemdateien enthält</translation>
 <translation id="7187428571767585875">Registrierungseinträge, die entfernt oder geändert werden:</translation>
 <translation id="7187855807420906517">Wenn Sie eine Website verlassen oder offline gehen, setzen Websites die Synchronisierung normalerweise trotzdem fort, um Aufgaben wie das Hochladen von Fotos oder das Versenden einer Chatnachricht zu beenden</translation>
 <translation id="7189234443051076392">Achten Sie darauf, dass auf Ihrem Gerät ausreichend Speicherplatz vorhanden ist</translation>
@@ -6030,6 +6050,7 @@
 <translation id="7871109039747854576">Kandidatenliste mit den Tasten "<ph name="COMMA" />" und "<ph name="PERIOD" />" paginieren</translation>
 <translation id="787268756490971083">Aus</translation>
 <translation id="7874257161694977650">Chrome-Hintergründe</translation>
+<translation id="7876027585589532670">Verknüpfung kann nicht bearbeitet werden</translation>
 <translation id="7877451762676714207">Unbekannter Serverfehler. Bitte versuchen Sie es erneut oder wenden Sie sich an den Serveradministrator.</translation>
 <translation id="7879631849810108578">Tastenkombination festgelegt: <ph name="IDS_SHORT_SET_COMMAND" /></translation>
 <translation id="7880823633812189969">Lokale Daten werden beim nächsten Neustart gelöscht</translation>
@@ -6315,6 +6336,7 @@
 <translation id="8189750580333936930">Privacy Sandbox</translation>
 <translation id="8190193592390505034">Verbindung zu <ph name="PROVIDER_NAME" /> wird hergestellt.</translation>
 <translation id="8191230140820435481">Apps, Erweiterungen und Designs verwalten</translation>
+<translation id="8192944472786724289"><ph name="APP_NAME" /> möchte den Inhalt Ihres Bildschirms teilen.</translation>
 <translation id="8195027750202970175">Dateigröße</translation>
 <translation id="8198323535106903877"><ph name="NUMBER_OF_APPS" /> Apps werden installiert</translation>
 <translation id="8199300056570174101">Netzwerk(dienst) und Geräteeigenschaften</translation>
@@ -6964,6 +6986,7 @@
 <translation id="8931475688782629595">Verwalten, welche Daten synchronisiert werden</translation>
 <translation id="8932654652795262306">Instant Tethering-Details</translation>
 <translation id="8932894639908691771">Optionen für Schalterzugriff</translation>
+<translation id="893298445929867520">Einkaufswagen ausgeblendet. Sie werden wieder angezeigt, wenn Sie Änderungen vornehmen.</translation>
 <translation id="8933960630081805351">Im Finder &amp;anzeigen</translation>
 <translation id="8934732568177537184">Weiter</translation>
 <translation id="8938306522009698937">Handler</translation>
@@ -7240,6 +7263,7 @@
 <translation id="942532530371314860"><ph name="APP_NAME" /> hat einen Chrome-Tab und Audio freigegeben.</translation>
 <translation id="945522503751344254">Feedback geben</translation>
 <translation id="947329552760389097">&amp;Elemente untersuchen</translation>
+<translation id="947667444780368238"><ph name="ORIGIN" /> kann Dateien in diesem Ordner nicht öffnen, weil er Systemdateien enthält</translation>
 <translation id="951991426597076286">Ablehnen</translation>
 <translation id="956500788634395331">Sie sind vor potenziell schädlichen Erweiterungen geschützt</translation>
 <translation id="957960681186851048">Diese Website hat versucht, automatisch mehrere Dateien herunterzuladen</translation>
diff --git a/chrome/app/resources/generated_resources_eu.xtb b/chrome/app/resources/generated_resources_eu.xtb
index 52c9c47..2042c9d 100644
--- a/chrome/app/resources/generated_resources_eu.xtb
+++ b/chrome/app/resources/generated_resources_eu.xtb
@@ -575,7 +575,7 @@
 <translation id="1627408615528139100">Deskargatu da jada</translation>
 <translation id="1628948239858170093">Ireki aurretik aztertu egin nahi al duzu fitxategia?</translation>
 <translation id="1629314197035607094">Pasahitza iraungi egin da</translation>
-<translation id="1629521517399325891">Erabiltzailearen ziurtagiria ez dago erabilgarri sarea autentifikatzeko.</translation>
+<translation id="1629521517399325891">Erabiltzaile-ziurtagiria ez dago erabilgarri sarea autentifikatzeko.</translation>
 <translation id="163072119192489970">Datuak bidaltzen eta jasotzen amai dezakete</translation>
 <translation id="1630768113285622200">Berrabiarazi eta egin aurrera</translation>
 <translation id="1632082166874334883">Google-ko kontuan gordetako pasahitza</translation>
@@ -1180,7 +1180,7 @@
 <translation id="2300383962156589922">Pertsonalizatu eta kontrolatu <ph name="APP_NAME" /></translation>
 <translation id="2301382460326681002">Luzapenaren erro-direktorioak ez du balio.</translation>
 <translation id="23030561267973084">"<ph name="EXTENSION_NAME" />" luzapenak baimen gehigarriak eskatu ditu.</translation>
-<translation id="230529452743010958">Google-ren zerbitzuak erabiltzean egin dituzun jardueretan oinarrituta ari gara erakusten produktua. Jarduera horiei buruzko datuak ikusi eta ezabatu nahi badituzu, eta haiei buruzko ezarpenak aldatu, joan <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /> webgunera.</translation>
+<translation id="230529452743010958">Google-ren zerbitzuak erabiltzean egin dituzun jardueretan oinarrituta ari gara erakusten produktua. Jarduera horiei buruzko datuak ikusi eta ezabatu nahi badituzu eta haiei buruzko ezarpenak aldatu, joan <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /> webgunera.</translation>
 <translation id="23055578400314116">Hautatu erabiltzaile-izen bat</translation>
 <translation id="2307462900900812319">Konfiguratu sarea</translation>
 <translation id="230927227160767054">Orri honek zerbitzu-kudeatzaile bat instalatu nahi du.</translation>
@@ -3703,7 +3703,7 @@
 <translation id="5187826826541650604"><ph name="KEY_NAME" /> (<ph name="DEVICE" />)</translation>
 <translation id="5190187232518914472">Ekarri gogora gogoko oroitzapenak. Albumak gehitu edo editatzeko, joan <ph name="LINK_BEGIN" />Google Argazkiak<ph name="LINK_END" /> zerbitzura.</translation>
 <translation id="5190926251776387065">Aktibatu ataka</translation>
-<translation id="5191094172448199359">Idatzi dituzun PIN kodeak ez datoz bat</translation>
+<translation id="5191094172448199359">Idatzi dituzun PINak ez datoz bat</translation>
 <translation id="5191251636205085390">Kontrolatu hirugarrenen cookieak ordezteko helburua duten teknologia berriak eta lortu haiei buruzko informazio gehiago</translation>
 <translation id="51918995459521422"><ph name="ORIGIN" /> webguneak fitxategi bat baino gehiago deskargatu nahi ditu</translation>
 <translation id="5192062846343383368">Zabaldu Family Link aplikazioa gainbegiratze-ezarpenak ikusteko.</translation>
@@ -5088,7 +5088,7 @@
 <translation id="6793723358811598107">"<ph name="CURRENTKEY" />" tekla "<ph name="ACTION" />" ekintzari esleituta dago dagoeneko. Irteteko, sakatu edozein tekla.</translation>
 <translation id="6795884519221689054">Panda</translation>
 <translation id="6797493596609571643">Arazoren bat izan da.</translation>
-<translation id="6798420440063423019">Segurtasun-giltza blokeatuta dago PIN kodea gehiegitan idatzi delako oker. Segurtasun-giltza berrezarri beharko duzu.</translation>
+<translation id="6798420440063423019">Segurtasun-giltza blokeatuta dago PINa gehiegitan idatzi delako oker. Segurtasun-giltza berrezarri beharko duzu.</translation>
 <translation id="6798578729981748444">Inportazioa amaitzeko, itxi Firefox-eko leiho guztiak.</translation>
 <translation id="6798780071646309401">maiuskulak aktibatuta daude</translation>
 <translation id="6798954102094737107"><ph name="PLUGIN_NAME" /> plugina</translation>
@@ -5434,7 +5434,7 @@
 <translation id="7180865173735832675">Pertsonalizatu</translation>
 <translation id="7182791023900310535">Eraman pasahitza</translation>
 <translation id="7186088072322679094">Mantendu tresna-barran</translation>
-<translation id="7186303001964993981"><ph name="ORIGIN" /> webguneak ezin du ireki karpeta sistemaren fitxategiak dituelako</translation>
+<translation id="7186303001964993981"><ph name="ORIGIN" /> webguneak ezin du ireki karpeta sistemaren fitxategiak daudelako</translation>
 <translation id="7187428571767585875">Erregistroan kendu edo aldatu beharreko sarrerak:</translation>
 <translation id="7187855807420906517">Irteten edo deskonektatzen zarenean, webguneek sinkronizatzen jarraitzen dute zereginak amaitzeko, hala nola argazkiak kargatzeko edo txat-mezuak bidaltzeko</translation>
 <translation id="7189234443051076392">Ziurtatu gailuan behar adina toki duzula</translation>
diff --git a/chrome/app/resources/generated_resources_fr-CA.xtb b/chrome/app/resources/generated_resources_fr-CA.xtb
index 1977b0b..887bb6d 100644
--- a/chrome/app/resources/generated_resources_fr-CA.xtb
+++ b/chrome/app/resources/generated_resources_fr-CA.xtb
@@ -2637,7 +2637,7 @@
 <translation id="3916445069167113093">Ce type de fichier risque d'endommager votre ordinateur. Voulez-vous vraiment télécharger <ph name="FILE_NAME" />?</translation>
 <translation id="3918972485393593704">Signaler les détails à Google</translation>
 <translation id="3919145445993746351">Pour utiliser vos extensions sur tous vos ordinateurs, activez la synchronisation</translation>
-<translation id="3919798653937160644">Les pages que vous consultez dans cette fenêtre ne sont pas consignées dans l'historique du navigateur et ne laissent aucune autre trace sur votre ordinateur (comme des témoins), une fois que vous avez fermé toutes les fenêtres ouvertes en tant qu'invité. Tous les fichiers téléchargés sont toutefois conservés.</translation>
+<translation id="3919798653937160644">Les pages que vous consultez dans cette fenêtre ne sont pas consignées dans l'historique du navigateur et ne laissent aucune autre trace sur votre ordinateur (comme des témoins) une fois que vous avez fermé toutes les fenêtres ouvertes en tant qu'invité. Tous les fichiers téléchargés sont toutefois conservés.</translation>
 <translation id="3920504717067627103">Politiques pour les certificats</translation>
 <translation id="392089482157167418">Activer ChromeVox (commentaires audio)</translation>
 <translation id="3920909973552939961">Non autorisés à installer des modules de traitement de paiement</translation>
diff --git a/chrome/app/resources/generated_resources_gu.xtb b/chrome/app/resources/generated_resources_gu.xtb
index ad50da0..038ecafb 100644
--- a/chrome/app/resources/generated_resources_gu.xtb
+++ b/chrome/app/resources/generated_resources_gu.xtb
@@ -1639,7 +1639,7 @@
 <translation id="2804680522274557040">કૅમેરા બંધ કર્યો</translation>
 <translation id="2805539617243680210">આગળ વધવા માટે તમે સંપૂર્ણ રીતે સજ્જ છો!</translation>
 <translation id="2805646850212350655">Microsoft Encrypting File System</translation>
-<translation id="2805756323405976993">એપ્સ</translation>
+<translation id="2805756323405976993">ઍપ</translation>
 <translation id="2805760958323556153">ExtensionInstallForcelistનું નીતિ મૂલ્ય અમાન્ય છે. કૃપા કરીને તમારા વ્યવસ્થાપકનો સંપર્ક કરો.</translation>
 <translation id="2805770823691782631">વધારાની વિગતો</translation>
 <translation id="2806372837663997957">તમે જે ડિવાઇસ સાથે શેર કરવાનો પ્રયાસ કરો છો, તેણે વિનંતી સ્વીકારી નથી</translation>
@@ -6525,7 +6525,7 @@
 <translation id="8425768983279799676">તમે તમારા ડિવાઇસને અનલૉક કરવા માટે તમારા પિનનો ઉપયોગ કરી શકો છો.</translation>
 <translation id="8426713856918551002">સક્ષમ કરી રહ્યાં છીએ</translation>
 <translation id="8427292751741042100">કોઈ પણ હોસ્ટ પર એમ્બેડ કરેલ</translation>
-<translation id="8428213095426709021">સેટિંગ્સ</translation>
+<translation id="8428213095426709021">સેટિંગ</translation>
 <translation id="8428271547607112339">શાળાનું એકાઉન્ટ ઉમેરો</translation>
 <translation id="8428628598981198790">આ સાઇટ સાથે તમારા સુરક્ષા કોડનો ઉપયોગ કરી શકાતો નથી</translation>
 <translation id="8428634594422941299">સમજાઈ ગયું</translation>
diff --git a/chrome/app/resources/generated_resources_hi.xtb b/chrome/app/resources/generated_resources_hi.xtb
index dfd661c8..1c15320d 100644
--- a/chrome/app/resources/generated_resources_hi.xtb
+++ b/chrome/app/resources/generated_resources_hi.xtb
@@ -4532,7 +4532,7 @@
 <translation id="6143186082490678276">सहायता पाएं</translation>
 <translation id="6143366292569327983">वह भाषा चुनें जिसका अनुवाद करना है</translation>
 <translation id="6144938890088808325">Chromebook को बेहतर बनाने में हमारी सहायता करें</translation>
-<translation id="6146409560350811147">सिंक करने की सुविधा काम नहीं कर रही. फिर से साइन इन करने की कोशिश करें.</translation>
+<translation id="6146409560350811147">सिंक करने की सुविधा काम नहीं कर रही. साइन इन करने की फिर से कोशिश करें.</translation>
 <translation id="6147020289383635445">प्रिंट की झलक नहीं देखी जा सकी.</translation>
 <translation id="6148576794665275391">अभी खोलें</translation>
 <translation id="6149015141270619212">इंटरनेट से कनेक्ट नहीं किया जा सकता</translation>
@@ -7268,7 +7268,7 @@
 <translation id="942532530371314860"><ph name="APP_NAME" /> एक Chrome टैब और ऑडियो शेयर कर रहा है.</translation>
 <translation id="945522503751344254">फ़ीडबैक भेजें</translation>
 <translation id="947329552760389097">&amp;एलिमेंट जाँचें</translation>
-<translation id="947667444780368238"><ph name="ORIGIN" /> की मदद से, इस फ़ोल्डर में मौजूद फ़ाइलें नहीं खोली जा सकतीं, क्योंकि ये सिस्टम फ़ाइलें हैं</translation>
+<translation id="947667444780368238"><ph name="ORIGIN" /> की मदद से, इस फ़ोल्डर में मौजूद फ़ाइलें नहीं खोली जा सकतीं, क्योंकि इस फ़ोल्डर में सिस्टम फ़ाइलें हैं</translation>
 <translation id="951991426597076286">अस्वीकार करें</translation>
 <translation id="956500788634395331">आप ऐसे एक्सटेंशन से सुरक्षित हैं जो शायद नुकसान पहुंचा सकते हैं</translation>
 <translation id="957960681186851048">इस साइट ने अपने आप  कई फ़ाइलें डाउनलोड करने की कोशिश की है</translation>
diff --git a/chrome/app/resources/generated_resources_kn.xtb b/chrome/app/resources/generated_resources_kn.xtb
index 322ba3e..e21723a 100644
--- a/chrome/app/resources/generated_resources_kn.xtb
+++ b/chrome/app/resources/generated_resources_kn.xtb
@@ -2403,7 +2403,8 @@
 <translation id="3677911431265050325">ಮೊಬೈಲ್ ಸೈಟ್‌ಗಾಗಿ ವಿನಂತಿಸಿ</translation>
 <translation id="3677959414150797585">ಆ್ಯಪ್‌ಗಳು, ವೆಬ್‌ಪುಟಗಳು ಮತ್ತು ಇತ್ಯಾದಿಯನ್ನು ಒಳಗೊಂಡಿದೆ. ಬಳಕೆಯ ಡೇಟಾವನ್ನು ಹಂಚಿಕೊಳ್ಳಲು ನೀವು ಆರಿಸಿದ್ದರೆ ಮಾತ್ರ ಸಲಹೆಗಳನ್ನು ಸುಧಾರಿಸಲು ಅಂಕಿಅಂಶಗಳನ್ನು ಕಳುಹಿಸುತ್ತದೆ.</translation>
 <translation id="3678156199662914018">ವಿಸ್ತರಣೆ: <ph name="EXTENSION_NAME" /></translation>
-<translation id="3678188444105291936">ನೀವು ಈ ವಿಂಡೋದಲ್ಲಿ ವೀಕ್ಷಿಸುವ ಪುಟಗಳು ಬ್ರೌಸರ್ ಇತಿಹಾಸದಲ್ಲಿ ಗೋಚರಿಸುವುದಿಲ್ಲ ಮತ್ತು ನೀವು ಸೈನ್ ಔಟ್ ಮಾಡಿದ ನಂತರ, ಅವುಗಳು ಕುಕೀಗಳಂತಹ ಇತರ ಗುರುತುಗಳನ್ನು ಕಂಪ್ಯೂಟರ್‌ನಲ್ಲಿ ಉಳಿಯಲು ಬಿಡುವುದಿಲ್ಲ. ನೀವು ಡೌನ್‌ಲೋಡ್ ಮಾಡಿದ ಫೈಲ್‌ಗಳು ಮತ್ತು ನೀವು ರಚಿಸಿದ ಬುಕ್‌ಮಾರ್ಕ್‌ಗಳನ್ನು ರಕ್ಷಣೆ ಮಾಡಿ ಇಟ್ಟುಕೊಳ್ಳುವುದಿಲ್ಲ.</translation>
+<translation id="3678188444105291936">ನೀವು ಈ ವಿಂಡೋದಲ್ಲಿ ವೀಕ್ಷಿಸುವ ಪುಟಗಳು ಬ್ರೌಸರ್ ಇತಿಹಾಸದಲ್ಲಿ ಗೋಚರಿಸುವುದಿಲ್ಲ ಮತ್ತು ನೀವು ಸೈನ್ ಔಟ್ ಮಾಡಿದ ನಂತರ, ಅವುಗಳು ಕುಕೀಗಳಂತಹ ಇತರ ಗುರುತುಗಳನ್ನು ಕಂಪ್ಯೂಟರ್‌ನಲ್ಲಿ ಉಳಿಯಲು ಬಿಡುವುದಿಲ್ಲ. ನೀವು ಡೌನ್‌ಲೋಡ್ ಮಾಡಿದ ಫೈಲ್‌ಗಳು ಮತ್ತು ನೀವು ರಚಿಸಿದ ಬುಕ್‌ಮಾರ್ಕ್‌ಗಳನ್ನು 
+ಸಂಗ್ರಹಿಸಿ ಇಟ್ಟುಕೊಳ್ಳುವುದಿಲ್ಲ.</translation>
 <translation id="3680683624079082902">ಪಠ್ಯದಿಂದ ಧ್ವನಿಯ ಧ್ವನಿ</translation>
 <translation id="3681311097828166361">ನಿಮ್ಮ ಪ್ರತಿಕ್ರಿಯೆಗೆ ಧನ್ಯವಾದಗಳು. ನೀವು ಇದೀಗ ಆಫ್‌ಲೈನ್‌ನಲ್ಲಿರುವಿರಿ ಮತ್ತು ನಿಮ್ಮ ವರದಿಯನ್ನು ನಂತರ ಕಳುಹಿಸಲಾಗುತ್ತದೆ.</translation>
 <translation id="3682824389861648626">ಚಲನೆಯ ಮಿತಿ</translation>
diff --git a/chrome/app/resources/generated_resources_pa.xtb b/chrome/app/resources/generated_resources_pa.xtb
index 5f6f658..78c0c6ab 100644
--- a/chrome/app/resources/generated_resources_pa.xtb
+++ b/chrome/app/resources/generated_resources_pa.xtb
@@ -576,6 +576,7 @@
 <translation id="1627408615528139100">ਪਹਿਲਾਂ ਤੋਂ ਡਾਊਨਲੋਡ ਕੀਤੀ ਗਈ</translation>
 <translation id="1628948239858170093">ਕੀ ਖੋਲ੍ਹਣ ਤੋਂ ਪਹਿਲਾਂ ਫ਼ਾਈਲ ਨੂੰ ਸਕੈਨ ਕਰਨਾ ਹੈ?</translation>
 <translation id="1629314197035607094">ਪਾਸਵਰਡ ਦੀ ਮਿਆਦ ਮੁੱਕ ਗਈ</translation>
+<translation id="1629521517399325891">ਨੈੱਟਵਰਕ ਪ੍ਰਮਾਣੀਕਰਨ ਲਈ ਵਰਤੋਂਕਾਰ ਪ੍ਰਮਾਣ-ਪੱਤਰ ਉਪਲਬਧ ਨਹੀਂ ਹੈ।</translation>
 <translation id="163072119192489970">ਡਾਟਾ ਭੇਜਣ ਅਤੇ ਪ੍ਰਾਪਤ ਕਰਨ ਦੀ ਪ੍ਰਕਿਰਿਆ ਨੂੰ ਪੂਰਾ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਹੈ</translation>
 <translation id="1630768113285622200">ਮੁੜ-ਸ਼ੁਰੂ ਕਰੋ ਅਤੇ ਜਾਰੀ ਰੱਖੋ</translation>
 <translation id="1632082166874334883">ਤੁਹਾਡੇ Google ਖਾਤੇ ਵਿੱਚ ਸਟੋਰ ਕੀਤਾ ਪਾਸਵਰਡ</translation>
@@ -1180,6 +1181,7 @@
 <translation id="2300383962156589922"><ph name="APP_NAME" /> ਨੂੰ ਵਿਉਂਤਬੱਧ ਕਰਕੇ ਕੰਟਰੋਲ ਕਰੋ</translation>
 <translation id="2301382460326681002">ਐਕਸਟੈਂਸ਼ਨ ਰੂਟ ਡਾਇਰੈਕਟਰੀ ਅਵੈਧ ਹੈ।</translation>
 <translation id="23030561267973084">"<ph name="EXTENSION_NAME" />" ਨੇ ਵਾਧੂ ਅਨੁਮਤੀਆਂ ਦੀ ਬੇਨਤੀ ਕੀਤੀ ਹੈ।</translation>
+<translation id="230529452743010958">ਤੁਸੀਂ ਇਹ ਆਈਟਮ Google ਸੇਵਾਵਾਂ ਨੂੰ ਵਰਤ ਕੇ ਆਪਣੀ ਪਿਛਲੀ ਸਰਗਰਮੀ ਦੇ ਆਧਾਰ 'ਤੇ ਦੇਖ ਰਹੇ ਹੋ। ਤੁਸੀਂ <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /> 'ਤੇ ਆਪਣੇ ਡਾਟੇ ਨੂੰ ਦੇਖ ਸਕਦੇ ਹੋ, ਇਸਨੂੰ ਮਿਟਾ ਸਕਦੇ ਹੋ ਅਤੇ ਆਪਣੀਆਂ ਸੈਟਿੰਗਾਂ ਨੂੰ ਬਦਲ ਸਕਦੇ ਹੋ।</translation>
 <translation id="23055578400314116">ਕੋਈ ਵਰਤੋਂਕਾਰ ਨਾਮ ਚੁਣੋ</translation>
 <translation id="2307462900900812319">ਨੈੱਟਵਰਕ ਸੰਰੂਪਿਤ ਕਰੋ</translation>
 <translation id="230927227160767054">ਇਹ ਪੰਨਾ ਇੱਕ ਸੇਵਾ ਹੈਂਡਲਰ ਸਥਾਪਤ ਕਰਨਾ ਚਾਹੁੰਦਾ ਹੈ।</translation>
@@ -1405,6 +1407,7 @@
 <translation id="2541706104884128042">ਸੌਣ ਦਾ ਨਵਾਂ ਸਮਾਂ ਸੈੱਟ ਕੀਤਾ ਗਿਆ</translation>
 <translation id="2542050502251273923">ff_debug ਵਰਤ ਕੇ ਨੈੱਟਵਰਕ ਕਨੈਕਸ਼ਨ ਪ੍ਰਬੰਧਕ ਅਤੇ ਹੋਰ ਸੇਵਾਵਾਂ ਦਾ ਡੀਬੱਗਿੰਗ ਪੱਧਰ ਸੈੱਟ ਕਰਦਾ ਹੈ।</translation>
 <translation id="2544292303401268586">ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਨੇ ਐਪਾਂ ਨੂੰ ਅੱਪਡੇਟ ਕਰਨ ਲਈ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਨੂੰ ਮੁੜ-ਸ਼ੁਰੂ ਕਰਨ ਦੀ ਬੇਨਤੀ ਕੀਤੀ ਹੈ। ਇਸਨੂੰ ਪੂਰਾ ਹੋਣ ਵਿੱਚ ਕਈ ਮਿੰਟ ਲੱਗ ਸਕਦੇ ਹਨ।</translation>
+<translation id="2544352060595557290">ਇਹ ਟੈਬ</translation>
 <translation id="2544853746127077729">ਪ੍ਰਮਾਣੀਕਰਨ ਪ੍ਰਮਾਣ-ਪੱਤਰ ਨੂੰ ਨੈੱਟਵਰਕ ਵੱਲੋਂ ਅਸਵੀਕਾਰ ਕੀਤਾ ਗਿਆ</translation>
 <translation id="2546283357679194313">ਕੁਕੀਜ਼ ਅਤੇ ਸਾਈਟ ਡਾਟਾ</translation>
 <translation id="2548347166720081527">ਮਨਜ਼ੂਰਸ਼ੁਦਾ <ph name="PERMISSION" /></translation>
@@ -1570,6 +1573,7 @@
 <translation id="2734760316755174687"><ph name="SITE_GROUP_NAME" /> ਦੀਆਂ ਸਾਈਟਾਂ ਨੂੰ ਵੀ ਰੀਸੈੱਟ ਕੀਤਾ ਜਾਵੇਗਾ।</translation>
 <translation id="2735712963799620190">ਸਮਾਂ ਨਿਯਤ ਕਰੋ</translation>
 <translation id="2737363922397526254">ਸਮੇਟੋ ...</translation>
+<translation id="2737916598897808047"><ph name="APP_NAME" /> ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ ਦੀਆਂ ਸਮੱਗਰੀਆਂ ਨੂੰ <ph name="TARGET_NAME" /> ਨਾਲ ਸਾਂਝਾ ਕਰਨਾ ਚਾਹੁੰਦੀ ਹੈ।</translation>
 <translation id="2738771556149464852">ਬਾਅਦ ਵਿੱਚ ਨਹੀਂ</translation>
 <translation id="2739191690716947896">ਡੀਬੱਗ</translation>
 <translation id="2739240477418971307">ਆਪਣੀਆਂ ਪਹੁੰਚਯੋਗਤਾ ਸੈਟਿੰਗਾਂ ਬਦਲੋ</translation>
@@ -2397,6 +2401,7 @@
 <translation id="3677911431265050325">ਮੋਬਾਈਲ ਸਾਈਟ ਦੀ ਬੇਨਤੀ ਕਰੋ</translation>
 <translation id="3677959414150797585">ਐਪਾਂ, ਵੈੱਬ-ਪੰਨੇ ਅਤੇ ਬਹੁਤ ਕੁਝ ਸ਼ਾਮਲ ਹਨ। ਤੁਹਾਡੇ ਵੱਲੋਂ ਵਰਤੋਂ ਡਾਟੇ ਨੂੰ ਸਾਂਝਾ ਕਰਨ ਦੀ ਚੋਣ ਕੀਤੇ ਜਾਣ 'ਤੇ ਹੀ ਸੁਝਾਵਾਂ ਨੂੰ ਬਿਹਤਰ ਬਣਾਉਣ ਲਈ ਅੰਕੜੇ ਭੇਜੇ ਜਾਂਦੇ ਹਨ।</translation>
 <translation id="3678156199662914018">ਐਕਸਟੈਂਸ਼ਨ: <ph name="EXTENSION_NAME" /></translation>
+<translation id="3678188444105291936">ਜੋ ਪੰਨੇ ਤੁਸੀਂ ਇਸ ਵਿੰਡੋ ਵਿੱਚ ਦੇਖਦੇ ਹੋ, ਉਹ ਬ੍ਰਾਊਜ਼ਿੰਗ ਇਤਿਹਾਸ ਵਿੱਚ ਦਿਖਾਈ ਨਹੀਂ ਦੇਣਗੇ ਅਤੇ ਉਹ ਤੁਹਾਡੇ ਵੱਲੋਂ ਸਾਈਨ-ਆਊਟ ਕਰਨ ਤੋਂ ਬਾਅਦ ਕੰਪਿਊਟਰ 'ਤੇ ਹੋਰ ਟ੍ਰੇਸ ਨਹੀਂ ਛੱਡਣਗੇ, ਜਿਵੇਂ ਕੁਕੀਜ਼। ਜੋ ਫ਼ਾਈਲਾਂ ਤੁਸੀਂ ਡਾਊਨਲੋਡ ਕਰਦੇ ਹੋ ਅਤੇ ਬੁੱਕਮਾਰਕ ਜੋ ਤੁਸੀਂ ਬਣਾਉਂਦੇ ਹੋ, ਉਹ ਰੱਖਿਅਤ ਨਹੀਂ ਕੀਤੇ ਜਾਣਗੇ।</translation>
 <translation id="3680683624079082902">ਲਿਖਤ-ਤੋਂ-ਬੋਲੀ ਅਵਾਜ਼</translation>
 <translation id="3681311097828166361">ਤੁਹਾਡੇ ਵਿਚਾਰ ਲਈ ਤੁਹਾਡਾ ਧੰਨਵਾਦ। ਤੁਸੀਂ ਹੁਣ ਆਫ਼ਲਾਈਨ ਹੋ, ਅਤੇ ਤੁਹਾਡੀ ਰਿਪੋਰਟ ਬਾਅਦ ਵਿੱਚ ਭੇਜੀ ਜਾਵੇਗੀ।</translation>
 <translation id="3682824389861648626">ਹਰਕਤ ਦੀ ਘੱਟੋ-ਘੱਟ ਸੀਮਾ</translation>
@@ -2598,6 +2603,7 @@
 <translation id="3884152383786131369">ਕਈ ਭਾਸ਼ਾਵਾਂ ਵਿੱਚ ਉਪਲਬਧ ਵੈੱਬ ਸਮੱਗਰੀ ਇਸ ਸੂਚੀ ਤੋਂ ਪਹਿਲੀ ਸਮਰਥਿਤ ਭਾਸ਼ਾ ਦੀ ਵਰਤੋਂ ਕਰੇਗੀ। ਇਹ ਤਰਜੀਹਾਂ ਤੁਹਾਡੀਆਂ ਬ੍ਰਾਊਜ਼ਰ ਸੈਟਿੰਗਾਂ ਨਾਲ ਸਮਕਾਲੀਕਿਰਤ ਕੀਤੀਆਂ ਜਾਂਦੀਆਂ ਹਨ। <ph name="BEGIN_LINK_LEARN_MORE" />ਹੋਰ ਜਾਣੋ<ph name="END_LINK_LEARN_MORE" /></translation>
 <translation id="3886446263141354045">ਇਸ ਸਾਈਟ 'ਤੇ ਪਹੁੰਚ ਦੀ ਤੁਹਾਡੀ ਬੇਨਤੀ <ph name="NAME" /> ਨੂੰ ਭੇਜੀ ਗਈ ਹੈ</translation>
 <translation id="3888550877729210209"><ph name="LOCK_SCREEN_APP_NAME" /> ਨਾਲ ਨੋਟ-ਕਥਨ ਲਏ ਜਾ ਰਹੇ ਹਨ</translation>
+<translation id="3888586133700543064">ਇਹ ਜਾਣਕਾਰੀ ਤੁਹਾਡੀ Assistant ਸੰਬੰਧੀ ਸਮੱਸਿਆ ਨੂੰ ਬਿਹਤਰ ਤਰੀਕੇ ਨਾਲ ਸਮਝਣ ਵਿੱਚ ਸਾਡੀ ਮਦਦ ਕਰਦੀ ਹੈ। ਇਹ 90 ਦਿਨਾਂ ਤੱਕ ਸਟੋਰ ਕੀਤੀ ਜਾਂਦੀ ਹੈ ਅਤੇ ਇਸ 'ਤੇ ਪਹੁੰਚ ਢੁਕਵੀਆਂ ਇੰਜੀਨੀਅਰਿੰਗ ਅਤੇ ਵਿਚਾਰ ਟੀਮਾਂ ਤੱਕ ਸੀਮਤ ਹੁੰਦੀ ਹੈ।</translation>
 <translation id="3890064827463908288">ਵਾਈ-ਫਾਈ ਸਿੰਕ ਦੀ ਵਰਤੋਂ ਕਰਨ ਲਈ Chrome ਸਮਕਾਲੀਕਰਨ ਨੂੰ ਚਾਲੂ ਕਰੋ</translation>
 <translation id="3892414795099177503">OpenVPN / L2TP ਸ਼ਾਮਲ ਕਰੋ...</translation>
 <translation id="3893536212201235195">ਆਪਣੀਆਂ ਪਹੁੰਚਯੋਗਤਾ ਸੈਟਿੰਗਾਂ ਪੜ੍ਹੋ ਅਤੇ ਬਦਲੋ</translation>
@@ -2629,6 +2635,7 @@
 <translation id="3916445069167113093">ਇਸ ਕਿਸਮ ਦੀ ਫ਼ਾਈਲ ਤੁਹਾਡੇ ਕੰਪਿਊਟਰ ਨੂੰ ਨੁਕਸਾਨ ਪਹੁੰਚਾ ਸਕਦੀ ਹੈ। ਕੀ ਤੁਸੀਂ ਫੇਰ ਵੀ <ph name="FILE_NAME" /> ਨੂੰ ਰੱਖਣਾ ਚਾਹੁੰਦੇ ਹੋ?</translation>
 <translation id="3918972485393593704">Google ਨੂੰ ਵੇਰਵਿਆਂ ਦੀ ਰਿਪੋਰਟ ਕਰੋ</translation>
 <translation id="3919145445993746351">ਆਪਣੇ ਸਾਰੇ ਕੰਪਿਊਟਰਾਂ 'ਤੇ ਆਪਣੀਆਂ ਐਕਸਟੈਂਸ਼ਨਾਂ ਪ੍ਰਾਪਤ ਕਰਨ ਲਈ, ਸਮਕਾਲੀਕਰਨ ਚਾਲੂ ਕਰੋ</translation>
+<translation id="3919798653937160644">ਜੋ ਪੰਨੇ ਤੁਸੀਂ ਇਸ ਵਿੰਡੋ ਵਿੱਚ ਦੇਖਦੇ ਹੋ, ਉਹ ਬ੍ਰਾਊਜ਼ਿੰਗ ਇਤਿਹਾਸ ਵਿੱਚ ਦਿਖਾਈ ਨਹੀਂ ਦੇਣਗੇ ਅਤੇ ਉਹ ਤੁਹਾਡੇ ਵੱਲੋਂ ਸਾਰੀਆਂ ਖੁੱਲ੍ਹੀਆਂ ਮਹਿਮਾਨ ਵਿੰਡੋਆਂ ਨੂੰ ਬੰਦ ਕੀਤੇ ਜਾਣ ਤੋਂ ਬਾਅਦ ਕੰਪਿਊਟਰ 'ਤੇ ਹੋਰ ਟ੍ਰੇਸ ਨਹੀਂ ਛੱਡਣਗੇ, ਜਿਵੇਂ ਕੁਕੀਜ਼। ਹਾਲਾਂਕਿ ਜੋ ਫ਼ਾਈਲਾਂ ਤੁਸੀਂ ਡਾਊਨਲੋਡ ਕਰਦੇ ਹੋ, ਸੁਰੱਖਿਅਤ ਰੱਖੀਆਂ ਜਾਣਗੀਆਂ।</translation>
 <translation id="3920504717067627103">ਪ੍ਰਮਾਣ-ਪੱਤਰ ਨੀਤੀਆਂ</translation>
 <translation id="392089482157167418">ChromeVox ਨੂੰ ਚਾਲੂ ਕਰੋ (ਬੋਲੀ ਪ੍ਰਤੀਕਰਮ)</translation>
 <translation id="3920909973552939961">ਭੁਗਤਾਨ ਹੈਂਡਲਰਾਂ ਨੂੰ ਸਥਾਪਤ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ</translation>
@@ -2964,6 +2971,7 @@
 <translation id="4332976768901252016">ਮਾਪਿਆਂ ਦੇ ਕੰਟਰੋਲ ਸੈੱਟਅੱਪ ਕਰੋ</translation>
 <translation id="4333854382783149454">RSA ਐਨਕ੍ਰਿਪਸ਼ਨ ਨਾਲ PKCS #1 SHA-1</translation>
 <translation id="4336434711095810371">ਸਾਰਾ ਡਾਟਾ ਕਲੀਅਰ ਕਰੋ</translation>
+<translation id="4340125850502689798">ਵਰਤੋਂਕਾਰ ਦਾ ਅਵੈਧ ਨਾਮ</translation>
 <translation id="4340515029017875942"><ph name="ORIGIN" />, "<ph name="EXTENSION_NAME" />" ਐਪ ਨਾਲ ਸੰਚਾਰ ਕਰਨਾ ਚਾਹੁੰਦਾ ਹੈ</translation>
 <translation id="4341577178275615435">ਕੈਰਟ ਬ੍ਰਾਊਜ਼ਿੰਗ ਨੂੰ ਚਾਲੂ ਜਾਂ ਬੰਦ ਕਰਨ ਲਈ, F7 ਸ਼ਾਰਟਕੱਟ ਵਰਤੋ</translation>
 <translation id="434198521554309404">ਤੇਜ਼। ਸੁਰੱਖਿਅਤ। ਵਰਤੋਂ ਕਰਨ ਵਿੱਚ ਆਸਾਨ।</translation>
@@ -3577,6 +3585,7 @@
 <translation id="5057110919553308744">ਜਦੋਂ ਤੁਸੀਂ ਐਕਸਟੈਂਸ਼ਨ 'ਤੇ ਕਲਿੱਕ ਕਰਦੇ ਹੋ</translation>
 <translation id="5057403786441168405">ਆਪਣੇ ਸਾਈਨ-ਇਨ ਕੀਤੇ ਖਾਤਿਆਂ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ। Chrome ਅਤੇ Google Play ਵਿੱਚ ਵੈੱਬਸਾਈਟਾਂ, ਐਪਾਂ ਅਤੇ ਐਕਸਟੈਂਸ਼ਨਾਂ ਇਜਾਜ਼ਤਾਂ ਦੇ ਆਧਾਰ 'ਤੇ ਤੁਹਾਡੇ ਅਨੁਭਵ ਨੂੰ ਵਿਉਂਤਬੱਧ ਕਰਨ ਲਈ ਇਹਨਾਂ ਖਾਤਿਆਂ ਨੂੰ ਵਰਤ ਸਕਦੀਆਂ ਹਨ। <ph name="LINK_BEGIN" />ਹੋਰ ਜਾਣੋ<ph name="LINK_END" /></translation>
 <translation id="5059241099014281248">ਸਾਈਨ-ਇਨ 'ਤੇ ਪਾਬੰਦੀ ਲਗਾਓ</translation>
+<translation id="5059526285558225588">ਇਹ ਚੁਣੋ ਕਿ ਕੀ ਸਾਂਝਾ ਕਰਨਾ ਹੈ</translation>
 <translation id="5060332552815861872">ਰੱਖਿਅਤ ਕਰਨ ਲਈ 1 ਪ੍ਰਿੰਟਰ ਉਪਲਬਧ ਹੈ।</translation>
 <translation id="5061347216700970798">{NUM_BOOKMARKS,plural, =1{ਇਸ ਫੋਲਡਰ ਵਿੱਚ ਇੱਕ ਬੁੱਕਮਾਰਕ ਹੈ। ਕੀ ਤੁਸੀਂ ਪੱਕਾ ਇਸ ਨੂੰ ਮਿਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ?}one{ਇਸ ਫੋਲਡਰ ਵਿੱਚ # ਬੁੱਕਮਾਰਕ ਹਨ। ਕੀ ਤੁਸੀਂ ਪੱਕਾ ਇਸ ਨੂੰ ਮਿਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ?}other{ਇਸ ਫੋਲਡਰ ਵਿੱਚ # ਬੁੱਕਮਾਰਕ ਹਨ। ਕੀ ਤੁਸੀਂ ਪੱਕਾ ਇਸ ਨੂੰ ਮਿਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ?}}</translation>
 <translation id="5062930723426326933">ਸਾਈਨ-ਇਨ ਅਸਫਲ, ਇੰਟਰਨੈੱਟ ਨਾਲ ਕਨੈਕਟ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।</translation>
@@ -3693,6 +3702,7 @@
 <translation id="5187826826541650604"><ph name="KEY_NAME" /> (<ph name="DEVICE" />)</translation>
 <translation id="5190187232518914472">ਆਪਣੀਆਂ ਮਨਪਸੰਦ ਯਾਦਾਂ ਨੂੰ ਤਾਜ਼ਾ ਕਰੋ। ਐਲਬਮਾਂ ਸ਼ਾਮਲ ਜਾਂ ਉਹਨਾਂ ਦਾ ਸੰਪਾਦਨ ਕਰਨ ਲਈ, <ph name="LINK_BEGIN" />Google Photos<ph name="LINK_END" /> 'ਤੇ ਜਾਓ।</translation>
 <translation id="5190926251776387065">ਪੋਰਟ ਕਿਰਿਆਸ਼ੀਲ ਕਰੋ</translation>
+<translation id="5191094172448199359">ਤੁਹਾਡੇ ਵੱਲੋਂ ਦਾਖਲ ਕੀਤੇ ਪਿੰਨ ਮੇਲ ਨਹੀਂ ਖਾਂਦੇ</translation>
 <translation id="5191251636205085390">ਨਵੀਆਂ ਤਕਨੀਕਾਂ ਬਾਰੇ ਜਾਣੋ ਅਤੇ ਉਹਨਾਂ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ ਜਿਨ੍ਹਾਂ ਦਾ ਉਦੇਸ਼ ਤੀਜੀ-ਧਿਰ ਦੀਆਂ ਕੁਕੀਜ਼ ਨੂੰ ਬਦਲਣਾ ਹੈ</translation>
 <translation id="51918995459521422"><ph name="ORIGIN" /> ਇੱਕ ਤੋਂ ਵੱਧ ਫ਼ਾਈਲਾਂ ਡਾਊਨਲੋਡ ਕਰਨਾ ਚਾਹੁੰਦੀ ਹੈ</translation>
 <translation id="5192062846343383368">ਆਪਣੀਆਂ ਨਿਗਰਾਨੀ ਸੈਟਿੰਗਾਂ ਦੇਖਣ ਲਈ Family Link ਐਪ ਖੋਲ੍ਹੋ</translation>
@@ -3705,6 +3715,7 @@
 <translation id="5204673965307125349">ਕਿਰਪਾ ਕਰਕੇ ਡੀਵਾਈਸ ਪਾਵਰਵਾਸ਼ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।</translation>
 <translation id="5204967432542742771">ਪਾਸਵਰਡ ਦਰਜ ਕਰੋ</translation>
 <translation id="5205484256512407285">ਟ੍ਰਾਂਸਫ਼ਰ ਕਰਨ ਲਈ ਕਦੇ ਵੀ ਮੋਬਾਈਲ ਡਾਟੇ ਦੀ ਵਰਤੋਂ ਨਾ ਕਰੋ</translation>
+<translation id="520568280985468584">ਨੈੱਟਵਰਕ ਨੂੰ ਸਫਲਤਾਪੂਰਬਕ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ ਹੈ। ਤੁਹਾਡੇ ਸੈਲਿਊਲਰ ਨੈੱਟਵਰਕ ਨੂੰ ਕਿਰਿਆਸ਼ੀਲ ਹੋਣ ਲਈ ਕਈ ਮਿੰਟ ਲੱਗ ਸਕਦੇ ਹਨ।</translation>
 <translation id="5206215183583316675">ਕੀ "<ph name="CERTIFICATE_NAME" />" ਮਿਟਾਉਣਾ ਹੈ?</translation>
 <translation id="520621735928254154">ਪ੍ਰਮਾਣ-ਪੱਤਰ ਆਯਾਤ ਗੜਬੜ</translation>
 <translation id="5206787458656075734">{COUNT,plural, =1{ਛੇੜਛਾੜ ਵਾਲਾ ਪਾਸਵਰਡ ਸਫਲਤਾਪੂਰਕ ਬਦਲਿਆ ਗਿਆ। ਤੁਹਾਡੇ ਕੋਲ # ਹੋਰ ਛੇੜਛਾੜ ਵਾਲਾ ਪਾਸਵਰਡ ਹੈ। Chrome ਹੁਣੇ ਇਸ ਪਾਸਵਰਡ ਦੀ ਜਾਂਚ ਕਰਨ ਦੀ ਸਿਫ਼ਾਰਸ਼ ਕਰਦਾ ਹੈ।}one{ਛੇੜਛਾੜ ਵਾਲਾ ਪਾਸਵਰਡ ਸਫਲਤਾਪੂਰਕ ਬਦਲਿਆ ਗਿਆ। ਤੁਹਾਡੇ ਕੋਲ # ਹੋਰ ਛੇੜਛਾੜ ਵਾਲਾ ਪਾਸਵਰਡ ਹੈ। Chrome ਹੁਣੇ ਇਸ ਪਾਸਵਰਡ ਦੀ ਜਾਂਚ ਕਰਨ ਦੀ ਸਿਫ਼ਾਰਸ਼ ਕਰਦਾ ਹੈ।}other{ਛੇੜਛਾੜ ਵਾਲਾ ਪਾਸਵਰਡ ਸਫਲਤਾਪੂਰਕ ਬਦਲਿਆ ਗਿਆ। ਤੁਹਾਡੇ ਕੋਲ # ਹੋਰ ਛੇੜਛਾੜ ਵਾਲੇ ਪਾਸਵਰਡ ਹਨ। Chrome ਹੁਣੇ ਇਹਨਾਂ ਪਾਸਵਰਡਾਂ ਦੀ ਜਾਂਚ ਕਰਨ ਦੀ ਸਿਫ਼ਾਰਸ਼ ਕਰਦਾ ਹੈ।}}</translation>
@@ -4339,6 +4350,7 @@
 <translation id="5935656526031444304">ਸੁਰੱਖਿਅਤ ਬ੍ਰਾਊਜ਼ਿੰਗ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ</translation>
 <translation id="5938002010494270685">ਸੁਰੱਖਿਆ ਅੱਪਗ੍ਰੇਡ ਉਪਲਬਧ ਹੈ</translation>
 <translation id="5939518447894949180">ਰੀਸੈਟ ਕਰੋ</translation>
+<translation id="5939719276406088041">ਸ਼ਾਰਟਕੱਟ ਬਣਾਇਆ ਨਹੀਂ ਜਾ ਸਕਦਾ</translation>
 <translation id="5941153596444580863">ਵਿਅਕਤੀ ਜੋੜੋ...</translation>
 <translation id="5941343993301164315">ਕਿਰਪਾ ਕਰਕੇ <ph name="TOKEN_NAME" /> 'ਤੇ ਸਾਈਨ-ਇਨ ਕਰੋ।</translation>
 <translation id="5941711191222866238">ਨਿਊਨਤਮ</translation>
@@ -4426,6 +4438,7 @@
 <translation id="6043994281159824495">ਹੁਣ ਸਾਈਨ-ਆਊਟ ਕਰੋ</translation>
 <translation id="6044805581023976844"><ph name="APP_NAME" /><ph name="TAB_NAME" /> ਦੇ ਨਾਲ Chrome ਟੈਬ ਅਤੇ ਆਡੀਓ ਨੂੰ ਸਾਂਝਾ ਕਰ ਰਹੀ ਹੈ।</translation>
 <translation id="6045114302329202345">ਮੁੱਖ TrackPoint ਬਟਨ</translation>
+<translation id="6047632800149092791">ਸਮਕਾਲੀਕਰਨ ਕੰਮ ਨਹੀਂ ਕਰ ਰਿਹਾ ਹੈ। ਸਾਈਨ ਆਊਟ ਕਰਕੇ ਦੁਬਾਰਾ ਸਾਈਨ-ਇਨ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰੋ।</translation>
 <translation id="6049004884579590341">ਪੂਰੀ ਸਕ੍ਰੀਨ ਤੋਂ ਬਾਹਰ ਜਾਣ ਲਈ |<ph name="ACCELERATOR" />| ਨੂੰ ਦਬਾਈ ਰੱਖੋ</translation>
 <translation id="6051354611314852653">ਓਹੋ! ਸਿਸਟਮ ਇਸ ਡੀਵਾਈਸ ਲਈ API ਪਹੁੰਚ ਦਾ ਅਧਿਕਾਰ ਦੇਣ ਵਿੱਚ ਅਸਫਲ ਰਿਹਾ।</translation>
 <translation id="6052976518993719690">SSL ਸਰਟੀਫਿਕੇਸ਼ਨ ਅਧਿਕਾਰ</translation>
@@ -4518,6 +4531,7 @@
 <translation id="6143186082490678276">ਸਹਾਇਤਾ ਪ੍ਰਾਪਤ ਕਰੋ</translation>
 <translation id="6143366292569327983">ਪੰਨੇ ਦੀ ਉਹ ਭਾਸ਼ਾ ਚੁਣੋ, ਜਿਸ ਤੋਂ ਅਨੁਵਾਦ ਕਰਨਾ ਹੈ</translation>
 <translation id="6144938890088808325">Chromebooks ਨੂੰ ਬਿਹਤਰ ਬਣਾਉਣ ਵਿੱਚ ਸਾਡੀ ਮਦਦ ਕਰੋ</translation>
+<translation id="6146409560350811147">ਸਮਕਾਲੀਕਰਨ ਕੰਮ ਨਹੀਂ ਕਰ ਰਿਹਾ ਹੈ। ਦੁਬਾਰਾ ਸਾਈਨ ਇਨ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰੋ।</translation>
 <translation id="6147020289383635445">ਪ੍ਰਿੰਟ ਪੂਰਵ-ਝਲਕ ਅਸਫਲ ਰਹੀ।</translation>
 <translation id="6148576794665275391">ਹੁਣੇ ਖੋਲ੍ਹੋ</translation>
 <translation id="6149015141270619212">ਇੰਟਰਨੈੱਟ ਨਾਲ ਕਨੈਕਟ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ</translation>
@@ -4585,6 +4599,7 @@
 <translation id="6232017090690406397">ਬੈਟਰੀ</translation>
 <translation id="6232116551750539448"><ph name="NAME" /> ਵਿੱਚ ਕਨੈਕਸ਼ਨ ਖੋਹ ਗਿਆ ਹੈ।</translation>
 <translation id="6233154960150021497">ਕੀ-ਬੋਰਡ ਦੀ ਬਜਾਏ ਅਵਾਜ਼ ਦੀ ਵਰਤੋਂ ਕਰਨ ਲਈ ਪੂਰਵ-ਨਿਰਧਾਰਤ</translation>
+<translation id="6234108445915742946">Chrome ਦੇ ਸੇਵਾ ਦੇ ਨਿਯਮ 31 ਮਾਰਚ ਨੂੰ ਬਦਲ ਰਹੇ ਹਨ</translation>
 <translation id="6234474535228214774">ਸਥਾਪਨਾ ਵਿਚਾਰ-ਅਧੀਨ ਹੈ</translation>
 <translation id="6237474966939441970">ਸਟਾਈਲਸ ਨੋਟ-ਕਥਨ ਬਣਾਉਣ ਵਾਲੀ ਐਪ</translation>
 <translation id="6237816943013845465">ਤੁਹਾਨੂੰ ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ ਰੈਜ਼ੋਲਿਊਸ਼ਨ ਵਿਵਸਥਿਤ ਕਰਨ ਦਿੰਦੀ ਹੈ</translation>
@@ -4883,6 +4898,7 @@
 <translation id="656293578423618167">ਫਾਈਲ ਪਾਥ ਜਾਂ ਨਾਮ ਬਹੁਤ ਜ਼ਿਆਦਾ ਵੱਡਾ ਹੈ। ਕਿਰਪਾ ਕਰਕੇ ਇੱਕ ਛੋਟੇ ਨਾਮ ਨਾਲ ਜਾਂ ਦੂਜੇ ਨਿਰਧਾਰਿਤ ਟਿਕਾਣੇ ਵਿੱਚ ਰੱਖਿਅਤ ਕਰੋ।</translation>
 <translation id="6563469144985748109">ਤੁਹਾਡੇ ਪ੍ਰਬੰਧਕ ਨੇ ਹਾਲੇ ਇਸ ਦੀ ਮਨਜ਼ੂਰੀ ਨਹੀਂ ਦਿੱਤੀ ਹੈ</translation>
 <translation id="6569934958368283244">ਦੂਜੇ ਲੋਕ</translation>
+<translation id="6573497332121198392">ਸ਼ਾਰਟਕੱਟ ਹਟਾਇਆ ਨਹੀਂ ਜਾ ਸਕਦਾ</translation>
 <translation id="657402800789773160">&amp;ਇਹ ਸਫ਼ਾ ਰੀਲੋਡ ਕਰੋ</translation>
 <translation id="6577284282025554716">ਡਾਊਨਲੋਡ ਰੱਦ ਹੋਇਆ: <ph name="FILE_NAME" /></translation>
 <translation id="657866106756413002">ਨੈੱਟਵਰਕ ਸਿਹਤ ਦਾ ਸਨੈਪਸ਼ਾਟ</translation>
@@ -4890,6 +4906,7 @@
 <translation id="6579705087617859690"><ph name="WINDOW_TITLE" /> - ਡੈਸਕਟਾਪ ਸਮੱਗਰੀ ਨੂੰ ਸਾਂਝਾ ਕੀਤਾ ਗਿਆ</translation>
 <translation id="6580203076670148210">ਸਕੈਨ ਕਰਨ ਦੀ ਗਤੀ</translation>
 <translation id="6582080224869403177">ਆਪਣੀ ਸੁਰੱਖਿਆ ਨੂੰ ਅੱਪਗ੍ਰੇਡ ਕਰਨ ਲਈ ਆਪਣੀ <ph name="DEVICE_TYPE" /> ਨੂੰ ਰੀਸੈੱਟ ਕਰੋ।</translation>
+<translation id="6582274660680936615">ਤੁਸੀਂ ਮਹਿਮਾਨ ਵਜੋਂ ਬ੍ਰਾਊਜ਼ ਕਰ ਰਹੇ ਹੋ</translation>
 <translation id="6584878029876017575">Microsoft ਲਾਈਫਟਾਈਮ ਸਾਈਨਿੰਗ</translation>
 <translation id="6586099239452884121">ਮਹਿਮਾਨ ਬ੍ਰਾਊਜ਼ਿੰਗ</translation>
 <translation id="6586451623538375658">ਪ੍ਰਾਈਮਰੀ ਮਾਊਸ ਬਟਨ ਸਵੈਪ ਕਰੋ</translation>
@@ -5059,6 +5076,7 @@
 <translation id="6782468519961184511">ਤੁਹਾਡਾ ਪ੍ਰਸ਼ਾਸਕ ਵਧੀਕ Google ਖਾਤਿਆਂ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਦਿੰਦਾ</translation>
 <translation id="6785518634832172390">ਪਿੰਨ 12 ਜਾਂ ਇਸ ਤੋਂ ਘੱਟ ਅੰਕਾਂ ਦਾ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ</translation>
 <translation id="6786747875388722282">ਐਕਸਟੈਂਸ਼ਨਾਂ</translation>
+<translation id="6787097042755590313">ਹੋਰ ਟੈਬ</translation>
 <translation id="6787839852456839824">ਕੀ-ਬੋਰਡ ਸ਼ਾਰਟਕੱਟ</translation>
 <translation id="6788210894632713004">ਅਣਪੈਕ ਕੀਤੀ ਐਕਸਟੈਂਸ਼ਨ</translation>
 <translation id="6789592661892473991">ਲੇਟਵੇਂ ਤੌਰ 'ਤੇ ਵੰਡੋ</translation>
@@ -5069,6 +5087,7 @@
 <translation id="6793723358811598107">'<ph name="CURRENTKEY" />' ਨੂੰ ਪਹਿਲਾਂ ਹੀ '<ph name="ACTION" />' ਕਾਰਵਾਈ ਦੇ ਜ਼ਿੰਮੇ ਲਗਾ ਦਿੱਤਾ ਗਿਆ ਹੈ। ਬਾਹਰ ਜਾਣ ਲਈ ਕਿਸੇ ਵੀ ਕੁੰਜੀ ਨੂੰ ਦਬਾਓ।</translation>
 <translation id="6795884519221689054">ਪਾਂਡਾ</translation>
 <translation id="6797493596609571643">ਓਹੋ, ਕੋਈ ਗੜਬੜ ਹੋ ਗਈ।</translation>
+<translation id="6798420440063423019">ਸੁਰੱਖਿਆ ਕੁੰਜੀ ਲਾਕ ਹੋ ਗਈ ਹੈ ਕਿਉਂਕਿ ਗਲਤ ਪਿੰਨ ਬਹੁਤ ਵਾਰ ਦਾਖਲ ਕੀਤਾ ਗਿਆ। ਤੁਹਾਨੂੰ ਸੁਰੱਖਿਆ ਕੁੰਜੀ ਨੂੰ ਰੀਸੈੱਟ ਕਰਨਾ ਪਵੇਗਾ।</translation>
 <translation id="6798578729981748444">ਆਯਾਤ ਨੂੰ ਪੂਰਾ ਕਰਨ ਲਈ, ਸਾਰੀਆਂ Firefox ਵਿੰਡੋਆਂ ਬੰਦ ਕਰੋ।</translation>
 <translation id="6798780071646309401">ਕੈਪਸ ਲੌਕ ਚਾਲੂ</translation>
 <translation id="6798954102094737107">ਪਲੱਗਇਨ: <ph name="PLUGIN_NAME" /></translation>
@@ -5414,6 +5433,7 @@
 <translation id="7180865173735832675">ਵਿਉਂਤਬੱਧ ਕਰੋ</translation>
 <translation id="7182791023900310535">ਆਪਣਾ ਪਾਸਵਰਡ ਲਿਜਾਓ</translation>
 <translation id="7186088072322679094">ਟੂਲਬਾਰ ਵਿੱਚ ਰੱਖੋ</translation>
+<translation id="7186303001964993981"><ph name="ORIGIN" /> ਸਾਈਟ ਇਸ ਫੋਲਡਰ ਨੂੰ ਨਹੀਂ ਖੋਲ੍ਹ ਸਕਦੀ ਕਿਉਂਕਿ ਇਸ ਵਿੱਚ ਸਿਸਟਮ ਫ਼ਾਈਲਾਂ ਹਨ</translation>
 <translation id="7187428571767585875">ਹਟਾਏ ਜਾਣ ਜਾਂ ਬਦਲੇ ਜਾਣ ਲਈ ਰਜਿਸਟਰੀ ਇੰਦਰਾਜ਼:</translation>
 <translation id="7187855807420906517">ਤੁਹਾਡੇ ਵੱਲੋਂ ਸਾਈਟ ਛੱਡਣ ਜਾਂ ਆਫ਼ਲਾਈਨ ਹੋਣ ਤੋਂ ਬਾਅਦ ਵੀ ਸਾਈਟਾਂ ਆਮ ਤੌਰ 'ਤੇ ਫ਼ੋਟੋਆਂ ਅੱਪਲੋਡ ਕਰਨ ਜਾਂ ਚੈਟ ਸੁਨੇਹੇ ਭੇਜਣ ਜਿਹੇ ਕਾਰਜ ਪੂਰੇ ਕਰਨ ਲਈ ਸਮਕਾਲੀਕਰਨ ਕਰਨਾ ਜਾਰੀ ਰੱਖਦੀਆਂ ਹਨ</translation>
 <translation id="7189234443051076392">ਪੱਕਾ ਕਰੋ ਕਿ ਤੁਹਾਡੇ ਡੀਵਾਈਸ 'ਤੇ ਲੋੜੀਂਦੀ ਜਗ੍ਹਾ ਹੈ</translation>
@@ -6032,6 +6052,7 @@
 <translation id="7871109039747854576">ਉਮੀਦਵਾਰ ਸੂਚੀ ਨੂੰ ਸਫ਼ਾਬੱਧ ਕਰਨ ਲਈ <ph name="COMMA" /> ਅਤੇ <ph name="PERIOD" /> ਕੁੰਜੀਆਂ ਵਰਤੋ</translation>
 <translation id="787268756490971083">ਬੰਦ</translation>
 <translation id="7874257161694977650">Chrome ਬੈਕਗ੍ਰਾਊਂਡਾਂ</translation>
+<translation id="7876027585589532670">ਸ਼ਾਰਟਕੱਟ ਦਾ ਸੰਪਾਦਨ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ</translation>
 <translation id="7877451762676714207">ਅਗਿਆਤ ਸਰਵਰ ਅਸ਼ੁੱਧੀ। ਕਿਰਪਾ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ ਜਾਂ ਸਰਵਰ ਪ੍ਰਬੰਧਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।</translation>
 <translation id="7879631849810108578">ਸ਼ਾਰਟਕੱਟ ਸੈੱਟ ਕੀਤਾ ਗਿਆ: <ph name="IDS_SHORT_SET_COMMAND" /></translation>
 <translation id="7880823633812189969">ਜਦੋਂ ਤੁਸੀਂ ਡੀਵਾਈਸ ਨੂੰ ਮੁੜ-ਸ਼ੁਰੂ ਕਰੋਗੇ ਤਾਂ ਸਥਾਨਕ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ</translation>
@@ -6316,6 +6337,7 @@
 <translation id="8189750580333936930">ਪਰਦੇਦਾਰੀ ਸੈਂਡਬਾਕਸ</translation>
 <translation id="8190193592390505034"><ph name="PROVIDER_NAME" /> ਨਾਲ ਕਨੈਕਟ ਕਰ ਰਿਹਾ ਹੈ</translation>
 <translation id="8191230140820435481">ਆਪਣੇ ਐਪਸ, ਐਕਸਟੈਂਸ਼ਨਾਂ ਅਤੇ ਵਿਸ਼ੇ ਵਿਵਸਥਿਤ ਕਰੋ</translation>
+<translation id="8192944472786724289"><ph name="APP_NAME" /> ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ ਦੀਆਂ ਸਮੱਗਰੀਆਂ ਨੂੰ ਸਾਂਝਾ ਕਰਨਾ ਚਾਹੁੰਦੀ ਹੈ।</translation>
 <translation id="8195027750202970175">ਡਿਸਕ 'ਤੇ ਆਕਾਰ</translation>
 <translation id="8198323535106903877">ਅਸੀਂ ਤੁਹਾਡੇ ਲਈ ਉਹ <ph name="NUMBER_OF_APPS" /> ਐਪਾਂ ਸਥਾਪਤ ਕਰਾਂਗੇ</translation>
 <translation id="8199300056570174101">ਨੈੱਟਵਰਕ (ਸੇਵਾ) ਅਤੇ ਡੀਵਾਈਸ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ</translation>
@@ -6966,6 +6988,7 @@
 <translation id="8931475688782629595">ਸਮਕਾਲੀਕਰਨ ਕੀਤੇ ਡਾਟੇ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ</translation>
 <translation id="8932654652795262306">ਤਤਕਾਲ ਟੈਦਰਿੰਗ ਸੰਬੰਧੀ ਵੇਰਵੇ</translation>
 <translation id="8932894639908691771">ਸਵਿੱਚ ਪਹੁੰਚ ਦੇ ਵਿਕਲਪ</translation>
+<translation id="893298445929867520">ਕਾਰਟ ਲੁਕਾਏ ਗਏ। ਜਦੋਂ ਤੁਸੀਂ ਤਬਦੀਲੀਆਂ ਕਰਦੇ ਹੋ ਤਾਂ ਉਹ ਦੁਬਾਰਾ ਦਿਖਾਈ ਦੇਣਗੇ।</translation>
 <translation id="8933960630081805351">&amp;ਫਾਈਂਡਰ ਵਿੱਚ ਦਿਖਾਓ</translation>
 <translation id="8934732568177537184">ਜਾਰੀ ਰੱਖੋ</translation>
 <translation id="8938306522009698937">ਹੈਂਡਲਰ</translation>
@@ -7242,6 +7265,7 @@
 <translation id="942532530371314860"><ph name="APP_NAME" /> Chrome ਟੈਬ ਅਤੇ ਆਡੀਓ ਸਾਂਝੀ ਕਰ ਰਹੀ ਹੈ।</translation>
 <translation id="945522503751344254">ਪ੍ਰਤੀਕਰਮ ਭੇਜੋ</translation>
 <translation id="947329552760389097">&amp;ਅੰਸ਼ਾਂ ਦੀ ਜਾਂਚ ਕਰੋ</translation>
+<translation id="947667444780368238"><ph name="ORIGIN" /> ਸਾਈਟ ਇਸ ਫੋਲਡਰ ਵਿਚਲੀਆਂ ਫ਼ਾਈਲਾਂ ਨੂੰ ਖੋਲ੍ਹ ਨਹੀਂ ਸਕਦੀ ਕਿਉਂਕਿ ਇਸ ਵਿੱਚ ਸਿਸਟਮ ਫ਼ਾਈਲਾਂ ਹਨ</translation>
 <translation id="951991426597076286">ਅਸਵੀਕਾਰ ਕਰੋ</translation>
 <translation id="956500788634395331">ਤੁਸੀਂ ਸੰਭਾਵੀ ਤੌਰ 'ਤੇ ਨੁਕਸਾਨਦੇਹ ਐਕਸਟੈਂਸ਼ਨਾਂ ਤੋਂ ਸੁਰੱਖਿਅਤ ਹੋ</translation>
 <translation id="957960681186851048">ਇਸ ਸਾਈਟ ਨੇ ਸਵੈਚਲਿਤ ਤੌਰ 'ਤੇ ਇੱਕ ਤੋਂ ਵੱਧ ਫ਼ਾਈਲਾਂ ਡਾਊਨਲੋਡ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ</translation>
diff --git a/chrome/app/resources/generated_resources_pl.xtb b/chrome/app/resources/generated_resources_pl.xtb
index 838473b..04aec95 100644
--- a/chrome/app/resources/generated_resources_pl.xtb
+++ b/chrome/app/resources/generated_resources_pl.xtb
@@ -484,7 +484,7 @@
 <translation id="1526335046150927198">Włącz szybkie przewijanie na touchpadzie</translation>
 <translation id="1526560967942511387">Dokument bez tytułu</translation>
 <translation id="1527336312600375509">Częstotliwość odświeżania monitora</translation>
-<translation id="152913213824448541">Udostępnianie w pobliżu kontakty</translation>
+<translation id="152913213824448541">Kontakty wykorzystywane przez Udostępnianie w pobliżu</translation>
 <translation id="1529891865407786369">Źródło zasilania</translation>
 <translation id="1530838837447122178">Otwórz ustawienia myszy i touchpada</translation>
 <translation id="1531275250079031713">Pokaż okno „Dodaj nową sieć Wi-Fi”</translation>
@@ -3584,7 +3584,7 @@
 <translation id="5057110919553308744">Gdy klikniesz rozszerzenie</translation>
 <translation id="5057403786441168405">Zarządzanie kontami zalogowanych użytkowników. Witryny, aplikacje i rozszerzenia w Chrome i Google Play mogą używać tych kont do dostosowywania swojego wyglądu i działania (jeśli mają odpowiednie uprawnienia). <ph name="LINK_BEGIN" />Więcej informacji<ph name="LINK_END" /></translation>
 <translation id="5059241099014281248">Ograniczanie logowania się</translation>
-<translation id="5059526285558225588">Wybierz udostępniane dane</translation>
+<translation id="5059526285558225588">Wybierz, co chcesz udostępnić</translation>
 <translation id="5060332552815861872">Dostępna do zapisania jest jedna drukarka.</translation>
 <translation id="5061347216700970798">{NUM_BOOKMARKS,plural, =1{Ten folder zawiera zakładkę. Na pewno chcesz go usunąć?}few{Ten folder zawiera # zakładki. Na pewno chcesz go usunąć?}many{Ten folder zawiera # zakładek. Na pewno chcesz go usunąć?}other{Ten folder zawiera # zakładki. Na pewno chcesz go usunąć?}}</translation>
 <translation id="5062930723426326933">Logowanie nieudane. Połącz się z internetem i spróbuj ponownie.</translation>
@@ -3714,7 +3714,7 @@
 <translation id="5204673965307125349">Wykonaj Powerwash urządzenia i spróbuj jeszcze raz.</translation>
 <translation id="5204967432542742771">Wpisz hasło</translation>
 <translation id="5205484256512407285">Nigdy nie używaj mobilnej transmisji danych</translation>
-<translation id="520568280985468584">Sieć komórkowa została dodana. Może stać się aktywna po kilku minutach.</translation>
+<translation id="520568280985468584">Sieć komórkowa została dodana. Może minąć kilka minut, zanim się uaktywni.</translation>
 <translation id="5206215183583316675">Usunąć „<ph name="CERTIFICATE_NAME" />”?</translation>
 <translation id="520621735928254154">Błąd importowania certyfikatu</translation>
 <translation id="5206787458656075734">{COUNT,plural, =1{Zmieniono przejęte hasło. Masz jeszcze # przejęte hasło. Chrome zaleca, by jak najszybciej je sprawdzić.}few{Zmieniono przejęte hasło. Masz jeszcze # przejęte hasła. Chrome zaleca, by jak najszybciej je sprawdzić.}many{Zmieniono przejęte hasło. Masz jeszcze # przejętych haseł. Chrome zaleca, by jak najszybciej je sprawdzić.}other{Zmieniono przejęte hasło. Masz jeszcze # przejętego hasła. Chrome zaleca, by jak najszybciej je sprawdzić.}}</translation>
@@ -4437,7 +4437,7 @@
 <translation id="6043994281159824495">Wyloguj się teraz</translation>
 <translation id="6044805581023976844"><ph name="APP_NAME" /> udostępnia kartę i dźwięk z Chrome karcie <ph name="TAB_NAME" />.</translation>
 <translation id="6045114302329202345">Podstawowy przycisk TrackPointa</translation>
-<translation id="6047632800149092791">Synchronizacja nie działa. Wyloguj się i zaloguj się ponownie.</translation>
+<translation id="6047632800149092791">Synchronizacja nie działa. Wyloguj się i zaloguj ponownie.</translation>
 <translation id="6049004884579590341">Naciśnij i przytrzymaj |<ph name="ACCELERATOR" />|, by zamknąć pełny ekran</translation>
 <translation id="6051354611314852653">Ups. System nie może autoryzować dostępu do interfejsu API dla tego urządzenia.</translation>
 <translation id="6052976518993719690">Urząd certyfikacji protokołu SSL</translation>
@@ -5086,7 +5086,7 @@
 <translation id="6793723358811598107">Klawisz „<ph name="CURRENTKEY" />” jest już przypisany do czynności „<ph name="ACTION" />”. Naciśnij dowolny klawisz, by zakończyć.</translation>
 <translation id="6795884519221689054">Panda</translation>
 <translation id="6797493596609571643">Ups, coś poszło nie tak.</translation>
-<translation id="6798420440063423019">Klucz bezpieczeństwa jest zablokowany z powodu wprowadzenia nieprawidłowego kodu PIN zbyt wiele razy. Musisz zresetować klucz bezpieczeństwa.</translation>
+<translation id="6798420440063423019">Klucz bezpieczeństwa został zablokowany z powodu wprowadzenia nieprawidłowego kodu PIN zbyt wiele razy. Musisz zresetować klucz bezpieczeństwa.</translation>
 <translation id="6798578729981748444">Aby zakończyć importowanie, zamknij wszystkie okna Firefoksa.</translation>
 <translation id="6798780071646309401">caps lock włączony</translation>
 <translation id="6798954102094737107">Wtyczka: <ph name="PLUGIN_NAME" /></translation>
diff --git a/chrome/app/resources/generated_resources_sv.xtb b/chrome/app/resources/generated_resources_sv.xtb
index 8acfbf7..04d839dd 100644
--- a/chrome/app/resources/generated_resources_sv.xtb
+++ b/chrome/app/resources/generated_resources_sv.xtb
@@ -3057,7 +3057,7 @@
 <translation id="4430019312045809116">Volym</translation>
 <translation id="4430369329743628066">Ett bokmärke har lagts till</translation>
 <translation id="4432621511648257259">Fel lösenord</translation>
-<translation id="4434045419905280838">Popup och omdirigeringar</translation>
+<translation id="4434045419905280838">Popup-fönster och omdirigeringar</translation>
 <translation id="443454694385851356">Äldre (osäker)</translation>
 <translation id="443475966875174318">Uppdatera och ta bort inkompatibla appar</translation>
 <translation id="4438043733494739848">Genomskinlig</translation>
diff --git a/chrome/app/resources/generated_resources_ta.xtb b/chrome/app/resources/generated_resources_ta.xtb
index 41f1fb1..8a9e8029 100644
--- a/chrome/app/resources/generated_resources_ta.xtb
+++ b/chrome/app/resources/generated_resources_ta.xtb
@@ -2402,7 +2402,7 @@
 <translation id="3677911431265050325">மொபைல் தளத்தைக் கோரு</translation>
 <translation id="3677959414150797585">ஆப்ஸ், இணையப் பக்கங்கள் மற்றும் பல அடங்கும். உபயோகத் தரவுப் பகிர்வை தேர்வுசெய்திருந்தால் மட்டுமே பரிந்துரைகளை மேம்படுத்துவதற்காகப் புள்ளிவிவரங்களை அனுப்பும்.</translation>
 <translation id="3678156199662914018">நீட்டிப்பு: <ph name="EXTENSION_NAME" /></translation>
-<translation id="3678188444105291936">இந்தச் சாளரத்தில் நீங்கள் பார்க்கும் பக்கங்கள் உலாவியின் வரலாற்றில் தோன்றாது, மேலும் நீங்கள் வெளியேறியபிறகு அவை குக்கீகள் போன்ற பிற தடங்களைக் கம்ப்யூட்டரில் விட்டுச் செல்லாது. நீங்கள் பதிவிறக்கும் கோப்புகளும் உருவாக்கும் புக்மார்க்குகளும் பாதுகாக்கப்படாது.</translation>
+<translation id="3678188444105291936">இந்தச் சாளரத்தில் நீங்கள் பார்க்கும் பக்கங்கள் உலாவியின் வரலாற்றில் தோன்றாது. நீங்கள் வெளியேறியபிறகு அவை குக்கீகள் போன்ற பிற தடங்களைக் கம்ப்யூட்டரில் விட்டுச் செல்லாது. நீங்கள் பதிவிறக்கும் கோப்புகளும் உருவாக்கும் புக்மார்க்குகளும் பாதுகாக்கப்படாது.</translation>
 <translation id="3680683624079082902">’உரையிலிருந்து பேச்சு’ செயல்முறைக்கான குரல்</translation>
 <translation id="3681311097828166361">உங்கள் கருத்திற்கு நன்றி. இப்போது ஆஃப்லைனில் உள்ளீர்கள், உங்கள் அறிக்கை பின்னர் அனுப்பப்படும்.</translation>
 <translation id="3682824389861648626">நகர்வு வரம்பு</translation>
@@ -2636,7 +2636,7 @@
 <translation id="3916445069167113093">இவ்வகையான கோப்பு உங்கள் கம்ப்யூட்டரைப் பாதிக்கக்கூடும். இருப்பினும் <ph name="FILE_NAME" /> ஐ வைத்திருக்க வேண்டுமா?</translation>
 <translation id="3918972485393593704">Googleளுக்கு விவரங்களை அனுப்பு</translation>
 <translation id="3919145445993746351">உங்கள் அனைத்துக் கணிணிகளிலும் நீட்டிப்புகளைப் பெற, ஒத்திசைவை இயக்கவும்</translation>
-<translation id="3919798653937160644">இந்தச் சாளரத்தில் நீங்கள் பார்க்கும் பக்கங்கள் உலாவியின் வரலாற்றில் தோன்றாது, மேலும் திறக்கப்பட்டிருக்கும் கெஸ்ட் சாளரங்கள் அனைத்தையும் மூடியபிறகு அவை குக்கீகள் போன்ற பிற தடங்களைக் கம்ப்யூட்டரில் விட்டுச் செல்லாது. இருப்பினும், நீங்கள் பதிவிறக்கிய கோப்புகள் அனைத்தும் பாதுகாக்கப்படும்.</translation>
+<translation id="3919798653937160644">இந்தச் சாளரத்தில் நீங்கள் பார்க்கும் பக்கங்கள் உலாவியின் வரலாற்றில் தோன்றாது. திறக்கப்பட்டிருக்கும் கெஸ்ட் சாளரங்கள் அனைத்தையும் மூடியபிறகு அவை குக்கீகள் போன்ற பிற தடங்களைக் கம்ப்யூட்டரில் விட்டுச் செல்லாது. இருப்பினும், நீங்கள் பதிவிறக்கிய கோப்புகள் அனைத்தும் பாதுகாக்கப்படும்.</translation>
 <translation id="3920504717067627103">சான்றிதழ் கொள்கைகள்</translation>
 <translation id="392089482157167418">ChromeVox (பேச்சுவடிவ கருத்து) ஐ இயக்கு</translation>
 <translation id="3920909973552939961">பேமெண்ட் ஹேண்ட்லர்களை நிறுவ அனுமதி இல்லாத தளங்கள்</translation>
@@ -3716,7 +3716,7 @@
 <translation id="5204673965307125349">சாதனத்தைப் பவர்வாஷ் செய்து, மீண்டும் முயலவும்.</translation>
 <translation id="5204967432542742771">கடவுச்சொல்</translation>
 <translation id="5205484256512407285">பரிமாற்றத்திற்கு எப்போதும் மொபைல் டேட்டாவைப் பயன்படுத்தாது</translation>
-<translation id="520568280985468584">நெட்வொர்க் சேர்க்கப்பட்டது. மொபைல் நெட்வொர்க் செயல்பட பல நிமிடங்கள் ஆகக்கூடும்.</translation>
+<translation id="520568280985468584">நெட்வொர்க் சேர்க்கப்பட்டது. மொபைல் நெட்வொர்க் செயல்பட சில நிமிடங்கள் ஆகக்கூடும்.</translation>
 <translation id="5206215183583316675">"<ph name="CERTIFICATE_NAME" />"ஐ நீக்கவா?</translation>
 <translation id="520621735928254154">சான்றிதழ் இறக்குமதியாவதில் பிழை</translation>
 <translation id="5206787458656075734">{COUNT,plural, =1{களவாடப்பட்ட கடவுச்சொல் மாற்றப்பட்டது. இன்னும் # களவாடப்பட்ட கடவுச்சொல் உள்ளது. இப்போதே இந்தக் கடவுச்சொச்லைச் சரிபார்க்கும்படி Chrome பரிந்துரைக்கிறது.}other{களவாடப்பட்ட கடவுச்சொல் மாற்றப்பட்டது. இன்னும் # களவாடப்பட்ட கடவுச்சொற்கள் உள்ளன. இப்போதே இந்தக் கடவுச்சொற்களைச் சரிபார்க்கும்படி Chrome பரிந்துரைக்கிறது.}}</translation>
diff --git a/chrome/app/resources/generated_resources_uk.xtb b/chrome/app/resources/generated_resources_uk.xtb
index 76c3d0d..27649581 100644
--- a/chrome/app/resources/generated_resources_uk.xtb
+++ b/chrome/app/resources/generated_resources_uk.xtb
@@ -1183,7 +1183,7 @@
 <translation id="2300383962156589922">Налаштування та керування <ph name="APP_NAME" /></translation>
 <translation id="2301382460326681002">Кореневий каталог розширення недійсний.</translation>
 <translation id="23030561267973084">"<ph name="EXTENSION_NAME" />" запитує додаткові дозволи.</translation>
-<translation id="230529452743010958">Цей товар рекомендовано вам на основі ваших попередніх дій у сервісах Google. Ви можете переглянути й видалити дані про свої дії або змінити їх налаштування на сторінці <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" />.</translation>
+<translation id="230529452743010958">Цей контент показано вам на основі ваших попередніх дій у сервісах Google. Ви можете переглянути й видалити дані про свої дії або змінити їх налаштування на сторінці <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" />.</translation>
 <translation id="23055578400314116">Виберіть ім'я користувача</translation>
 <translation id="2307462900900812319">Установити параметри мережі</translation>
 <translation id="230927227160767054">Ця сторінка хоче встановити обробника служби.</translation>
@@ -1410,7 +1410,7 @@
 <translation id="2541706104884128042">Налаштовано новий час сну</translation>
 <translation id="2542050502251273923">Налаштовує рівень налагодження менеджера й інших сервісів з'єднання з мережею за допомогою ff_debug.</translation>
 <translation id="2544292303401268586">Адміністратор надіслав запит на перезапуск пристрою, щоб оновити додатки. Це може тривати кілька хвилин.</translation>
-<translation id="2544352060595557290">Ця вкладка</translation>
+<translation id="2544352060595557290">Цю вкладку</translation>
 <translation id="2544853746127077729">Сертифікат автентифікації відхилений мережею</translation>
 <translation id="2546283357679194313">Файли cookie та дані із сайтів</translation>
 <translation id="2548347166720081527">Дозволено: <ph name="PERMISSION" /></translation>
@@ -2405,7 +2405,7 @@
 <translation id="3677911431265050325">Мобільний сайт</translation>
 <translation id="3677959414150797585">Зокрема, додатки, веб-сторінки й інше. Надсилає статистику, щоб покращувати пропозиції, лише якщо ви погодилися ділитися даними про використання.</translation>
 <translation id="3678156199662914018">Розширення: <ph name="EXTENSION_NAME" /></translation>
-<translation id="3678188444105291936">Сторінки, які ви переглядаєте в цьому вікні, не відображатимуться в історії веб-перегляду, а після вашого виходу не залишать у комп'ютері інших слідів, наприклад, файлів cookie. Завантажені вами файли та створені закладки не зберігаються.</translation>
+<translation id="3678188444105291936">Сторінки, які ви переглядаєте в цьому вікні, не записуватимуться в історію веб-перегляду, а після вашого виходу не залишать на комп'ютері інших слідів (на зразок файлів cookie). Завантажені вами файли та створені закладки не зберігатимуться.</translation>
 <translation id="3680683624079082902">Голос синтезу мовлення</translation>
 <translation id="3681311097828166361">Дякуємо за відгук. Звіт буде надіслано пізніше, оскільки зараз ви офлайн.</translation>
 <translation id="3682824389861648626">Мінімальна кількість рухів</translation>
@@ -2639,7 +2639,7 @@
 <translation id="3916445069167113093">Цей тип файлу може зашкодити вашому комп’ютеру. Усе одно зберегти <ph name="FILE_NAME" />?</translation>
 <translation id="3918972485393593704">Надішліть у Google докладнішу інформацію</translation>
 <translation id="3919145445993746351">Щоб користуватися розширеннями на всіх комп’ютерах, увімкніть синхронізацію</translation>
-<translation id="3919798653937160644">Сторінки, які ви переглядаєте в цьому вікні, не відображатимуться в історії веб-перегляду, а після закриття всіх вікон, відкритих у гостьовому режимі, не залишать у комп'ютері інших слідів, наприклад файлів cookie. Однак завантажені файли зберігаються.</translation>
+<translation id="3919798653937160644">Сторінки, які ви переглядаєте в цьому вікні, не записуватимуться в історію веб-перегляду, а також не залишать на комп'ютері інших слідів (на зразок файлів cookie), коли ви закриєте всі вікна, відкриті в гостьовому режимі. Однак завантажені файли зберігатимуться.</translation>
 <translation id="3920504717067627103">Політика сертифікатів</translation>
 <translation id="392089482157167418">Увімкнути ChromeVox (голосові підказки)</translation>
 <translation id="3920909973552939961">Заборонено встановлювати обробники платежів</translation>
@@ -2975,7 +2975,7 @@
 <translation id="4332976768901252016">Налаштуйте батьківський контроль</translation>
 <translation id="4333854382783149454">PKCS #1 SHA-1 із шифруванням RSA</translation>
 <translation id="4336434711095810371">Видалити всі дані</translation>
-<translation id="4340125850502689798">Неправильне ім'я користувача</translation>
+<translation id="4340125850502689798">Недійсне ім'я користувача</translation>
 <translation id="4340515029017875942"><ph name="ORIGIN" /> хоче обмінюватися даними з додатком <ph name="EXTENSION_NAME" /></translation>
 <translation id="4341577178275615435">Щоб увімкнути або вимкнути клавішну навігацію, натисніть F7</translation>
 <translation id="434198521554309404">Швидкий. Безпечний. Простий.</translation>
@@ -3589,7 +3589,7 @@
 <translation id="5057110919553308744">Коли ви натискаєте розширення</translation>
 <translation id="5057403786441168405">Керуйте обліковими записами, у які ви ввійшли. За їх допомогою веб-сайти, додатки й розширення в Chrome і Google Play можуть персоналізувати налаштування, залежно від наданих дозволів. <ph name="LINK_BEGIN" />Докладніше<ph name="LINK_END" /></translation>
 <translation id="5059241099014281248">Обмежити вхід</translation>
-<translation id="5059526285558225588">Виберіть, чим поділитися</translation>
+<translation id="5059526285558225588">Виберіть, що показувати</translation>
 <translation id="5060332552815861872">Можна зберегти 1 принтер.</translation>
 <translation id="5061347216700970798">{NUM_BOOKMARKS,plural, =1{Ця папка містить закладку. Усе одно видалити?}one{Ця папка містить # закладку. Усе одно видалити?}few{Ця папка містить # закладки. Усе одно видалити?}many{Ця папка містить # закладок. Усе одно видалити?}other{Ця папка містить # закладки. Усе одно видалити?}}</translation>
 <translation id="5062930723426326933">Помилка входу. Під’єднайтеся до Інтернету та повторіть спробу.</translation>
@@ -3719,7 +3719,7 @@
 <translation id="5204673965307125349">Виконайте Powerwash на пристрої та повторіть спробу.</translation>
 <translation id="5204967432542742771">Введіть пароль</translation>
 <translation id="5205484256512407285">Ніколи не використовувати мобільний трафік для передавання</translation>
-<translation id="520568280985468584">Мережу додано. Для активації мобільної мережі може знадобитися кілька хвилин.</translation>
+<translation id="520568280985468584">Мобільну мережу додано. Для її активації може знадобитися кілька хвилин.</translation>
 <translation id="5206215183583316675">Видалити сертифікат "<ph name="CERTIFICATE_NAME" />"?</translation>
 <translation id="520621735928254154">Не вдалось імпортувати сертифікат</translation>
 <translation id="5206787458656075734">{COUNT,plural, =1{Зламаний пароль змінено. У вас є ще # зламаний пароль. Chrome радить негайно перевірити його.}one{Зламаний пароль змінено. У вас є ще # зламаний пароль. Chrome радить негайно перевірити їх.}few{Зламаний пароль змінено. У вас є ще # зламані паролі. Chrome радить негайно перевірити їх.}many{Зламаний пароль змінено. У вас є ще # зламаних паролів. Chrome радить негайно перевірити їх.}other{Зламаний пароль змінено. У вас є ще # зламаного пароля. Chrome радить негайно перевірити їх.}}</translation>
@@ -5080,7 +5080,7 @@
 <translation id="6782468519961184511">Адміністратор забороняє використовувати додаткові облікові записи Google</translation>
 <translation id="6785518634832172390">PIN-код має складатися щонайбільше з 12 цифр</translation>
 <translation id="6786747875388722282">Розширення</translation>
-<translation id="6787097042755590313">Інша вкладка</translation>
+<translation id="6787097042755590313">Іншу вкладку</translation>
 <translation id="6787839852456839824">Комбінації клавіш</translation>
 <translation id="6788210894632713004">розширення</translation>
 <translation id="6789592661892473991">Розділити горизонтально</translation>
diff --git a/chrome/app/resources/generated_resources_uz.xtb b/chrome/app/resources/generated_resources_uz.xtb
index f066c81d..2aa9a67e 100644
--- a/chrome/app/resources/generated_resources_uz.xtb
+++ b/chrome/app/resources/generated_resources_uz.xtb
@@ -2400,7 +2400,7 @@
 <translation id="3677911431265050325">Mobil versiya</translation>
 <translation id="3677959414150797585">Ilova, veb sahifa va boshqalardan iborat. Takliflarni yaxshilash maqsadida faqat siz tanlagan statistik axborotlar yuboriladi.</translation>
 <translation id="3678156199662914018">Kengaytma: <ph name="EXTENSION_NAME" /></translation>
-<translation id="3678188444105291936">Bu oynada ko‘riladigan sahifalar brauzer tarixida qolmaydi, barcha ochiq turgan Mehmon oynalarini yopganingizdan keyin ular kompyuterda cookie fayllari singari iz ham qoldirmaydi. Ammo, yuklab olingan fayllar saqlanib qoladi.</translation>
+<translation id="3678188444105291936">Bu oynada ochiladigan sahifalar brauzer tarixida qolmaydi, barcha ochiq turgan Mehmon oynalarini yopganingizdan keyin ular kompyuterda cookie fayllari singari iz ham qoldirmaydi. Ammo, yuklab olingan fayllar saqlanib qoladi.</translation>
 <translation id="3680683624079082902">Matnni nutqqa aylantirish ovozi</translation>
 <translation id="3681311097828166361">Fikr-mulohaza uchun rahmat! Hozir internet bilan aloqa yo‘qligi sababli xabaringiz keyinroq yuboriladi.</translation>
 <translation id="3682824389861648626">Harakat chegarasi</translation>
@@ -2634,7 +2634,7 @@
 <translation id="3916445069167113093">Bunday turdagi fayl kompyuteringizga zarar yetkazishi mumkin. <ph name="FILE_NAME" /> baribir saqlansinmi?</translation>
 <translation id="3918972485393593704">Tafsilotlarni Google’ga yuborish</translation>
 <translation id="3919145445993746351">Kengaytmalardan barcha qurilmalaringizda foydalanish uchun sinxronizatsiyani yoqing</translation>
-<translation id="3919798653937160644">Bu oynada ko‘riladigan sahifalar brauzer tarixida qolmaydi, barcha ochiq turgan Mehmon oynalarini yopganingizdan keyin ular kompyuterda cookie fayli singari iz ham qoldirmaydi. Ammo, yuklab olingan fayllar saqlanib qoladi.</translation>
+<translation id="3919798653937160644">Bu oynada ochiladigan sahifalar brauzer tarixida qolmaydi, barcha ochiq turgan Mehmon oynalarini yopganingizdan keyin ular kompyuterda cookie fayli singari iz ham qoldirmaydi. Ammo, yuklab olingan fayllar saqlanib qoladi.</translation>
 <translation id="3920504717067627103">Sertifikat siyosati</translation>
 <translation id="392089482157167418">ChromeVox (ovozli ta’rif) kengaytmasini yoqish</translation>
 <translation id="3920909973552939961">Toʻlov vositalarini oʻrnatish taqiqlangan</translation>
@@ -4437,7 +4437,7 @@
 <translation id="6043994281159824495">Chiqish</translation>
 <translation id="6044805581023976844">“<ph name="APP_NAME" />” ilovasi <ph name="TAB_NAME" /> saytiga Chrome sahifasi va audioga kirish uchun ruxsat berdi.</translation>
 <translation id="6045114302329202345">Asosiy TrackPoint tugmasi</translation>
-<translation id="6047632800149092791">Sinxronizatsiya ishlamayapti. Profilingizdan chiqing va qaytadan urinib ko‘ring.</translation>
+<translation id="6047632800149092791">Sinxronizatsiya ishlamayapti. Profilingizdan chiqing va qaytadan urining.</translation>
 <translation id="6049004884579590341">To‘liq ekran rejimidan chiqish uchun |<ph name="ACCELERATOR" />| tugmasini bosib turing</translation>
 <translation id="6051354611314852653">Bu qurilmada API ruxsatini berib bo‘lmadi.</translation>
 <translation id="6052976518993719690">SSL sertifikatlash markazi</translation>
@@ -4905,7 +4905,7 @@
 <translation id="6579705087617859690"><ph name="WINDOW_TITLE" /> - Ekran namoyish qilinmoqda</translation>
 <translation id="6580203076670148210">Tekshirish tezligi</translation>
 <translation id="6582080224869403177">Xavfsizlik maqsadlarida <ph name="DEVICE_TYPE" /> qurilmangizni ilk sozlamalarga qaytaring.</translation>
-<translation id="6582274660680936615">Siz mehmon rejimida kirdingiz</translation>
+<translation id="6582274660680936615">Siz Mehmon rejimidasiz</translation>
 <translation id="6584878029876017575">Microsoft doimiy imzolash vositasi</translation>
 <translation id="6586099239452884121">Mehmon rejimi</translation>
 <translation id="6586451623538375658">Sichqoncha tugmalarining o‘rnini almashtirish</translation>
@@ -5086,7 +5086,7 @@
 <translation id="6793723358811598107">“<ph name="CURRENTKEY" />” tugmasi allaqachon “<ph name="ACTION" />” amaliga biriktirilgan. Chiqish uchun istalgan tugmani bosing.</translation>
 <translation id="6795884519221689054">Panda</translation>
 <translation id="6797493596609571643">Xatolik sodir bo‘ldi.</translation>
-<translation id="6798420440063423019">PIN kod koʻp marta xato kiritilganligi uchun elektron kalit qulflandi. Elektron kalit sozlamalarini qayta tiklang.</translation>
+<translation id="6798420440063423019">PIN kod juda koʻp marta xato kiritilganligi uchun elektron kalit qulflandi. Elektron kalit sozlamalarini asliga qaytaring.</translation>
 <translation id="6798578729981748444">Importni yakunlash uchun barcha Firefox oynalarini yoping.</translation>
 <translation id="6798780071646309401">caps lock yoniq</translation>
 <translation id="6798954102094737107">Plagin: <ph name="PLUGIN_NAME" /></translation>
@@ -6987,7 +6987,7 @@
 <translation id="8931475688782629595">Sinxronlanadigan maʼlumotlarni boshqarish</translation>
 <translation id="8932654652795262306">Modem rejimi axboroti</translation>
 <translation id="8932894639908691771">Switch Access parametrlari</translation>
-<translation id="893298445929867520">Savatlar yashirildi. Oʻzgarishlar kiritsangiz, ular yana chiqadi.</translation>
+<translation id="893298445929867520">Savatlar berkitildi. Oʻzgarishlar kiritsangiz, ular yana chiqadi.</translation>
 <translation id="8933960630081805351">Finder’da ko‘rsatish</translation>
 <translation id="8934732568177537184">Davom etish</translation>
 <translation id="8938306522009698937">ishlov berish vositalari</translation>
diff --git a/chrome/app/resources/generated_resources_zh-CN.xtb b/chrome/app/resources/generated_resources_zh-CN.xtb
index a7f6591..61835d7 100644
--- a/chrome/app/resources/generated_resources_zh-CN.xtb
+++ b/chrome/app/resources/generated_resources_zh-CN.xtb
@@ -572,6 +572,7 @@
 <translation id="1627408615528139100">已下载</translation>
 <translation id="1628948239858170093">打开前,先扫描文件?</translation>
 <translation id="1629314197035607094">密码已过期</translation>
+<translation id="1629521517399325891">用户证书不适用于网络身份验证。</translation>
 <translation id="163072119192489970">允许完成数据收发操作</translation>
 <translation id="1630768113285622200">重启并继续</translation>
 <translation id="1632082166874334883">您的 Google 帐号中存储的密码</translation>
@@ -1176,6 +1177,7 @@
 <translation id="2300383962156589922">自定义和控制<ph name="APP_NAME" /></translation>
 <translation id="2301382460326681002">扩展程序根目录无效。</translation>
 <translation id="23030561267973084">“<ph name="EXTENSION_NAME" />”请求获得更多权限。</translation>
+<translation id="230529452743010958">这项内容是系统根据您曾在使用 Google 服务时进行的活动向您显示的。您可在 <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /> 上查看/删除您的数据以及更改您的设置。</translation>
 <translation id="23055578400314116">选择用户名</translation>
 <translation id="2307462900900812319">配置网络</translation>
 <translation id="230927227160767054">此页面想要安装一个服务处理程序。</translation>
@@ -1401,6 +1403,7 @@
 <translation id="2541706104884128042">已设定新的就寝时间</translation>
 <translation id="2542050502251273923">使用 ff_debug 设定网络连接管理器和其他服务的调试级别。</translation>
 <translation id="2544292303401268586">您的管理员请求重启您的设备以更新应用。这可能需要几分钟才能完成。</translation>
+<translation id="2544352060595557290">此标签页</translation>
 <translation id="2544853746127077729">身份验证证书遭到网络拒绝</translation>
 <translation id="2546283357679194313">Cookie 和网站数据</translation>
 <translation id="2548347166720081527">已允许使用<ph name="PERMISSION" /></translation>
@@ -1566,6 +1569,7 @@
 <translation id="2734760316755174687"><ph name="SITE_GROUP_NAME" /> 下的网站也会重置。</translation>
 <translation id="2735712963799620190">排定时间</translation>
 <translation id="2737363922397526254">收起...</translation>
+<translation id="2737916598897808047"><ph name="APP_NAME" />想与 <ph name="TARGET_NAME" /> 分享您屏幕上的内容。</translation>
 <translation id="2738771556149464852">不晚于</translation>
 <translation id="2739191690716947896">调试</translation>
 <translation id="2739240477418971307">更改您的无障碍设置</translation>
@@ -2394,6 +2398,7 @@
 <translation id="3677911431265050325">请求切换到移动版网站</translation>
 <translation id="3677959414150797585">包括应用、网页等。仅当您已选择分享使用情况数据时,才会发送统计信息以完善建议。</translation>
 <translation id="3678156199662914018">扩展程序:<ph name="EXTENSION_NAME" /></translation>
+<translation id="3678188444105291936">当您退出访客模式后,您在此窗口中查看过的网页将不会显示在浏览器历史记录中,也不会在计算机上留下其他痕迹(例如 Cookie)。系统不会保留您下载的文件和创建的书签。</translation>
 <translation id="3680683624079082902">文字转语音的语音偏好</translation>
 <translation id="3681311097828166361">感谢您提交反馈。您目前处于离线状态,系统将在您上线后提交您的反馈报告。</translation>
 <translation id="3682824389861648626">鼠标移动阈值</translation>
@@ -2595,6 +2600,7 @@
 <translation id="3884152383786131369">能以多种语言显示的网页内容将会使用此列表中第一项受支持的语言。这些偏好设置会与您的浏览器设置同步。<ph name="BEGIN_LINK_LEARN_MORE" />了解详情<ph name="END_LINK_LEARN_MORE" /></translation>
 <translation id="3886446263141354045">系统已将您想访问此网站的请求发送给<ph name="NAME" /></translation>
 <translation id="3888550877729210209">使用“<ph name="LOCK_SCREEN_APP_NAME" />”创建记事</translation>
+<translation id="3888586133700543064">这些信息有助于我们更好地了解您所遇到的 Google 助理问题。这些信息最多会存储 90 天,且仅限相关的工程团队和反馈团队访问。</translation>
 <translation id="3890064827463908288">您需要开启 Chrome 同步才能使用 Wi-Fi 同步功能</translation>
 <translation id="3892414795099177503">添加 OpenVPN / L2TP…</translation>
 <translation id="3893536212201235195">读取和更改您的无障碍设置</translation>
@@ -2626,6 +2632,7 @@
 <translation id="3916445069167113093">此类型的文件可能会损害您的计算机。您仍然要保留 <ph name="FILE_NAME" /> 吗?</translation>
 <translation id="3918972485393593704">向 Google 报告详细信息</translation>
 <translation id="3919145445993746351">若想在您的所有计算机上使用您的扩展程序,请开启同步功能</translation>
+<translation id="3919798653937160644">当您关闭以访客身份打开的所有窗口后,您在此窗口中查看过的网页将不会显示在浏览器历史记录中,也不会在计算机上留下其他痕迹(例如 Cookie)。不过,系统会保留您下载的所有文件。</translation>
 <translation id="3920504717067627103">证书政策</translation>
 <translation id="392089482157167418">启用 ChromeVox(语音反馈)</translation>
 <translation id="3920909973552939961">不允许安装付款处理程序</translation>
@@ -2960,6 +2967,7 @@
 <translation id="4332976768901252016">设置“家长控制”功能</translation>
 <translation id="4333854382783149454">PKCS #1,带有 RSA 加密的 SHA-1</translation>
 <translation id="4336434711095810371">清除所有数据</translation>
+<translation id="4340125850502689798">用户名无效</translation>
 <translation id="4340515029017875942"><ph name="ORIGIN" /> 希望与“<ph name="EXTENSION_NAME" />”应用通信</translation>
 <translation id="4341577178275615435">如需开启或关闭光标浏览模式,请使用快捷键 F7</translation>
 <translation id="434198521554309404">快速、安全、易用。</translation>
@@ -3573,6 +3581,7 @@
 <translation id="5057110919553308744">当您点击此扩展程序时</translation>
 <translation id="5057403786441168405">管理您登录过的帐号。Chrome 和 Google Play 中的网站、应用和扩展程序可能会使用这些帐号为您定制专属体验,具体取决于所获权限。<ph name="LINK_BEGIN" />了解详情<ph name="LINK_END" /></translation>
 <translation id="5059241099014281248">限制登录</translation>
+<translation id="5059526285558225588">选择要分享什么</translation>
 <translation id="5060332552815861872">有 1 台可保存的打印机。</translation>
 <translation id="5061347216700970798">{NUM_BOOKMARKS,plural, =1{此文件夹包含 1 个书签。确定要删除此文件夹吗?}other{此文件夹包含 # 个书签。确定要删除此文件夹吗?}}</translation>
 <translation id="5062930723426326933">登录失败,请连接到互联网,然后重试。</translation>
@@ -3689,6 +3698,7 @@
 <translation id="5187826826541650604"><ph name="KEY_NAME" /> (<ph name="DEVICE" />)</translation>
 <translation id="5190187232518914472">重现您的美好回忆。如需添加或编辑影集,请转至 <ph name="LINK_BEGIN" />Google 相册<ph name="LINK_END" />。</translation>
 <translation id="5190926251776387065">启用此端口</translation>
+<translation id="5191094172448199359">您输入的 PIN 码不一致</translation>
 <translation id="5191251636205085390">了解和掌控旨在取代第三方 Cookie 的新技术</translation>
 <translation id="51918995459521422"><ph name="ORIGIN" /> 想下载多个文件</translation>
 <translation id="5192062846343383368">打开 Family Link 应用,查看您的监管设置</translation>
@@ -3701,6 +3711,7 @@
 <translation id="5204673965307125349">请对此设备执行 Powerwash,然后重试。</translation>
 <translation id="5204967432542742771">输入密码</translation>
 <translation id="5205484256512407285">一律不使用移动数据进行传输</translation>
+<translation id="520568280985468584">已成功添加网络。不过,您的移动网络可能要过几分钟才可用。</translation>
 <translation id="5206215183583316675">要删除“<ph name="CERTIFICATE_NAME" />”吗?</translation>
 <translation id="520621735928254154">导入证书时出现错误</translation>
 <translation id="5206787458656075734">{COUNT,plural, =1{已成功更改这个已泄露的密码。您还有 # 个已泄露的密码。Chrome 建议您立即检查这个密码。}other{已成功更改这个已泄露的密码。您还有 # 个已泄露的密码。Chrome 建议您立即检查这些密码。}}</translation>
@@ -4335,6 +4346,7 @@
 <translation id="5935656526031444304">管理安全浏览设置</translation>
 <translation id="5938002010494270685">可进行安全性升级</translation>
 <translation id="5939518447894949180">重置</translation>
+<translation id="5939719276406088041">无法创建快捷方式</translation>
 <translation id="5941153596444580863">添加用户…</translation>
 <translation id="5941343993301164315">请登录 <ph name="TOKEN_NAME" />。</translation>
 <translation id="5941711191222866238">最小化</translation>
@@ -4422,6 +4434,7 @@
 <translation id="6043994281159824495">立即退出</translation>
 <translation id="6044805581023976844"><ph name="APP_NAME" /> 正在与 <ph name="TAB_NAME" /> 共享 Chrome 标签页和音频。</translation>
 <translation id="6045114302329202345">TrackPoint 主按钮</translation>
+<translation id="6047632800149092791">同步功能无法正常运行。请尝试退出帐号并重新登录。</translation>
 <translation id="6049004884579590341">按住 |<ph name="ACCELERATOR" />| 即可退出全屏模式</translation>
 <translation id="6051354611314852653">糟糕!系统无法将 API 访问权限授予此设备。</translation>
 <translation id="6052976518993719690">SSL 证书授权中心</translation>
@@ -4514,6 +4527,7 @@
 <translation id="6143186082490678276">获取帮助</translation>
 <translation id="6143366292569327983">选择要翻译的网页语言</translation>
 <translation id="6144938890088808325">帮助我们改进 Chromebook</translation>
+<translation id="6146409560350811147">同步功能无法正常运行。请尝试重新登录。</translation>
 <translation id="6147020289383635445">打印预览失败。</translation>
 <translation id="6148576794665275391">立即打开</translation>
 <translation id="6149015141270619212">无法连接到互联网</translation>
@@ -4581,6 +4595,7 @@
 <translation id="6232017090690406397">电池</translation>
 <translation id="6232116551750539448">与“<ph name="NAME" />”的连接已中断</translation>
 <translation id="6233154960150021497">默认为使用语音(而非键盘)</translation>
+<translation id="6234108445915742946">Chrome 的《服务条款》将于 3 月 31 日变更</translation>
 <translation id="6234474535228214774">正等待安装</translation>
 <translation id="6237474966939441970">触控笔记事应用</translation>
 <translation id="6237816943013845465">可让您调整屏幕分辨率</translation>
@@ -4879,6 +4894,7 @@
 <translation id="656293578423618167">该文件的路径或名称过长。请以较短的名称保存或保存到其他位置。</translation>
 <translation id="6563469144985748109">您的管理员尚未批准此网站</translation>
 <translation id="6569934958368283244">其他人</translation>
+<translation id="6573497332121198392">无法移除快捷方式</translation>
 <translation id="657402800789773160">重新加载此页(&amp;R)</translation>
 <translation id="6577284282025554716">已取消下载“<ph name="FILE_NAME" />”</translation>
 <translation id="657866106756413002">网络状况概要</translation>
@@ -4886,6 +4902,7 @@
 <translation id="6579705087617859690"><ph name="WINDOW_TITLE" /> - 已分享桌面内容</translation>
 <translation id="6580203076670148210">扫描速度</translation>
 <translation id="6582080224869403177">请重置您的 <ph name="DEVICE_TYPE" />,以进行安全性升级。</translation>
+<translation id="6582274660680936615">您正在以访客身份浏览</translation>
 <translation id="6584878029876017575">Microsoft 生存时间签名</translation>
 <translation id="6586099239452884121">访客浏览</translation>
 <translation id="6586451623538375658">切换鼠标主按钮</translation>
@@ -5055,6 +5072,7 @@
 <translation id="6782468519961184511">您的管理员不允许添加其他 Google 帐号</translation>
 <translation id="6785518634832172390">PIN 码不得超过 12 位数</translation>
 <translation id="6786747875388722282">扩展程序</translation>
+<translation id="6787097042755590313">另一标签页</translation>
 <translation id="6787839852456839824">键盘快捷键</translation>
 <translation id="6788210894632713004">未封装的扩展程序</translation>
 <translation id="6789592661892473991">水平分割</translation>
@@ -5065,6 +5083,7 @@
 <translation id="6793723358811598107">“<ph name="CURRENTKEY" />”键已分配给“<ph name="ACTION" />”操作。按任意键即可退出。</translation>
 <translation id="6795884519221689054">熊猫</translation>
 <translation id="6797493596609571643">糟糕,出问题了。</translation>
+<translation id="6798420440063423019">此安全密钥已被锁定,因为您输错 PIN 码的次数过多。您需要重置此安全密钥。</translation>
 <translation id="6798578729981748444">要想顺利完成导入,请关闭所有 Firefox 窗口。</translation>
 <translation id="6798780071646309401">已开启大写锁定模式</translation>
 <translation id="6798954102094737107">插件:<ph name="PLUGIN_NAME" /></translation>
@@ -5410,6 +5429,7 @@
 <translation id="7180865173735832675">自定义</translation>
 <translation id="7182791023900310535">移动您的密码</translation>
 <translation id="7186088072322679094">固定在工具栏中</translation>
+<translation id="7186303001964993981"><ph name="ORIGIN" /> 无法打开此文件夹,因为其中含有系统文件</translation>
 <translation id="7187428571767585875">要移除或要更改的注册表项:</translation>
 <translation id="7187855807420906517">在您退出或离线后,网站通常会保持同步以完成各项任务(例如上传照片或发送聊天消息)</translation>
 <translation id="7189234443051076392">确保您的设备上有足够的空间</translation>
@@ -6029,6 +6049,7 @@
 <translation id="7871109039747854576">用 <ph name="COMMA" /> 键和 <ph name="PERIOD" /> 键在候选字词列表中翻页</translation>
 <translation id="787268756490971083">已关闭</translation>
 <translation id="7874257161694977650">Chrome 背景</translation>
+<translation id="7876027585589532670">无法修改快捷方式</translation>
 <translation id="7877451762676714207">未知服务器错误。请重试或与服务器管理员联系。</translation>
 <translation id="7879631849810108578">已成功设置快捷键:<ph name="IDS_SHORT_SET_COMMAND" /></translation>
 <translation id="7880823633812189969">系统会在您重启设备时删除本地数据</translation>
@@ -6314,6 +6335,7 @@
 <translation id="8189750580333936930">隐私沙盒</translation>
 <translation id="8190193592390505034">正在连接到<ph name="PROVIDER_NAME" /></translation>
 <translation id="8191230140820435481">管理您的应用、扩展程序和主题背景</translation>
+<translation id="8192944472786724289"><ph name="APP_NAME" />想分享您屏幕上的内容。</translation>
 <translation id="8195027750202970175">占用的存储空间</translation>
 <translation id="8198323535106903877">我们将为您安装这 <ph name="NUMBER_OF_APPS" /> 款应用</translation>
 <translation id="8199300056570174101">网络(服务)和设备属性</translation>
@@ -6963,6 +6985,7 @@
 <translation id="8931475688782629595">管理您的同步数据</translation>
 <translation id="8932654652795262306">“即时网络共享”的网络详细信息</translation>
 <translation id="8932894639908691771">开关控制选项</translation>
+<translation id="893298445929867520">购物车已隐藏。当您做出更改时,它们会再次现身。</translation>
 <translation id="8933960630081805351">在 Finder 中显示(&amp;S)</translation>
 <translation id="8934732568177537184">继续</translation>
 <translation id="8938306522009698937">处理程序</translation>
@@ -7239,6 +7262,7 @@
 <translation id="942532530371314860"><ph name="APP_NAME" /> 正在共享 Chrome 标签页和音频。</translation>
 <translation id="945522503751344254">发送反馈</translation>
 <translation id="947329552760389097">检查元素(&amp;I)</translation>
+<translation id="947667444780368238"><ph name="ORIGIN" /> 无法打开此文件夹内的文件,因为此文件夹含有系统文件</translation>
 <translation id="951991426597076286">拒绝</translation>
 <translation id="956500788634395331">系统会保护您免受可能有害的扩展程序的威胁</translation>
 <translation id="957960681186851048">此网站试图自动下载多个文件</translation>
diff --git a/chrome/app/resources/generated_resources_zh-HK.xtb b/chrome/app/resources/generated_resources_zh-HK.xtb
index 2ee696a..89c1bc02 100644
--- a/chrome/app/resources/generated_resources_zh-HK.xtb
+++ b/chrome/app/resources/generated_resources_zh-HK.xtb
@@ -5087,7 +5087,7 @@
 <translation id="6793723358811598107">「<ph name="CURRENTKEY" />」鍵已指派給「<ph name="ACTION" />」動作。請按任何按鍵以離開。</translation>
 <translation id="6795884519221689054">熊貓</translation>
 <translation id="6797493596609571643">糟糕,發生錯誤。</translation>
-<translation id="6798420440063423019">由於您輸入太多次錯誤的 PIN,因此安全密鑰已被鎖定。您需要重設安全密鑰。</translation>
+<translation id="6798420440063423019">您輸入錯誤 PIN 的次數過多,因此安全密鑰已被鎖定。您需要重設安全密鑰。</translation>
 <translation id="6798578729981748444">如要完成匯入,請關閉所有 Firefox 視窗。</translation>
 <translation id="6798780071646309401">大寫鎖定已開啟</translation>
 <translation id="6798954102094737107">外掛程式:<ph name="PLUGIN_NAME" /></translation>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index b20e05ec..3aed1f08 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1666,8 +1666,6 @@
     "speech/chrome_speech_recognition_manager_delegate.h",
     "speech/network_speech_recognizer.cc",
     "speech/network_speech_recognizer.h",
-    "speech/on_device_speech_recognizer.cc",
-    "speech/on_device_speech_recognizer.h",
     "speech/speech_recognizer.cc",
     "speech/speech_recognizer.h",
     "speech/speech_recognizer_delegate.cc",
@@ -2375,6 +2373,7 @@
       "//chrome/browser/ui/webui/chromeos/add_supervision:mojo_bindings",
       "//chrome/browser/ui/webui/chromeos/crostini_installer:mojo_bindings",
       "//chrome/browser/ui/webui/chromeos/crostini_upgrader:mojo_bindings",
+      "//chrome/browser/ui/webui/chromeos/emoji:mojo_bindings",
       "//chrome/browser/ui/webui/chromeos/machine_learning:mojo_bindings",
       "//chrome/browser/ui/webui/settings/chromeos/constants:mojom",
       "//chrome/browser/ui/webui/settings/chromeos/search:mojo_bindings",
@@ -3994,6 +3993,8 @@
                                                               # to extensions
                                                               # section ?
       "speech/extension_api/tts_extension_api_constants.h",
+      "speech/on_device_speech_recognizer.cc",
+      "speech/on_device_speech_recognizer.h",
       "speech/speech_recognition_client_browser_interface.cc",
       "speech/speech_recognition_client_browser_interface.h",
       "speech/speech_recognition_client_browser_interface_factory.cc",
diff --git a/chrome/browser/accessibility/caption_controller.cc b/chrome/browser/accessibility/caption_controller.cc
index 467a0db..d5464af 100644
--- a/chrome/browser/accessibility/caption_controller.cc
+++ b/chrome/browser/accessibility/caption_controller.cc
@@ -67,6 +67,9 @@
 }
 
 void CaptionController::Init() {
+  base::UmaHistogramBoolean("Accessibility.LiveCaption.FeatureEnabled",
+                            base::FeatureList::IsEnabled(media::kLiveCaption));
+
   // Hidden behind a feature flag.
   if (!base::FeatureList::IsEnabled(media::kLiveCaption))
     return;
@@ -78,8 +81,6 @@
     return;
 #endif
 
-  base::UmaHistogramBoolean("Accessibility.LiveCaption.FeatureEnabled",
-                            base::FeatureList::IsEnabled(media::kLiveCaption));
   base::UmaHistogramBoolean(
       "Accessibility.LiveCaption.UseSodaForLiveCaption",
       base::FeatureList::IsEnabled(media::kUseSodaForLiveCaption));
diff --git a/chrome/browser/apps/app_service/app_service_metrics.cc b/chrome/browser/apps/app_service/app_service_metrics.cc
index 4daf306..5fee331 100644
--- a/chrome/browser/apps/app_service/app_service_metrics.cc
+++ b/chrome/browser/apps/app_service/app_service_metrics.cc
@@ -150,6 +150,10 @@
       base::UmaHistogramEnumeration("Apps.DefaultAppLaunch.FromFullRestore",
                                     default_app_name);
       break;
+    case apps::mojom::LaunchSource::kFromSmartTextContextMenu:
+      base::UmaHistogramEnumeration(
+          "Apps.DefaultAppLaunch.FromSmartTextContextMenu", default_app_name);
+      break;
   }
 }
 
@@ -184,6 +188,7 @@
     case apps::mojom::LaunchSource::kFromSharesheet:
     case apps::mojom::LaunchSource::kFromReleaseNotesNotification:
     case apps::mojom::LaunchSource::kFromFullRestore:
+    case apps::mojom::LaunchSource::kFromSmartTextContextMenu:
       break;
   }
 }
diff --git a/chrome/browser/apps/app_service/arc_apps.cc b/chrome/browser/apps/app_service/arc_apps.cc
index 7e4f455b3..5b17afb 100644
--- a/chrome/browser/apps/app_service/arc_apps.cc
+++ b/chrome/browser/apps/app_service/arc_apps.cc
@@ -216,6 +216,10 @@
       user_interaction_type =
           arc::UserInteractionType::APP_STARTED_FROM_FULL_RESTORE;
       break;
+    case apps::mojom::LaunchSource::kFromSmartTextContextMenu:
+      user_interaction_type = arc::UserInteractionType::
+          APP_STARTED_FROM_SMART_TEXT_SELECTION_CONTEXT_MENU;
+      break;
     default:
       NOTREACHED();
       return base::nullopt;
@@ -1010,16 +1014,17 @@
   }
 }
 
-void ArcApps::OnTaskCreated(int task_id,
+void ArcApps::OnTaskCreated(int32_t task_id,
                             const std::string& package_name,
                             const std::string& activity,
-                            const std::string& intent) {
+                            const std::string& intent,
+                            int32_t session_id) {
   const std::string app_id = ArcAppListPrefs::GetAppId(package_name, activity);
   app_id_to_task_ids_[app_id].insert(task_id);
   task_id_to_app_id_[task_id] = app_id;
 }
 
-void ArcApps::OnTaskDestroyed(int task_id) {
+void ArcApps::OnTaskDestroyed(int32_t task_id) {
   auto it = task_id_to_app_id_.find(task_id);
   if (it == task_id_to_app_id_.end()) {
     return;
diff --git a/chrome/browser/apps/app_service/arc_apps.h b/chrome/browser/apps/app_service/arc_apps.h
index 23545016..2545b09 100644
--- a/chrome/browser/apps/app_service/arc_apps.h
+++ b/chrome/browser/apps/app_service/arc_apps.h
@@ -135,11 +135,12 @@
   void OnPackageModified(
       const arc::mojom::ArcPackageInfo& package_info) override;
   void OnPackageListInitialRefreshed() override;
-  void OnTaskCreated(int task_id,
+  void OnTaskCreated(int32_t task_id,
                      const std::string& package_name,
                      const std::string& activity,
-                     const std::string& intent) override;
-  void OnTaskDestroyed(int task_id) override;
+                     const std::string& intent,
+                     int32_t session_id) override;
+  void OnTaskDestroyed(int32_t task_id) override;
 
   // arc::ArcIntentHelperObserver overrides.
   void OnIntentFiltersUpdated(
diff --git a/chrome/browser/apps/app_service/extension_apps_base.cc b/chrome/browser/apps/app_service/extension_apps_base.cc
index a1055a0f..c963ae9b 100644
--- a/chrome/browser/apps/app_service/extension_apps_base.cc
+++ b/chrome/browser/apps/app_service/extension_apps_base.cc
@@ -116,6 +116,7 @@
     case apps::mojom::LaunchSource::kFromSharesheet:
     case apps::mojom::LaunchSource::kFromReleaseNotesNotification:
     case apps::mojom::LaunchSource::kFromFullRestore:
+    case apps::mojom::LaunchSource::kFromSmartTextContextMenu:
       return ash::LAUNCH_FROM_UNKNOWN;
   }
 }
@@ -437,6 +438,7 @@
     case apps::mojom::LaunchSource::kFromSharesheet:
     case apps::mojom::LaunchSource::kFromReleaseNotesNotification:
     case apps::mojom::LaunchSource::kFromFullRestore:
+    case apps::mojom::LaunchSource::kFromSmartTextContextMenu:
       break;
   }
 
diff --git a/chrome/browser/apps/app_service/intent_util.cc b/chrome/browser/apps/app_service/intent_util.cc
index 0ae55a8a..8c18a18 100644
--- a/chrome/browser/apps/app_service/intent_util.cc
+++ b/chrome/browser/apps/app_service/intent_util.cc
@@ -19,6 +19,7 @@
 constexpr char kIntentExtraText[] = "android.intent.extra.TEXT";
 constexpr char kIntentExtraSubject[] = "android.intent.extra.SUBJECT";
 constexpr char kIntentExtraStartType[] = "org.chromium.arc.start_type";
+constexpr char kIntentActionPrefix[] = "android.intent.action";
 
 const char* GetArcIntentAction(const std::string& action) {
   if (action == apps_util::kIntentActionMain) {
@@ -29,6 +30,9 @@
     return arc::kIntentActionSend;
   } else if (action == apps_util::kIntentActionSendMultiple) {
     return arc::kIntentActionSendMultiple;
+  } else if (action.compare(0, strlen(kIntentActionPrefix),
+                            kIntentActionPrefix) == 0) {
+    return action.c_str();
   } else {
     return arc::kIntentActionView;
   }
@@ -59,6 +63,28 @@
                                     share_title);
 }
 
+apps::mojom::IntentPtr CreateIntentForArcIntentAndActivity(
+    arc::mojom::IntentInfoPtr arc_intent,
+    arc::mojom::ActivityNamePtr activity) {
+  auto intent = apps::mojom::Intent::New();
+  if (arc_intent) {
+    intent->action = std::move(arc_intent->action);
+    intent->data = std::move(arc_intent->data);
+    intent->mime_type = std::move(arc_intent->type);
+    intent->categories = std::move(arc_intent->categories);
+    intent->ui_bypassed = arc_intent->ui_bypassed
+                              ? apps::mojom::OptionalBool::kTrue
+                              : apps::mojom::OptionalBool::kFalse;
+    intent->extras = std::move(arc_intent->extras);
+  }
+
+  if (activity) {
+    intent->activity_name = std::move(activity->activity_name);
+  }
+
+  return intent;
+}
+
 base::flat_map<std::string, std::string> CreateArcIntentExtras(
     const apps::mojom::IntentPtr& intent) {
   auto extras = base::flat_map<std::string, std::string>();
@@ -79,10 +105,11 @@
 arc::mojom::IntentInfoPtr CreateArcIntent(
     const apps::mojom::IntentPtr& intent) {
   arc::mojom::IntentInfoPtr arc_intent;
-  if (!intent->url.has_value() && !intent->share_text.has_value() &&
-      !intent->activity_name.has_value()) {
+  if (!intent->action.has_value() && !intent->url.has_value() &&
+      !intent->share_text.has_value() && !intent->activity_name.has_value()) {
     return arc_intent;
   }
+
   arc_intent = arc::mojom::IntentInfo::New();
   if (intent->action.has_value()) {
     arc_intent->action = GetArcIntentAction(intent->action.value());
@@ -96,6 +123,22 @@
       intent->start_type.has_value()) {
     arc_intent->extras = CreateArcIntentExtras(intent);
   }
+  if (intent->categories.has_value()) {
+    arc_intent->categories = intent->categories;
+  }
+  if (intent->data.has_value()) {
+    arc_intent->data = intent->data;
+  }
+  if (intent->mime_type.has_value()) {
+    arc_intent->type = intent->mime_type;
+  }
+  if (intent->ui_bypassed != apps::mojom::OptionalBool::kUnknown) {
+    arc_intent->ui_bypassed =
+        intent->ui_bypassed == apps::mojom::OptionalBool::kTrue ? true : false;
+  }
+  if (intent->extras.has_value()) {
+    arc_intent->extras = intent->extras;
+  }
   return arc_intent;
 }
 
diff --git a/chrome/browser/apps/app_service/intent_util.h b/chrome/browser/apps/app_service/intent_util.h
index 58f3993..7f13208 100644
--- a/chrome/browser/apps/app_service/intent_util.h
+++ b/chrome/browser/apps/app_service/intent_util.h
@@ -7,6 +7,7 @@
 
 #include <vector>
 
+#include "components/arc/mojom/intent_common.mojom.h"
 #include "components/arc/mojom/intent_helper.mojom-forward.h"
 #include "components/services/app_service/public/mojom/types.mojom.h"
 
@@ -24,7 +25,7 @@
 // Create an intent struct from the file paths and mime types
 // of a list of files.
 // This util has to live under chrome/ because it uses fileapis
-// and cannot be inlucded in components/.
+// and cannot be included in components/.
 apps::mojom::IntentPtr CreateShareIntentFromFiles(
     Profile* profile,
     const std::vector<base::FilePath>& file_paths,
@@ -33,7 +34,7 @@
 // Create an intent struct from the file paths, mime types
 // of a list of files, and the share text and title.
 // This util has to live under chrome/ because it uses fileapis
-// and cannot be inlucded in components/.
+// and cannot be included in components/.
 apps::mojom::IntentPtr CreateShareIntentFromFiles(
     Profile* profile,
     const std::vector<base::FilePath>& file_paths,
@@ -41,6 +42,11 @@
     const std::string& share_text,
     const std::string& share_title);
 
+// Create an intent struct from the arc intent and arc activity.
+apps::mojom::IntentPtr CreateIntentForArcIntentAndActivity(
+    arc::mojom::IntentInfoPtr arc_intent,
+    arc::mojom::ActivityNamePtr activity);
+
 // Convert between App Service and ARC IntentFilters.
 arc::IntentFilter CreateArcIntentFilter(
     const std::string& package_name,
diff --git a/chrome/browser/apps/app_service/intent_util_unittest.cc b/chrome/browser/apps/app_service/intent_util_unittest.cc
new file mode 100644
index 0000000..dbb2167
--- /dev/null
+++ b/chrome/browser/apps/app_service/intent_util_unittest.cc
@@ -0,0 +1,129 @@
+// Copyright 2021 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 <string>
+#include <utility>
+#include <vector>
+
+#include "base/containers/flat_map.h"
+#include "chrome/browser/apps/app_service/intent_util.h"
+#include "components/arc/intent_helper/intent_constants.h"
+#include "components/arc/mojom/intent_helper.mojom.h"
+#include "components/services/app_service/public/cpp/intent_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class IntentUtilsTest : public testing::Test {
+ protected:
+  arc::mojom::IntentInfoPtr CreateArcIntent() {
+    arc::mojom::IntentInfoPtr arc_intent = arc::mojom::IntentInfo::New();
+    arc_intent->action = "android.intent.action.PROCESS_TEXT";
+    std::vector<std::string> categories = {"text"};
+    arc_intent->categories = categories;
+    arc_intent->data = "/tmp";
+    arc_intent->type = "text/plain";
+    arc_intent->ui_bypassed = false;
+    base::flat_map<std::string, std::string> extras = {
+        {"android.intent.action.PROCESS_TEXT", "arc_apps"}};
+    arc_intent->extras = extras;
+    return arc_intent;
+  }
+
+  arc::mojom::ActivityNamePtr CreateActivity() {
+    arc::mojom::ActivityNamePtr arc_activity = arc::mojom::ActivityName::New();
+    arc_activity->package_name = "com.google.android.apps.translate";
+    arc_activity->activity_name =
+        "com.google.android.apps.translate.TranslateActivity";
+    return arc_activity;
+  }
+
+  bool IsEqual(arc::mojom::IntentInfoPtr src_intent,
+               arc::mojom::IntentInfoPtr dst_intent) {
+    if (!src_intent && !dst_intent) {
+      return true;
+    }
+
+    if (!src_intent || !dst_intent) {
+      return false;
+    }
+
+    if (src_intent->action != dst_intent->action) {
+      return false;
+    }
+
+    if (src_intent->categories != dst_intent->categories) {
+      return false;
+    }
+
+    if (src_intent->data != dst_intent->data) {
+      return false;
+    }
+
+    if (src_intent->ui_bypassed != dst_intent->ui_bypassed) {
+      return false;
+    }
+
+    if (src_intent->extras != dst_intent->extras) {
+      return false;
+    }
+
+    return true;
+  }
+
+  bool IsEqual(arc::mojom::ActivityNamePtr src_activity,
+               arc::mojom::ActivityNamePtr dst_activity) {
+    if (!src_activity && !dst_activity) {
+      return true;
+    }
+
+    if (!src_activity || !dst_activity) {
+      return false;
+    }
+
+    if (src_activity->activity_name != dst_activity->activity_name) {
+      return false;
+    }
+
+    return true;
+  }
+};
+
+TEST_F(IntentUtilsTest, CreateIntentForArcIntentAndActivity) {
+  arc::mojom::IntentInfoPtr arc_intent = CreateArcIntent();
+  arc::mojom::ActivityNamePtr src_activity = CreateActivity();
+  apps::mojom::IntentPtr intent =
+      apps_util::CreateIntentForArcIntentAndActivity(arc_intent.Clone(),
+                                                     src_activity.Clone());
+
+  arc::mojom::ActivityNamePtr dst_activity = arc::mojom::ActivityName::New();
+  if (intent->activity_name.has_value() &&
+      !intent->activity_name.value().empty()) {
+    dst_activity->activity_name = intent->activity_name.value();
+  }
+
+  EXPECT_TRUE(
+      IsEqual(std::move(arc_intent), apps_util::CreateArcIntent(intent)));
+  EXPECT_TRUE(IsEqual(std::move(src_activity), std::move(dst_activity)));
+}
+
+TEST_F(IntentUtilsTest, CreateIntentForActivity) {
+  const std::string& activity_name = "com.android.vending.AssetBrowserActivity";
+  const std::string& start_type = "initialStart";
+  apps::mojom::IntentPtr intent =
+      apps_util::CreateIntentForActivity(activity_name, start_type);
+  arc::mojom::IntentInfoPtr arc_intent = apps_util::CreateArcIntent(intent);
+
+  ASSERT_TRUE(intent);
+  ASSERT_TRUE(arc_intent);
+
+  EXPECT_EQ(arc::kIntentActionMain, arc_intent->action);
+
+  base::flat_map<std::string, std::string> extras;
+  extras.insert(std::make_pair("org.chromium.arc.start_type", start_type));
+  EXPECT_TRUE(arc_intent->extras.has_value());
+  EXPECT_EQ(extras, arc_intent->extras);
+
+  arc_intent->extras = apps_util::CreateArcIntentExtras(intent);
+  EXPECT_TRUE(intent->activity_name.has_value());
+  EXPECT_EQ(activity_name, intent->activity_name.value());
+}
diff --git a/chrome/browser/apps/app_service/launch_utils.cc b/chrome/browser/apps/app_service/launch_utils.cc
index bc08e1b..5f54d99 100644
--- a/chrome/browser/apps/app_service/launch_utils.cc
+++ b/chrome/browser/apps/app_service/launch_utils.cc
@@ -197,6 +197,7 @@
     case apps::mojom::LaunchSource::kFromChromeInternal:
     case apps::mojom::LaunchSource::kFromReleaseNotesNotification:
     case apps::mojom::LaunchSource::kFromFullRestore:
+    case apps::mojom::LaunchSource::kFromSmartTextContextMenu:
       return apps::mojom::AppLaunchSource::kSourceChromeInternal;
     case apps::mojom::LaunchSource::kFromInstalledNotification:
       return apps::mojom::AppLaunchSource::kSourceInstalledNotification;
diff --git a/chrome/browser/apps/app_service/web_apps_base.cc b/chrome/browser/apps/app_service/web_apps_base.cc
index f867d07..f81c0327 100644
--- a/chrome/browser/apps/app_service/web_apps_base.cc
+++ b/chrome/browser/apps/app_service/web_apps_base.cc
@@ -315,6 +315,7 @@
     case apps::mojom::LaunchSource::kFromSharesheet:
     case apps::mojom::LaunchSource::kFromReleaseNotesNotification:
     case apps::mojom::LaunchSource::kFromFullRestore:
+    case apps::mojom::LaunchSource::kFromSmartTextContextMenu:
       break;
   }
 
diff --git a/chrome/browser/apps/platform_apps/api/arc_apps_private/arc_apps_private_apitest.cc b/chrome/browser/apps/platform_apps/api/arc_apps_private/arc_apps_private_apitest.cc
index 9127673..3773bc6 100644
--- a/chrome/browser/apps/platform_apps/api/arc_apps_private/arc_apps_private_apitest.cc
+++ b/chrome/browser/apps/platform_apps/api/arc_apps_private/arc_apps_private_apitest.cc
@@ -87,7 +87,7 @@
   app_instance()->SendRefreshAppList({launchable_app});
   static_cast<arc::mojom::AppHost*>(prefs)->OnTaskCreated(
       0 /* task_id */, "Package_1", "Dummy_activity_1", "App_1",
-      base::nullopt /* intent */);
+      base::nullopt /* intent */, 0 /* session_id */);
 
   // Stopping the service makes the app non-ready.
   arc::ArcServiceManager::Get()->arc_bridge_service()->app()->CloseInstance(
@@ -133,7 +133,7 @@
   app_instance()->SendRefreshAppList({launchable_app});
   static_cast<arc::mojom::AppHost*>(prefs)->OnTaskCreated(
       0 /* task_id */, "Package_1", "Dummy_activity_1", "App_1",
-      base::nullopt /* intent */);
+      base::nullopt /* intent */, 0 /* session_id */);
   // Verify the JS test receives the onInstalled event for the launchable app
   // only, and the app is launched successfully.
   EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
diff --git a/chrome/browser/ash/accessibility/dictation.cc b/chrome/browser/ash/accessibility/dictation.cc
index 56f5fb4..cffe422 100644
--- a/chrome/browser/ash/accessibility/dictation.cc
+++ b/chrome/browser/ash/accessibility/dictation.cc
@@ -9,12 +9,14 @@
 #include "chrome/browser/ash/accessibility/accessibility_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/speech/network_speech_recognizer.h"
+#include "chrome/browser/speech/on_device_speech_recognizer.h"
 #include "chrome/common/pref_names.h"
 #include "components/language/core/browser/pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/storage_partition.h"
 #include "services/audio/public/cpp/sounds/sounds_manager.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "ui/accessibility/accessibility_switches.h"
 #include "ui/base/ime/chromeos/extension_ime_util.h"
 #include "ui/base/ime/chromeos/ime_bridge.h"
 #include "ui/base/ime/chromeos/ime_input_context_handler_interface.h"
@@ -58,7 +60,9 @@
 }  // namespace
 
 Dictation::Dictation(Profile* profile)
-    : composition_(std::make_unique<ui::CompositionText>()), profile_(profile) {
+    : current_state_(SPEECH_RECOGNIZER_OFF),
+      composition_(std::make_unique<ui::CompositionText>()),
+      profile_(profile) {
   if (GetInputContext() && GetInputContext()->GetInputMethod())
     GetInputContext()->GetInputMethod()->AddObserver(this);
 }
@@ -74,13 +78,20 @@
     return false;
   }
 
-  speech_recognizer_ = std::make_unique<NetworkSpeechRecognizer>(
-      weak_ptr_factory_.GetWeakPtr(),
-      content::BrowserContext::GetDefaultStoragePartition(profile_)
-          ->GetURLLoaderFactoryForBrowserProcessIOThread(),
-      profile_->GetPrefs()->GetString(language::prefs::kAcceptLanguages),
-      GetUserLanguage(profile_));
-  speech_recognizer_->Start();
+  if (OnDeviceSpeechRecognizer::IsOnDeviceSpeechRecognizerAvailable() &&
+      switches::IsExperimentalAccessibilityDictationOfflineEnabled()) {
+    // On-device recognition is behind a flag and then only available if
+    // SODA is installed on-device.
+    speech_recognizer_ = std::make_unique<OnDeviceSpeechRecognizer>(
+        weak_ptr_factory_.GetWeakPtr(), profile_);
+  } else {
+    speech_recognizer_ = std::make_unique<NetworkSpeechRecognizer>(
+        weak_ptr_factory_.GetWeakPtr(),
+        content::BrowserContext::GetDefaultStoragePartition(profile_)
+            ->GetURLLoaderFactoryForBrowserProcessIOThread(),
+        profile_->GetPrefs()->GetString(language::prefs::kAcceptLanguages),
+        GetUserLanguage(profile_));
+  }
   return true;
 }
 
@@ -108,12 +119,26 @@
 
 void Dictation::OnSpeechRecognitionStateChanged(
     SpeechRecognizerStatus new_state) {
-  if (new_state == SPEECH_RECOGNIZER_RECOGNIZING)
+  SpeechRecognizerStatus next_state = new_state;
+  if (new_state == SPEECH_RECOGNIZER_RECOGNIZING) {
+    // If we are starting to listen to audio, play a tone for the user.
     audio::SoundsManager::Get()->Play(static_cast<int>(Sound::kDictationStart));
-  else if (new_state == SPEECH_RECOGNIZER_READY)
-    // This state is only reached when nothing has been said for a fixed time.
-    // In this case, the expected behavior is for dictation to terminate.
+  } else if (new_state == SPEECH_RECOGNIZER_ERROR) {
     DictationOff();
+    next_state = SPEECH_RECOGNIZER_OFF;
+  } else if (new_state == SPEECH_RECOGNIZER_READY) {
+    if (current_state_ == SPEECH_RECOGNIZER_OFF && speech_recognizer_) {
+      // The SpeechRecognizer was initialized after being created, and
+      // is ready to start recognizing speech.
+      speech_recognizer_->Start();
+    } else {
+      // This state is only reached when nothing has been said for a fixed time.
+      // In this case, the expected behavior is for dictation to terminate.
+      DictationOff();
+      next_state = SPEECH_RECOGNIZER_OFF;
+    }
+  }
+  current_state_ = next_state;
 }
 
 void Dictation::OnTextInputStateChanged(const ui::TextInputClient* client) {
@@ -128,6 +153,7 @@
 }
 
 void Dictation::DictationOff() {
+  current_state_ = SPEECH_RECOGNIZER_OFF;
   if (!speech_recognizer_)
     return;
 
diff --git a/chrome/browser/ash/accessibility/dictation.h b/chrome/browser/ash/accessibility/dictation.h
index e43e9c9..961899527 100644
--- a/chrome/browser/ash/accessibility/dictation.h
+++ b/chrome/browser/ash/accessibility/dictation.h
@@ -57,6 +57,8 @@
   // Saves current dictation result and stops listening.
   void DictationOff();
 
+  SpeechRecognizerStatus current_state_;
+
   std::unique_ptr<SpeechRecognizer> speech_recognizer_;
   std::unique_ptr<ui::CompositionText> composition_;
 
diff --git a/chrome/browser/ash/accessibility/dictation_browsertest.cc b/chrome/browser/ash/accessibility/dictation_browsertest.cc
index 6258ad44..45da1a73 100644
--- a/chrome/browser/ash/accessibility/dictation_browsertest.cc
+++ b/chrome/browser/ash/accessibility/dictation_browsertest.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/ash/accessibility/accessibility_manager.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "content/public/test/browser_test.h"
+#include "content/public/test/fake_speech_recognition_manager.h"
 #include "ui/base/ime/chromeos/ime_bridge.h"
 #include "ui/base/ime/chromeos/mock_ime_input_context_handler.h"
 #include "ui/base/ime/dummy_text_input_client.h"
@@ -32,6 +33,24 @@
             .composition_text;
   }
   ~DictationTest() override = default;
+  DictationTest(const DictationTest&) = delete;
+  DictationTest& operator=(const DictationTest&) = delete;
+
+  void SetUp() override {
+    // Use a fake speech recognition manager so that we don't end up with an
+    // error finding the audio input device when running on a headless
+    // environment.
+    fake_speech_recognition_manager_.reset(
+        new content::FakeSpeechRecognitionManager());
+    // Don't send a fake response from the fake manager. The fake manager can
+    // only send one final response before shutting off. We will do more
+    // granular testing of multiple not-final and final results by sending
+    // OnSpeechResult callbacks to Dictation directly.
+    fake_speech_recognition_manager_->set_should_send_fake_response(false);
+    content::SpeechRecognitionManager::SetManagerForTesting(
+        fake_speech_recognition_manager_.get());
+    InProcessBrowserTest::SetUp();
+  }
 
   void SetUpOnMainThread() override {
     ui::IMEBridge::Get()->SetInputContextHandler(input_context_handler_.get());
@@ -50,6 +69,23 @@
     GetManager()->dictation_->OnTextInputStateChanged(client);
   }
 
+  void ToggleDictation() {
+    bool is_turning_on =
+        !GetManager()->dictation_ ||
+        GetManager()->dictation_->current_state_ == SPEECH_RECOGNIZER_OFF;
+    GetManager()->ToggleDictation();
+    if (is_turning_on) {
+      // SpeechRecognitionManager is asynchronous: it is turned on from the UI
+      // thread. Wait for it to complete before moving on to ensures that we are
+      // ready to receive speech. In Dictation, a tone is played when
+      // recognition starts, indicating to the user that they can begin
+      // speaking.
+      fake_speech_recognition_manager_->WaitForRecognitionStarted();
+      // Now wait for the callbacks to propagate on the UI thread.
+      base::RunLoop().RunUntilIdle();
+    }
+  }
+
   ui::CompositionText GetLastCompositionText() {
     return input_context_handler_->last_update_composition_arg()
         .composition_text;
@@ -57,12 +93,12 @@
 
   std::unique_ptr<ui::MockIMEInputContextHandler> input_context_handler_;
   ui::CompositionText empty_composition_text_;
+  std::unique_ptr<content::FakeSpeechRecognitionManager>
+      fake_speech_recognition_manager_;
 };
 
 IN_PROC_BROWSER_TEST_F(DictationTest, RecognitionEnds) {
-  AccessibilityManager* manager = GetManager();
-
-  manager->ToggleDictation();
+  ToggleDictation();
   EXPECT_EQ(GetLastCompositionText().text, empty_composition_text_.text);
 
   SendSpeechResult(kFirstSpeechResult, false /* is_final */);
@@ -81,11 +117,10 @@
 
 IN_PROC_BROWSER_TEST_F(DictationTest, RecognitionEndsWithChromeVoxEnabled) {
   AccessibilityManager* manager = GetManager();
-
   EnableChromeVox();
   EXPECT_TRUE(manager->IsSpokenFeedbackEnabled());
 
-  manager->ToggleDictation();
+  ToggleDictation();
   EXPECT_EQ(GetLastCompositionText().text, empty_composition_text_.text);
 
   SendSpeechResult(kFirstSpeechResult, false /* is_final */);
@@ -100,17 +135,22 @@
             input_context_handler_->last_commit_text());
 }
 
-IN_PROC_BROWSER_TEST_F(DictationTest, UserEndsDictation) {
-  AccessibilityManager* manager = GetManager();
+IN_PROC_BROWSER_TEST_F(DictationTest, UserEndsDictationBeforeSpeech) {
+  ToggleDictation();
+  ToggleDictation();
+  EXPECT_EQ(GetLastCompositionText().text, empty_composition_text_.text);
+  EXPECT_EQ(0, input_context_handler_->commit_text_call_count());
+}
 
-  manager->ToggleDictation();
+IN_PROC_BROWSER_TEST_F(DictationTest, UserEndsDictation) {
+  ToggleDictation();
   EXPECT_EQ(GetLastCompositionText().text, empty_composition_text_.text);
 
   SendSpeechResult(kFinalSpeechResult, false /* is_final */);
   EXPECT_EQ(base::ASCIIToUTF16(kFinalSpeechResult),
             GetLastCompositionText().text);
 
-  manager->ToggleDictation();
+  ToggleDictation();
   EXPECT_EQ(1, input_context_handler_->commit_text_call_count());
   EXPECT_EQ(base::ASCIIToUTF16(kFinalSpeechResult),
             input_context_handler_->last_commit_text());
@@ -122,13 +162,13 @@
   EnableChromeVox();
   EXPECT_TRUE(manager->IsSpokenFeedbackEnabled());
 
-  manager->ToggleDictation();
+  ToggleDictation();
   EXPECT_EQ(GetLastCompositionText().text, empty_composition_text_.text);
 
   SendSpeechResult(kFinalSpeechResult, false /* is_final */);
   EXPECT_EQ(GetLastCompositionText().text, empty_composition_text_.text);
 
-  manager->ToggleDictation();
+  ToggleDictation();
   EXPECT_EQ(1, input_context_handler_->commit_text_call_count());
   EXPECT_EQ(base::ASCIIToUTF16(kFinalSpeechResult),
             input_context_handler_->last_commit_text());
@@ -136,20 +176,26 @@
 
 IN_PROC_BROWSER_TEST_F(DictationTest, SwitchInputContext) {
   // Turn on dictation and say something.
-  AccessibilityManager::Get()->ToggleDictation();
+  ToggleDictation();
   SendSpeechResult(kFirstSpeechResult, true /* is_final */);
 
   // Speech goes to the default IMEInputContextHandler.
   EXPECT_EQ(base::ASCIIToUTF16(kFirstSpeechResult),
             input_context_handler_->last_commit_text());
 
-  // Simulate a remote app instantiating a new IMEInputContextHandler, like the
-  // keyboard shortcut viewer app creating a second InputMethodChromeOS.
+  // Simulate a remote app instantiating a new IMEInputContextHandler, like
+  // the keyboard shortcut viewer app creating a second InputMethodChromeOS.
   ui::MockIMEInputContextHandler input_context_handler2;
   ui::IMEBridge::Get()->SetInputContextHandler(&input_context_handler2);
 
+  // Wait for speech to be stopped before continuing, or we might try to
+  // turn it off with ToggleDictation below.
+  fake_speech_recognition_manager_->WaitForRecognitionEnded();
+  // Now wait for the callbacks to propagate on the UI thread.
+  base::RunLoop().RunUntilIdle();
+
   // Turn on dictation and say something else.
-  AccessibilityManager::Get()->ToggleDictation();
+  ToggleDictation();
   SendSpeechResult(kSecondSpeechResult, true /* is_final */);
 
   // Speech goes to the new IMEInputContextHandler.
@@ -161,7 +207,7 @@
 
 IN_PROC_BROWSER_TEST_F(DictationTest, ChangeInputField) {
   // Turn on dictation and start speaking.
-  AccessibilityManager::Get()->ToggleDictation();
+  ToggleDictation();
   SendSpeechResult(kFinalSpeechResult, false /* is_final */);
 
   // Change the input state to a new client.
diff --git a/chrome/browser/ash/app_mode/arc/arc_kiosk_app_launcher.cc b/chrome/browser/ash/app_mode/arc/arc_kiosk_app_launcher.cc
index 08208729..d4f3f18 100644
--- a/chrome/browser/ash/app_mode/arc/arc_kiosk_app_launcher.cc
+++ b/chrome/browser/ash/app_mode/arc/arc_kiosk_app_launcher.cc
@@ -37,7 +37,8 @@
 void ArcKioskAppLauncher::OnTaskCreated(int32_t task_id,
                                         const std::string& package_name,
                                         const std::string& activity,
-                                        const std::string& intent) {
+                                        const std::string& intent,
+                                        int32_t session_id) {
   std::unique_ptr<ArcAppListPrefs::AppInfo> app = prefs_->GetApp(app_id_);
   if (!app || app->package_name != package_name || app->activity != activity)
     return;
diff --git a/chrome/browser/ash/app_mode/arc/arc_kiosk_app_launcher.h b/chrome/browser/ash/app_mode/arc/arc_kiosk_app_launcher.h
index 0938d15d..670a664 100644
--- a/chrome/browser/ash/app_mode/arc/arc_kiosk_app_launcher.h
+++ b/chrome/browser/ash/app_mode/arc/arc_kiosk_app_launcher.h
@@ -42,7 +42,8 @@
   void OnTaskCreated(int32_t task_id,
                      const std::string& package_name,
                      const std::string& activity,
-                     const std::string& intent) override;
+                     const std::string& intent,
+                     int32_t session_id) override;
 
   // aura::EnvObserver overrides.
   void OnWindowInitialized(aura::Window* window) override;
diff --git a/chrome/browser/ash/app_mode/arc/arc_kiosk_app_service.cc b/chrome/browser/ash/app_mode/arc/arc_kiosk_app_service.cc
index faae607..1935ee7a 100644
--- a/chrome/browser/ash/app_mode/arc/arc_kiosk_app_service.cc
+++ b/chrome/browser/ash/app_mode/arc/arc_kiosk_app_service.cc
@@ -79,7 +79,8 @@
 void ArcKioskAppService::OnTaskCreated(int32_t task_id,
                                        const std::string& package_name,
                                        const std::string& activity,
-                                       const std::string& intent) {
+                                       const std::string& intent,
+                                       int32_t session_id) {
   // Store task id of the app to stop it later when needed.
   if (app_info_ && package_name == app_info_->package_name &&
       activity == app_info_->activity) {
diff --git a/chrome/browser/ash/app_mode/arc/arc_kiosk_app_service.h b/chrome/browser/ash/app_mode/arc/arc_kiosk_app_service.h
index 8d02913..37481f7 100644
--- a/chrome/browser/ash/app_mode/arc/arc_kiosk_app_service.h
+++ b/chrome/browser/ash/app_mode/arc/arc_kiosk_app_service.h
@@ -58,7 +58,8 @@
   void OnTaskCreated(int32_t task_id,
                      const std::string& package_name,
                      const std::string& activity,
-                     const std::string& intent) override;
+                     const std::string& intent,
+                     int32_t session_id) override;
   void OnTaskDestroyed(int32_t task_id) override;
   void OnPackageListInitialRefreshed() override;
 
diff --git a/chrome/browser/ash/crosapi/metrics_reporting_ash.cc b/chrome/browser/ash/crosapi/metrics_reporting_ash.cc
index 4356a5d7..d90eadf 100644
--- a/chrome/browser/ash/crosapi/metrics_reporting_ash.cc
+++ b/chrome/browser/ash/crosapi/metrics_reporting_ash.cc
@@ -30,7 +30,7 @@
     // Use primary profile because Lacros does not support multi-signin.
     Profile* profile = ProfileManager::GetPrimaryUserProfile();
     // Chrome OS uses this wrapper around the underlying metrics pref.
-    chromeos::StatsReportingController::Get()->SetEnabled(profile, enabled);
+    ash::StatsReportingController::Get()->SetEnabled(profile, enabled);
   }
 };
 
diff --git a/chrome/browser/ash/login/demo_mode/demo_setup_browsertest.cc b/chrome/browser/ash/login/demo_mode/demo_setup_browsertest.cc
index 89e711f..6646038 100644
--- a/chrome/browser/ash/login/demo_mode/demo_setup_browsertest.cc
+++ b/chrome/browser/ash/login/demo_mode/demo_setup_browsertest.cc
@@ -33,6 +33,7 @@
 #include "chrome/browser/ash/login/test/oobe_screen_waiter.h"
 #include "chrome/browser/ash/login/test/oobe_screens_utils.h"
 #include "chrome/browser/ash/login/test/test_condition_waiter.h"
+#include "chrome/browser/ash/login/test/test_predicate_waiter.h"
 #include "chrome/browser/ash/login/ui/login_display_host.h"
 #include "chrome/browser/ash/login/wizard_controller.h"
 #include "chrome/browser/component_updater/cros_component_installer_chromeos.h"
@@ -179,16 +180,18 @@
     test::ExecuteOobeJS(query);
   }
 
-  // Returns whether a custom item with `custom_item_name` is shown as a first
-  // element on the network list.
-  bool IsCustomNetworkListElementShown(const std::string& custom_item_name) {
+  // Returns whether a custom offline item is shown as a first element on the
+  // network list.
+  static bool IsOfflineNetworkListElementShown() {
+    const char kOfflineNetworkElement[] = "offlineDemoSetupListItemName";
+
     const std::string element_selector = base::StrCat(
         {test::GetOobeElementPath(kNetworkScreen),
          ".getNetworkListItemWithQueryForTest('network-list-item')"});
     const std::string query =
         base::StrCat({"!!", element_selector, " && ", element_selector,
-                      ".item.customItemName == '", custom_item_name, "' && !",
-                      element_selector, ".hidden"});
+                      ".item.customItemName == '", kOfflineNetworkElement,
+                      "' && !", element_selector, ".hidden"});
     return test::OobeJS().GetBool(query);
   }
 
@@ -636,7 +639,7 @@
 
   // Offline Demo Mode is not available when there are no preinstalled demo
   // resources.
-  EXPECT_FALSE(IsCustomNetworkListElementShown("offlineDemoSetupListItemName"));
+  EXPECT_FALSE(IsOfflineNetworkListElementShown());
 }
 
 IN_PROC_BROWSER_TEST_F(DemoSetupArcSupportedTest, OfflineSetupFlowSuccess) {
@@ -908,9 +911,8 @@
   EXPECT_TRUE(StartupUtils::IsDeviceRegistered());
 }
 
-// Test is flaky: crbug.com/1099402
 IN_PROC_BROWSER_TEST_F(DemoSetupArcSupportedTest,
-                       DISABLED_ShowOfflineSetupOptionOnNetworkList) {
+                       ShowOfflineSetupOptionOnNetworkList) {
   TriggerDemoModeOnWelcomeScreen();
 
   SimulateOfflineEnvironment();
@@ -918,7 +920,9 @@
 
   test::WaitForNetworkSelectionScreen();
 
-  EXPECT_TRUE(IsCustomNetworkListElementShown("offlineDemoSetupListItemName"));
+  test::TestPredicateWaiter waiter(
+      base::BindRepeating([]() { return IsOfflineNetworkListElementShown(); }));
+  waiter.Wait();
 }
 
 IN_PROC_BROWSER_TEST_F(DemoSetupArcSupportedTest,
@@ -926,7 +930,7 @@
   test::WaitForWelcomeScreen();
   test::TapWelcomeNext();
   test::WaitForNetworkSelectionScreen();
-  EXPECT_FALSE(IsCustomNetworkListElementShown("offlineDemoSetupListItemName"));
+  EXPECT_FALSE(IsOfflineNetworkListElementShown());
 }
 
 class DemoSetupProgressStepsTest : public DemoSetupArcSupportedTest {
diff --git a/chrome/browser/ash/login/existing_user_controller.h b/chrome/browser/ash/login/existing_user_controller.h
index b81a57bb..046ef7d 100644
--- a/chrome/browser/ash/login/existing_user_controller.h
+++ b/chrome/browser/ash/login/existing_user_controller.h
@@ -29,6 +29,8 @@
 #include "chrome/browser/ash/login/screens/encryption_migration_mode.h"
 #include "chrome/browser/ash/login/session/user_session_manager.h"
 #include "chrome/browser/ash/login/ui/login_display.h"
+// TODO(https://crbug.com/1164001): move CrosSettings to forward declaration
+// when moved to chrome/browser/ash/.
 #include "chrome/browser/ash/settings/cros_settings.h"
 #include "chrome/browser/ash/settings/device_settings_service.h"
 #include "chromeos/login/auth/login_performer.h"
@@ -49,8 +51,6 @@
 }
 
 namespace chromeos {
-
-class CrosSettings;
 class LoginDisplay;
 class OAuth2TokenInitializer;
 
diff --git a/chrome/browser/ash/login/lock/fingerprint_unlock_browsertest.cc b/chrome/browser/ash/login/lock/fingerprint_unlock_browsertest.cc
index a7f544a..b34eec28d 100644
--- a/chrome/browser/ash/login/lock/fingerprint_unlock_browsertest.cc
+++ b/chrome/browser/ash/login/lock/fingerprint_unlock_browsertest.cc
@@ -8,6 +8,7 @@
 #include "base/test/simple_test_clock.h"
 #include "base/test/simple_test_tick_clock.h"
 #include "chrome/browser/ash/login/lock/screen_locker_tester.h"
+#include "chrome/browser/ash/login/quick_unlock/fingerprint_storage.h"
 #include "chrome/browser/ash/login/quick_unlock/quick_unlock_factory.h"
 #include "chrome/browser/ash/login/quick_unlock/quick_unlock_storage.h"
 #include "chrome/browser/ash/login/quick_unlock/quick_unlock_utils.h"
@@ -297,4 +298,47 @@
                                1)));
 }
 
+constexpr char kFingerprintSuccessHistogramName[] =
+    "Fingerprint.Unlock.AuthSuccessful";
+constexpr char kFingerprintAttemptsCountBeforeSuccessHistogramName[] =
+    "Fingerprint.Unlock.AttemptsCountBeforeSuccess";
+
+// Verifies that fingerprint auth success is recorded correctly.
+IN_PROC_BROWSER_TEST_F(FingerprintUnlockTest, FeatureUsageMetrics) {
+  // Show lock screen and wait until it is shown.
+  ScreenLockerTester tester;
+  tester.Lock();
+  base::HistogramTester histogram_tester;
+
+  // Mark strong auth, checks for strong auth.
+  // The default is one day, so verify moving the last strong auth time back 12
+  // hours (half of the expiration time) should not request strong auth.
+  MarkStrongAuth();
+  EXPECT_TRUE(HasStrongAuth());
+  FakeBiodClient::Get()->SendAuthScanDone(kFingerprint,
+                                          biod::SCAN_RESULT_TOO_FAST);
+  FakeBiodClient::Get()->SendAuthScanDone(kFingerprint,
+                                          biod::SCAN_RESULT_SUCCESS);
+  tester.WaitForUnlock();
+  histogram_tester.ExpectBucketCount(kFingerprintSuccessHistogramName,
+                                     /*success=*/1, 1);
+  histogram_tester.ExpectBucketCount(
+      "Fingerprint.Unlock.Result",
+      static_cast<int>(quick_unlock::FingerprintUnlockResult::kSuccess), 1);
+  histogram_tester.ExpectTotalCount(
+      kFingerprintAttemptsCountBeforeSuccessHistogramName, 1);
+  histogram_tester.ExpectBucketCount(
+      "ChromeOS.FeatureUsage.Fingerprint",
+      static_cast<int>(FeatureUsageMetrics::Event::kUsedWithSucess), 1);
+  histogram_tester.ExpectBucketCount(
+      "ChromeOS.FeatureUsage.Fingerprint",
+      static_cast<int>(FeatureUsageMetrics::Event::kUsedWithFailure), 1);
+
+  histogram_tester.ExpectBucketCount(kFingerprintSuccessHistogramName,
+                                     /*success=*/0, 1);
+  histogram_tester.ExpectBucketCount(
+      "Fingerprint.Unlock.Result",
+      static_cast<int>(quick_unlock::FingerprintUnlockResult::kMatchFailed), 1);
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/ash/login/lock/screen_locker.cc b/chrome/browser/ash/login/lock/screen_locker.cc
index 5b36440..7c9bd557 100644
--- a/chrome/browser/ash/login/lock/screen_locker.cc
+++ b/chrome/browser/ash/login/lock/screen_locker.cc
@@ -792,17 +792,15 @@
   if (!quick_unlock_storage ||
       !quick_unlock_storage->IsFingerprintAuthenticationAvailable()) {
     // In theory this should be very rare. The auth session should be ended when
-    // fingerprint becomes unavaliable.
-    LoginScreenClient::Get()->auth_recorder()->RecordFingerprintUnlockResult(
-        LoginAuthRecorder::FingerprintUnlockResult::kFingerprintUnavailable,
-        base::nullopt);
+    // fingerprint becomes unavailable.
+    quick_unlock_storage->fingerprint_storage()->RecordFingerprintUnlockResult(
+        quick_unlock::FingerprintUnlockResult::kFingerprintUnavailable);
     return;
   }
 
   if (IsAuthTemporarilyDisabledForUser(primary_user->GetAccountId())) {
-    LoginScreenClient::Get()->auth_recorder()->RecordFingerprintUnlockResult(
-        LoginAuthRecorder::FingerprintUnlockResult::kAuthTemporarilyDisabled,
-        base::nullopt);
+    quick_unlock_storage->fingerprint_storage()->RecordFingerprintUnlockResult(
+        quick_unlock::FingerprintUnlockResult::kAuthTemporarilyDisabled);
     return;
   }
 
@@ -813,9 +811,8 @@
     LOG(ERROR) << "Fingerprint unlock failed because scan_result="
                << scan_result;
     OnFingerprintAuthFailure(*primary_user);
-    LoginScreenClient::Get()->auth_recorder()->RecordFingerprintUnlockResult(
-        LoginAuthRecorder::FingerprintUnlockResult::kMatchFailed,
-        base::nullopt);
+    quick_unlock_storage->fingerprint_storage()->RecordFingerprintUnlockResult(
+        quick_unlock::FingerprintUnlockResult::kMatchFailed);
     return;
   }
 
@@ -824,14 +821,12 @@
     LOG(ERROR) << "Fingerprint unlock failed because it does not match primary"
                << " user's record";
     OnFingerprintAuthFailure(*primary_user);
-    LoginScreenClient::Get()->auth_recorder()->RecordFingerprintUnlockResult(
-        LoginAuthRecorder::FingerprintUnlockResult::kMatchNotForPrimaryUser,
-        base::nullopt);
+    quick_unlock_storage->fingerprint_storage()->RecordFingerprintUnlockResult(
+        quick_unlock::FingerprintUnlockResult::kMatchNotForPrimaryUser);
     return;
   }
-  LoginScreenClient::Get()->auth_recorder()->RecordFingerprintUnlockResult(
-      LoginAuthRecorder::FingerprintUnlockResult::kSuccess,
-      quick_unlock_storage->fingerprint_storage()->unlock_attempt_count());
+  quick_unlock_storage->fingerprint_storage()->RecordFingerprintUnlockResult(
+      quick_unlock::FingerprintUnlockResult::kSuccess);
   ash::LoginScreen::Get()->GetModel()->NotifyFingerprintAuthResult(
       primary_user->GetAccountId(), true /*success*/);
   VLOG(1) << "Fingerprint unlock is successful.";
diff --git a/chrome/browser/ash/login/login_auth_recorder.cc b/chrome/browser/ash/login/login_auth_recorder.cc
index c75f20d2..07b795110 100644
--- a/chrome/browser/ash/login/login_auth_recorder.cc
+++ b/chrome/browser/ash/login/login_auth_recorder.cc
@@ -173,24 +173,6 @@
   }
 }
 
-void LoginAuthRecorder::RecordFingerprintUnlockResult(
-    FingerprintUnlockResult result,
-    const base::Optional<int>& num_attempts) {
-  if (session_manager::SessionManager::Get()->session_state() !=
-      session_manager::SessionState::LOCKED) {
-    return;
-  }
-  base::UmaHistogramEnumeration("Fingerprint.Unlock.Result", result);
-
-  const bool success = (result == FingerprintUnlockResult::kSuccess);
-  base::UmaHistogramBoolean("Fingerprint.Unlock.AuthSuccessful", success);
-  if (success) {
-    DCHECK(num_attempts);
-    base::UmaHistogramCounts100("Fingerprint.Unlock.AttemptsCountBeforeSuccess",
-                                num_attempts.value());
-  }
-}
-
 void LoginAuthRecorder::OnSessionStateChanged() {
   // Reset local state.
   last_auth_method_ = AuthMethod::kNothing;
diff --git a/chrome/browser/ash/login/login_auth_recorder.h b/chrome/browser/ash/login/login_auth_recorder.h
index 08be511..7d230b6 100644
--- a/chrome/browser/ash/login/login_auth_recorder.h
+++ b/chrome/browser/ash/login/login_auth_recorder.h
@@ -73,11 +73,6 @@
   // Called when user attempts authentication using AuthMethod `type`.
   void RecordAuthMethod(AuthMethod type);
 
-  // Called after a fingerprint unlock attempt to record the result.
-  // `num_attempts`:  Only valid when auth success to record number of attempts.
-  void RecordFingerprintUnlockResult(FingerprintUnlockResult result,
-                                     const base::Optional<int>& num_attempts);
-
   // session_manager::SessionManagerObserver
   void OnSessionStateChanged() override;
 
diff --git a/chrome/browser/ash/login/login_auth_recorder_browsertest.cc b/chrome/browser/ash/login/login_auth_recorder_browsertest.cc
index e9ccfdd1..ce0f3285 100644
--- a/chrome/browser/ash/login/login_auth_recorder_browsertest.cc
+++ b/chrome/browser/ash/login/login_auth_recorder_browsertest.cc
@@ -20,10 +20,6 @@
     "Ash.Login.Lock.AuthMethod.Used.ClamShellMode";
 constexpr char kAuthMethodSwitchHistogramName[] =
     "Ash.Login.Lock.AuthMethod.Switched";
-constexpr char kFingerprintSuccessHistogramName[] =
-    "Fingerprint.Unlock.AuthSuccessful";
-constexpr char kFingerprintAttemptsCountBeforeSuccessHistogramName[] =
-    "Fingerprint.Unlock.AttemptsCountBeforeSuccess";
 
 }  // namespace
 
@@ -52,14 +48,6 @@
     metrics_recorder()->RecordAuthMethod(auth_method);
   }
 
-  void SetFingerprintUnlockResult(
-      LoginAuthRecorder::FingerprintUnlockResult result) {
-    metrics_recorder()->RecordFingerprintUnlockResult(
-        result, result == LoginAuthRecorder::FingerprintUnlockResult::kSuccess
-                    ? base::Optional<int>(1)
-                    : base::nullopt);
-  }
-
   void ExpectBucketCount(const std::string& name,
                          LoginAuthRecorder::AuthMethod method,
                          int count) {
@@ -193,32 +181,4 @@
                     LoginAuthRecorder::AuthMethodSwitchType::kPinToPassword, 1);
 }
 
-// Verifies that fingerprint auth success is recorded correctly.
-IN_PROC_BROWSER_TEST_F(LoginAuthRecorderTest, FingerprintAuthSuccess) {
-  session_manager::SessionManager::Get()->SetSessionState(
-      session_manager::SessionState::LOCKED);
-  SetFingerprintUnlockResult(
-      LoginAuthRecorder::FingerprintUnlockResult::kSuccess);
-  histogram_tester_->ExpectBucketCount(kFingerprintSuccessHistogramName,
-                                       1 /*success*/, 1);
-  histogram_tester_->ExpectBucketCount(
-      "Fingerprint.Unlock.Result",
-      static_cast<int>(LoginAuthRecorder::FingerprintUnlockResult::kSuccess),
-      1);
-  histogram_tester_->ExpectTotalCount(
-      kFingerprintAttemptsCountBeforeSuccessHistogramName, 1);
-
-  SetFingerprintUnlockResult(
-      LoginAuthRecorder::FingerprintUnlockResult::kMatchFailed);
-  histogram_tester_->ExpectBucketCount(kFingerprintSuccessHistogramName,
-                                       0 /*success*/, 1);
-  histogram_tester_->ExpectBucketCount(
-      "Fingerprint.Unlock.Result",
-      static_cast<int>(
-          LoginAuthRecorder::FingerprintUnlockResult::kMatchFailed),
-      1);
-  histogram_tester_->ExpectTotalCount(
-      kFingerprintAttemptsCountBeforeSuccessHistogramName, 1);
-}
-
 }  // namespace chromeos
diff --git a/chrome/browser/ash/login/quick_unlock/fingerprint_storage.cc b/chrome/browser/ash/login/quick_unlock/fingerprint_storage.cc
index df5d5198..54db5ff 100644
--- a/chrome/browser/ash/login/quick_unlock/fingerprint_storage.cc
+++ b/chrome/browser/ash/login/quick_unlock/fingerprint_storage.cc
@@ -7,6 +7,7 @@
 #include "base/metrics/histogram_functions.h"
 #include "chrome/browser/ash/login/quick_unlock/quick_unlock_utils.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
+#include "chrome/browser/chromeos/feature_usage_metrics/feature_usage_metrics.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/dbus/biod/biod_client.h"
@@ -18,6 +19,12 @@
 namespace chromeos {
 namespace quick_unlock {
 
+namespace {
+
+constexpr char kFingerprintUMAFeatureName[] = "Fingerprint";
+
+}
+
 class FingerprintMetricsReporter : public device::mojom::FingerprintObserver {
  public:
   // device::mojom::FingerprintObserver:
@@ -47,6 +54,7 @@
 // static
 void FingerprintStorage::RegisterProfilePrefs(PrefRegistrySimple* registry) {
   registry->RegisterIntegerPref(prefs::kQuickUnlockFingerprintRecord, 0);
+  FeatureUsageMetrics::RegisterPref(registry, kFingerprintUMAFeatureName);
 }
 
 FingerprintStorage::FingerprintStorage(Profile* profile) : profile_(profile) {
@@ -65,10 +73,33 @@
 
   metrics_reporter_ = std::make_unique<FingerprintMetricsReporter>();
   fp_service_->AddFingerprintObserver(metrics_reporter_->GetRemote());
+  feature_usage_metrics_service_ = std::make_unique<FeatureUsageMetrics>(
+      kFingerprintUMAFeatureName, profile_->GetPrefs(), this);
 }
 
 FingerprintStorage::~FingerprintStorage() {}
 
+bool FingerprintStorage::IsEligible() const {
+  return IsFingerprintSupported();
+}
+
+bool FingerprintStorage::IsEnabled() const {
+  return IsFingerprintEnabled(profile_) && HasRecord();
+}
+
+void FingerprintStorage::RecordFingerprintUnlockResult(
+    FingerprintUnlockResult result) {
+  base::UmaHistogramEnumeration("Fingerprint.Unlock.Result", result);
+
+  const bool success = (result == FingerprintUnlockResult::kSuccess);
+  base::UmaHistogramBoolean("Fingerprint.Unlock.AuthSuccessful", success);
+  if (success) {
+    base::UmaHistogramCounts100("Fingerprint.Unlock.AttemptsCountBeforeSuccess",
+                                unlock_attempt_count());
+  }
+  feature_usage_metrics_service_->RecordUsage(success);
+}
+
 bool FingerprintStorage::IsFingerprintAvailable() const {
   return !ExceededUnlockAttempts() && IsFingerprintEnabled(profile_) &&
          HasRecord();
diff --git a/chrome/browser/ash/login/quick_unlock/fingerprint_storage.h b/chrome/browser/ash/login/quick_unlock/fingerprint_storage.h
index e404b06..66de3365 100644
--- a/chrome/browser/ash/login/quick_unlock/fingerprint_storage.h
+++ b/chrome/browser/ash/login/quick_unlock/fingerprint_storage.h
@@ -7,8 +7,8 @@
 
 #include "base/macros.h"
 #include "base/time/time.h"
+#include "chrome/browser/chromeos/feature_usage_metrics/feature_usage_metrics.h"
 #include "mojo/public/cpp/bindings/remote.h"
-
 #include "services/device/public/mojom/fingerprint.mojom.h"
 
 class PrefRegistrySimple;
@@ -23,7 +23,22 @@
 class FingerprintMetricsReporter;
 class QuickUnlockStorage;
 
-class FingerprintStorage {
+// The result of fingerprint auth attempt on the lock screen. These values are
+// persisted to logs. Entries should not be renumbered and numeric values
+// should never be reused.
+enum class FingerprintUnlockResult {
+  kSuccess = 0,
+  kFingerprintUnavailable = 1,
+  kAuthTemporarilyDisabled = 2,
+  kMatchFailed = 3,
+  kMatchNotForPrimaryUser = 4,
+  kMaxValue = kMatchNotForPrimaryUser,
+};
+
+// `FingerprintStorage` manages fingerprint user preferences. Keeps them in sync
+// with the actual fingerprint records state. The class also reports fingerprint
+// metrics.
+class FingerprintStorage : public FeatureUsageMetrics::Delegate {
  public:
   static const int kMaximumUnlockAttempts = 5;
 
@@ -31,7 +46,15 @@
   static void RegisterProfilePrefs(PrefRegistrySimple* registry);
 
   explicit FingerprintStorage(Profile* profile);
-  ~FingerprintStorage();
+  ~FingerprintStorage() final;
+
+  // FeatureUsageMetrics::Delegate:
+  bool IsEligible() const final;
+  bool IsEnabled() const final;
+
+  // Called after a fingerprint unlock attempt to record the result.
+  // `num_attempts`:  Only valid when auth success to record number of attempts.
+  void RecordFingerprintUnlockResult(FingerprintUnlockResult result);
 
   // Returns true if fingerprint unlock is currently available.
   // This does not check if strong auth is available.
@@ -65,6 +88,7 @@
   mojo::Remote<device::mojom::Fingerprint> fp_service_;
 
   std::unique_ptr<FingerprintMetricsReporter> metrics_reporter_;
+  std::unique_ptr<FeatureUsageMetrics> feature_usage_metrics_service_;
 
   base::WeakPtrFactory<FingerprintStorage> weak_factory_{this};
 
diff --git a/chrome/browser/ash/login/quick_unlock/quick_unlock_utils.cc b/chrome/browser/ash/login/quick_unlock/quick_unlock_utils.cc
index 2d6edf3..371e1e6 100644
--- a/chrome/browser/ash/login/quick_unlock/quick_unlock_utils.cc
+++ b/chrome/browser/ash/login/quick_unlock/quick_unlock_utils.cc
@@ -142,13 +142,18 @@
   return default_location;
 }
 
+bool IsFingerprintSupported() {
+  const base::CommandLine* command_line =
+      base::CommandLine::ForCurrentProcess();
+  return base::FeatureList::IsEnabled(::features::kQuickUnlockFingerprint) &&
+         command_line->HasSwitch(switches::kFingerprintSensorLocation);
+}
+
 bool IsFingerprintEnabled(Profile* profile) {
   if (enable_for_testing_)
     return true;
 
-  // Disable fingerprint if the device does not have a fingerprint reader.
-  const base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
-  if (!cl->HasSwitch(switches::kFingerprintSensorLocation))
+  if (!IsFingerprintSupported())
     return false;
 
   // Disable fingerprint if the profile does not belong to the primary user.
@@ -159,8 +164,7 @@
   if (IsFingerprintDisabledByPolicy(profile->GetPrefs()))
     return false;
 
-  // Enable fingerprint unlock only if the switch is present.
-  return base::FeatureList::IsEnabled(::features::kQuickUnlockFingerprint);
+  return true;
 }
 
 void EnabledForTesting(bool state) {
diff --git a/chrome/browser/ash/login/quick_unlock/quick_unlock_utils.h b/chrome/browser/ash/login/quick_unlock/quick_unlock_utils.h
index 5afdaef..3a5d4a8 100644
--- a/chrome/browser/ash/login/quick_unlock/quick_unlock_utils.h
+++ b/chrome/browser/ash/login/quick_unlock/quick_unlock_utils.h
@@ -47,6 +47,9 @@
 // Returns true if the quick unlock feature flag is present.
 bool IsPinEnabled(PrefService* pref_service);
 
+// Returns true if the fingerprint is supported by the device.
+bool IsFingerprintSupported();
+
 // Returns true if the fingerprint is allowed for specified profile.
 bool IsFingerprintEnabled(Profile* profile);
 
diff --git a/chrome/browser/ash/login/users/supervised_user_manager_impl.h b/chrome/browser/ash/login/users/supervised_user_manager_impl.h
index 5f7d7d2..105e2d2 100644
--- a/chrome/browser/ash/login/users/supervised_user_manager_impl.h
+++ b/chrome/browser/ash/login/users/supervised_user_manager_impl.h
@@ -10,11 +10,13 @@
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "chrome/browser/ash/login/users/supervised_user_manager.h"
+// TODO(https://crbug.com/1164001): forward declare CrosSettings when moved to
+// ash.
+#include "chrome/browser/ash/settings/cros_settings.h"
 
 namespace chromeos {
 
 class ChromeUserManagerImpl;
-class CrosSettings;
 class SupervisedUserTestBase;
 
 // TODO(crbug.com/1155729): Check this entire class is not used anymore for
diff --git a/chrome/browser/ash/login/version_info_updater.h b/chrome/browser/ash/login/version_info_updater.h
index 095e0b44..ff24baa 100644
--- a/chrome/browser/ash/login/version_info_updater.h
+++ b/chrome/browser/ash/login/version_info_updater.h
@@ -11,6 +11,8 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+// TODO(https://crbug.com/1164001): move CrosSettings to forward declaration
+// when moved to chrome/browser/ash/.
 #include "chrome/browser/ash/settings/cros_settings.h"
 #include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "components/policy/core/common/cloud/cloud_policy_store.h"
@@ -21,8 +23,6 @@
 
 namespace chromeos {
 
-class CrosSettings;
-
 // Fetches all info we want to show on OOBE/Login screens about system
 // version, boot times and cloud policy.
 class VersionInfoUpdater : public policy::CloudPolicyStore::Observer {
diff --git a/chrome/browser/ash/settings/cros_settings.cc b/chrome/browser/ash/settings/cros_settings.cc
index 35d6388..1ba04b8 100644
--- a/chrome/browser/ash/settings/cros_settings.cc
+++ b/chrome/browser/ash/settings/cros_settings.cc
@@ -20,7 +20,7 @@
 #include "chromeos/settings/system_settings_provider.h"
 #include "google_apis/gaia/gaia_auth_util.h"
 
-namespace chromeos {
+namespace ash {
 
 static CrosSettings* g_cros_settings = nullptr;
 
@@ -342,4 +342,4 @@
   CrosSettings::Shutdown();
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ash/settings/cros_settings.h b/chrome/browser/ash/settings/cros_settings.h
index 98cdba5..4966c44ab 100644
--- a/chrome/browser/ash/settings/cros_settings.h
+++ b/chrome/browser/ash/settings/cros_settings.h
@@ -27,7 +27,7 @@
 class Value;
 }  // namespace base
 
-namespace chromeos {
+namespace ash {
 
 class DeviceSettingsService;
 class SupervisedUserCrosSettingsProvider;
@@ -165,12 +165,12 @@
   DISALLOW_COPY_AND_ASSIGN(ScopedTestCrosSettings);
 };
 
-}  // namespace chromeos
+}  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove after //chrome/browser/chromeos
-// source migration is finished.
-namespace ash {
-using ::chromeos::CrosSettings;
-}
+// TODO(https://crbug.com/1164001): remove when Chrome OS code migration is
+// done.
+namespace chromeos {
+using ::ash::CrosSettings;
+}  // namespace chromeos
 
 #endif  // CHROME_BROWSER_ASH_SETTINGS_CROS_SETTINGS_H_
diff --git a/chrome/browser/ash/settings/cros_settings_unittest.cc b/chrome/browser/ash/settings/cros_settings_unittest.cc
index e5af69e..ea1bbbaa 100644
--- a/chrome/browser/ash/settings/cros_settings_unittest.cc
+++ b/chrome/browser/ash/settings/cros_settings_unittest.cc
@@ -36,7 +36,7 @@
 
 namespace em = enterprise_management;
 
-namespace chromeos {
+namespace ash {
 
 namespace {
 constexpr char kOwner[] = "me@owner";
@@ -143,7 +143,7 @@
       content::BrowserTaskEnvironment::IO_MAINLOOP};
 
   ScopedTestingLocalState local_state_;
-  ScopedStubInstallAttributes scoped_install_attributes_;
+  chromeos::ScopedStubInstallAttributes scoped_install_attributes_;
   ScopedTestDeviceSettingsService scoped_test_device_settings_;
   ScopedTestCrosSettings scoped_test_cros_settings_;
 
@@ -360,8 +360,7 @@
 // not set.
 TEST_F(CrosSettingsTest, AllowFamilyLinkAccountsWithEmptyAllowlist) {
   base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(
-      chromeos::features::kFamilyLinkOnSchoolDevice);
+  scoped_feature_list.InitAndEnableFeature(features::kFamilyLinkOnSchoolDevice);
 
   device_policy_.payload().mutable_allow_new_users()->set_allow_new_users(
       false);
@@ -386,7 +385,7 @@
 TEST_F(CrosSettingsTest, AllowFamilyLinkAccountsWithFeatureDisabled) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndDisableFeature(
-      chromeos::features::kFamilyLinkOnSchoolDevice);
+      features::kFamilyLinkOnSchoolDevice);
 
   device_policy_.payload().mutable_allow_new_users()->set_allow_new_users(
       false);
@@ -411,8 +410,7 @@
 
 TEST_F(CrosSettingsTest, AllowFamilyLinkAccountsWithAllowlist) {
   base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(
-      chromeos::features::kFamilyLinkOnSchoolDevice);
+  scoped_feature_list.InitAndEnableFeature(features::kFamilyLinkOnSchoolDevice);
 
   device_policy_.payload().mutable_allow_new_users()->set_allow_new_users(
       false);
@@ -435,4 +433,4 @@
   EXPECT_FALSE(IsUserAllowed(kUser1, user_manager::USER_TYPE_REGULAR));
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ash/settings/device_settings_cache.cc b/chrome/browser/ash/settings/device_settings_cache.cc
index a5c8d40..8b1acef7 100644
--- a/chrome/browser/ash/settings/device_settings_cache.cc
+++ b/chrome/browser/ash/settings/device_settings_cache.cc
@@ -16,7 +16,7 @@
 
 namespace em = enterprise_management;
 
-namespace chromeos {
+namespace ash {
 
 namespace device_settings_cache {
 
@@ -57,4 +57,4 @@
 
 }  // namespace device_settings_cache
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ash/settings/device_settings_cache.h b/chrome/browser/ash/settings/device_settings_cache.h
index 35cd65bd..53cd6f9 100644
--- a/chrome/browser/ash/settings/device_settings_cache.h
+++ b/chrome/browser/ash/settings/device_settings_cache.h
@@ -14,7 +14,7 @@
 class PrefService;
 class PrefRegistrySimple;
 
-namespace chromeos {
+namespace ash {
 
 // There is need (metrics at OOBE stage) to store settings (that normally would
 // go into DeviceSettings storage) before owner has been assigned (hence no key
@@ -41,6 +41,6 @@
 
 }  // namespace device_settings_cache
 
-}  // namespace chromeos
+}  // namespace ash
 
 #endif  // CHROME_BROWSER_ASH_SETTINGS_DEVICE_SETTINGS_CACHE_H_
diff --git a/chrome/browser/ash/settings/device_settings_cache_unittest.cc b/chrome/browser/ash/settings/device_settings_cache_unittest.cc
index 80cde8e8..8029bd9 100644
--- a/chrome/browser/ash/settings/device_settings_cache_unittest.cc
+++ b/chrome/browser/ash/settings/device_settings_cache_unittest.cc
@@ -12,7 +12,7 @@
 
 namespace em = enterprise_management;
 
-namespace chromeos {
+namespace ash {
 
 class DeviceSettingsCacheTest : public testing::Test {
  protected:
@@ -54,4 +54,4 @@
   EXPECT_FALSE(device_settings_cache::Retrieve(&policy_out, &local_state_));
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ash/settings/device_settings_provider.cc b/chrome/browser/ash/settings/device_settings_provider.cc
index 56dd0dc5..080f2ef2 100644
--- a/chrome/browser/ash/settings/device_settings_provider.cc
+++ b/chrome/browser/ash/settings/device_settings_provider.cc
@@ -48,7 +48,7 @@
 
 namespace em = enterprise_management;
 
-namespace chromeos {
+namespace ash {
 
 namespace {
 
@@ -228,7 +228,7 @@
         policy.user_allowlist().user_allowlist_size() > 0));
   new_values_cache->SetBoolean(
       kAccountsPrefFamilyLinkAccountsAllowed,
-      chromeos::features::IsFamilyLinkOnSchoolDeviceEnabled() &&
+      features::IsFamilyLinkOnSchoolDeviceEnabled() &&
           user_allowlist_enforced &&
           policy.has_family_link_accounts_allowed() &&
           policy.family_link_accounts_allowed()
@@ -248,7 +248,7 @@
           policy.guest_mode_enabled().guest_mode_enabled());
 
   bool supervised_users_enabled = false;
-  if (!InstallAttributes::Get()->IsEnterpriseManaged()) {
+  if (!chromeos::InstallAttributes::Get()->IsEnterpriseManaged()) {
     supervised_users_enabled = true;
   }
   new_values_cache->SetBoolean(kAccountsPrefSupervisedUsersEnabled,
@@ -696,7 +696,8 @@
     // If the policy is missing, default to reporting enabled on enterprise-
     // enrolled devices, c.f. crbug/456186.
     new_values_cache->SetBoolean(
-        kStatsReportingPref, InstallAttributes::Get()->IsEnterpriseManaged());
+        kStatsReportingPref,
+        chromeos::InstallAttributes::Get()->IsEnterpriseManaged());
   }
 
   if (!policy.has_release_channel() ||
@@ -1025,7 +1026,7 @@
   // Default value of the policy in case it's missing.
   bool show_low_disk_space_notification = true;
   // Disable the notification by default for enrolled devices.
-  if (InstallAttributes::Get()->IsEnterpriseManaged())
+  if (chromeos::InstallAttributes::Get()->IsEnterpriseManaged())
     show_low_disk_space_notification = false;
   if (policy.has_device_show_low_disk_space_notification()) {
     const em::DeviceShowLowDiskSpaceNotificationProto& container(
@@ -1330,7 +1331,8 @@
 bool DeviceSettingsProvider::MitigateMissingPolicy() {
   // First check if the device has been owned already and if not exit
   // immediately.
-  if (InstallAttributes::Get()->GetMode() != policy::DEVICE_MODE_CONSUMER)
+  if (chromeos::InstallAttributes::Get()->GetMode() !=
+      policy::DEVICE_MODE_CONSUMER)
     return false;
 
   // If we are here the policy file were corrupted or missing. This can happen
@@ -1444,4 +1446,4 @@
   return settings_loaded;
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ash/settings/device_settings_provider.h b/chrome/browser/ash/settings/device_settings_provider.h
index 9dc1990..3436b2a 100644
--- a/chrome/browser/ash/settings/device_settings_provider.h
+++ b/chrome/browser/ash/settings/device_settings_provider.h
@@ -29,7 +29,7 @@
 class ChromeDeviceSettingsProto;
 }  // namespace enterprise_management
 
-namespace chromeos {
+namespace ash {
 
 // CrosSettingsProvider implementation that works with device settings.
 // Dependency: chromeos::InstallAttributes must be initialized while this class
@@ -152,6 +152,12 @@
   DISALLOW_COPY_AND_ASSIGN(DeviceSettingsProvider);
 };
 
+}  // namespace ash
+
+// TODO(https://crbug.com/1164001): remove when Chrome OS code migration is
+// done.
+namespace chromeos {
+using ::ash::DeviceSettingsProvider;
 }  // namespace chromeos
 
 #endif  // CHROME_BROWSER_ASH_SETTINGS_DEVICE_SETTINGS_PROVIDER_H_
diff --git a/chrome/browser/ash/settings/device_settings_provider_unittest.cc b/chrome/browser/ash/settings/device_settings_provider_unittest.cc
index 666beaf..690b98fe 100644
--- a/chrome/browser/ash/settings/device_settings_provider_unittest.cc
+++ b/chrome/browser/ash/settings/device_settings_provider_unittest.cc
@@ -38,7 +38,7 @@
 
 namespace em = enterprise_management;
 
-namespace chromeos {
+namespace ash {
 
 using ::testing::_;
 using ::testing::AnyNumber;
@@ -1193,7 +1193,7 @@
 TEST_F(DeviceSettingsProviderTest, DeviceFamilyLinkAccountsAllowedDisabled) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndDisableFeature(
-      chromeos::features::kFamilyLinkOnSchoolDevice);
+      features::kFamilyLinkOnSchoolDevice);
 
   base::Value default_value(false);
   VerifyPolicyValue(kAccountsPrefFamilyLinkAccountsAllowed, &default_value);
@@ -1208,8 +1208,7 @@
 // Tests DeviceFamilyLinkAccountsAllowed policy with the feature enabled.
 TEST_F(DeviceSettingsProviderTest, DeviceFamilyLinkAccountsAllowedEnabled) {
   base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(
-      chromeos::features::kFamilyLinkOnSchoolDevice);
+  scoped_feature_list.InitAndEnableFeature(features::kFamilyLinkOnSchoolDevice);
 
   base::Value default_value(false);
   VerifyPolicyValue(kAccountsPrefFamilyLinkAccountsAllowed, &default_value);
@@ -1255,4 +1254,4 @@
   EXPECT_EQ(base::Value(false), *provider_->Get(kBorealisAllowedForDevice));
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ash/settings/device_settings_service.cc b/chrome/browser/ash/settings/device_settings_service.cc
index 8b12c34..c30af5c 100644
--- a/chrome/browser/ash/settings/device_settings_service.cc
+++ b/chrome/browser/ash/settings/device_settings_service.cc
@@ -30,7 +30,7 @@
 using ownership::OwnerKeyUtil;
 using ownership::PublicKey;
 
-namespace chromeos {
+namespace ash {
 
 DeviceSettingsService::Observer::~Observer() {}
 
@@ -97,7 +97,7 @@
 }
 
 void DeviceSettingsService::SetSessionManager(
-    SessionManagerClient* session_manager_client,
+    chromeos::SessionManagerClient* session_manager_client,
     scoped_refptr<OwnerKeyUtil> owner_key_util) {
   DCHECK(session_manager_client);
   DCHECK(owner_key_util.get());
@@ -380,4 +380,4 @@
   DeviceSettingsService::Shutdown();
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ash/settings/device_settings_service.h b/chrome/browser/ash/settings/device_settings_service.h
index b33e2a8..5f276a8e 100644
--- a/chrome/browser/ash/settings/device_settings_service.h
+++ b/chrome/browser/ash/settings/device_settings_service.h
@@ -34,7 +34,13 @@
 }  // namespace off_hours
 }  // namespace policy
 
+// TODO(https://crbug.com/1164001): remove when OwnerSettingsServiceChromeOS is
+// moved to ash.
 namespace chromeos {
+class OwnerSettingsServiceChromeOS;
+}  // namespace chromeos
+
+namespace ash {
 
 class SessionManagerOperation;
 
@@ -50,7 +56,7 @@
 //
 // DeviceSettingsService generates notifications for key and policy update
 // events so interested parties can reload state as appropriate.
-class DeviceSettingsService : public SessionManagerClient::Observer {
+class DeviceSettingsService : public chromeos::SessionManagerClient::Observer {
  public:
   // Indicates ownership status of the device (listed in upgrade order).
   enum OwnershipStatus {
@@ -110,7 +116,7 @@
   ~DeviceSettingsService() override;
 
   // To be called on startup once threads are initialized and D-Bus is ready.
-  void SetSessionManager(SessionManagerClient* session_manager_client,
+  void SetSessionManager(chromeos::SessionManagerClient* session_manager_client,
                          scoped_refptr<ownership::OwnerKeyUtil> owner_key_util);
 
   // Prevents the service from making further calls to session_manager_client
@@ -212,7 +218,7 @@
   void PropertyChangeComplete(bool success) override;
 
  private:
-  friend class OwnerSettingsServiceChromeOS;
+  friend class ::chromeos::OwnerSettingsServiceChromeOS;
 
   // Enqueues a new operation. Takes ownership of |operation| and starts it
   // right away if there is no active operation currently.
@@ -248,7 +254,7 @@
   // Processes pending callbacks from GetOwnershipStatusAsync().
   void RunPendingOwnershipStatusCallbacks();
 
-  SessionManagerClient* session_manager_client_ = nullptr;
+  chromeos::SessionManagerClient* session_manager_client_ = nullptr;
   scoped_refptr<ownership::OwnerKeyUtil> owner_key_util_;
 
   Status store_status_ = STORE_SUCCESS;
@@ -296,6 +302,12 @@
   DISALLOW_COPY_AND_ASSIGN(ScopedTestDeviceSettingsService);
 };
 
+}  // namespace ash
+
+// TODO(https://crbug.com/1164001): remove when Chrome OS code migration is
+// done.
+namespace chromeos {
+using ::ash::DeviceSettingsService;
 }  // namespace chromeos
 
 #endif  // CHROME_BROWSER_ASH_SETTINGS_DEVICE_SETTINGS_SERVICE_H_
diff --git a/chrome/browser/ash/settings/device_settings_service_unittest.cc b/chrome/browser/ash/settings/device_settings_service_unittest.cc
index b8cb77c..466f1d15 100644
--- a/chrome/browser/ash/settings/device_settings_service_unittest.cc
+++ b/chrome/browser/ash/settings/device_settings_service_unittest.cc
@@ -26,7 +26,7 @@
 
 using ::testing::Mock;
 
-namespace chromeos {
+namespace ash {
 
 namespace {
 
@@ -507,4 +507,4 @@
   EXPECT_TRUE(is_owner_);
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ash/settings/device_settings_test_helper.cc b/chrome/browser/ash/settings/device_settings_test_helper.cc
index 530e8b2..c5e162e 100644
--- a/chrome/browser/ash/settings/device_settings_test_helper.cc
+++ b/chrome/browser/ash/settings/device_settings_test_helper.cc
@@ -21,7 +21,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/test/test_utils.h"
 
-namespace chromeos {
+namespace ash {
 
 ScopedDeviceSettingsTestHelper::ScopedDeviceSettingsTestHelper() {
   DeviceSettingsService::Initialize();
@@ -55,10 +55,10 @@
       base::WrapUnique(user_manager_));
   owner_key_util_ = new ownership::MockOwnerKeyUtil();
   device_settings_service_ = std::make_unique<DeviceSettingsService>();
-  dbus_setter_ = DBusThreadManager::GetSetterForTesting();
-  CryptohomeClient::InitializeFake();
+  dbus_setter_ = chromeos::DBusThreadManager::GetSetterForTesting();
+  chromeos::CryptohomeClient::InitializeFake();
   PowerManagerClient::InitializeFake();
-  TpmManagerClient::InitializeFake();
+  chromeos::TpmManagerClient::InitializeFake();
   OwnerSettingsServiceChromeOSFactory::SetDeviceSettingsServiceForTesting(
       device_settings_service_.get());
   OwnerSettingsServiceChromeOSFactory::GetInstance()->SetOwnerKeyUtilForTesting(
@@ -82,10 +82,10 @@
   FlushDeviceSettings();
   device_settings_service_->UnsetSessionManager();
   device_settings_service_.reset();
-  TpmManagerClient::Shutdown();
+  chromeos::TpmManagerClient::Shutdown();
   PowerManagerClient::Shutdown();
-  CryptohomeClient::Shutdown();
-  DBusThreadManager::Shutdown();
+  chromeos::CryptohomeClient::Shutdown();
+  chromeos::DBusThreadManager::Shutdown();
   device_policy_.reset();
   base::RunLoop().RunUntilIdle();
   profile_.reset();
@@ -124,4 +124,4 @@
     service->OnTPMTokenReady(true /* token is enabled */);
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ash/settings/device_settings_test_helper.h b/chrome/browser/ash/settings/device_settings_test_helper.h
index 44f1bcd..222b411 100644
--- a/chrome/browser/ash/settings/device_settings_test_helper.h
+++ b/chrome/browser/ash/settings/device_settings_test_helper.h
@@ -24,8 +24,10 @@
 class TestingProfile;
 
 namespace chromeos {
-
 class DBusThreadManagerSetter;
+}  // namespace chromeos
+
+namespace ash {
 
 // Wraps the singleton device settings and initializes it to the point where it
 // reports OWNERSHIP_NONE for the ownership status.
@@ -79,7 +81,7 @@
   // with the global instance (DeviceSettingsService::Get()).
   std::unique_ptr<DeviceSettingsService> device_settings_service_;
 
-  std::unique_ptr<DBusThreadManagerSetter> dbus_setter_;
+  std::unique_ptr<chromeos::DBusThreadManagerSetter> dbus_setter_;
 
   std::unique_ptr<TestingProfile> profile_;
 
@@ -89,6 +91,13 @@
   DISALLOW_COPY_AND_ASSIGN(DeviceSettingsTestBase);
 };
 
+}  // namespace ash
+
+// TODO(https://crbug.com/1164001): remove when Chrome OS code migration is
+// done.
+namespace chromeos {
+using ::ash::DeviceSettingsTestBase;
+using ::ash::ScopedDeviceSettingsTestHelper;
 }  // namespace chromeos
 
 #endif  // CHROME_BROWSER_ASH_SETTINGS_DEVICE_SETTINGS_TEST_HELPER_H_
diff --git a/chrome/browser/ash/settings/owner_flags_storage.cc b/chrome/browser/ash/settings/owner_flags_storage.cc
index ccd711d..b8554608 100644
--- a/chrome/browser/ash/settings/owner_flags_storage.cc
+++ b/chrome/browser/ash/settings/owner_flags_storage.cc
@@ -17,7 +17,7 @@
 #include "components/prefs/pref_service.h"
 #include "third_party/cros_system_api/switches/chrome_switches.h"
 
-namespace chromeos {
+namespace ash {
 namespace about_flags {
 
 OwnerFlagsStorage::OwnerFlagsStorage(
@@ -97,4 +97,4 @@
 }
 
 }  // namespace about_flags
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ash/settings/owner_flags_storage.h b/chrome/browser/ash/settings/owner_flags_storage.h
index 8923b4cc..a45abef 100644
--- a/chrome/browser/ash/settings/owner_flags_storage.h
+++ b/chrome/browser/ash/settings/owner_flags_storage.h
@@ -12,7 +12,7 @@
 class OwnerSettingsService;
 }
 
-namespace chromeos {
+namespace ash {
 
 namespace about_flags {
 
@@ -60,6 +60,14 @@
 std::set<std::string> ParseFlagsFromCommandLine();
 
 }  // namespace about_flags
+}  // namespace ash
+
+// TODO(https://crbug.com/1164001): remove when Chrome OS code migration is
+// done.
+namespace chromeos {
+namespace about_flags {
+using ::ash::about_flags::OwnerFlagsStorage;
+}  // namespace about_flags
 }  // namespace chromeos
 
 #endif  // CHROME_BROWSER_ASH_SETTINGS_OWNER_FLAGS_STORAGE_H_
diff --git a/chrome/browser/ash/settings/scoped_cros_settings_test_helper.cc b/chrome/browser/ash/settings/scoped_cros_settings_test_helper.cc
index e036b7f..87c5313 100644
--- a/chrome/browser/ash/settings/scoped_cros_settings_test_helper.cc
+++ b/chrome/browser/ash/settings/scoped_cros_settings_test_helper.cc
@@ -22,7 +22,7 @@
 #include "content/public/test/test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace chromeos {
+namespace ash {
 
 ScopedCrosSettingsTestHelper::ScopedCrosSettingsTestHelper(
     bool create_settings_service)
@@ -138,13 +138,14 @@
   }
 }
 
-StubInstallAttributes* ScopedCrosSettingsTestHelper::InstallAttributes() {
+chromeos::StubInstallAttributes*
+ScopedCrosSettingsTestHelper::InstallAttributes() {
   return test_install_attributes_->Get();
 }
 
 void ScopedCrosSettingsTestHelper::Initialize(bool create_settings_service) {
   if (create_settings_service) {
-    test_install_attributes_.reset(new ScopedStubInstallAttributes());
+    test_install_attributes_.reset(new chromeos::ScopedStubInstallAttributes());
     CHECK(!DeviceSettingsService::IsInitialized());
     test_device_settings_service_.reset(new ScopedTestDeviceSettingsService());
     test_cros_settings_.reset(
@@ -152,4 +153,4 @@
   }
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ash/settings/scoped_cros_settings_test_helper.h b/chrome/browser/ash/settings/scoped_cros_settings_test_helper.h
index c36f9c75..8caef2c 100644
--- a/chrome/browser/ash/settings/scoped_cros_settings_test_helper.h
+++ b/chrome/browser/ash/settings/scoped_cros_settings_test_helper.h
@@ -21,8 +21,11 @@
 }
 
 namespace chromeos {
-
 class FakeOwnerSettingsService;
+}  // namespace chromeos
+
+namespace ash {
+
 class ScopedTestCrosSettings;
 class ScopedTestDeviceSettingsService;
 
@@ -46,8 +49,8 @@
 
   // Method to create an owner settings service that uses
   // |stub_settings_provider_| as settings write path.
-  std::unique_ptr<FakeOwnerSettingsService> CreateOwnerSettingsService(
-      Profile* profile);
+  std::unique_ptr<chromeos::FakeOwnerSettingsService>
+  CreateOwnerSettingsService(Profile* profile);
 
   // Returns the stubbed CrosSettingsProvider - the one that is swapped into
   // |CrosSettings| once |ReplaceDeviceSettingsProviderWithStub()| is called.
@@ -82,10 +85,11 @@
 
   // Get the scoped install attributes to change them as needed for the
   // current test.
-  StubInstallAttributes* InstallAttributes();
+  chromeos::StubInstallAttributes* InstallAttributes();
 
  private:
-  std::unique_ptr<ScopedStubInstallAttributes> test_install_attributes_;
+  std::unique_ptr<chromeos::ScopedStubInstallAttributes>
+      test_install_attributes_;
   std::unique_ptr<ScopedTestDeviceSettingsService>
       test_device_settings_service_;
   std::unique_ptr<ScopedTestCrosSettings> test_cros_settings_;
@@ -98,11 +102,12 @@
   DISALLOW_COPY_AND_ASSIGN(ScopedCrosSettingsTestHelper);
 };
 
-}  // namespace chromeos
+}  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when moved to chrome/browser/ash/.
-namespace ash {
-using ::chromeos::ScopedCrosSettingsTestHelper;
-}
+// TODO(https://crbug.com/1164001): remove after //chrome/browser/chromeos
+// source migration is finished.
+namespace chromeos {
+using ::ash::ScopedCrosSettingsTestHelper;
+}  // namespace chromeos
 
 #endif  // CHROME_BROWSER_ASH_SETTINGS_SCOPED_CROS_SETTINGS_TEST_HELPER_H_
diff --git a/chrome/browser/ash/settings/scoped_testing_cros_settings.cc b/chrome/browser/ash/settings/scoped_testing_cros_settings.cc
index 4fa0f158..09cb10ba 100644
--- a/chrome/browser/ash/settings/scoped_testing_cros_settings.cc
+++ b/chrome/browser/ash/settings/scoped_testing_cros_settings.cc
@@ -10,7 +10,7 @@
 
 #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.h"
 
-namespace chromeos {
+namespace ash {
 
 ScopedTestingCrosSettings::ScopedTestingCrosSettings() {
   test_instance_ = std::make_unique<CrosSettings>();
@@ -38,4 +38,4 @@
   CrosSettings::ShutdownForTesting();
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ash/settings/scoped_testing_cros_settings.h b/chrome/browser/ash/settings/scoped_testing_cros_settings.h
index 0af20a8..ad8225c 100644
--- a/chrome/browser/ash/settings/scoped_testing_cros_settings.h
+++ b/chrome/browser/ash/settings/scoped_testing_cros_settings.h
@@ -8,12 +8,14 @@
 #include <memory>
 
 #include "base/macros.h"
+// TODO(https://crbug.com/1164001): forward declare SystemSettingsProvider when
+// moved to ash.
+#include "chromeos/settings/system_settings_provider.h"
 
-namespace chromeos {
+namespace ash {
 
 class CrosSettings;
 class StubCrosSettingsProvider;
-class SystemSettingsProvider;
 
 // Helper class which calls CrosSettings::SetForTesting when it is constructed,
 // and calls CrosSettings::ShutdownForTesting when it goes out of scope,
@@ -51,6 +53,12 @@
   DISALLOW_COPY_AND_ASSIGN(ScopedTestingCrosSettings);
 };
 
+}  // namespace ash
+
+// TODO(https://crbug.com/1164001): remove when Chrome OS code migration is
+// done.
+namespace chromeos {
+using ::ash::ScopedTestingCrosSettings;
 }  // namespace chromeos
 
 #endif  // CHROME_BROWSER_ASH_SETTINGS_SCOPED_TESTING_CROS_SETTINGS_H_
diff --git a/chrome/browser/ash/settings/session_manager_operation.cc b/chrome/browser/ash/settings/session_manager_operation.cc
index b042b4a..e48da55 100644
--- a/chrome/browser/ash/settings/session_manager_operation.cc
+++ b/chrome/browser/ash/settings/session_manager_operation.cc
@@ -30,7 +30,7 @@
 
 namespace em = enterprise_management;
 
-namespace chromeos {
+namespace ash {
 
 SessionManagerOperation::SessionManagerOperation(Callback callback)
     : callback_(std::move(callback)) {}
@@ -38,7 +38,7 @@
 SessionManagerOperation::~SessionManagerOperation() {}
 
 void SessionManagerOperation::Start(
-    SessionManagerClient* session_manager_client,
+    chromeos::SessionManagerClient* session_manager_client,
     scoped_refptr<OwnerKeyUtil> owner_key_util,
     scoped_refptr<PublicKey> public_key) {
   session_manager_client_ = session_manager_client;
@@ -265,4 +265,4 @@
     StartLoading();
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ash/settings/session_manager_operation.h b/chrome/browser/ash/settings/session_manager_operation.h
index 7cb7f35..e643762 100644
--- a/chrome/browser/ash/settings/session_manager_operation.h
+++ b/chrome/browser/ash/settings/session_manager_operation.h
@@ -27,7 +27,7 @@
 class PublicKey;
 }
 
-namespace chromeos {
+namespace ash {
 
 // Handles a single transaction with session manager. This is a virtual base
 // class that contains common infrastructure for key and policy loading. There
@@ -42,7 +42,7 @@
   virtual ~SessionManagerOperation();
 
   // Starts the operation.
-  void Start(SessionManagerClient* session_manager_client,
+  void Start(chromeos::SessionManagerClient* session_manager_client,
              scoped_refptr<ownership::OwnerKeyUtil> owner_key_util,
              scoped_refptr<ownership::PublicKey> public_key);
 
@@ -81,7 +81,7 @@
   // operation should not perform further processing or trigger callbacks.
   void ReportResult(DeviceSettingsService::Status status);
 
-  SessionManagerClient* session_manager_client() {
+  chromeos::SessionManagerClient* session_manager_client() {
     return session_manager_client_;
   }
 
@@ -112,13 +112,13 @@
 
   // Validates device settings after retrieval from session_manager.
   void ValidateDeviceSettings(
-      SessionManagerClient::RetrievePolicyResponseType response_type,
+      chromeos::SessionManagerClient::RetrievePolicyResponseType response_type,
       const std::string& policy_blob);
 
   // Extracts status and device settings from the validator and reports them.
   void ReportValidatorStatus(policy::DeviceCloudPolicyValidator* validator);
 
-  SessionManagerClient* session_manager_client_ = nullptr;
+  chromeos::SessionManagerClient* session_manager_client_ = nullptr;
   scoped_refptr<ownership::OwnerKeyUtil> owner_key_util_;
 
   Callback callback_;
@@ -182,6 +182,6 @@
   DISALLOW_COPY_AND_ASSIGN(StoreSettingsOperation);
 };
 
-}  // namespace chromeos
+}  // namespace ash
 
 #endif  // CHROME_BROWSER_ASH_SETTINGS_SESSION_MANAGER_OPERATION_H_
diff --git a/chrome/browser/ash/settings/session_manager_operation_unittest.cc b/chrome/browser/ash/settings/session_manager_operation_unittest.cc
index 2bd5283..50d5f24b9 100644
--- a/chrome/browser/ash/settings/session_manager_operation_unittest.cc
+++ b/chrome/browser/ash/settings/session_manager_operation_unittest.cc
@@ -40,7 +40,7 @@
 using testing::Mock;
 using testing::_;
 
-namespace chromeos {
+namespace ash {
 namespace {
 
 class ObservableFakeSessionManagerClient : public FakeSessionManagerClient {
@@ -292,4 +292,4 @@
             op.device_settings()->SerializeAsString());
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ash/settings/shutdown_policy_forwarder.cc b/chrome/browser/ash/settings/shutdown_policy_forwarder.cc
index 601d327..01045b30 100644
--- a/chrome/browser/ash/settings/shutdown_policy_forwarder.cc
+++ b/chrome/browser/ash/settings/shutdown_policy_forwarder.cc
@@ -7,7 +7,7 @@
 #include "ash/public/cpp/shutdown_controller.h"
 #include "chrome/browser/ash/settings/cros_settings.h"
 
-namespace chromeos {
+namespace ash {
 
 ShutdownPolicyForwarder::ShutdownPolicyForwarder()
     : shutdown_policy_handler_(CrosSettings::Get(), this) {
@@ -18,8 +18,8 @@
 ShutdownPolicyForwarder::~ShutdownPolicyForwarder() = default;
 
 void ShutdownPolicyForwarder::OnShutdownPolicyChanged(bool reboot_on_shutdown) {
-  // Forward the setting to ash.
-  ash::ShutdownController::Get()->SetRebootOnShutdown(reboot_on_shutdown);
+  // Forward the setting to ShutdownController.
+  ShutdownController::Get()->SetRebootOnShutdown(reboot_on_shutdown);
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ash/settings/shutdown_policy_forwarder.h b/chrome/browser/ash/settings/shutdown_policy_forwarder.h
index 8bd5fdf..341ffe7 100644
--- a/chrome/browser/ash/settings/shutdown_policy_forwarder.h
+++ b/chrome/browser/ash/settings/shutdown_policy_forwarder.h
@@ -8,9 +8,9 @@
 #include "base/macros.h"
 #include "chrome/browser/ash/settings/shutdown_policy_handler.h"
 
-namespace chromeos {
+namespace ash {
 
-// Forwards the current DeviceRebootOnShutdown policy to ash.
+// Forwards the current DeviceRebootOnShutdown policy.
 class ShutdownPolicyForwarder : public ShutdownPolicyHandler::Delegate {
  public:
   ShutdownPolicyForwarder();
@@ -25,6 +25,12 @@
   DISALLOW_COPY_AND_ASSIGN(ShutdownPolicyForwarder);
 };
 
+}  // namespace ash
+
+// TODO(https://crbug.com/1164001): remove when Chrome OS code migration is
+// done.
+namespace chromeos {
+using ::ash::ShutdownPolicyForwarder;
 }  // namespace chromeos
 
 #endif  // CHROME_BROWSER_ASH_SETTINGS_SHUTDOWN_POLICY_FORWARDER_H_
diff --git a/chrome/browser/ash/settings/shutdown_policy_handler.cc b/chrome/browser/ash/settings/shutdown_policy_handler.cc
index aeab24d..8ba768c 100644
--- a/chrome/browser/ash/settings/shutdown_policy_handler.cc
+++ b/chrome/browser/ash/settings/shutdown_policy_handler.cc
@@ -9,7 +9,7 @@
 #include "chromeos/settings/cros_settings_names.h"
 #include "chromeos/settings/cros_settings_provider.h"
 
-namespace chromeos {
+namespace ash {
 
 ShutdownPolicyHandler::ShutdownPolicyHandler(CrosSettings* cros_settings,
                                              Delegate* delegate)
@@ -39,4 +39,4 @@
   delegate_->OnShutdownPolicyChanged(reboot_on_shutdown);
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ash/settings/shutdown_policy_handler.h b/chrome/browser/ash/settings/shutdown_policy_handler.h
index 61d1f6e4..1cc70a7 100644
--- a/chrome/browser/ash/settings/shutdown_policy_handler.h
+++ b/chrome/browser/ash/settings/shutdown_policy_handler.h
@@ -12,7 +12,7 @@
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ash/settings/cros_settings.h"
 
-namespace chromeos {
+namespace ash {
 
 // This class observes the device setting |DeviceRebootOnShutdown|. Changes to
 // this policy are communicated to the ShutdownPolicyHandler::Delegate by
@@ -48,6 +48,6 @@
   DISALLOW_COPY_AND_ASSIGN(ShutdownPolicyHandler);
 };
 
-}  // namespace chromeos
+}  // namespace ash
 
 #endif  // CHROME_BROWSER_ASH_SETTINGS_SHUTDOWN_POLICY_HANDLER_H_
diff --git a/chrome/browser/ash/settings/shutdown_policy_handler_unittest.cc b/chrome/browser/ash/settings/shutdown_policy_handler_unittest.cc
index 284606b..d159cd7 100644
--- a/chrome/browser/ash/settings/shutdown_policy_handler_unittest.cc
+++ b/chrome/browser/ash/settings/shutdown_policy_handler_unittest.cc
@@ -14,7 +14,7 @@
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace chromeos {
+namespace ash {
 
 class ShutdownPolicyHandlerTest : public testing::Test,
                                   public ShutdownPolicyHandler::Delegate {
@@ -25,10 +25,10 @@
   // testing::Test:
   void SetUp() override {
     testing::Test::SetUp();
-    DBusThreadManager::Initialize();
+    chromeos::DBusThreadManager::Initialize();
   }
 
-  void TearDown() override { DBusThreadManager::Shutdown(); }
+  void TearDown() override { chromeos::DBusThreadManager::Shutdown(); }
 
   void SetRebootOnShutdown(bool reboot_on_shutdown) {
     scoped_testing_cros_settings_.device_settings()->SetBoolean(
@@ -88,4 +88,4 @@
   EXPECT_FALSE(reboot_on_shutdown_);
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ash/settings/stats_reporting_controller.cc b/chrome/browser/ash/settings/stats_reporting_controller.cc
index 312cc3b5..227703e2 100644
--- a/chrome/browser/ash/settings/stats_reporting_controller.cc
+++ b/chrome/browser/ash/settings/stats_reporting_controller.cc
@@ -24,7 +24,7 @@
 
 }  // namespace
 
-namespace chromeos {
+namespace ash {
 
 static StatsReportingController* g_stats_reporting_controller = nullptr;
 
@@ -240,4 +240,4 @@
   return CrosSettings::Get()->GetBoolean(kStatsReportingPref, result);
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ash/settings/stats_reporting_controller.h b/chrome/browser/ash/settings/stats_reporting_controller.h
index fa9d3ab..c85c10b 100644
--- a/chrome/browser/ash/settings/stats_reporting_controller.h
+++ b/chrome/browser/ash/settings/stats_reporting_controller.h
@@ -21,7 +21,7 @@
 class OwnerSettingsService;
 }
 
-namespace chromeos {
+namespace ash {
 
 // An extra layer on top of CrosSettings / OwnerSettingsService that allows for
 // writing a setting before ownership is taken, for one setting only:
@@ -157,11 +157,12 @@
   DISALLOW_COPY_AND_ASSIGN(StatsReportingController);
 };
 
-}  // namespace chromeos
+}  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when moved to ash.
-namespace ash {
-using ::chromeos::StatsReportingController;
-}
+// TODO(https://crbug.com/1164001): remove when Chrome OS code migration is
+// done.
+namespace chromeos {
+using ::ash::StatsReportingController;
+}  // namespace chromeos
 
 #endif  // CHROME_BROWSER_ASH_SETTINGS_STATS_REPORTING_CONTROLLER_H_
diff --git a/chrome/browser/ash/settings/stats_reporting_controller_unittest.cc b/chrome/browser/ash/settings/stats_reporting_controller_unittest.cc
index 42675f5..ffb76d38 100644
--- a/chrome/browser/ash/settings/stats_reporting_controller_unittest.cc
+++ b/chrome/browser/ash/settings/stats_reporting_controller_unittest.cc
@@ -26,7 +26,7 @@
 #include "content/public/test/test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace chromeos {
+namespace ash {
 
 TestingPrefServiceSimple* RegisterPrefs(TestingPrefServiceSimple* local_state) {
   StatsReportingController::RegisterLocalStatePrefs(local_state->registry());
@@ -95,7 +95,7 @@
   content::BrowserTaskEnvironment task_environment_{
       content::BrowserTaskEnvironment::IO_MAINLOOP};
   TestingPrefServiceSimple local_state_;
-  ScopedStubInstallAttributes scoped_install_attributes_;
+  chromeos::ScopedStubInstallAttributes scoped_install_attributes_;
   FakeSessionManagerClient fake_session_manager_client_;
   ScopedTestDeviceSettingsService scoped_device_settings_;
   ScopedTestCrosSettings scoped_cros_settings_{RegisterPrefs(&local_state_)};
@@ -255,4 +255,4 @@
   ExpectThatSignedStoredValueIs(true);
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ash/settings/stub_cros_settings_provider.cc b/chrome/browser/ash/settings/stub_cros_settings_provider.cc
index 507fa67e..f62ff61 100644
--- a/chrome/browser/ash/settings/stub_cros_settings_provider.cc
+++ b/chrome/browser/ash/settings/stub_cros_settings_provider.cc
@@ -11,7 +11,7 @@
 #include "chrome/browser/ash/settings/device_settings_provider.h"
 #include "chromeos/settings/cros_settings_names.h"
 
-namespace chromeos {
+namespace ash {
 
 StubCrosSettingsProvider::StubCrosSettingsProvider(
     const NotifyObserversCallback& notify_cb)
@@ -109,4 +109,4 @@
   // |kDeviceOwner| will be set to the logged-in user by |UserManager|.
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ash/settings/stub_cros_settings_provider.h b/chrome/browser/ash/settings/stub_cros_settings_provider.h
index e814c22..0e38887 100644
--- a/chrome/browser/ash/settings/stub_cros_settings_provider.h
+++ b/chrome/browser/ash/settings/stub_cros_settings_provider.h
@@ -13,7 +13,7 @@
 #include "chromeos/settings/cros_settings_provider.h"
 #include "components/prefs/pref_value_map.h"
 
-namespace chromeos {
+namespace ash {
 
 // CrosSettingsProvider implementation that stores settings in memory unsigned.
 class StubCrosSettingsProvider : public CrosSettingsProvider {
@@ -63,6 +63,12 @@
   DISALLOW_COPY_AND_ASSIGN(StubCrosSettingsProvider);
 };
 
+}  // namespace ash
+
+// TODO(https://crbug.com/1164001): remove when Chrome OS code migration is
+// done.
+namespace chromeos {
+using ::ash::StubCrosSettingsProvider;
 }  // namespace chromeos
 
 #endif  // CHROME_BROWSER_ASH_SETTINGS_STUB_CROS_SETTINGS_PROVIDER_H_
diff --git a/chrome/browser/ash/settings/stub_cros_settings_provider_unittest.cc b/chrome/browser/ash/settings/stub_cros_settings_provider_unittest.cc
index 0b35110..237677f 100644
--- a/chrome/browser/ash/settings/stub_cros_settings_provider_unittest.cc
+++ b/chrome/browser/ash/settings/stub_cros_settings_provider_unittest.cc
@@ -13,7 +13,7 @@
 #include "chromeos/settings/cros_settings_names.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace chromeos {
+namespace ash {
 
 class StubCrosSettingsProviderTest : public testing::Test {
  protected:
@@ -91,4 +91,4 @@
   EXPECT_TRUE(closure);  // The |closure| was not taken or run.
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ash/settings/supervised_user_cros_settings_provider.cc b/chrome/browser/ash/settings/supervised_user_cros_settings_provider.cc
index f789ed4f..f32e873 100644
--- a/chrome/browser/ash/settings/supervised_user_cros_settings_provider.cc
+++ b/chrome/browser/ash/settings/supervised_user_cros_settings_provider.cc
@@ -11,7 +11,7 @@
 #include "components/account_id/account_id.h"
 #include "components/user_manager/user_manager.h"
 
-namespace chromeos {
+namespace ash {
 
 SupervisedUserCrosSettingsProvider::SupervisedUserCrosSettingsProvider(
     const CrosSettingsProvider::NotifyObserversCallback& notify_cb)
@@ -58,4 +58,4 @@
   return false;
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ash/settings/supervised_user_cros_settings_provider.h b/chrome/browser/ash/settings/supervised_user_cros_settings_provider.h
index 7867323..a87dd7f0 100644
--- a/chrome/browser/ash/settings/supervised_user_cros_settings_provider.h
+++ b/chrome/browser/ash/settings/supervised_user_cros_settings_provider.h
@@ -15,7 +15,7 @@
 class Value;
 }
 
-namespace chromeos {
+namespace ash {
 
 class SupervisedUserCrosSettingsProvider : public CrosSettingsProvider {
  public:
@@ -35,6 +35,6 @@
   DISALLOW_COPY_AND_ASSIGN(SupervisedUserCrosSettingsProvider);
 };
 
-}  // namespace chromeos
+}  // namespace ash
 
 #endif  // CHROME_BROWSER_ASH_SETTINGS_SUPERVISED_USER_CROS_SETTINGS_PROVIDER_H_
diff --git a/chrome/browser/ash/settings/token_encryptor.cc b/chrome/browser/ash/settings/token_encryptor.cc
index ee75beb..9521104 100644
--- a/chrome/browser/ash/settings/token_encryptor.cc
+++ b/chrome/browser/ash/settings/token_encryptor.cc
@@ -19,7 +19,7 @@
 #include "crypto/sha2.h"
 #include "crypto/symmetric_key.h"
 
-namespace chromeos {
+namespace ash {
 
 namespace {
 const size_t kNonceSize = 16;
@@ -122,4 +122,4 @@
   return token;
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ash/settings/token_encryptor.h b/chrome/browser/ash/settings/token_encryptor.h
index 9488593c..a27edcc 100644
--- a/chrome/browser/ash/settings/token_encryptor.h
+++ b/chrome/browser/ash/settings/token_encryptor.h
@@ -14,7 +14,7 @@
 class SymmetricKey;
 }
 
-namespace chromeos {
+namespace ash {
 
 // Interface class for classes that encrypt and decrypt tokens using the
 // system salt.
@@ -72,6 +72,12 @@
   DISALLOW_COPY_AND_ASSIGN(CryptohomeTokenEncryptor);
 };
 
+}  // namespace ash
+
+// TODO(https://crbug.com/1164001): remove when Chrome OS code migration is
+// done.
+namespace chromeos {
+using ::ash::CryptohomeTokenEncryptor;
 }  // namespace chromeos
 
 #endif  // CHROME_BROWSER_ASH_SETTINGS_TOKEN_ENCRYPTOR_H_
diff --git a/chrome/browser/ash/system/device_disabling_manager_unittest.cc b/chrome/browser/ash/system/device_disabling_manager_unittest.cc
index a35ef474..8e13592 100644
--- a/chrome/browser/ash/system/device_disabling_manager_unittest.cc
+++ b/chrome/browser/ash/system/device_disabling_manager_unittest.cc
@@ -75,7 +75,7 @@
 
  private:
   content::BrowserTaskEnvironment task_environment_;
-  chromeos::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
+  ScopedCrosSettingsTestHelper cros_settings_test_helper_;
   chromeos::FakeChromeUserManager fake_user_manager_;
   std::unique_ptr<DeviceDisablingManager> device_disabling_manager_;
   chromeos::system::FakeStatisticsProvider statistics_provider_;
@@ -279,7 +279,7 @@
 }
 
 void DeviceDisablingManagerTest::TearDown() {
-  chromeos::DeviceSettingsService::Get()->UnsetSessionManager();
+  DeviceSettingsService::Get()->UnsetSessionManager();
   DeviceDisablingManagerTestBase::TearDown();
 }
 
@@ -298,8 +298,8 @@
   scoped_refptr<ownership::MockOwnerKeyUtil> owner_key_util(
       new ownership::MockOwnerKeyUtil);
   owner_key_util->SetPublicKeyFromPrivateKey(*device_policy_.GetSigningKey());
-  chromeos::DeviceSettingsService::Get()->SetSessionManager(
-      &session_manager_client_, owner_key_util);
+  DeviceSettingsService::Get()->SetSessionManager(&session_manager_client_,
+                                                  owner_key_util);
   SimulatePolicyFetch();
 }
 
@@ -323,7 +323,7 @@
 void DeviceDisablingManagerTest::SimulatePolicyFetch() {
   device_policy_.Build();
   session_manager_client_.set_device_policy(device_policy_.GetBlob());
-  chromeos::DeviceSettingsService::Get()->OwnerKeySet(true);
+  DeviceSettingsService::Get()->OwnerKeySet(true);
   content::RunAllTasksUntilIdle();
 }
 
diff --git a/chrome/browser/ash/web_applications/terminal_source.cc b/chrome/browser/ash/web_applications/terminal_source.cc
index 9c939a7..aae111c 100644
--- a/chrome/browser/ash/web_applications/terminal_source.cc
+++ b/chrome/browser/ash/web_applications/terminal_source.cc
@@ -49,7 +49,6 @@
   if (!result) {
     static const base::NoDestructor<base::flat_map<std::string, std::string>>
         kTestFiles({
-            {"html/crosh.html", ""},
             {"html/terminal.html", "<script src='/js/terminal.js'></script>"},
             {"js/terminal.js",
              "chrome.terminalPrivate.openVmshellProcess([], () => {})"},
@@ -71,20 +70,18 @@
 
 // static
 std::unique_ptr<TerminalSource> TerminalSource::ForCrosh(Profile* profile) {
-  return base::WrapUnique(new TerminalSource(
-      profile, chrome::kChromeUIUntrustedCroshURL, "html/crosh.html"));
+  return base::WrapUnique(
+      new TerminalSource(profile, chrome::kChromeUIUntrustedCroshURL));
 }
 
 // static
 std::unique_ptr<TerminalSource> TerminalSource::ForTerminal(Profile* profile) {
-  return base::WrapUnique(new TerminalSource(
-      profile, chrome::kChromeUIUntrustedTerminalURL, "html/terminal.html"));
+  return base::WrapUnique(
+      new TerminalSource(profile, chrome::kChromeUIUntrustedTerminalURL));
 }
 
-TerminalSource::TerminalSource(Profile* profile,
-                               std::string source,
-                               std::string default_file)
-    : profile_(profile), source_(source), default_file_(default_file) {
+TerminalSource::TerminalSource(Profile* profile, std::string source)
+    : profile_(profile), source_(source) {
   auto* webui_allowlist = WebUIAllowlist::GetOrCreate(profile);
   const url::Origin terminal_origin = url::Origin::Create(GURL(source));
   CHECK(!terminal_origin.opaque());
@@ -115,7 +112,7 @@
   // skip first '/' in path.
   std::string path = url.path().substr(1);
   if (path.empty())
-    path = default_file_;
+    path = "html/terminal.html";
 
   // Replace $i8n{themeColor} in *.html.
   if (base::EndsWith(path, ".html", base::CompareCase::INSENSITIVE_ASCII)) {
diff --git a/chrome/browser/ash/web_applications/terminal_source.h b/chrome/browser/ash/web_applications/terminal_source.h
index 98cc0a0..25ed809 100644
--- a/chrome/browser/ash/web_applications/terminal_source.h
+++ b/chrome/browser/ash/web_applications/terminal_source.h
@@ -27,9 +27,7 @@
   ~TerminalSource() override;
 
  private:
-  explicit TerminalSource(Profile* profile,
-                          std::string source,
-                          std::string default_file);
+  explicit TerminalSource(Profile* profile, std::string source);
 
   // content::URLDataSource:
   std::string GetSource() override;
@@ -48,7 +46,6 @@
 
   Profile* profile_;
   std::string source_;
-  std::string default_file_;
   ui::TemplateReplacements replacements_;
 
   DISALLOW_COPY_AND_ASSIGN(TerminalSource);
diff --git a/chrome/browser/autofill/autofill_offer_notification_infobar_delegate_mobile_unittest.cc b/chrome/browser/autofill/autofill_offer_notification_infobar_delegate_mobile_unittest.cc
index 2cfc85d..5815985 100644
--- a/chrome/browser/autofill/autofill_offer_notification_infobar_delegate_mobile_unittest.cc
+++ b/chrome/browser/autofill/autofill_offer_notification_infobar_delegate_mobile_unittest.cc
@@ -9,17 +9,21 @@
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/infobars/core/infobar_delegate.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 namespace autofill {
 
 TEST(AutofillOfferNotificationInfoBarDelegateMobileTest,
      CreditCardIdentifierString) {
+  GURL offer_details_url = GURL("http://pay.google.com");
   CreditCard card = test::GetCreditCard();
   std::unique_ptr<AutofillOfferNotificationInfoBarDelegateMobile> delegate =
-      std::make_unique<AutofillOfferNotificationInfoBarDelegateMobile>(card);
+      std::make_unique<AutofillOfferNotificationInfoBarDelegateMobile>(
+          offer_details_url, card);
 
   EXPECT_EQ(delegate->credit_card_identifier_string(),
             card.CardIdentifierStringForAutofillDisplay());
+  EXPECT_EQ(offer_details_url, delegate->deep_link_url());
 }
 
 }  // namespace autofill
diff --git a/chrome/browser/background/background_mode_manager_unittest.cc b/chrome/browser/background/background_mode_manager_unittest.cc
index 116895f3..4f4a35f 100644
--- a/chrome/browser/background/background_mode_manager_unittest.cc
+++ b/chrome/browser/background/background_mode_manager_unittest.cc
@@ -311,7 +311,7 @@
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   // ChromeOS needs extra services to run in the following order.
-  chromeos::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
+  ash::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
   chromeos::ScopedTestUserManager test_user_manager_;
 #endif
 
diff --git a/chrome/browser/browser_process_platform_part_chromeos.cc b/chrome/browser/browser_process_platform_part_chromeos.cc
index 0b9123b..470a554 100644
--- a/chrome/browser/browser_process_platform_part_chromeos.cc
+++ b/chrome/browser/browser_process_platform_part_chromeos.cc
@@ -108,7 +108,7 @@
   device_disabling_manager_delegate_.reset(
       new ash::system::DeviceDisablingManagerDefaultDelegate);
   device_disabling_manager_.reset(new ash::system::DeviceDisablingManager(
-      device_disabling_manager_delegate_.get(), chromeos::CrosSettings::Get(),
+      device_disabling_manager_delegate_.get(), ash::CrosSettings::Get(),
       user_manager::UserManager::Get()));
   device_disabling_manager_->Init();
 }
diff --git a/chrome/browser/chrome_browser_interface_binders.cc b/chrome/browser/chrome_browser_interface_binders.cc
index e9a4b52..d9e0e4b 100644
--- a/chrome/browser/chrome_browser_interface_binders.cc
+++ b/chrome/browser/chrome_browser_interface_binders.cc
@@ -170,6 +170,8 @@
 #include "chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_ui.h"
 #include "chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader.mojom.h"
 #include "chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_ui.h"
+#include "chrome/browser/ui/webui/chromeos/emoji/emoji_picker.mojom.h"
+#include "chrome/browser/ui/webui/chromeos/emoji/emoji_ui.h"
 #include "chrome/browser/ui/webui/chromeos/internet_config_dialog.h"
 #include "chrome/browser/ui/webui/chromeos/internet_detail_dialog.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
@@ -836,6 +838,11 @@
 
   RegisterWebUIControllerInterfaceBinder<chromeos::scanning::mojom::ScanService,
                                          chromeos::ScanningUI>(map);
+
+  if (base::FeatureList::IsEnabled(chromeos::features::kImeSystemEmojiPicker)) {
+    RegisterWebUIControllerInterfaceBinder<
+        emoji_picker::mojom::PageHandlerFactory, chromeos::EmojiUI>(map);
+  }
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 #if BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OFFICIAL_BUILD)
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 3b6508d6..411a2ab 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -886,8 +886,8 @@
   PrefService* local_state = browser_process_->local_state();
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  chromeos::CrosSettings::Initialize(local_state);
-  chromeos::StatsReportingController::Initialize(local_state);
+  ash::CrosSettings::Initialize(local_state);
+  ash::StatsReportingController::Initialize(local_state);
   arc::StabilityMetricsManager::Initialize(local_state);
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
@@ -1836,8 +1836,8 @@
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   arc::StabilityMetricsManager::Shutdown();
-  chromeos::StatsReportingController::Shutdown();
-  chromeos::CrosSettings::Shutdown();
+  ash::StatsReportingController::Shutdown();
+  ash::CrosSettings::Shutdown();
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 #endif  // defined(OS_ANDROID)
 }
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 3ec2a45..4147f5d 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -1870,6 +1870,8 @@
     "external_metrics.h",
     "external_protocol_dialog.cc",
     "external_protocol_dialog.h",
+    "feature_usage_metrics/feature_usage_metrics.cc",
+    "feature_usage_metrics/feature_usage_metrics.h",
     "file_manager/app_id.h",
     "file_manager/app_service_file_tasks.cc",
     "file_manager/app_service_file_tasks.h",
@@ -3775,6 +3777,7 @@
     "extensions/signin_screen_policy_provider_unittest.cc",
     "extensions/wallpaper_private_api_unittest.cc",
     "external_metrics_unittest.cc",
+    "feature_usage_metrics/feature_usage_metrics_unittest.cc",
     "file_manager/app_service_file_tasks_unittest.cc",
     "file_manager/documents_provider_root_manager_unittest.cc",
     "file_manager/file_tasks_notifier_unittest.cc",
diff --git a/chrome/browser/chromeos/arc/arc_util.cc b/chrome/browser/chromeos/arc/arc_util.cc
index 1749d65..0a32ff8 100644
--- a/chrome/browser/chromeos/arc/arc_util.cc
+++ b/chrome/browser/chromeos/arc/arc_util.cc
@@ -149,8 +149,8 @@
         return true;
     }
   }
-  if (chromeos::CrosSettings::Get()->GetBoolean(
-          chromeos::kUnaffiliatedArcAllowed, &arc_allowed)) {
+  if (ash::CrosSettings::Get()->GetBoolean(chromeos::kUnaffiliatedArcAllowed,
+                                           &arc_allowed)) {
     return arc_allowed;
   }
   // If device policy is not set, allow ARC.
@@ -534,8 +534,7 @@
   }
 
   bool pref = false;
-  chromeos::CrosSettings::Get()->GetBoolean(chromeos::kStatsReportingPref,
-                                            &pref);
+  ash::CrosSettings::Get()->GetBoolean(chromeos::kStatsReportingPref, &pref);
   return pref;
 }
 
diff --git a/chrome/browser/chromeos/arc/arc_util_unittest.cc b/chrome/browser/chromeos/arc/arc_util_unittest.cc
index 5e5fb543..83ee3a22 100644
--- a/chrome/browser/chromeos/arc/arc_util_unittest.cc
+++ b/chrome/browser/chromeos/arc/arc_util_unittest.cc
@@ -204,7 +204,7 @@
   std::unique_ptr<base::test::ScopedCommandLine> command_line_;
   base::test::ScopedFeatureList feature_list_;
   content::BrowserTaskEnvironment task_environment_;
-  chromeos::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
+  ash::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
   base::ScopedTempDir data_dir_;
   std::unique_ptr<TestingProfileManager> profile_manager_;
   std::unique_ptr<user_manager::ScopedUserManager> user_manager_enabler_;
diff --git a/chrome/browser/chromeos/arc/cast_receiver/arc_cast_receiver_service.cc b/chrome/browser/chromeos/arc/cast_receiver/arc_cast_receiver_service.cc
index 7f9f733..5f2661bd 100644
--- a/chrome/browser/chromeos/arc/cast_receiver/arc_cast_receiver_service.cc
+++ b/chrome/browser/chromeos/arc/cast_receiver/arc_cast_receiver_service.cc
@@ -69,12 +69,10 @@
       base::BindRepeating(&ArcCastReceiverService::OnCastReceiverEnabledChanged,
                           base::Unretained(this)));
 
-  receiver_name_subscription_ =
-      chromeos::CrosSettings::Get()->AddSettingsObserver(
-          chromeos::kCastReceiverName,
-          base::BindRepeating(
-              &ArcCastReceiverService::OnCastReceiverNameChanged,
-              base::Unretained(this)));
+  receiver_name_subscription_ = ash::CrosSettings::Get()->AddSettingsObserver(
+      chromeos::kCastReceiverName,
+      base::BindRepeating(&ArcCastReceiverService::OnCastReceiverNameChanged,
+                          base::Unretained(this)));
 }
 
 ArcCastReceiverService::~ArcCastReceiverService() {
@@ -109,8 +107,8 @@
   if (!cast_receiver_instance)
     return;
   std::string name;
-  if (!chromeos::CrosSettings::Get()->GetString(chromeos::kCastReceiverName,
-                                                &name) ||
+  if (!ash::CrosSettings::Get()->GetString(chromeos::kCastReceiverName,
+                                           &name) ||
       name.empty()) {
     return;
   }
diff --git a/chrome/browser/chromeos/arc/instance_throttle/arc_app_launch_throttle_observer.cc b/chrome/browser/chromeos/arc/instance_throttle/arc_app_launch_throttle_observer.cc
index ee4eeb47..da45959 100644
--- a/chrome/browser/chromeos/arc/instance_throttle/arc_app_launch_throttle_observer.cc
+++ b/chrome/browser/chromeos/arc/instance_throttle/arc_app_launch_throttle_observer.cc
@@ -55,7 +55,8 @@
     int32_t task_id,
     const std::string& package_name,
     const std::string& activity,
-    const std::string& intent) {
+    const std::string& intent,
+    int32_t session_id) {
   OnLaunchedOrRequestExpired(package_name);
 }
 
diff --git a/chrome/browser/chromeos/arc/instance_throttle/arc_app_launch_throttle_observer.h b/chrome/browser/chromeos/arc/instance_throttle/arc_app_launch_throttle_observer.h
index 39cd84b..364e65a 100644
--- a/chrome/browser/chromeos/arc/instance_throttle/arc_app_launch_throttle_observer.h
+++ b/chrome/browser/chromeos/arc/instance_throttle/arc_app_launch_throttle_observer.h
@@ -41,7 +41,8 @@
   void OnTaskCreated(int32_t task_id,
                      const std::string& package_name,
                      const std::string& activity,
-                     const std::string& intent) override;
+                     const std::string& intent,
+                     int32_t session_id) override;
 
  private:
   void OnLaunchedOrRequestExpired(const std::string& name);
diff --git a/chrome/browser/chromeos/arc/instance_throttle/arc_app_launch_throttle_observer_unittest.cc b/chrome/browser/chromeos/arc/instance_throttle/arc_app_launch_throttle_observer_unittest.cc
index 8752c856..2fe8932f 100644
--- a/chrome/browser/chromeos/arc/instance_throttle/arc_app_launch_throttle_observer_unittest.cc
+++ b/chrome/browser/chromeos/arc/instance_throttle/arc_app_launch_throttle_observer_unittest.cc
@@ -60,15 +60,15 @@
 
   // App2 launch requested but finishes before App1, observer is still active.
   observer()->OnAppLaunchRequested(app2);
-  observer()->OnTaskCreated(0, app2.package_name, "", "");
+  observer()->OnTaskCreated(0, app2.package_name, "", "", /*session_id=*/0);
   EXPECT_TRUE(observer()->active());
 
   // App3 finishes launch but observer is not waiting for app3, so it is still
   // active.
-  observer()->OnTaskCreated(0, app3.package_name, "", "");
+  observer()->OnTaskCreated(0, app3.package_name, "", "", /*session_id=*/0);
 
   // App1 finishes launch, observer is inactive.
-  observer()->OnTaskCreated(0, app1.package_name, "", "");
+  observer()->OnTaskCreated(0, app1.package_name, "", "", /*session_id=*/0);
 }
 
 // Check that a launch request expires.
diff --git a/chrome/browser/chromeos/arc/intent_helper/arc_settings_service.cc b/chrome/browser/chromeos/arc/intent_helper/arc_settings_service.cc
index 5fd4b96..6d6ba02c 100644
--- a/chrome/browser/chromeos/arc/intent_helper/arc_settings_service.cc
+++ b/chrome/browser/chromeos/arc/intent_helper/arc_settings_service.cc
@@ -361,7 +361,7 @@
   // ARC setup and therefore are not observed here.
 
   reporting_consent_subscription_ =
-      chromeos::StatsReportingController::Get()->AddObserver(
+      ash::StatsReportingController::Get()->AddObserver(
           base::BindRepeating(&ArcSettingsServiceImpl::SyncReportingConsent,
                               base::Unretained(this), /*initial_sync=*/false));
 
diff --git a/chrome/browser/chromeos/arc/intent_helper/arc_settings_service_unittest.cc b/chrome/browser/chromeos/arc/intent_helper/arc_settings_service_unittest.cc
index cecf710d..35f4416b 100644
--- a/chrome/browser/chromeos/arc/intent_helper/arc_settings_service_unittest.cc
+++ b/chrome/browser/chromeos/arc/intent_helper/arc_settings_service_unittest.cc
@@ -58,9 +58,9 @@
     chromeos::NetworkHandler::Initialize();
     network_config_helper_ = std::make_unique<
         chromeos::network_config::CrosNetworkConfigTestHelper>();
-    chromeos::StatsReportingController::RegisterLocalStatePrefs(
+    ash::StatsReportingController::RegisterLocalStatePrefs(
         local_state_.registry());
-    chromeos::StatsReportingController::Initialize(&local_state_);
+    ash::StatsReportingController::Initialize(&local_state_);
 
     arc_service_manager_ = std::make_unique<ArcServiceManager>();
     arc_session_manager_ =
@@ -104,7 +104,7 @@
     arc_session_manager_.reset();
     arc_service_manager_.reset();
 
-    chromeos::StatsReportingController::Shutdown();
+    ash::StatsReportingController::Shutdown();
     chromeos::NetworkHandler::Shutdown();
     chromeos::DBusThreadManager::Shutdown();
   }
diff --git a/chrome/browser/chromeos/arc/intent_helper/start_smart_selection_action_menu.cc b/chrome/browser/chromeos/arc/intent_helper/start_smart_selection_action_menu.cc
index 4472402..9d7e251b 100644
--- a/chrome/browser/chromeos/arc/intent_helper/start_smart_selection_action_menu.cc
+++ b/chrome/browser/chromeos/arc/intent_helper/start_smart_selection_action_menu.cc
@@ -9,12 +9,18 @@
 #include <utility>
 
 #include "base/bind.h"
-#include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/apps/app_service/app_icon_factory.h"
+#include "chrome/browser/apps/app_service/app_service_proxy.h"
+#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
+#include "chrome/browser/apps/app_service/intent_util.h"
+#include "chrome/browser/apps/app_service/launch_utils.h"
+#include "chrome/browser/chromeos/arc/session/arc_session_manager.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/arc/arc_service_manager.h"
@@ -25,6 +31,9 @@
 #include "components/renderer_context_menu/render_view_context_menu_proxy.h"
 #include "content/public/browser/context_menu_params.h"
 #include "ui/base/models/image_model.h"
+#include "ui/display/display.h"
+#include "ui/display/screen.h"
+#include "ui/gfx/geometry/point.h"
 #include "ui/gfx/image/image_skia_operations.h"
 
 namespace arc {
@@ -98,13 +107,22 @@
   if (!instance)
     return;
 
-  instance->HandleIntent(std::move(actions_[index]->action_intent),
-                         std::move(actions_[index]->activity));
+  gfx::Point point = display::Screen::GetScreen()->GetCursorScreenPoint();
+  display::Display display =
+      display::Screen::GetScreen()->GetDisplayNearestPoint(point);
 
-  UMA_HISTOGRAM_ENUMERATION(
-      "Arc.UserInteraction",
-      arc::UserInteractionType::
-          APP_STARTED_FROM_SMART_TEXT_SELECTION_CONTEXT_MENU);
+  Profile* profile = ArcSessionManager::Get()->profile();
+  apps::AppServiceProxy* proxy =
+      apps::AppServiceProxyFactory::GetForProfile(profile);
+  proxy->LaunchAppWithIntent(
+      ArcAppListPrefs::Get(profile)->GetAppIdByPackageName(
+          actions_[index]->activity->package_name),
+      ui::EF_NONE,
+      apps_util::CreateIntentForArcIntentAndActivity(
+          std::move(actions_[index]->action_intent),
+          std::move(actions_[index]->activity)),
+      apps::mojom::LaunchSource::kFromSmartTextContextMenu,
+      apps::MakeWindowInfo(display.id()));
 }
 
 void StartSmartSelectionActionMenu::HandleTextSelectionActions(
diff --git a/chrome/browser/chromeos/arc/metrics/arc_metrics_service_proxy.cc b/chrome/browser/chromeos/arc/metrics/arc_metrics_service_proxy.cc
index a15ddb3a..36cf859 100644
--- a/chrome/browser/chromeos/arc/metrics/arc_metrics_service_proxy.cc
+++ b/chrome/browser/chromeos/arc/metrics/arc_metrics_service_proxy.cc
@@ -66,7 +66,8 @@
 void ArcMetricsServiceProxy::OnTaskCreated(int32_t task_id,
                                            const std::string& package_name,
                                            const std::string& activity,
-                                           const std::string& intent) {
+                                           const std::string& intent,
+                                           int32_t session_id) {
   arc_metrics_service_->OnTaskCreated(task_id, package_name, activity, intent);
 }
 
diff --git a/chrome/browser/chromeos/arc/metrics/arc_metrics_service_proxy.h b/chrome/browser/chromeos/arc/metrics/arc_metrics_service_proxy.h
index 721c0d65..3fde3b93 100644
--- a/chrome/browser/chromeos/arc/metrics/arc_metrics_service_proxy.h
+++ b/chrome/browser/chromeos/arc/metrics/arc_metrics_service_proxy.h
@@ -41,7 +41,8 @@
   void OnTaskCreated(int32_t task_id,
                      const std::string& package_name,
                      const std::string& activity,
-                     const std::string& intent) override;
+                     const std::string& intent,
+                     int32_t session_id) override;
   void OnTaskDestroyed(int32_t task_id) override;
 
   // ArcSessionManagerObserver overrides.
diff --git a/chrome/browser/chromeos/arc/oemcrypto/arc_oemcrypto_bridge.cc b/chrome/browser/chromeos/arc/oemcrypto/arc_oemcrypto_bridge.cc
index ba35395..237dd2a 100644
--- a/chrome/browser/chromeos/arc/oemcrypto/arc_oemcrypto_bridge.cc
+++ b/chrome/browser/chromeos/arc/oemcrypto/arc_oemcrypto_bridge.cc
@@ -78,7 +78,7 @@
   // OEMCrypto utilizes Attestation as the root of trust for its DRM
   // implementation.
   bool attestation_enabled = false;
-  if (!chromeos::CrosSettings::Get()->GetBoolean(
+  if (!ash::CrosSettings::Get()->GetBoolean(
           chromeos::kAttestationForContentProtectionEnabled,
           &attestation_enabled)) {
     LOG(ERROR) << "Failed to get attestation device setting";
diff --git a/chrome/browser/chromeos/arc/optin/arc_optin_preference_handler.cc b/chrome/browser/chromeos/arc/optin/arc_optin_preference_handler.cc
index 872dae2c..7fc4685 100644
--- a/chrome/browser/chromeos/arc/optin/arc_optin_preference_handler.cc
+++ b/chrome/browser/chromeos/arc/optin/arc_optin_preference_handler.cc
@@ -26,10 +26,9 @@
 
 void ArcOptInPreferenceHandler::Start() {
   reporting_consent_subscription_ =
-      chromeos::StatsReportingController::Get()->AddObserver(
-          base::BindRepeating(
-              &ArcOptInPreferenceHandler::OnMetricsPreferenceChanged,
-              base::Unretained(this)));
+      ash::StatsReportingController::Get()->AddObserver(base::BindRepeating(
+          &ArcOptInPreferenceHandler::OnMetricsPreferenceChanged,
+          base::Unretained(this)));
 
   pref_change_registrar_.Init(pref_service_);
   pref_change_registrar_.Add(
@@ -65,7 +64,7 @@
 
 void ArcOptInPreferenceHandler::SendMetricsMode() {
   if (g_browser_process->local_state()) {
-    bool enabled = chromeos::StatsReportingController::Get()->IsEnabled();
+    bool enabled = ash::StatsReportingController::Get()->IsEnabled();
     observer_->OnMetricsModeChanged(enabled, IsMetricsReportingPolicyManaged());
   }
 }
@@ -95,7 +94,7 @@
 }
 
 void ArcOptInPreferenceHandler::EnableMetrics(bool is_enabled) {
-  chromeos::StatsReportingController::Get()->SetEnabled(
+  ash::StatsReportingController::Get()->SetEnabled(
       ProfileManager::GetActiveUserProfile(), is_enabled);
 }
 
diff --git a/chrome/browser/chromeos/arc/optin/arc_terms_of_service_default_negotiator_unittest.cc b/chrome/browser/chromeos/arc/optin/arc_terms_of_service_default_negotiator_unittest.cc
index 1fb2f15b..3e661ca 100644
--- a/chrome/browser/chromeos/arc/optin/arc_terms_of_service_default_negotiator_unittest.cc
+++ b/chrome/browser/chromeos/arc/optin/arc_terms_of_service_default_negotiator_unittest.cc
@@ -67,9 +67,9 @@
         IdentityManagerFactory::GetForProfile(profile()),
         "testing@account.com");
 
-    chromeos::StatsReportingController::RegisterLocalStatePrefs(
+    ash::StatsReportingController::RegisterLocalStatePrefs(
         local_state_.registry());
-    chromeos::StatsReportingController::Initialize(&local_state_);
+    ash::StatsReportingController::Initialize(&local_state_);
 
     support_host_ = std::make_unique<ArcSupportHost>(profile());
     fake_arc_support_ = std::make_unique<FakeArcSupport>(support_host_.get());
@@ -83,7 +83,7 @@
     support_host_.reset();
     user_manager_enabler_.reset();
 
-    chromeos::StatsReportingController::Shutdown();
+    ash::StatsReportingController::Shutdown();
     BrowserWithTestWindowTest::TearDown();
   }
 
diff --git a/chrome/browser/chromeos/arc/session/arc_session_manager_unittest.cc b/chrome/browser/chromeos/arc/session/arc_session_manager_unittest.cc
index 480a9620..9375aae6 100644
--- a/chrome/browser/chromeos/arc/session/arc_session_manager_unittest.cc
+++ b/chrome/browser/chromeos/arc/session/arc_session_manager_unittest.cc
@@ -2174,7 +2174,7 @@
   GetFakeUserManager()->LoginUser(account_id);
 
   // Set DeviceRebootOnUserSignout to ALWAYS.
-  chromeos::ScopedCrosSettingsTestHelper settings_helper{
+  ash::ScopedCrosSettingsTestHelper settings_helper{
       /* create_settings_service=*/false};
   settings_helper.ReplaceDeviceSettingsProviderWithStub();
   settings_helper.SetInteger(
diff --git a/chrome/browser/chromeos/arc/tracing/arc_app_performance_tracing.cc b/chrome/browser/chromeos/arc/tracing/arc_app_performance_tracing.cc
index 4272dad8..9543ed7 100644
--- a/chrome/browser/chromeos/arc/tracing/arc_app_performance_tracing.cc
+++ b/chrome/browser/chromeos/arc/tracing/arc_app_performance_tracing.cc
@@ -228,7 +228,8 @@
 void ArcAppPerformanceTracing::OnTaskCreated(int32_t task_id,
                                              const std::string& package_name,
                                              const std::string& activity,
-                                             const std::string& intent) {
+                                             const std::string& intent,
+                                             int32_t session_id) {
   const std::string app_id = ArcAppListPrefs::GetAppId(package_name, activity);
   task_id_to_app_id_[task_id] = std::make_pair(app_id, package_name);
   MaybeStartTracing();
diff --git a/chrome/browser/chromeos/arc/tracing/arc_app_performance_tracing.h b/chrome/browser/chromeos/arc/tracing/arc_app_performance_tracing.h
index 5f5566b..9c706b5 100644
--- a/chrome/browser/chromeos/arc/tracing/arc_app_performance_tracing.h
+++ b/chrome/browser/chromeos/arc/tracing/arc_app_performance_tracing.h
@@ -86,7 +86,8 @@
   void OnTaskCreated(int32_t task_id,
                      const std::string& package_name,
                      const std::string& activity,
-                     const std::string& intent) override;
+                     const std::string& intent,
+                     int32_t session_id) override;
   void OnTaskDestroyed(int32_t task_id) override;
 
   // exo::SurfaceObserver:
diff --git a/chrome/browser/chromeos/arc/tracing/arc_app_performance_tracing_unittest.cc b/chrome/browser/chromeos/arc/tracing/arc_app_performance_tracing_unittest.cc
index bd922f1a..163e1ceb 100644
--- a/chrome/browser/chromeos/arc/tracing/arc_app_performance_tracing_unittest.cc
+++ b/chrome/browser/chromeos/arc/tracing/arc_app_performance_tracing_unittest.cc
@@ -93,7 +93,7 @@
         arc_widget->GetNativeWindow(), arc_widget->GetNativeWindow());
     tracing_helper().GetTracing()->OnTaskCreated(
         1 /* task_Id */, kFocusAppPackage, kFocusAppActivity,
-        std::string() /* intent */);
+        std::string() /* intent */, 0 /* session_id */);
     DCHECK(tracing_helper().GetTracingSession());
     tracing_helper().GetTracingSession()->FireTimerForTesting();
     DCHECK(tracing_helper().GetTracingSession());
@@ -119,7 +119,7 @@
   // Report task first.
   tracing_helper().GetTracing()->OnTaskCreated(
       1 /* task_Id */, kFocusAppPackage, kFocusAppActivity,
-      std::string() /* intent */);
+      std::string() /* intent */, 0 /* session_id */);
   EXPECT_FALSE(tracing_helper().GetTracingSession());
 
   // Create window second.
@@ -147,7 +147,7 @@
   // Report task second.
   tracing_helper().GetTracing()->OnTaskCreated(
       2 /* task_Id */, kFocusAppPackage, kFocusAppActivity,
-      std::string() /* intent */);
+      std::string() /* intent */, 0 /* session_id */);
   ASSERT_TRUE(tracing_helper().GetTracingSession());
   // Scheduled but not started.
   EXPECT_FALSE(tracing_helper().GetTracingSession()->tracing_active());
@@ -166,7 +166,7 @@
   EXPECT_FALSE(tracing_helper().GetTracingSession());
   tracing_helper().GetTracing()->OnTaskCreated(
       1 /* task_Id */, kNonFocusAppPackage, kNonFocusAppActivity,
-      std::string() /* intent */);
+      std::string() /* intent */, 0 /* session_id */);
   EXPECT_FALSE(tracing_helper().GetTracingSession());
   arc_widget->Close();
 }
@@ -220,7 +220,7 @@
   EXPECT_FALSE(tracing_helper().GetTracingSession());
   tracing_helper().GetTracing()->OnTaskCreated(
       1 /* task_Id */, kFocusAppPackage, kFocusAppActivity,
-      std::string() /* intent */);
+      std::string() /* intent */, 0 /* session_id */);
   EXPECT_FALSE(tracing_helper().GetTracingSession());
   arc_widget->Close();
 }
@@ -237,7 +237,7 @@
       arc_widget->GetNativeWindow(), arc_widget->GetNativeWindow());
   tracing_helper().GetTracing()->OnTaskCreated(
       1 /* task_Id */, kFocusAppPackage, kFocusAppActivity,
-      std::string() /* intent */);
+      std::string() /* intent */, 0 /* session_id */);
 
   // No report before launch
   base::Time timestamp = base::Time::Now();
diff --git a/chrome/browser/chromeos/attestation/attestation_policy_browsertest.cc b/chrome/browser/chromeos/attestation/attestation_policy_browsertest.cc
index 0315dcd..a8994a1 100644
--- a/chrome/browser/chromeos/attestation/attestation_policy_browsertest.cc
+++ b/chrome/browser/chromeos/attestation/attestation_policy_browsertest.cc
@@ -26,7 +26,7 @@
 
 class AttestationDevicePolicyTest
     : public DevicePolicyCrosBrowserTest,
-      public chromeos::DeviceSettingsService::Observer {
+      public ash::DeviceSettingsService::Observer {
  public:
     // DeviceSettingsService::Observer
   void DeviceSettingsUpdated() override { operation_complete_ = true; }
@@ -41,10 +41,10 @@
 
   // Refreshes device policy and waits for it to be applied.
   virtual void SyncRefreshDevicePolicy() {
-    chromeos::DeviceSettingsService::Get()->AddObserver(this);
+    ash::DeviceSettingsService::Get()->AddObserver(this);
     RefreshDevicePolicy();
     WaitForAsyncOperation();
-    chromeos::DeviceSettingsService::Get()->RemoveObserver(this);
+    ash::DeviceSettingsService::Get()->RemoveObserver(this);
   }
 
   enterprise_management::AttestationSettingsProto* GetDevicePolicyProto() {
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index 11a4875e..60377e7f 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -143,7 +143,7 @@
 #include "chrome/browser/ui/ash/assistant/assistant_state_client.h"
 #include "chrome/browser/ui/ash/image_downloader_impl.h"
 #include "chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.h"
-#include "chrome/browser/ui/webui/chromeos/emoji/emoji_dialog.h"
+#include "chrome/browser/ui/webui/chromeos/emoji/emoji_ui.h"
 #include "chrome/common/channel_info.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_features.h"
@@ -707,10 +707,6 @@
   // on ChromeKeyboardControllerClient.
   chrome_keyboard_controller_client_ = ChromeKeyboardControllerClient::Create();
 
-  if (base::FeatureList::IsEnabled(chromeos::features::kImeSystemEmojiPicker)) {
-    ui::SetShowEmojiKeyboardCallback(
-        base::BindRepeating(&EmojiPickerDialog::Show));
-  }
 
   // ProfileHelper has to be initialized after UserManager instance is created.
   ProfileHelper::Get()->Initialize();
@@ -936,6 +932,11 @@
     ProfileHelper::GetSigninProfile();
   }
 
+  if (base::FeatureList::IsEnabled(chromeos::features::kImeSystemEmojiPicker)) {
+    ui::SetShowEmojiKeyboardCallback(
+        base::BindRepeating(&EmojiUI::Show, base::Unretained(profile())));
+  }
+
   BootTimesRecorder::Get()->OnChromeProcessStart();
 
   // Initialize the network portal detector for Chrome OS. The network
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.h b/chrome/browser/chromeos/chrome_browser_main_chromeos.h
index a6b8d48..1cf64f7 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.h
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.h
@@ -17,6 +17,9 @@
 #include "chrome/browser/ash/app_mode/web_app/web_kiosk_app_manager.h"
 // TODO(https://crbug.com/1164001): forward declare when moved to
 // chrome/browser/ash/.
+#include "chrome/browser/ash/settings/shutdown_policy_forwarder.h"
+// TODO(https://crbug.com/1164001): forward declare when moved to
+// chrome/browser/ash/.
 #include "chrome/browser/ash/system/breakpad_consent_watcher.h"
 #include "chrome/browser/chrome_browser_main_linux.h"
 #include "chrome/browser/chromeos/external_metrics.h"
@@ -76,7 +79,6 @@
 class PowerMetricsReporter;
 class RendererFreezer;
 class SessionTerminationManager;
-class ShutdownPolicyForwarder;
 class SystemTokenCertDBInitializer;
 class WilcoDtcSupportdManager;
 
diff --git a/chrome/browser/chromeos/chromebox_for_meetings/device_info/device_info_service.cc b/chrome/browser/chromeos/chromebox_for_meetings/device_info/device_info_service.cc
index 071765d..2c2dbba 100644
--- a/chrome/browser/chromeos/chromebox_for_meetings/device_info/device_info_service.cc
+++ b/chrome/browser/chromeos/chromebox_for_meetings/device_info/device_info_service.cc
@@ -81,8 +81,8 @@
   }
 
   VLOG(3) << "mojom::DeviceInfo Service Adaptor is connected.";
-  CHECK(chromeos::DeviceSettingsService::IsInitialized());
-  chromeos::DeviceSettingsService::Get()->AddObserver(this);
+  CHECK(ash::DeviceSettingsService::IsInitialized());
+  ash::DeviceSettingsService::Get()->AddObserver(this);
 }
 
 void DeviceInfoService::OnAdaptorDisconnect() {
@@ -115,7 +115,7 @@
 }
 
 void DeviceInfoService::UpdatePolicyInfo() {
-  auto* device_settings = chromeos::DeviceSettingsService::Get();
+  auto* device_settings = ash::DeviceSettingsService::Get();
   if (!device_settings || !device_settings->policy_data()) {
     return;
   }
@@ -205,7 +205,7 @@
 void DeviceInfoService::Reset() {
   receivers_.Clear();
   policy_remotes_.Clear();
-  chromeos::DeviceSettingsService::Get()->RemoveObserver(this);
+  ash::DeviceSettingsService::Get()->RemoveObserver(this);
 }
 
 }  // namespace cfm
diff --git a/chrome/browser/chromeos/chromebox_for_meetings/device_info/device_info_service_unittest.cc b/chrome/browser/chromeos/chromebox_for_meetings/device_info/device_info_service_unittest.cc
index cf9f7ae5..344bba6 100644
--- a/chrome/browser/chromeos/chromebox_for_meetings/device_info/device_info_service_unittest.cc
+++ b/chrome/browser/chromeos/chromebox_for_meetings/device_info/device_info_service_unittest.cc
@@ -50,7 +50,7 @@
         new ownership::MockOwnerKeyUtil());
     owner_key_util_->SetPublicKeyFromPrivateKey(
         *device_policy_.GetSigningKey());
-    chromeos::DeviceSettingsService::Get()->SetSessionManager(
+    ash::DeviceSettingsService::Get()->SetSessionManager(
         &session_manager_client_, owner_key_util_);
 
     CfmHotlineClient::InitializeFake();
@@ -62,7 +62,7 @@
   void TearDown() override {
     DeviceInfoService::Shutdown();
     CfmHotlineClient::Shutdown();
-    chromeos::DeviceSettingsService::Get()->UnsetSessionManager();
+    ash::DeviceSettingsService::Get()->UnsetSessionManager();
   }
 
   FakeCfmHotlineClient* GetClient() {
@@ -80,7 +80,7 @@
     device_policy_.policy_data().set_gaia_id(base::NumberToString(gaia_id));
     device_policy_.Build();
     session_manager_client_.set_device_policy(device_policy_.GetBlob());
-    chromeos::DeviceSettingsService::Get()->Load();
+    ash::DeviceSettingsService::Get()->Load();
     content::RunAllTasksUntilIdle();
   }
 
@@ -131,7 +131,7 @@
   mojo::Remote<mojom::MeetDevicesInfo> device_info_remote_;
   mojo::ReceiverSet<mojom::CfmServiceContext> context_receiver_set_;
   mojo::Remote<mojom::CfmServiceAdaptor> adaptor_remote_;
-  chromeos::ScopedTestDeviceSettingsService scoped_device_settings_service_;
+  ash::ScopedTestDeviceSettingsService scoped_device_settings_service_;
   chromeos::FakeSessionManagerClient session_manager_client_;
   FakeServiceConnectionImpl fake_service_connection_;
   policy::DevicePolicyBuilder device_policy_;
diff --git a/chrome/browser/chromeos/chromebox_for_meetings/logger/reporting_pipeline.cc b/chrome/browser/chromeos/chromebox_for_meetings/logger/reporting_pipeline.cc
index 3035a49..19de52e 100644
--- a/chrome/browser/chromeos/chromebox_for_meetings/logger/reporting_pipeline.cc
+++ b/chrome/browser/chromeos/chromebox_for_meetings/logger/reporting_pipeline.cc
@@ -47,14 +47,14 @@
 }
 
 void ReportingPipeline::Init() {
-  CHECK(chromeos::DeviceSettingsService::IsInitialized());
-  chromeos::DeviceSettingsService::Get()->AddObserver(this);
+  CHECK(ash::DeviceSettingsService::IsInitialized());
+  ash::DeviceSettingsService::Get()->AddObserver(this);
   // Device settings update may not be triggered in some cases
   DeviceSettingsUpdated();
 }
 
 void ReportingPipeline::Reset() {
-  chromeos::DeviceSettingsService::Get()->RemoveObserver(this);
+  ash::DeviceSettingsService::Get()->RemoveObserver(this);
   dm_token_.clear();
   update_status_callback_.Run(mojom::LoggerState::kUninitialized);
 }
@@ -81,7 +81,7 @@
 }
 
 void ReportingPipeline::DeviceSettingsUpdated() {
-  auto* policy_data = chromeos::DeviceSettingsService::Get()->policy_data();
+  auto* policy_data = ash::DeviceSettingsService::Get()->policy_data();
 
   if (!policy_data || !policy_data->has_request_token() ||
       policy_data->request_token().empty()) {
diff --git a/chrome/browser/chromeos/chromebox_for_meetings/logger/reporting_pipeline.h b/chrome/browser/chromeos/chromebox_for_meetings/logger/reporting_pipeline.h
index 3a71f48..079e3073 100644
--- a/chrome/browser/chromeos/chromebox_for_meetings/logger/reporting_pipeline.h
+++ b/chrome/browser/chromeos/chromebox_for_meetings/logger/reporting_pipeline.h
@@ -19,7 +19,7 @@
 // Implementation of the CfmLoggerService::Delegate usign the chrome encrypted
 // reporting pipeline.
 class ReportingPipeline : public CfmLoggerService::Delegate,
-                          public chromeos::DeviceSettingsService::Observer {
+                          public ash::DeviceSettingsService::Observer {
  public:
   // Args: mojom::MeetDevicesLogger: The current enabled state of the service.
   using UpdateStatusCallback =
@@ -38,7 +38,7 @@
                CfmLoggerService::EnqueueCallback callback) override;
 
  protected:
-  // ::chromeos::DeviceSettingsService::Observer impl
+  // ::ash::DeviceSettingsService::Observer impl
   void DeviceSettingsUpdated() override;
   void OnDeviceSettingsServiceShutdown() override;
 
diff --git a/chrome/browser/chromeos/crostini/crostini_features.cc b/chrome/browser/chromeos/crostini/crostini_features.cc
index 3a0cc82a..0148778 100644
--- a/chrome/browser/chromeos/crostini/crostini_features.cc
+++ b/chrome/browser/chromeos/crostini/crostini_features.cc
@@ -26,7 +26,7 @@
 
 bool IsUnaffiliatedCrostiniAllowedByPolicy() {
   bool unaffiliated_crostini_allowed;
-  if (chromeos::CrosSettings::Get()->GetBoolean(
+  if (ash::CrosSettings::Get()->GetBoolean(
           chromeos::kDeviceUnaffiliatedCrostiniAllowed,
           &unaffiliated_crostini_allowed)) {
     return unaffiliated_crostini_allowed;
@@ -64,7 +64,7 @@
   auto repeating_callback =
       base::AdaptCallbackForRepeating(std::move(callback));
 
-  auto* const cros_settings = chromeos::CrosSettings::Get();
+  auto* const cros_settings = ash::CrosSettings::Get();
   auto status = cros_settings->PrepareTrustedValues(base::BindOnce(
       &CanChangeAdbSideloadingOnManagedDevice, repeating_callback,
       is_profile_enterprise_managed, is_affiliated_user, user_policy));
diff --git a/chrome/browser/chromeos/crostini/crostini_features_unittest.cc b/chrome/browser/chromeos/crostini/crostini_features_unittest.cc
index dd77a30..8a2f6a5 100644
--- a/chrome/browser/chromeos/crostini/crostini_features_unittest.cc
+++ b/chrome/browser/chromeos/crostini/crostini_features_unittest.cc
@@ -248,7 +248,7 @@
   TestingProfile profile_;
   FakeCrostiniFeatures crostini_features_;
   base::test::ScopedFeatureList scoped_feature_list_;
-  chromeos::ScopedCrosSettingsTestHelper scoped_settings_helper_{
+  ash::ScopedCrosSettingsTestHelper scoped_settings_helper_{
       /* create_settings_service=*/false};
 
   chromeos::FakeChromeUserManager* user_manager_;
diff --git a/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc b/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
index 1c70953..5c1a01d 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
+++ b/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
@@ -383,7 +383,7 @@
   fake_user_manager()->LoginUser(account_id);
 
   // Set DeviceRebootOnUserSignout to always.
-  chromeos::ScopedCrosSettingsTestHelper settings_helper{
+  ash::ScopedCrosSettingsTestHelper settings_helper{
       /* create_settings_service=*/false};
   settings_helper.ReplaceDeviceSettingsProviderWithStub();
   settings_helper.SetInteger(
@@ -418,7 +418,7 @@
   fake_user_manager()->LoginUser(account_id);
 
   // Set DeviceRebootOnUserSignout to always.
-  chromeos::ScopedCrosSettingsTestHelper settings_helper{
+  ash::ScopedCrosSettingsTestHelper settings_helper{
       /* create_settings_service=*/false};
   settings_helper.ReplaceDeviceSettingsProviderWithStub();
   settings_helper.SetInteger(
diff --git a/chrome/browser/chromeos/display/quirks_manager_delegate_impl.cc b/chrome/browser/chromeos/display/quirks_manager_delegate_impl.cc
index 84cee99..9db2487 100644
--- a/chrome/browser/chromeos/display/quirks_manager_delegate_impl.cc
+++ b/chrome/browser/chromeos/display/quirks_manager_delegate_impl.cc
@@ -38,8 +38,8 @@
 
 bool QuirksManagerDelegateImpl::DevicePolicyEnabled() const {
   bool quirks_enabled = true;
-  chromeos::CrosSettings::Get()->GetBoolean(
-      chromeos::kDeviceQuirksDownloadEnabled, &quirks_enabled);
+  ash::CrosSettings::Get()->GetBoolean(chromeos::kDeviceQuirksDownloadEnabled,
+                                       &quirks_enabled);
   return quirks_enabled;
 }
 
diff --git a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
index 48e1aaf0..21d7496 100644
--- a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
+++ b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
@@ -4376,15 +4376,15 @@
   Profile* profile = Profile::FromBrowserContext(browser_context());
 
   bool value;
-  if (chromeos::CrosSettings::Get()->GetBoolean(chromeos::kStatsReportingPref,
-                                                &value) &&
+  if (ash::CrosSettings::Get()->GetBoolean(chromeos::kStatsReportingPref,
+                                           &value) &&
       value == target_value_) {
     VLOG(1) << "Value at target; returning early";
     return RespondNow(NoArguments());
   }
 
-  chromeos::StatsReportingController* stats_reporting_controller =
-      chromeos::StatsReportingController::Get();
+  ash::StatsReportingController* stats_reporting_controller =
+      ash::StatsReportingController::Get();
 
   stats_reporting_controller->SetOnDeviceSettingsStoredCallBack(base::BindOnce(
       &AutotestPrivateSetMetricsEnabledFunction::OnDeviceSettingsStored, this));
@@ -4397,8 +4397,8 @@
 
 void AutotestPrivateSetMetricsEnabledFunction::OnDeviceSettingsStored() {
   bool actual;
-  if (!chromeos::CrosSettings::Get()->GetBoolean(chromeos::kStatsReportingPref,
-                                                 &actual)) {
+  if (!ash::CrosSettings::Get()->GetBoolean(chromeos::kStatsReportingPref,
+                                            &actual)) {
     NOTREACHED() << "AutotestPrivateSetMetricsEnabledFunction: "
                  << "kStatsReportingPref should be set";
     Respond(Error(base::StrCat(
diff --git a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_apitest.cc b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_apitest.cc
index a8adae7..3de106d 100644
--- a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_apitest.cc
+++ b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_apitest.cc
@@ -76,7 +76,7 @@
         ->set_test_mode(true);
   }
 
-  chromeos::ScopedTestingCrosSettings scoped_testing_cros_settings_;
+  ash::ScopedTestingCrosSettings scoped_testing_cros_settings_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(AutotestPrivateApiTest);
diff --git a/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader_unittest.cc b/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader_unittest.cc
index e5b534f..3d40feb8 100644
--- a/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader_unittest.cc
+++ b/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader_unittest.cc
@@ -185,7 +185,7 @@
   content::InProcessUtilityThreadHelper in_process_utility_thread_helper_;
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  chromeos::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
+  ash::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 };
 
diff --git a/chrome/browser/chromeos/extensions/echo_private_api.cc b/chrome/browser/chromeos/extensions/echo_private_api.cc
index 387c029..9834ce4b 100644
--- a/chrome/browser/chromeos/extensions/echo_private_api.cc
+++ b/chrome/browser/chromeos/extensions/echo_private_api.cc
@@ -216,13 +216,13 @@
 
 void EchoPrivateGetUserConsentFunction::CheckRedeemOffersAllowed() {
   chromeos::CrosSettingsProvider::TrustedStatus status =
-      chromeos::CrosSettings::Get()->PrepareTrustedValues(base::BindOnce(
+      ash::CrosSettings::Get()->PrepareTrustedValues(base::BindOnce(
           &EchoPrivateGetUserConsentFunction::CheckRedeemOffersAllowed, this));
   if (status == chromeos::CrosSettingsProvider::TEMPORARILY_UNTRUSTED)
     return;
 
   bool allow = true;
-  chromeos::CrosSettings::Get()->GetBoolean(
+  ash::CrosSettings::Get()->GetBoolean(
       chromeos::kAllowRedeemChromeOsRegistrationOffers, &allow);
 
   OnRedeemOffersAllowedChecked(allow);
diff --git a/chrome/browser/chromeos/extensions/info_private_api.cc b/chrome/browser/chromeos/extensions/info_private_api.cc
index 6cf28902..b72095b 100644
--- a/chrome/browser/chromeos/extensions/info_private_api.cc
+++ b/chrome/browser/chromeos/extensions/info_private_api.cc
@@ -409,7 +409,7 @@
     }
     // TODO(crbug.com/697817): Convert CrosSettings::Get to take a unique_ptr.
     return base::WrapUnique<base::Value>(
-        chromeos::CrosSettings::Get()
+        ash::CrosSettings::Get()
             ->GetPref(chromeos::kSystemTimezone)
             ->DeepCopy());
   }
diff --git a/chrome/browser/chromeos/extensions/login_screen/login_screen_ui/login_screen_ui_api.cc b/chrome/browser/chromeos/extensions/login_screen/login_screen_ui/login_screen_ui_api.cc
index 9d3070d..a478ac313 100644
--- a/chrome/browser/chromeos/extensions/login_screen/login_screen_ui/login_screen_ui_api.cc
+++ b/chrome/browser/chromeos/extensions/login_screen/login_screen_ui/login_screen_ui_api.cc
@@ -37,14 +37,21 @@
 LoginScreenUiCloseFunction::~LoginScreenUiCloseFunction() = default;
 
 ExtensionFunction::ResponseAction LoginScreenUiCloseFunction::Run() {
-  std::string error;
-  bool success =
-      chromeos::login_screen_extension_ui::UiHandler::Get(true /*can_create*/)
-          ->Close(extension(), &error);
+  chromeos::login_screen_extension_ui::UiHandler::Get(true /*can_create*/)
+      ->Close(extension(),
+              base::BindOnce(&LoginScreenUiCloseFunction::OnClosed, this));
+  // UiHandler::Close() repsonds asynchronously for success, but not for error.
+  return did_respond() ? AlreadyResponded() : RespondLater();
+}
 
-  if (!success)
-    return RespondNow(Error(error));
-  return RespondNow(NoArguments());
+void LoginScreenUiCloseFunction::OnClosed(
+    bool success,
+    const base::Optional<std::string>& error) {
+  if (!success) {
+    Respond(Error(error.value()));
+    return;
+  }
+  Respond(NoArguments());
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/chromeos/extensions/login_screen/login_screen_ui/login_screen_ui_api.h b/chrome/browser/chromeos/extensions/login_screen/login_screen_ui/login_screen_ui_api.h
index 8d5f2cb2..6dd3882d 100644
--- a/chrome/browser/chromeos/extensions/login_screen/login_screen_ui/login_screen_ui_api.h
+++ b/chrome/browser/chromeos/extensions/login_screen/login_screen_ui/login_screen_ui_api.h
@@ -38,6 +38,9 @@
   ResponseAction Run() override;
 
  private:
+  // Callback upon completion of window closing.
+  void OnClosed(bool success, const base::Optional<std::string>& error);
+
   DISALLOW_COPY_AND_ASSIGN(LoginScreenUiCloseFunction);
 };
 
diff --git a/chrome/browser/chromeos/extensions/login_screen/login_screen_ui/ui_handler.cc b/chrome/browser/chromeos/extensions/login_screen/login_screen_ui/ui_handler.cc
index 6f801a7..071e8dd 100644
--- a/chrome/browser/chromeos/extensions/login_screen/login_screen_ui/ui_handler.cc
+++ b/chrome/browser/chromeos/extensions/login_screen/login_screen_ui/ui_handler.cc
@@ -125,7 +125,7 @@
   CreateOptions create_options(
       GetHardcodedExtensionName(extension),
       extension->GetResourceURL(resource_path), can_be_closed_by_user,
-      base::BindOnce(base::IgnoreResult(&UiHandler::RemoveWindowForExtension),
+      base::BindOnce(base::IgnoreResult(&UiHandler::OnWindowClosed),
                      weak_ptr_factory_.GetWeakPtr(), extension->id()));
 
   current_window_ = std::make_unique<ExtensionIdToWindowMapping>(
@@ -134,26 +134,42 @@
   return true;
 }
 
-bool UiHandler::Close(const extensions::Extension* extension,
-                      std::string* error) {
+void UiHandler::Close(const extensions::Extension* extension,
+                      WindowClosedCallback close_callback) {
   CHECK(CanUseLoginScreenUiApi(extension));
-  if (!RemoveWindowForExtension(extension->id())) {
-    *error = kErrorNoExistingWindow;
-    return false;
-  }
-  return true;
+  close_callback_ = std::move(close_callback);
+  RemoveWindowForExtension(extension->id());
 }
 
-bool UiHandler::RemoveWindowForExtension(const std::string& extension_id) {
+void UiHandler::RemoveWindowForExtension(const std::string& extension_id) {
+  if (!HasOpenWindow(extension_id)) {
+    if (!close_callback_.is_null()) {
+      std::move(close_callback_).Run(/*success=*/false, kErrorNoExistingWindow);
+      close_callback_.Reset();
+    }
+    return;
+  }
+
+  ResetWindowAndHide();
+}
+
+void UiHandler::OnWindowClosed(const std::string& extension_id) {
+  if (!close_callback_.is_null()) {
+    std::move(close_callback_).Run(/*success=*/true, base::nullopt);
+    close_callback_.Reset();
+  }
+
   if (!HasOpenWindow(extension_id))
-    return false;
+    return;
 
-  current_window_.reset(nullptr);
+  ResetWindowAndHide();
+}
 
+void UiHandler::ResetWindowAndHide() {
   ash::LoginScreen::Get()->GetModel()->NotifyOobeDialogState(
       ash::OobeDialogState::HIDDEN);
 
-  return true;
+  current_window_.reset(nullptr);
 }
 
 bool UiHandler::HasOpenWindow(const std::string& extension_id) const {
diff --git a/chrome/browser/chromeos/extensions/login_screen/login_screen_ui/ui_handler.h b/chrome/browser/chromeos/extensions/login_screen/login_screen_ui/ui_handler.h
index 34c5bc9..b6f227b3 100644
--- a/chrome/browser/chromeos/extensions/login_screen/login_screen_ui/ui_handler.h
+++ b/chrome/browser/chromeos/extensions/login_screen/login_screen_ui/ui_handler.h
@@ -8,6 +8,7 @@
 #include <memory>
 #include <string>
 
+#include "base/callback.h"
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observer.h"
 #include "components/session_manager/core/session_manager.h"
@@ -45,6 +46,10 @@
 class UiHandler : public session_manager::SessionManagerObserver,
                   public extensions::ExtensionRegistryObserver {
  public:
+  using WindowClosedCallback =
+      base::OnceCallback<void(bool success,
+                              const base::Optional<std::string>& error)>;
+
   static UiHandler* Get(bool can_create);
   static void Shutdown();
 
@@ -60,13 +65,18 @@
 
   // Endpoint for calls to the chrome.loginScreenUi.close() API. If an error
   // occurs, |error| will contain the error description.
-  bool Close(const extensions::Extension* extension, std::string* error);
+  void Close(const extensions::Extension* extension,
+             WindowClosedCallback close_callback);
 
-  // Removes and closes the window for the given |extension_id|. This is also
-  // passed as close callback to the windows during creation to detect when a
-  // window was manually closed by the user. Returns true, if a window was
-  // closed.
-  bool RemoveWindowForExtension(const std::string& extension_id);
+  // Removes and closes the window for the given |extension_id|.
+  void RemoveWindowForExtension(const std::string& extension_id);
+
+  // Is passed as close callback to the windows during creation to detect when a
+  // window was manually closed by the user.
+  void OnWindowClosed(const std::string& extension_id);
+
+  // Resets the current window and sets the OOBE dialog state to HIDDEN.
+  void ResetWindowAndHide();
 
   bool HasOpenWindow(const std::string& extension_id) const;
 
@@ -96,6 +106,8 @@
 
   std::unique_ptr<ExtensionIdToWindowMapping> current_window_;
 
+  WindowClosedCallback close_callback_;
+
   ScopedObserver<session_manager::SessionManager,
                  session_manager::SessionManagerObserver>
       session_manager_observer_{this};
diff --git a/chrome/browser/chromeos/extensions/login_screen/login_screen_ui/ui_handler_unittest.cc b/chrome/browser/chromeos/extensions/login_screen/login_screen_ui/ui_handler_unittest.cc
index 43d74118..4fb243c 100644
--- a/chrome/browser/chromeos/extensions/login_screen/login_screen_ui/ui_handler_unittest.cc
+++ b/chrome/browser/chromeos/extensions/login_screen/login_screen_ui/ui_handler_unittest.cc
@@ -7,9 +7,10 @@
 #include <memory>
 
 #include "base/test/gtest_util.h"
-#include "chrome/browser/ash/settings/scoped_cros_settings_test_helper.h"
+#include "base/test/mock_callback.h"
 #include "chrome/browser/ash/login/ui/login_screen_extension_ui/create_options.h"
 #include "chrome/browser/ash/login/ui/login_screen_extension_ui/window.h"
+#include "chrome/browser/ash/settings/scoped_cros_settings_test_helper.h"
 #include "chrome/browser/ui/ash/test_login_screen.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/test/base/testing_browser_process.h"
@@ -157,9 +158,13 @@
   }
 
   void CheckCanCloseWindow(const extensions::Extension* extension) {
-    std::string error;
-    EXPECT_TRUE(ui_handler_->Close(extension, &error));
-    EXPECT_TRUE(error.empty());
+    base::MockCallback<UiHandler::WindowClosedCallback> callback;
+    EXPECT_CALL(callback,
+                Run(true, base::Optional<std::string>(base::nullopt)));
+    ui_handler_->Close(extension, callback.Get());
+    // Invoke close callback from dialog delegate because UiHandler::Close() is
+    // synchronous and will invoke its callback after that.
+    fake_window_factory_->RunLastCloseCallback();
     EXPECT_FALSE(ui_handler_->HasOpenWindow(extension->id()));
   }
 
@@ -175,9 +180,12 @@
 
   void CheckCannotCloseWindow(const extensions::Extension* extension,
                               const std::string& expected_error) {
-    std::string error;
-    EXPECT_FALSE(ui_handler_->Close(extension, &error));
-    EXPECT_EQ(expected_error, error);
+    base::MockCallback<UiHandler::WindowClosedCallback> callback;
+    EXPECT_CALL(callback,
+                Run(false, base::Optional<std::string>(expected_error)));
+    ui_handler_->Close(extension, callback.Get());
+    // No need to invoke the close callback here since in case of no open window
+    // we directly invoke the callback with an error.
   }
 
   void CheckCannotUseAPI(const extensions::Extension* extension) {
diff --git a/chrome/browser/chromeos/extensions/users_private/users_private_api.cc b/chrome/browser/chromeos/extensions/users_private/users_private_api.cc
index 23f2230..4d812913 100644
--- a/chrome/browser/chromeos/extensions/users_private/users_private_api.cc
+++ b/chrome/browser/chromeos/extensions/users_private/users_private_api.cc
@@ -62,7 +62,7 @@
 }
 
 bool IsExistingUser(const std::string& username) {
-  return chromeos::CrosSettings::Get()->FindEmailInList(
+  return ash::CrosSettings::Get()->FindEmailInList(
       chromeos::kAccountsPrefUsers, username, /*wildcard_match=*/nullptr);
 }
 
diff --git a/chrome/browser/chromeos/extensions/users_private/users_private_apitest.cc b/chrome/browser/chromeos/extensions/users_private/users_private_apitest.cc
index 9305871..3f468cd 100644
--- a/chrome/browser/chromeos/extensions/users_private/users_private_apitest.cc
+++ b/chrome/browser/chromeos/extensions/users_private/users_private_apitest.cc
@@ -158,7 +158,7 @@
 
  private:
   chromeos::ScopedStubInstallAttributes scoped_stub_install_attributes_;
-  chromeos::ScopedTestingCrosSettings scoped_testing_cros_settings_;
+  ash::ScopedTestingCrosSettings scoped_testing_cros_settings_;
 
   DISALLOW_COPY_AND_ASSIGN(UsersPrivateApiTest);
 };
diff --git a/chrome/browser/chromeos/extensions/wallpaper_private_api_unittest.cc b/chrome/browser/chromeos/extensions/wallpaper_private_api_unittest.cc
index 8fe19ab..76bb73a 100644
--- a/chrome/browser/chromeos/extensions/wallpaper_private_api_unittest.cc
+++ b/chrome/browser/chromeos/extensions/wallpaper_private_api_unittest.cc
@@ -53,7 +53,7 @@
  private:
   std::unique_ptr<content::BrowserTaskEnvironment> task_environment_;
 
-  chromeos::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
+  ash::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
 
   chromeos::FakeChromeUserManager* fake_user_manager_;
 
diff --git a/chrome/browser/chromeos/feature_usage_metrics/feature_usage_metrics.cc b/chrome/browser/chromeos/feature_usage_metrics/feature_usage_metrics.cc
new file mode 100644
index 0000000..93ebb85f
--- /dev/null
+++ b/chrome/browser/chromeos/feature_usage_metrics/feature_usage_metrics.cc
@@ -0,0 +1,110 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/feature_usage_metrics/feature_usage_metrics.h"
+
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/metrics/histogram_functions.h"
+#include "components/metrics/daily_event.h"
+
+namespace chromeos {
+
+namespace {
+
+// Interval for asking metrics::DailyEvent to check whether a day has passed.
+constexpr base::TimeDelta kCheckDailyEventInternal =
+    base::TimeDelta::FromMinutes(30);
+
+constexpr char kDailySamplePrefPrefix[] = "feature_usage.daily_sample.";
+constexpr char kFeatureUsageMetricPrefix[] = "ChromeOS.FeatureUsage.";
+
+std::string FeatureToPref(const std::string& feature_name) {
+  return kDailySamplePrefPrefix + feature_name;
+}
+
+std::string FeatureToHistogram(const std::string& feature_name) {
+  return kFeatureUsageMetricPrefix + feature_name;
+}
+
+// `DailyEventObserver` implements `metrics::DailyEvent::Observer`. It runs
+// `callback_` on the first usage and when the day has passed.
+class DailyEventObserver : public metrics::DailyEvent::Observer {
+ public:
+  explicit DailyEventObserver(base::RepeatingClosure callback)
+      : callback_(std::move(callback)) {
+    DCHECK(callback_);
+  }
+
+  DailyEventObserver(const DailyEventObserver&) = delete;
+  DailyEventObserver& operator=(const DailyEventObserver&) = delete;
+  ~DailyEventObserver() override = default;
+
+  // metrics::DailyEvent::Observer:
+  void OnDailyEvent(metrics::DailyEvent::IntervalType type) final {
+    if (type == metrics::DailyEvent::IntervalType::DAY_ELAPSED ||
+        type == metrics::DailyEvent::IntervalType::FIRST_RUN) {
+      callback_.Run();
+    }
+  }
+
+ private:
+  base::RepeatingClosure callback_;
+};
+
+}  // namespace
+
+FeatureUsageMetrics::FeatureUsageMetrics(const std::string& feature_name,
+                                         PrefService* pref_service,
+                                         Delegate* const delegate)
+    : FeatureUsageMetrics(feature_name, pref_service, delegate, nullptr) {}
+
+FeatureUsageMetrics::FeatureUsageMetrics(const std::string& feature_name,
+                                         PrefService* pref_service,
+                                         Delegate* const delegate,
+                                         const base::TickClock* tick_clock)
+    : histogram_name_(FeatureToHistogram(feature_name)),
+      pref_name_(FeatureToPref(feature_name)),
+      delegate_(delegate),
+      timer_(tick_clock ? std::make_unique<base::RepeatingTimer>(tick_clock)
+                        : std::make_unique<base::RepeatingTimer>()) {
+  DCHECK(delegate_);
+
+  daily_event_ = std::make_unique<metrics::DailyEvent>(
+      pref_service, pref_name_.c_str(), /*histogram_name=*/std::string());
+
+  auto observer = std::make_unique<DailyEventObserver>(base::BindRepeating(
+      // base::Unretained is safe because `this` owns `daily_event_` which owns
+      // the `observer`.
+      &FeatureUsageMetrics::ReportDailyMetrics, base::Unretained(this)));
+
+  daily_event_->AddObserver(std::move(observer));
+  daily_event_->CheckInterval();
+  timer_->Start(FROM_HERE, kCheckDailyEventInternal, daily_event_.get(),
+                &metrics::DailyEvent::CheckInterval);
+}
+
+FeatureUsageMetrics::~FeatureUsageMetrics() = default;
+
+// static
+void FeatureUsageMetrics::RegisterPref(PrefRegistrySimple* registry,
+                                       const std::string& feature_name) {
+  metrics::DailyEvent::RegisterPref(registry, FeatureToPref(feature_name));
+}
+
+void FeatureUsageMetrics::RecordUsage(bool success) const {
+  Event e = success ? Event::kUsedWithSucess : Event::kUsedWithFailure;
+  base::UmaHistogramEnumeration(histogram_name_, e);
+}
+
+void FeatureUsageMetrics::ReportDailyMetrics() const {
+  if (delegate_->IsEligible())
+    base::UmaHistogramEnumeration(histogram_name_, Event::kEligible);
+  if (delegate_->IsEnabled()) {
+    DCHECK(delegate_->IsEligible());
+    base::UmaHistogramEnumeration(histogram_name_, Event::kEnabled);
+  }
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/feature_usage_metrics/feature_usage_metrics.h b/chrome/browser/chromeos/feature_usage_metrics/feature_usage_metrics.h
new file mode 100644
index 0000000..5ee4270
--- /dev/null
+++ b/chrome/browser/chromeos/feature_usage_metrics/feature_usage_metrics.h
@@ -0,0 +1,90 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_FEATURE_USAGE_METRICS_FEATURE_USAGE_METRICS_H_
+#define CHROME_BROWSER_CHROMEOS_FEATURE_USAGE_METRICS_FEATURE_USAGE_METRICS_H_
+
+#include <memory>
+
+#include "base/observer_list.h"
+#include "base/time/tick_clock.h"
+#include "base/timer/timer.h"
+
+class PrefRegistrySimple;
+class PrefService;
+
+namespace metrics {
+class DailyEvent;
+}
+
+namespace chromeos {
+
+// Helper class to unify tracking features usage by users.
+// It provides unified naming for the tracked events. Which reduces effort on
+// the data analytics side to incorporate a new feature.
+// This class also provides a way to report daily if the device is eligible for
+// the feature and whether user has it enabled.
+class FeatureUsageMetrics {
+ public:
+  // These values are persisted to logs. Entries should not be renumbered and
+  // numeric values should never be reused.
+  enum class Event {
+    kEligible = 0,
+    kEnabled = 1,
+    kUsedWithSucess = 2,
+    kUsedWithFailure = 3,
+    kMaxValue = kUsedWithFailure,
+  };
+
+  // Consumers should implement this interface to report daily if the feature
+  // is eligible on the device and enabled.
+  class Delegate {
+   public:
+    // Whether the device is capable of running the feature.
+    virtual bool IsEligible() const = 0;
+
+    // Whether the user has enabled the feature for themselves. If `IsEnabled`
+    // returns true `IsEligible` must return true too.
+    virtual bool IsEnabled() const = 0;
+
+    virtual ~Delegate() = default;
+  };
+
+  // `feature_name` and `pref_service` must correspond to the `RegisterPref`
+  // call.
+  FeatureUsageMetrics(const std::string& feature_name,
+                      PrefService* pref_service,
+                      Delegate* delegate);
+  FeatureUsageMetrics(const std::string& feature_name,
+                      PrefService* pref_service,
+                      Delegate* delegate,
+                      const base::TickClock* tick_clock);
+  FeatureUsageMetrics(const FeatureUsageMetrics&) = delete;
+  FeatureUsageMetrics& operator=(const FeatureUsageMetrics&) = delete;
+  ~FeatureUsageMetrics();
+
+  // `RecordUsage` should be called on every usage of the feature. `success`
+  // indicates whether the usage was successful. For example if user touches the
+  // fingerprint sensor and the finger was not recognized `RecordUsage` should
+  // be called with `false`.
+  void RecordUsage(bool success) const;
+
+  static void RegisterPref(PrefRegistrySimple* registry,
+                           const std::string& feature_name);
+
+ private:
+  void ReportDailyMetrics() const;
+
+  const std::string histogram_name_;
+  const std::string pref_name_;
+  const Delegate* const delegate_;
+  std::unique_ptr<metrics::DailyEvent> daily_event_;
+
+  // Instructs |daily_event_| to check if a day has passed.
+  std::unique_ptr<base::RepeatingTimer> timer_;
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_FEATURE_USAGE_METRICS_FEATURE_USAGE_METRICS_H_
diff --git a/chrome/browser/chromeos/feature_usage_metrics/feature_usage_metrics_unittest.cc b/chrome/browser/chromeos/feature_usage_metrics/feature_usage_metrics_unittest.cc
new file mode 100644
index 0000000..b2b472d
--- /dev/null
+++ b/chrome/browser/chromeos/feature_usage_metrics/feature_usage_metrics_unittest.cc
@@ -0,0 +1,94 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/feature_usage_metrics/feature_usage_metrics.h"
+
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/task_environment.h"
+#include "base/time/clock.h"
+#include "base/time/time.h"
+#include "components/prefs/testing_pref_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+
+namespace {
+
+const char kTestFeature[] = "TestFeature";
+const char kTestMetric[] = "ChromeOS.FeatureUsage.TestFeature";
+
+}  // namespace
+
+class FeatureUsageMetricsTest : public ::testing::Test,
+                                public FeatureUsageMetrics::Delegate {
+ public:
+  FeatureUsageMetricsTest() {
+    FeatureUsageMetrics::RegisterPref(prefs_.registry(), kTestFeature);
+    ResetHistogramTester();
+    feature_usage_metrics_ = std::make_unique<FeatureUsageMetrics>(
+        kTestFeature, &prefs_, this, env_.GetMockTickClock());
+  }
+
+  // FeatureUsageMetrics::Delegate:
+  bool IsEligible() const override { return is_eligible_; }
+  bool IsEnabled() const override { return is_enabled_; }
+
+ protected:
+  void ResetHistogramTester() {
+    histogram_tester_ = std::make_unique<base::HistogramTester>();
+  }
+
+  base::test::TaskEnvironment env_{
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+
+  bool is_eligible_ = true;
+  bool is_enabled_ = true;
+
+  std::unique_ptr<base::HistogramTester> histogram_tester_;
+
+  TestingPrefServiceSimple prefs_;
+  std::unique_ptr<FeatureUsageMetrics> feature_usage_metrics_;
+};
+
+TEST_F(FeatureUsageMetricsTest, RecordUsageWithSuccess) {
+  feature_usage_metrics_->RecordUsage(/*success=*/true);
+  histogram_tester_->ExpectBucketCount(
+      kTestMetric,
+      static_cast<int>(FeatureUsageMetrics::Event::kUsedWithSucess), 1);
+}
+
+TEST_F(FeatureUsageMetricsTest, RecordUsageWithFailure) {
+  feature_usage_metrics_->RecordUsage(/*success=*/false);
+  histogram_tester_->ExpectBucketCount(
+      kTestMetric,
+      static_cast<int>(FeatureUsageMetrics::Event::kUsedWithFailure), 1);
+}
+
+TEST_F(FeatureUsageMetricsTest, DailyMetricsTest) {
+  // Initial metrics should be reported on IntervalType::FIRST_RUN.
+  histogram_tester_->ExpectBucketCount(
+      kTestMetric, static_cast<int>(FeatureUsageMetrics::Event::kEligible), 1);
+  histogram_tester_->ExpectBucketCount(
+      kTestMetric, static_cast<int>(FeatureUsageMetrics::Event::kEnabled), 1);
+
+  ResetHistogramTester();
+  is_enabled_ = false;
+  // Trigger IntervalType::DAY_ELAPSED event.
+  env_.FastForwardBy(base::TimeDelta::FromHours(24));
+  histogram_tester_->ExpectBucketCount(
+      kTestMetric, static_cast<int>(FeatureUsageMetrics::Event::kEligible), 1);
+  histogram_tester_->ExpectBucketCount(
+      kTestMetric, static_cast<int>(FeatureUsageMetrics::Event::kEnabled), 0);
+
+  ResetHistogramTester();
+  is_eligible_ = false;
+  // Trigger IntervalType::DAY_ELAPSED event.
+  env_.FastForwardBy(base::TimeDelta::FromHours(24));
+  histogram_tester_->ExpectBucketCount(
+      kTestMetric, static_cast<int>(FeatureUsageMetrics::Event::kEligible), 0);
+  histogram_tester_->ExpectBucketCount(
+      kTestMetric, static_cast<int>(FeatureUsageMetrics::Event::kEnabled), 0);
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc b/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc
index e21c4d3..bfa4beb 100644
--- a/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc
+++ b/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc
@@ -621,7 +621,7 @@
   };
 
   content::BrowserTaskEnvironment task_environment_;
-  chromeos::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
+  ash::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
   chromeos::ScopedTestUserManager test_user_manager_;
   TestingProfile test_profile_;
   base::CommandLine command_line_;
diff --git a/chrome/browser/chromeos/full_restore/full_restore_arc_task_handler.cc b/chrome/browser/chromeos/full_restore/full_restore_arc_task_handler.cc
index 761b1dfb..683e126 100644
--- a/chrome/browser/chromeos/full_restore/full_restore_arc_task_handler.cc
+++ b/chrome/browser/chromeos/full_restore/full_restore_arc_task_handler.cc
@@ -27,16 +27,17 @@
 
 FullRestoreArcTaskHandler::~FullRestoreArcTaskHandler() = default;
 
-void FullRestoreArcTaskHandler::OnTaskCreated(int task_id,
+void FullRestoreArcTaskHandler::OnTaskCreated(int32_t task_id,
                                               const std::string& package_name,
                                               const std::string& activity,
-                                              const std::string& intent) {
+                                              const std::string& intent,
+                                              int32_t session_id) {
   const std::string app_id = ArcAppListPrefs::GetAppId(package_name, activity);
-  ::full_restore::FullRestoreSaveHandler::GetInstance()->OnTaskCreated(app_id,
-                                                                       task_id);
+  ::full_restore::FullRestoreSaveHandler::GetInstance()->OnTaskCreated(
+      app_id, task_id, session_id);
 }
 
-void FullRestoreArcTaskHandler::OnTaskDestroyed(int task_id) {
+void FullRestoreArcTaskHandler::OnTaskDestroyed(int32_t task_id) {
   ::full_restore::FullRestoreSaveHandler::GetInstance()->OnTaskDestroyed(
       task_id);
 }
diff --git a/chrome/browser/chromeos/full_restore/full_restore_arc_task_handler.h b/chrome/browser/chromeos/full_restore/full_restore_arc_task_handler.h
index cb6e807..6d93e5a 100644
--- a/chrome/browser/chromeos/full_restore/full_restore_arc_task_handler.h
+++ b/chrome/browser/chromeos/full_restore/full_restore_arc_task_handler.h
@@ -35,10 +35,11 @@
   ~FullRestoreArcTaskHandler() override;
 
   // ArcAppListPrefs::Observer.
-  void OnTaskCreated(int task_id,
+  void OnTaskCreated(int32_t task_id,
                      const std::string& package_name,
                      const std::string& activity,
-                     const std::string& intent) override;
+                     const std::string& intent,
+                     int32_t session_id) override;
   void OnTaskDestroyed(int task_id) override;
 
  private:
diff --git a/chrome/browser/chromeos/lock_screen_apps/app_manager_impl_unittest.cc b/chrome/browser/chromeos/lock_screen_apps/app_manager_impl_unittest.cc
index 4c6dac0..277f242 100644
--- a/chrome/browser/chromeos/lock_screen_apps/app_manager_impl_unittest.cc
+++ b/chrome/browser/chromeos/lock_screen_apps/app_manager_impl_unittest.cc
@@ -450,7 +450,7 @@
   std::unique_ptr<base::test::ScopedCommandLine> command_line_;
   content::BrowserTaskEnvironment task_environment_;
 
-  chromeos::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
+  ash::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
   chromeos::ScopedTestUserManager user_manager_;
 
   TestingProfileManager profile_manager_;
diff --git a/chrome/browser/chromeos/lock_screen_apps/lock_screen_profile_creator_impl_unittest.cc b/chrome/browser/chromeos/lock_screen_apps/lock_screen_profile_creator_impl_unittest.cc
index dc1c725..d850241 100644
--- a/chrome/browser/chromeos/lock_screen_apps/lock_screen_profile_creator_impl_unittest.cc
+++ b/chrome/browser/chromeos/lock_screen_apps/lock_screen_profile_creator_impl_unittest.cc
@@ -358,7 +358,7 @@
   ScopedTestingLocalState local_state_;
   content::BrowserTaskEnvironment task_environment_;
 
-  chromeos::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
+  ash::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
   chromeos::ScopedTestUserManager test_user_manager_;
 
   UnittestProfileManager* profile_manager_;
diff --git a/chrome/browser/chromeos/ownership/fake_owner_settings_service.h b/chrome/browser/chromeos/ownership/fake_owner_settings_service.h
index d161718a..19a261f2 100644
--- a/chrome/browser/chromeos/ownership/fake_owner_settings_service.h
+++ b/chrome/browser/chromeos/ownership/fake_owner_settings_service.h
@@ -7,6 +7,9 @@
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+// TODO(https://crbug.com/1164001): forward declare StubCrosSettingsProvider
+// after //c/b/c/ownership is moved to ash.
+#include "chrome/browser/ash/settings/stub_cros_settings_provider.h"
 #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos.h"
 
 class Profile;
@@ -17,8 +20,6 @@
 
 namespace chromeos {
 
-class StubCrosSettingsProvider;
-
 class FakeOwnerSettingsService : public OwnerSettingsServiceChromeOS {
  public:
   FakeOwnerSettingsService(StubCrosSettingsProvider* provider,
diff --git a/chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.h b/chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.h
index 52b39bda..a733a85 100644
--- a/chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.h
+++ b/chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.h
@@ -10,6 +10,12 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/singleton.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+// TODO(https://crbug.com/1164001): forward declare DeviceSettingsService when
+// moved to ash.
+#include "chrome/browser/ash/settings/device_settings_service.h"
+// TODO(https://crbug.com/1164001): forward declare StubCrosSettingsProvider
+// when moved to ash.
+#include "chrome/browser/ash/settings/stub_cros_settings_provider.h"
 
 class KeyedService;
 
@@ -23,9 +29,7 @@
 
 namespace chromeos {
 
-class DeviceSettingsService;
 class OwnerSettingsServiceChromeOS;
-class StubCrosSettingsProvider;
 
 class OwnerSettingsServiceChromeOSFactory
     : public BrowserContextKeyedServiceFactory {
diff --git a/chrome/browser/chromeos/plugin_vm/plugin_vm_features.cc b/chrome/browser/chromeos/plugin_vm/plugin_vm_features.cc
index 75c160f..049f8396 100644
--- a/chrome/browser/chromeos/plugin_vm/plugin_vm_features.cc
+++ b/chrome/browser/chromeos/plugin_vm/plugin_vm_features.cc
@@ -92,8 +92,8 @@
 
   // Check that PluginVm is allowed to run by policy.
   bool plugin_vm_allowed_for_device;
-  if (!chromeos::CrosSettings::Get()->GetBoolean(
-          chromeos::kPluginVmAllowed, &plugin_vm_allowed_for_device)) {
+  if (!ash::CrosSettings::Get()->GetBoolean(chromeos::kPluginVmAllowed,
+                                            &plugin_vm_allowed_for_device)) {
     VLOG(1) << "Unable to determine Parallels device-level policy.";
     *reason = "Unable to determine if device-level policy allows running VMs";
     return false;
diff --git a/chrome/browser/chromeos/plugin_vm/plugin_vm_util.cc b/chrome/browser/chromeos/plugin_vm/plugin_vm_util.cc
index edbe425..e89a301 100644
--- a/chrome/browser/chromeos/plugin_vm/plugin_vm_util.cc
+++ b/chrome/browser/chromeos/plugin_vm/plugin_vm_util.cc
@@ -74,8 +74,8 @@
   if (FakeLicenseKeyIsSet())
     return GetFakeLicenseKey();
   std::string plugin_vm_license_key;
-  if (!chromeos::CrosSettings::Get()->GetString(chromeos::kPluginVmLicenseKey,
-                                                &plugin_vm_license_key)) {
+  if (!ash::CrosSettings::Get()->GetString(chromeos::kPluginVmLicenseKey,
+                                           &plugin_vm_license_key)) {
     return std::string();
   }
   return plugin_vm_license_key;
@@ -158,8 +158,8 @@
     Profile* profile,
     base::RepeatingCallback<void(bool)> callback)
     : profile_(profile), callback_(callback) {
-  DCHECK(chromeos::CrosSettings::IsInitialized());
-  chromeos::CrosSettings* cros_settings = chromeos::CrosSettings::Get();
+  DCHECK(ash::CrosSettings::IsInitialized());
+  ash::CrosSettings* cros_settings = ash::CrosSettings::Get();
   // Subscriptions are automatically removed when this object is destroyed.
   pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>();
   pref_change_registrar_->Init(profile->GetPrefs());
diff --git a/chrome/browser/chromeos/policy/adb_sideloading_allowance_mode_policy_handler.cc b/chrome/browser/chromeos/policy/adb_sideloading_allowance_mode_policy_handler.cc
index e7d903d..9f9bac1 100644
--- a/chrome/browser/chromeos/policy/adb_sideloading_allowance_mode_policy_handler.cc
+++ b/chrome/browser/chromeos/policy/adb_sideloading_allowance_mode_policy_handler.cc
@@ -32,7 +32,7 @@
     base::TimeDelta::FromDays(1);
 
 base::Optional<policy::AdbSideloadingAllowanceMode>
-GetAdbSideloadingDevicePolicyMode(const chromeos::CrosSettings* cros_settings,
+GetAdbSideloadingDevicePolicyMode(const ash::CrosSettings* cros_settings,
                                   const base::RepeatingClosure callback) {
   auto status = cros_settings->PrepareTrustedValues(callback);
 
@@ -85,7 +85,7 @@
 
 AdbSideloadingAllowanceModePolicyHandler::
     AdbSideloadingAllowanceModePolicyHandler(
-        chromeos::CrosSettings* cros_settings,
+        ash::CrosSettings* cros_settings,
         PrefService* local_state,
         chromeos::PowerManagerClient* power_manager_client,
         chromeos::AdbSideloadingPolicyChangeNotification*
diff --git a/chrome/browser/chromeos/policy/adb_sideloading_allowance_mode_policy_handler.h b/chrome/browser/chromeos/policy/adb_sideloading_allowance_mode_policy_handler.h
index d994426..783bf70 100644
--- a/chrome/browser/chromeos/policy/adb_sideloading_allowance_mode_policy_handler.h
+++ b/chrome/browser/chromeos/policy/adb_sideloading_allowance_mode_policy_handler.h
@@ -53,7 +53,7 @@
       chromeos::AdbSideloadingPolicyChangeNotification::Type;
 
   AdbSideloadingAllowanceModePolicyHandler(
-      chromeos::CrosSettings* cros_settings,
+      ash::CrosSettings* cros_settings,
       PrefService* local_state,
       chromeos::PowerManagerClient* power_manager_client,
       chromeos::AdbSideloadingPolicyChangeNotification*
@@ -100,7 +100,7 @@
   void MaybeShowPowerwashNotification(bool is_sideloading_enabled);
   void MaybeShowPowerwashUponRebootNotification();
 
-  chromeos::CrosSettings* const cros_settings_;
+  ash::CrosSettings* const cros_settings_;
 
   PrefService* const local_state_;
 
diff --git a/chrome/browser/chromeos/policy/adb_sideloading_allowance_mode_policy_handler_unittest.cc b/chrome/browser/chromeos/policy/adb_sideloading_allowance_mode_policy_handler_unittest.cc
index 6d7be0dc..84e3710a 100644
--- a/chrome/browser/chromeos/policy/adb_sideloading_allowance_mode_policy_handler_unittest.cc
+++ b/chrome/browser/chromeos/policy/adb_sideloading_allowance_mode_policy_handler_unittest.cc
@@ -44,7 +44,7 @@
 
     adb_sideloading_allowance_mode_policy_handler_ =
         new AdbSideloadingAllowanceModePolicyHandler(
-            chromeos::CrosSettings::Get(), local_state_.Get(),
+            ash::CrosSettings::Get(), local_state_.Get(),
             chromeos::PowerManagerClient::Get(), mock_notification_);
 
     adb_sideloading_allowance_mode_policy_handler_
@@ -113,7 +113,7 @@
   chromeos::FakeChromeUserManager* user_manager_;
   user_manager::ScopedUserManager user_manager_enabler_;
 
-  chromeos::ScopedTestingCrosSettings scoped_testing_cros_settings_;
+  ash::ScopedTestingCrosSettings scoped_testing_cros_settings_;
 
   chromeos::MockAdbSideloadingPolicyChangeNotification* mock_notification_;
   AdbSideloadingAllowanceModePolicyHandler*
diff --git a/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl_unittest.cc b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl_unittest.cc
index 6fe32d6..c75870e 100644
--- a/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl_unittest.cc
+++ b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl_unittest.cc
@@ -151,7 +151,7 @@
   data_decoder::test::InProcessDataDecoder in_process_data_decoder_;
   chromeos::FakeChromeUserManager* fake_user_manager_;
   user_manager::ScopedUserManager user_manager_enabler_;
-  chromeos::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
+  ash::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
   network::TestURLLoaderFactory test_url_loader_factory_;
   TestingProfileManager profile_manager_;
   session_manager::SessionManager session_manager_;
diff --git a/chrome/browser/chromeos/policy/bluetooth_policy_handler.cc b/chrome/browser/chromeos/policy/bluetooth_policy_handler.cc
index 8c0f5c0..b2a4e01 100644
--- a/chrome/browser/chromeos/policy/bluetooth_policy_handler.cc
+++ b/chrome/browser/chromeos/policy/bluetooth_policy_handler.cc
@@ -12,8 +12,7 @@
 
 namespace policy {
 
-BluetoothPolicyHandler::BluetoothPolicyHandler(
-    chromeos::CrosSettings* cros_settings)
+BluetoothPolicyHandler::BluetoothPolicyHandler(ash::CrosSettings* cros_settings)
     : cros_settings_(cros_settings) {
   bluetooth_policy_subscription_ = cros_settings_->AddSettingsObserver(
       chromeos::kAllowBluetooth,
diff --git a/chrome/browser/chromeos/policy/bluetooth_policy_handler.h b/chrome/browser/chromeos/policy/bluetooth_policy_handler.h
index e4ddd14d..b3555ae 100644
--- a/chrome/browser/chromeos/policy/bluetooth_policy_handler.h
+++ b/chrome/browser/chromeos/policy/bluetooth_policy_handler.h
@@ -20,7 +20,7 @@
 // setting.
 class BluetoothPolicyHandler {
  public:
-  explicit BluetoothPolicyHandler(chromeos::CrosSettings* cros_settings);
+  explicit BluetoothPolicyHandler(ash::CrosSettings* cros_settings);
   ~BluetoothPolicyHandler();
 
  private:
@@ -34,7 +34,7 @@
   // |Shutdown| on the Bluetooth stack in order to disable it.
   void SetBluetoothPolicy(scoped_refptr<device::BluetoothAdapter> adapter);
 
-  chromeos::CrosSettings* cros_settings_;
+  ash::CrosSettings* cros_settings_;
   base::CallbackListSubscription bluetooth_policy_subscription_;
   scoped_refptr<device::BluetoothAdapter> adapter_;
   base::WeakPtrFactory<BluetoothPolicyHandler> weak_factory_{this};
diff --git a/chrome/browser/chromeos/policy/bluetooth_policy_handler_unittest.cc b/chrome/browser/chromeos/policy/bluetooth_policy_handler_unittest.cc
index 0521563..e6ee9a2b 100644
--- a/chrome/browser/chromeos/policy/bluetooth_policy_handler_unittest.cc
+++ b/chrome/browser/chromeos/policy/bluetooth_policy_handler_unittest.cc
@@ -54,11 +54,11 @@
 
   base::test::TaskEnvironment task_environment_;
   scoped_refptr<TestingBluetoothAdapter> adapter_;
-  chromeos::ScopedTestingCrosSettings scoped_testing_cros_settings_;
+  ash::ScopedTestingCrosSettings scoped_testing_cros_settings_;
 };
 
 TEST_F(BluetoothPolicyHandlerTest, TestZeroOnOffOn) {
-  BluetoothPolicyHandler shutdown_policy_handler(chromeos::CrosSettings::Get());
+  BluetoothPolicyHandler shutdown_policy_handler(ash::CrosSettings::Get());
   EXPECT_TRUE(adapter_->IsPresent());
 
   SetAllowBluetooth(true);
@@ -75,14 +75,14 @@
 
 TEST_F(BluetoothPolicyHandlerTest, OffDuringStartup) {
   SetAllowBluetooth(false);
-  BluetoothPolicyHandler shutdown_policy_handler(chromeos::CrosSettings::Get());
+  BluetoothPolicyHandler shutdown_policy_handler(ash::CrosSettings::Get());
   EXPECT_FALSE(adapter_->IsPresent());
   EXPECT_FALSE(adapter_->IsPowered());
 }
 
 TEST_F(BluetoothPolicyHandlerTest, OnDuringStartup) {
   SetAllowBluetooth(true);
-  BluetoothPolicyHandler shutdown_policy_handler(chromeos::CrosSettings::Get());
+  BluetoothPolicyHandler shutdown_policy_handler(ash::CrosSettings::Get());
   EXPECT_TRUE(adapter_->IsPresent());
 }
 
diff --git a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
index c5440e9..91b22d1 100644
--- a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
+++ b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
@@ -133,10 +133,10 @@
   // TODO(satorux): Remove SystemSaltGetter::IsInitialized() when it's ready
   // (removing it now breaks tests). crbug.com/141016.
   if (chromeos::DBusThreadManager::IsInitialized() &&
-      chromeos::DeviceSettingsService::IsInitialized()) {
+      ash::DeviceSettingsService::IsInitialized()) {
     std::unique_ptr<DeviceCloudPolicyStoreChromeOS> device_cloud_policy_store =
         std::make_unique<DeviceCloudPolicyStoreChromeOS>(
-            chromeos::DeviceSettingsService::Get(),
+            ash::DeviceSettingsService::Get(),
             chromeos::InstallAttributes::Get(), GetBackgroundTaskRunner());
 
     if (chromeos::InstallAttributes::Get()->IsActiveDirectoryManaged()) {
@@ -204,8 +204,7 @@
     device_local_account_policy_service_ =
         std::make_unique<DeviceLocalAccountPolicyService>(
             chromeos::SessionManagerClient::Get(),
-            chromeos::DeviceSettingsService::Get(),
-            chromeos::CrosSettings::Get(),
+            ash::DeviceSettingsService::Get(), ash::CrosSettings::Get(),
             affiliated_invalidation_service_provider_.get(),
             GetBackgroundTaskRunner(), GetBackgroundTaskRunner(),
             GetBackgroundTaskRunner(), url_loader_factory);
@@ -244,7 +243,7 @@
           chromeos::NetworkHandler::Get()
               ->managed_network_configuration_handler(),
           chromeos::NetworkHandler::Get()->network_device_handler(),
-          chromeos::CrosSettings::Get(),
+          ash::CrosSettings::Get(),
           DeviceNetworkConfigurationUpdater::DeviceAssetIDFetcher());
   // NetworkCertLoader may be not initialized in tests.
   if (chromeos::NetworkCertLoader::IsInitialized()) {
@@ -253,10 +252,10 @@
   }
 
   bluetooth_policy_handler_ =
-      std::make_unique<BluetoothPolicyHandler>(chromeos::CrosSettings::Get());
+      std::make_unique<BluetoothPolicyHandler>(ash::CrosSettings::Get());
 
   hostname_handler_ =
-      std::make_unique<HostnameHandler>(chromeos::CrosSettings::Get());
+      std::make_unique<HostnameHandler>(ash::CrosSettings::Get());
 
   minimum_version_policy_handler_delegate_ =
       std::make_unique<MinimumVersionPolicyHandlerDelegateImpl>();
@@ -264,23 +263,23 @@
   minimum_version_policy_handler_ =
       std::make_unique<MinimumVersionPolicyHandler>(
           minimum_version_policy_handler_delegate_.get(),
-          chromeos::CrosSettings::Get());
+          ash::CrosSettings::Get());
 
   device_dock_mac_address_source_handler_ =
       std::make_unique<DeviceDockMacAddressHandler>(
-          chromeos::CrosSettings::Get(),
+          ash::CrosSettings::Get(),
           chromeos::NetworkHandler::Get()->network_device_handler());
 
   device_wifi_allowed_handler_ =
-      std::make_unique<DeviceWiFiAllowedHandler>(chromeos::CrosSettings::Get());
+      std::make_unique<DeviceWiFiAllowedHandler>(ash::CrosSettings::Get());
 
   tpm_auto_update_mode_policy_handler_ =
-      std::make_unique<TPMAutoUpdateModePolicyHandler>(
-          chromeos::CrosSettings::Get(), local_state);
+      std::make_unique<TPMAutoUpdateModePolicyHandler>(ash::CrosSettings::Get(),
+                                                       local_state);
 
   device_scheduled_update_checker_ =
       std::make_unique<DeviceScheduledUpdateChecker>(
-          chromeos::CrosSettings::Get(),
+          ash::CrosSettings::Get(),
           chromeos::NetworkHandler::Get()->network_state_handler());
 
   chromeos::BulkPrintersCalculatorFactory* calculator_factory =
@@ -304,11 +303,11 @@
             GetPolicyService()));
   }
   system_proxy_manager_ = std::make_unique<SystemProxyManager>(
-      chromeos::CrosSettings::Get(), local_state);
+      ash::CrosSettings::Get(), local_state);
 
   adb_sideloading_allowance_mode_policy_handler_ =
       std::make_unique<AdbSideloadingAllowanceModePolicyHandler>(
-          chromeos::CrosSettings::Get(), local_state,
+          ash::CrosSettings::Get(), local_state,
           chromeos::PowerManagerClient::Get(),
           new chromeos::AdbSideloadingPolicyChangeNotification());
 }
@@ -536,7 +535,7 @@
 void BrowserPolicyConnectorChromeOS::SetTimezoneIfPolicyAvailable() {
   typedef chromeos::CrosSettingsProvider Provider;
   Provider::TrustedStatus result =
-      chromeos::CrosSettings::Get()->PrepareTrustedValues(base::BindOnce(
+      ash::CrosSettings::Get()->PrepareTrustedValues(base::BindOnce(
           &BrowserPolicyConnectorChromeOS::SetTimezoneIfPolicyAvailable,
           weak_ptr_factory_.GetWeakPtr()));
 
@@ -544,8 +543,8 @@
     return;
 
   std::string timezone;
-  if (chromeos::CrosSettings::Get()->GetString(chromeos::kSystemTimezonePolicy,
-                                               &timezone) &&
+  if (ash::CrosSettings::Get()->GetString(chromeos::kSystemTimezonePolicy,
+                                          &timezone) &&
       !timezone.empty()) {
     chromeos::system::SetSystemAndSigninScreenTimezone(timezone);
   }
diff --git a/chrome/browser/chromeos/policy/cloud_external_data_policy_observer.cc b/chrome/browser/chromeos/policy/cloud_external_data_policy_observer.cc
index 28a8026..d8d5c4eb 100644
--- a/chrome/browser/chromeos/policy/cloud_external_data_policy_observer.cc
+++ b/chrome/browser/chromeos/policy/cloud_external_data_policy_observer.cc
@@ -117,7 +117,7 @@
 }
 
 CloudExternalDataPolicyObserver::CloudExternalDataPolicyObserver(
-    chromeos::CrosSettings* cros_settings,
+    ash::CrosSettings* cros_settings,
     DeviceLocalAccountPolicyService* device_local_account_policy_service,
     const std::string& policy,
     Delegate* delegate)
diff --git a/chrome/browser/chromeos/policy/cloud_external_data_policy_observer.h b/chrome/browser/chromeos/policy/cloud_external_data_policy_observer.h
index 1b297a1..9ae8bb6d 100644
--- a/chrome/browser/chromeos/policy/cloud_external_data_policy_observer.h
+++ b/chrome/browser/chromeos/policy/cloud_external_data_policy_observer.h
@@ -63,7 +63,7 @@
   // |device_local_account_policy_service| may be nullptr if unavailable (e.g.
   // Active Directory management mode).
   CloudExternalDataPolicyObserver(
-      chromeos::CrosSettings* cros_settings,
+      ash::CrosSettings* cros_settings,
       DeviceLocalAccountPolicyService* device_local_account_policy_service,
       const std::string& policy,
       Delegate* delegate);
@@ -106,7 +106,7 @@
       std::map<std::string, std::unique_ptr<PolicyServiceObserver>>;
   LoggedInUserObserverMap logged_in_user_observers_;
 
-  chromeos::CrosSettings* cros_settings_;
+  ash::CrosSettings* cros_settings_;
   DeviceLocalAccountPolicyService* device_local_account_policy_service_;
 
   // The policy that |this| observes.
diff --git a/chrome/browser/chromeos/policy/cloud_external_data_policy_observer_unittest.cc b/chrome/browser/chromeos/policy/cloud_external_data_policy_observer_unittest.cc
index f79ba20..55af388 100644
--- a/chrome/browser/chromeos/policy/cloud_external_data_policy_observer_unittest.cc
+++ b/chrome/browser/chromeos/policy/cloud_external_data_policy_observer_unittest.cc
@@ -88,7 +88,7 @@
 }  // namespace
 
 class CloudExternalDataPolicyObserverTest
-    : public chromeos::DeviceSettingsTestBase,
+    : public ash::DeviceSettingsTestBase,
       public CloudExternalDataPolicyObserver::Delegate {
  public:
   typedef std::pair<std::string, std::string> FetchedCall;
@@ -96,7 +96,7 @@
   CloudExternalDataPolicyObserverTest();
   ~CloudExternalDataPolicyObserverTest() override;
 
-  // chromeos::DeviceSettingsTestBase:
+  // ash::DeviceSettingsTestBase:
   void SetUp() override;
   void TearDown() override;
 
@@ -138,7 +138,7 @@
   std::string avatar_policy_1_;
   std::string avatar_policy_2_;
 
-  std::unique_ptr<chromeos::CrosSettings> cros_settings_;
+  std::unique_ptr<ash::CrosSettings> cros_settings_;
   std::unique_ptr<DeviceLocalAccountPolicyService>
       device_local_account_policy_service_;
   FakeAffiliatedInvalidationServiceProvider
@@ -179,13 +179,13 @@
 }
 
 void CloudExternalDataPolicyObserverTest::SetUp() {
-  chromeos::DeviceSettingsTestBase::SetUp();
+  ash::DeviceSettingsTestBase::SetUp();
 
   ASSERT_TRUE(profile_manager_.SetUp());
   shared_url_loader_factory_ =
       base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
           &url_loader_factory_);
-  cros_settings_ = std::make_unique<chromeos::CrosSettings>(
+  cros_settings_ = std::make_unique<ash::CrosSettings>(
       device_settings_service_.get(),
       TestingBrowserProcess::GetGlobal()->local_state());
   device_local_account_policy_service_.reset(
@@ -223,7 +223,7 @@
   device_local_account_policy_service_->Shutdown();
   device_local_account_policy_service_.reset();
   cros_settings_.reset();
-  chromeos::DeviceSettingsTestBase::TearDown();
+  ash::DeviceSettingsTestBase::TearDown();
 }
 
 
diff --git a/chrome/browser/chromeos/policy/device_auto_update_time_restrictions_utils.cc b/chrome/browser/chromeos/policy/device_auto_update_time_restrictions_utils.cc
index 0451961..1ed8c744 100644
--- a/chrome/browser/chromeos/policy/device_auto_update_time_restrictions_utils.cc
+++ b/chrome/browser/chromeos/policy/device_auto_update_time_restrictions_utils.cc
@@ -61,7 +61,7 @@
     Clock* clock,
     vector<WeeklyTimeInterval>* intervals_out) {
   const ListValue* intervals_list;
-  if (!chromeos::CrosSettings::Get()->GetList(
+  if (!ash::CrosSettings::Get()->GetList(
           chromeos::kDeviceAutoUpdateTimeRestrictions, &intervals_list)) {
     return false;
   }
diff --git a/chrome/browser/chromeos/policy/device_auto_update_time_restrictions_utils_unittest.cc b/chrome/browser/chromeos/policy/device_auto_update_time_restrictions_utils_unittest.cc
index 0131e35..90f0c04 100644
--- a/chrome/browser/chromeos/policy/device_auto_update_time_restrictions_utils_unittest.cc
+++ b/chrome/browser/chromeos/policy/device_auto_update_time_restrictions_utils_unittest.cc
@@ -115,7 +115,7 @@
 
   base::SimpleTestClock test_clock_;
   // These initialize CrosSettings and then tear down when the test is done.
-  chromeos::ScopedTestingCrosSettings scoped_testing_cros_settings_;
+  ash::ScopedTestingCrosSettings scoped_testing_cros_settings_;
 
  private:
   std::unique_ptr<icu::TimeZone> timezone_;
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_browsertest.cc b/chrome/browser/chromeos/policy/device_cloud_policy_browsertest.cc
index eee6bfc..df51102b 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_browsertest.cc
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_browsertest.cc
@@ -150,7 +150,7 @@
   }
 
   std::string GetOwnerPublicKey() const {
-    return chromeos::DeviceSettingsService::Get()->GetPublicKey()->as_string();
+    return ash::DeviceSettingsService::Get()->GetPublicKey()->as_string();
   }
 
   int GetInstalledPolicyKeyVersion() const {
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
index 91a23b23..9157d83 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
@@ -122,7 +122,7 @@
 };
 
 class DeviceCloudPolicyManagerChromeOSTest
-    : public chromeos::DeviceSettingsTestBase,
+    : public ash::DeviceSettingsTestBase,
       public chromeos::SessionManagerClient::Observer {
  protected:
   DeviceCloudPolicyManagerChromeOSTest()
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.cc b/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.cc
index 204b329..3483eeeb 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.cc
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.cc
@@ -50,7 +50,7 @@
 }  // namespace
 
 DeviceCloudPolicyStoreChromeOS::DeviceCloudPolicyStoreChromeOS(
-    chromeos::DeviceSettingsService* device_settings_service,
+    ash::DeviceSettingsService* device_settings_service,
     chromeos::InstallAttributes* install_attributes,
     scoped_refptr<base::SequencedTaskRunner> background_task_runner)
     : device_settings_service_(device_settings_service),
@@ -103,8 +103,7 @@
   DeviceCloudPolicyValidator::StartValidation(
       std::move(validator),
       base::BindOnce(&DeviceCloudPolicyStoreChromeOS::OnPolicyToStoreValidated,
-                     weak_factory_.GetWeakPtr(),
-                     /*is_initial=*/false));
+                     weak_factory_.GetWeakPtr()));
 }
 
 void DeviceCloudPolicyStoreChromeOS::Load() {
@@ -135,8 +134,7 @@
   DeviceCloudPolicyValidator::StartValidation(
       std::move(validator),
       base::BindOnce(&DeviceCloudPolicyStoreChromeOS::OnPolicyToStoreValidated,
-                     weak_factory_.GetWeakPtr(),
-                     /*is_initial=*/true));
+                     weak_factory_.GetWeakPtr()));
 }
 
 void DeviceCloudPolicyStoreChromeOS::DeviceSettingsUpdated() {
@@ -167,7 +165,6 @@
 }
 
 void DeviceCloudPolicyStoreChromeOS::OnPolicyToStoreValidated(
-    bool is_initial,
     DeviceCloudPolicyValidator* validator) {
   validation_result_ = validator->GetValidationResult();
   if (!validator->success()) {
@@ -176,11 +173,6 @@
     return;
   }
 
-  RecordDeviceIdValidityMetric(
-      is_initial ? "Enterprise.DevicePolicyDeviceIdValidity.InitialStore"
-                 : "Enterprise.DevicePolicyDeviceIdValidity.Update",
-      *validator->policy_data(), *install_attributes_);
-
   device_settings_service_->Store(
       std::move(validator->policy()),
       base::BindOnce(&DeviceCloudPolicyStoreChromeOS::OnPolicyStored,
@@ -201,9 +193,9 @@
   CheckDMToken();
   UpdateStatusFromService();
 
-  const chromeos::DeviceSettingsService::Status service_status =
+  const ash::DeviceSettingsService::Status service_status =
       device_settings_service_->status();
-  if (service_status == chromeos::DeviceSettingsService::STORE_SUCCESS) {
+  if (service_status == ash::DeviceSettingsService::STORE_SUCCESS) {
     policy_ = std::make_unique<em::PolicyData>();
     const em::PolicyData* policy_data = device_settings_service_->policy_data();
     if (policy_data) {
@@ -233,18 +225,18 @@
 
 void DeviceCloudPolicyStoreChromeOS::UpdateStatusFromService() {
   switch (device_settings_service_->status()) {
-    case chromeos::DeviceSettingsService::STORE_SUCCESS:
+    case ash::DeviceSettingsService::STORE_SUCCESS:
       status_ = STATUS_OK;
       return;
-    case chromeos::DeviceSettingsService::STORE_KEY_UNAVAILABLE:
+    case ash::DeviceSettingsService::STORE_KEY_UNAVAILABLE:
       status_ = STATUS_BAD_STATE;
       return;
-    case chromeos::DeviceSettingsService::STORE_OPERATION_FAILED:
+    case ash::DeviceSettingsService::STORE_OPERATION_FAILED:
       status_ = STATUS_STORE_ERROR;
       return;
-    case chromeos::DeviceSettingsService::STORE_NO_POLICY:
-    case chromeos::DeviceSettingsService::STORE_INVALID_POLICY:
-    case chromeos::DeviceSettingsService::STORE_VALIDATION_ERROR:
+    case ash::DeviceSettingsService::STORE_NO_POLICY:
+    case ash::DeviceSettingsService::STORE_INVALID_POLICY:
+    case ash::DeviceSettingsService::STORE_VALIDATION_ERROR:
       status_ = STATUS_LOAD_ERROR;
       return;
   }
@@ -252,17 +244,17 @@
 }
 
 void DeviceCloudPolicyStoreChromeOS::CheckDMToken() {
-  const chromeos::DeviceSettingsService::Status service_status =
+  const ash::DeviceSettingsService::Status service_status =
       device_settings_service_->status();
   switch (service_status) {
-    case chromeos::DeviceSettingsService::STORE_SUCCESS:
-    case chromeos::DeviceSettingsService::STORE_KEY_UNAVAILABLE:
-    case chromeos::DeviceSettingsService::STORE_NO_POLICY:
-    case chromeos::DeviceSettingsService::STORE_INVALID_POLICY:
-    case chromeos::DeviceSettingsService::STORE_VALIDATION_ERROR:
+    case ash::DeviceSettingsService::STORE_SUCCESS:
+    case ash::DeviceSettingsService::STORE_KEY_UNAVAILABLE:
+    case ash::DeviceSettingsService::STORE_NO_POLICY:
+    case ash::DeviceSettingsService::STORE_INVALID_POLICY:
+    case ash::DeviceSettingsService::STORE_VALIDATION_ERROR:
       // Continue with the check below.
       break;
-    case chromeos::DeviceSettingsService::STORE_OPERATION_FAILED:
+    case ash::DeviceSettingsService::STORE_OPERATION_FAILED:
       // Don't check for write errors or transient read errors.
       return;
   }
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h b/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h
index 0dd06c5..9bcf4164 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h
@@ -34,10 +34,10 @@
 // TODO(tnagel): Either drop "Cloud" from the name or refactor.
 class DeviceCloudPolicyStoreChromeOS
     : public CloudPolicyStore,
-      public chromeos::DeviceSettingsService::Observer {
+      public ash::DeviceSettingsService::Observer {
  public:
   DeviceCloudPolicyStoreChromeOS(
-      chromeos::DeviceSettingsService* device_settings_service,
+      ash::DeviceSettingsService* device_settings_service,
       chromeos::InstallAttributes* install_attributes,
       scoped_refptr<base::SequencedTaskRunner> background_task_runner);
   ~DeviceCloudPolicyStoreChromeOS() override;
@@ -56,7 +56,7 @@
   void InstallInitialPolicy(
       const enterprise_management::PolicyFetchResponse& policy);
 
-  // chromeos::DeviceSettingsService::Observer:
+  // ash::DeviceSettingsService::Observer:
   void DeviceSettingsUpdated() override;
   void OnDeviceSettingsServiceShutdown() override;
 
@@ -68,9 +68,7 @@
 
   // Called on completion on the policy validation prior to storing policy.
   // Starts the actual store operation.
-  // |is_initial| is whether the policy store is for the initial installation.
-  void OnPolicyToStoreValidated(bool is_initial,
-                                DeviceCloudPolicyValidator* validator);
+  void OnPolicyToStoreValidated(DeviceCloudPolicyValidator* validator);
 
   // Handles store completion operations updates status.
   void OnPolicyStored();
@@ -89,7 +87,7 @@
   // Whether DM token check has yet been done.
   bool dm_token_checked_ = false;
 
-  chromeos::DeviceSettingsService* device_settings_service_;
+  ash::DeviceSettingsService* device_settings_service_;
   chromeos::InstallAttributes* install_attributes_;
 
   scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos_unittest.cc b/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos_unittest.cc
index 4cb394c..a114ff3 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos_unittest.cc
@@ -45,8 +45,7 @@
 
 }  // namespace
 
-class DeviceCloudPolicyStoreChromeOSTest
-    : public chromeos::DeviceSettingsTestBase {
+class DeviceCloudPolicyStoreChromeOSTest : public ash::DeviceSettingsTestBase {
  protected:
   DeviceCloudPolicyStoreChromeOSTest()
       : local_state_(TestingBrowserProcess::GetGlobal()) {}
diff --git a/chrome/browser/chromeos/policy/device_dock_mac_address_source_handler.cc b/chrome/browser/chromeos/policy/device_dock_mac_address_source_handler.cc
index 5176631c..69ffa43 100644
--- a/chrome/browser/chromeos/policy/device_dock_mac_address_source_handler.cc
+++ b/chrome/browser/chromeos/policy/device_dock_mac_address_source_handler.cc
@@ -17,7 +17,7 @@
 namespace policy {
 
 DeviceDockMacAddressHandler::DeviceDockMacAddressHandler(
-    chromeos::CrosSettings* cros_settings,
+    ash::CrosSettings* cros_settings,
     chromeos::NetworkDeviceHandler* network_device_handler)
     : cros_settings_(cros_settings),
       network_device_handler_(network_device_handler) {
diff --git a/chrome/browser/chromeos/policy/device_dock_mac_address_source_handler.h b/chrome/browser/chromeos/policy/device_dock_mac_address_source_handler.h
index e32ea7b..56aa3bd6 100644
--- a/chrome/browser/chromeos/policy/device_dock_mac_address_source_handler.h
+++ b/chrome/browser/chromeos/policy/device_dock_mac_address_source_handler.h
@@ -22,14 +22,14 @@
 class DeviceDockMacAddressHandler {
  public:
   DeviceDockMacAddressHandler(
-      chromeos::CrosSettings* cros_settings,
+      ash::CrosSettings* cros_settings,
       chromeos::NetworkDeviceHandler* network_device_handler);
   ~DeviceDockMacAddressHandler();
 
  private:
   void OnDockMacAddressSourcePolicyChanged();
 
-  chromeos::CrosSettings* cros_settings_;
+  ash::CrosSettings* cros_settings_;
   chromeos::NetworkDeviceHandler* network_device_handler_;
   base::CallbackListSubscription dock_mac_address_source_policy_subscription_;
   base::WeakPtrFactory<DeviceDockMacAddressHandler> weak_factory_{this};
diff --git a/chrome/browser/chromeos/policy/device_dock_mac_address_source_handler_unittest.cc b/chrome/browser/chromeos/policy/device_dock_mac_address_source_handler_unittest.cc
index c2e0bb7..77f18e3 100644
--- a/chrome/browser/chromeos/policy/device_dock_mac_address_source_handler_unittest.cc
+++ b/chrome/browser/chromeos/policy/device_dock_mac_address_source_handler_unittest.cc
@@ -27,7 +27,7 @@
 
     device_dock_mac_address_handler_ =
         std::make_unique<DeviceDockMacAddressHandler>(
-            chromeos::CrosSettings::Get(), &network_device_handler_mock_);
+            ash::CrosSettings::Get(), &network_device_handler_mock_);
   }
 
  protected:
@@ -36,7 +36,7 @@
         chromeos::CrosSettingsProvider::TRUSTED);
   }
 
-  chromeos::ScopedCrosSettingsTestHelper scoped_cros_settings_test_helper_;
+  ash::ScopedCrosSettingsTestHelper scoped_cros_settings_test_helper_;
 
   testing::StrictMock<chromeos::MockNetworkDeviceHandler>
       network_device_handler_mock_;
diff --git a/chrome/browser/chromeos/policy/device_local_account.cc b/chrome/browser/chromeos/policy/device_local_account.cc
index d1a9f0c3..f2a5818b 100644
--- a/chrome/browser/chromeos/policy/device_local_account.cc
+++ b/chrome/browser/chromeos/policy/device_local_account.cc
@@ -233,7 +233,7 @@
 }
 
 std::vector<DeviceLocalAccount> GetDeviceLocalAccounts(
-    chromeos::CrosSettings* cros_settings) {
+    ash::CrosSettings* cros_settings) {
   // TODO(https://crbug.com/984021): handle TYPE_SAML_PUBLIC_SESSION
   std::vector<DeviceLocalAccount> accounts;
 
diff --git a/chrome/browser/chromeos/policy/device_local_account.h b/chrome/browser/chromeos/policy/device_local_account.h
index 3dbe42eb..257cf3b1 100644
--- a/chrome/browser/chromeos/policy/device_local_account.h
+++ b/chrome/browser/chromeos/policy/device_local_account.h
@@ -8,8 +8,11 @@
 #include <string>
 #include <vector>
 
-namespace chromeos {
+namespace ash {
 class CrosSettings;
+}  // namespace ash
+
+namespace chromeos {
 class OwnerSettingsServiceChromeOS;
 }  // namespace chromeos
 
@@ -128,7 +131,7 @@
 
 // Retrieves a list of device-local accounts from |cros_settings|.
 std::vector<DeviceLocalAccount> GetDeviceLocalAccounts(
-    chromeos::CrosSettings* cros_settings);
+    ash::CrosSettings* cros_settings);
 
 }  // namespace policy
 
diff --git a/chrome/browser/chromeos/policy/device_local_account_policy_service.cc b/chrome/browser/chromeos/policy/device_local_account_policy_service.cc
index bd7b1ba..f3e8aba 100644
--- a/chrome/browser/chromeos/policy/device_local_account_policy_service.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_policy_service.cc
@@ -54,7 +54,7 @@
 
 // Device local accounts are always affiliated.
 std::string GetDeviceDMToken(
-    chromeos::DeviceSettingsService* device_settings_service,
+    ash::DeviceSettingsService* device_settings_service,
     const std::vector<std::string>& user_affiliation_ids) {
   return device_settings_service->policy_data()->request_token();
 }
@@ -63,7 +63,7 @@
 // doesn't have credentials in device settings (i.e. is not
 // enterprise-enrolled).
 std::unique_ptr<CloudPolicyClient> CreateClient(
-    chromeos::DeviceSettingsService* device_settings_service,
+    ash::DeviceSettingsService* device_settings_service,
     DeviceManagementService* device_management_service,
     scoped_refptr<network::SharedURLLoaderFactory> system_url_loader_factory) {
   const em::PolicyData* policy_data = device_settings_service->policy_data();
@@ -184,7 +184,7 @@
 }
 
 void DeviceLocalAccountPolicyBroker::ConnectIfPossible(
-    chromeos::DeviceSettingsService* device_settings_service,
+    ash::DeviceSettingsService* device_settings_service,
     DeviceManagementService* device_management_service,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
   if (core_.client())
@@ -251,8 +251,8 @@
 
 DeviceLocalAccountPolicyService::DeviceLocalAccountPolicyService(
     chromeos::SessionManagerClient* session_manager_client,
-    chromeos::DeviceSettingsService* device_settings_service,
-    chromeos::CrosSettings* cros_settings,
+    ash::DeviceSettingsService* device_settings_service,
+    ash::CrosSettings* cros_settings,
     AffiliatedInvalidationServiceProvider* invalidation_service_provider,
     scoped_refptr<base::SequencedTaskRunner> store_background_task_runner,
     scoped_refptr<base::SequencedTaskRunner> extension_cache_task_runner,
diff --git a/chrome/browser/chromeos/policy/device_local_account_policy_service.h b/chrome/browser/chromeos/policy/device_local_account_policy_service.h
index 0bb4018..d610e71 100644
--- a/chrome/browser/chromeos/policy/device_local_account_policy_service.h
+++ b/chrome/browser/chromeos/policy/device_local_account_policy_service.h
@@ -26,18 +26,21 @@
 #include "components/policy/core/common/cloud/component_cloud_policy_service.h"
 #include "components/policy/core/common/schema_registry.h"
 
+namespace ash {
+class DeviceSettingsService;
+}  // namespace ash
+
 namespace base {
 class SequencedTaskRunner;
-}
+}  // namespace base
 
 namespace chromeos {
-class DeviceSettingsService;
 class SessionManagerClient;
-}
+}  // namespace chromeos
 
 namespace network {
 class SharedURLLoaderFactory;
-}
+}  // namespace network
 
 namespace policy {
 
@@ -105,7 +108,7 @@
   // Fire up the cloud connection for fetching policy for the account from the
   // cloud if this is an enterprise-managed device.
   void ConnectIfPossible(
-      chromeos::DeviceSettingsService* device_settings_service,
+      ash::DeviceSettingsService* device_settings_service,
       DeviceManagementService* device_management_service,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
 
@@ -165,8 +168,8 @@
 
   DeviceLocalAccountPolicyService(
       chromeos::SessionManagerClient* session_manager_client,
-      chromeos::DeviceSettingsService* device_settings_service,
-      chromeos::CrosSettings* cros_settings,
+      ash::DeviceSettingsService* device_settings_service,
+      ash::CrosSettings* cros_settings,
       AffiliatedInvalidationServiceProvider* invalidation_service_provider,
       scoped_refptr<base::SequencedTaskRunner> store_background_task_runner,
       scoped_refptr<base::SequencedTaskRunner> extension_cache_task_runner,
@@ -236,8 +239,8 @@
   base::ObserverList<Observer, true>::Unchecked observers_;
 
   chromeos::SessionManagerClient* session_manager_client_;
-  chromeos::DeviceSettingsService* device_settings_service_;
-  chromeos::CrosSettings* cros_settings_;
+  ash::DeviceSettingsService* device_settings_service_;
+  ash::CrosSettings* cros_settings_;
   AffiliatedInvalidationServiceProvider* invalidation_service_provider_;
 
   DeviceManagementService* device_management_service_;
diff --git a/chrome/browser/chromeos/policy/device_local_account_policy_service_unittest.cc b/chrome/browser/chromeos/policy/device_local_account_policy_service_unittest.cc
index 4fd05d7..5455e31 100644
--- a/chrome/browser/chromeos/policy/device_local_account_policy_service_unittest.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_policy_service_unittest.cc
@@ -79,12 +79,12 @@
 };
 
 class DeviceLocalAccountPolicyServiceTestBase
-    : public chromeos::DeviceSettingsTestBase {
+    : public ash::DeviceSettingsTestBase {
  public:
   DeviceLocalAccountPolicyServiceTestBase();
   ~DeviceLocalAccountPolicyServiceTestBase() override;
 
-  // chromeos::DeviceSettingsTestBase:
+  // ash::DeviceSettingsTestBase:
   void SetUp() override;
   void TearDown() override;
 
@@ -99,7 +99,7 @@
 
   PolicyMap expected_policy_map_;
   UserPolicyBuilder device_local_account_policy_;
-  std::unique_ptr<chromeos::CrosSettings> cros_settings_;
+  std::unique_ptr<ash::CrosSettings> cros_settings_;
   scoped_refptr<base::TestSimpleTaskRunner> extension_cache_task_runner_;
   MockDeviceManagementService mock_device_management_service_;
   FakeAffiliatedInvalidationServiceProvider
@@ -144,9 +144,9 @@
     ~DeviceLocalAccountPolicyServiceTestBase() = default;
 
 void DeviceLocalAccountPolicyServiceTestBase::SetUp() {
-  chromeos::DeviceSettingsTestBase::SetUp();
+  ash::DeviceSettingsTestBase::SetUp();
 
-  cros_settings_ = std::make_unique<chromeos::CrosSettings>(
+  cros_settings_ = std::make_unique<ash::CrosSettings>(
       device_settings_service_.get(),
       TestingBrowserProcess::GetGlobal()->local_state());
   extension_cache_task_runner_ = new base::TestSimpleTaskRunner;
@@ -169,7 +169,7 @@
   service_.reset();
   extension_cache_task_runner_->RunUntilIdle();
   cros_settings_.reset();
-  chromeos::DeviceSettingsTestBase::TearDown();
+  ash::DeviceSettingsTestBase::TearDown();
 }
 
 void DeviceLocalAccountPolicyServiceTestBase::CreatePolicyService() {
diff --git a/chrome/browser/chromeos/policy/device_local_account_policy_store.cc b/chrome/browser/chromeos/policy/device_local_account_policy_store.cc
index 102da28..92ba0dfd 100644
--- a/chrome/browser/chromeos/policy/device_local_account_policy_store.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_policy_store.cc
@@ -29,7 +29,7 @@
 DeviceLocalAccountPolicyStore::DeviceLocalAccountPolicyStore(
     const std::string& account_id,
     chromeos::SessionManagerClient* session_manager_client,
-    chromeos::DeviceSettingsService* device_settings_service,
+    ash::DeviceSettingsService* device_settings_service,
     scoped_refptr<base::SequencedTaskRunner> background_task_runner)
     : UserCloudPolicyStoreBase(background_task_runner,
                                PolicyScope::POLICY_SCOPE_USER,
@@ -185,7 +185,7 @@
         valid_timestamp_required, std::move(policy), std::move(callback),
         validate_in_background));
   } else {
-    chromeos::DeviceSettingsService::OwnershipStatus ownership_status =
+    ash::DeviceSettingsService::OwnershipStatus ownership_status =
         device_settings_service_->GetOwnershipStatus();
     Validate(valid_timestamp_required, std::move(policy), std::move(callback),
              validate_in_background, ownership_status);
@@ -197,9 +197,8 @@
     std::unique_ptr<em::PolicyFetchResponse> policy_response,
     ValidateCompletionCallback callback,
     bool validate_in_background,
-    chromeos::DeviceSettingsService::OwnershipStatus ownership_status) {
-  DCHECK_NE(chromeos::DeviceSettingsService::OWNERSHIP_UNKNOWN,
-            ownership_status);
+    ash::DeviceSettingsService::OwnershipStatus ownership_status) {
+  DCHECK_NE(ash::DeviceSettingsService::OWNERSHIP_UNKNOWN, ownership_status);
   const em::PolicyData* device_policy_data =
       device_settings_service_->policy_data();
   // Note that the key is obtained through the device settings service instead
diff --git a/chrome/browser/chromeos/policy/device_local_account_policy_store.h b/chrome/browser/chromeos/policy/device_local_account_policy_store.h
index 0bbb9eb..ece3f85 100644
--- a/chrome/browser/chromeos/policy/device_local_account_policy_store.h
+++ b/chrome/browser/chromeos/policy/device_local_account_policy_store.h
@@ -35,7 +35,7 @@
   DeviceLocalAccountPolicyStore(
       const std::string& account_id,
       chromeos::SessionManagerClient* client,
-      chromeos::DeviceSettingsService* device_settings_service,
+      ash::DeviceSettingsService* device_settings_service,
       scoped_refptr<base::SequencedTaskRunner> background_task_runner);
   ~DeviceLocalAccountPolicyStore() override;
 
@@ -96,11 +96,11 @@
       std::unique_ptr<enterprise_management::PolicyFetchResponse> policy,
       ValidateCompletionCallback callback,
       bool validate_in_background,
-      chromeos::DeviceSettingsService::OwnershipStatus ownership_status);
+      ash::DeviceSettingsService::OwnershipStatus ownership_status);
 
   const std::string account_id_;
   chromeos::SessionManagerClient* session_manager_client_;
-  chromeos::DeviceSettingsService* device_settings_service_;
+  ash::DeviceSettingsService* device_settings_service_;
 
   scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
 
diff --git a/chrome/browser/chromeos/policy/device_network_configuration_updater.cc b/chrome/browser/chromeos/policy/device_network_configuration_updater.cc
index ff68bc0d..9afacba 100644
--- a/chrome/browser/chromeos/policy/device_network_configuration_updater.cc
+++ b/chrome/browser/chromeos/policy/device_network_configuration_updater.cc
@@ -46,7 +46,7 @@
     PolicyService* policy_service,
     chromeos::ManagedNetworkConfigurationHandler* network_config_handler,
     chromeos::NetworkDeviceHandler* network_device_handler,
-    chromeos::CrosSettings* cros_settings,
+    ash::CrosSettings* cros_settings,
     const DeviceNetworkConfigurationUpdater::DeviceAssetIDFetcher&
         device_asset_id_fetcher) {
   std::unique_ptr<DeviceNetworkConfigurationUpdater> updater(
@@ -61,7 +61,7 @@
     PolicyService* policy_service,
     chromeos::ManagedNetworkConfigurationHandler* network_config_handler,
     chromeos::NetworkDeviceHandler* network_device_handler,
-    chromeos::CrosSettings* cros_settings,
+    ash::CrosSettings* cros_settings,
     const DeviceNetworkConfigurationUpdater::DeviceAssetIDFetcher&
         device_asset_id_fetcher)
     : NetworkConfigurationUpdater(onc::ONC_SOURCE_DEVICE_POLICY,
diff --git a/chrome/browser/chromeos/policy/device_network_configuration_updater.h b/chrome/browser/chromeos/policy/device_network_configuration_updater.h
index 0af76221..71b71974 100644
--- a/chrome/browser/chromeos/policy/device_network_configuration_updater.h
+++ b/chrome/browser/chromeos/policy/device_network_configuration_updater.h
@@ -16,13 +16,16 @@
 #include "components/onc/onc_constants.h"
 #include "net/cert/x509_certificate.h"
 
+namespace ash {
+class CrosSettings;
+}  // namespace ash
+
 namespace base {
 class DictionaryValue;
 class ListValue;
 }
 
 namespace chromeos {
-class CrosSettings;
 class ManagedNetworkConfigurationHandler;
 class NetworkDeviceHandler;
 }
@@ -52,7 +55,7 @@
       PolicyService* policy_service,
       chromeos::ManagedNetworkConfigurationHandler* network_config_handler,
       chromeos::NetworkDeviceHandler* network_device_handler,
-      chromeos::CrosSettings* cros_settings,
+      ash::CrosSettings* cros_settings,
       const DeviceAssetIDFetcher& device_asset_id_fetcher);
 
  private:
@@ -60,7 +63,7 @@
       PolicyService* policy_service,
       chromeos::ManagedNetworkConfigurationHandler* network_config_handler,
       chromeos::NetworkDeviceHandler* network_device_handler,
-      chromeos::CrosSettings* cros_settings,
+      ash::CrosSettings* cros_settings,
       const DeviceAssetIDFetcher& device_asset_id_fetcher);
 
   // NetworkConfigurationUpdater:
@@ -72,7 +75,7 @@
   void OnDataRoamingSettingChanged();
 
   chromeos::NetworkDeviceHandler* network_device_handler_;
-  chromeos::CrosSettings* cros_settings_;
+  ash::CrosSettings* cros_settings_;
   base::CallbackListSubscription data_roaming_setting_subscription_;
 
   // Returns the device's administrator-set asset id.
diff --git a/chrome/browser/chromeos/policy/device_policy_cros_browser_test.cc b/chrome/browser/chromeos/policy/device_policy_cros_browser_test.cc
index ff61adf1..df40ab9 100644
--- a/chrome/browser/chromeos/policy/device_policy_cros_browser_test.cc
+++ b/chrome/browser/chromeos/policy/device_policy_cros_browser_test.cc
@@ -171,7 +171,7 @@
   std::vector<base::CallbackListSubscription> subscriptions = {};
   for (auto setting_it = settings.cbegin(); setting_it != settings.cend();
        setting_it++) {
-    subscriptions.push_back(chromeos::CrosSettings::Get()->AddSettingsObserver(
+    subscriptions.push_back(ash::CrosSettings::Get()->AddSettingsObserver(
         *setting_it, run_loop.QuitClosure()));
   }
   RefreshDevicePolicy();
diff --git a/chrome/browser/chromeos/policy/device_wifi_allowed_handler.cc b/chrome/browser/chromeos/policy/device_wifi_allowed_handler.cc
index fce6d6a..6ada04e 100644
--- a/chrome/browser/chromeos/policy/device_wifi_allowed_handler.cc
+++ b/chrome/browser/chromeos/policy/device_wifi_allowed_handler.cc
@@ -16,7 +16,7 @@
 namespace policy {
 
 DeviceWiFiAllowedHandler::DeviceWiFiAllowedHandler(
-    chromeos::CrosSettings* cros_settings)
+    ash::CrosSettings* cros_settings)
     : cros_settings_(cros_settings) {
   wifi_policy_subscription_ = cros_settings_->AddSettingsObserver(
       chromeos::kDeviceWiFiAllowed,
diff --git a/chrome/browser/chromeos/policy/device_wifi_allowed_handler.h b/chrome/browser/chromeos/policy/device_wifi_allowed_handler.h
index 1e33bf0b..d49d7b3 100644
--- a/chrome/browser/chromeos/policy/device_wifi_allowed_handler.h
+++ b/chrome/browser/chromeos/policy/device_wifi_allowed_handler.h
@@ -18,13 +18,13 @@
 // setting.
 class DeviceWiFiAllowedHandler {
  public:
-  explicit DeviceWiFiAllowedHandler(chromeos::CrosSettings* cros_settings);
+  explicit DeviceWiFiAllowedHandler(ash::CrosSettings* cros_settings);
   ~DeviceWiFiAllowedHandler();
 
  private:
   void OnWiFiPolicyChanged();
 
-  chromeos::CrosSettings* cros_settings_;
+  ash::CrosSettings* cros_settings_;
   base::CallbackListSubscription wifi_policy_subscription_;
   base::WeakPtrFactory<DeviceWiFiAllowedHandler> weak_factory_{this};
 
diff --git a/chrome/browser/chromeos/policy/display_resolution_handler.cc b/chrome/browser/chromeos/policy/display_resolution_handler.cc
index ec76bd83..6305aa09 100644
--- a/chrome/browser/chromeos/policy/display_resolution_handler.cc
+++ b/chrome/browser/chromeos/policy/display_resolution_handler.cc
@@ -161,8 +161,8 @@
 void DisplayResolutionHandler::OnSettingUpdate() {
   policy_enabled_ = false;
   const base::DictionaryValue* resolution_pref = nullptr;
-  chromeos::CrosSettings::Get()->GetDictionary(
-      chromeos::kDeviceDisplayResolution, &resolution_pref);
+  ash::CrosSettings::Get()->GetDictionary(chromeos::kDeviceDisplayResolution,
+                                          &resolution_pref);
   if (!resolution_pref)
     return;
 
diff --git a/chrome/browser/chromeos/policy/display_resolution_handler_browsertest.cc b/chrome/browser/chromeos/policy/display_resolution_handler_browsertest.cc
index 0235cda..a1bb36ea 100644
--- a/chrome/browser/chromeos/policy/display_resolution_handler_browsertest.cc
+++ b/chrome/browser/chromeos/policy/display_resolution_handler_browsertest.cc
@@ -64,8 +64,8 @@
 
 PolicyValue GetPolicySetting() {
   const base::DictionaryValue* resolution_pref = nullptr;
-  chromeos::CrosSettings::Get()->GetDictionary(
-      chromeos::kDeviceDisplayResolution, &resolution_pref);
+  ash::CrosSettings::Get()->GetDictionary(chromeos::kDeviceDisplayResolution,
+                                          &resolution_pref);
   EXPECT_TRUE(resolution_pref) << "DeviceDisplayResolution setting is not set";
   const base::Value* width = resolution_pref->FindKeyOfType(
       {chromeos::kDeviceDisplayResolutionKeyExternalWidth},
@@ -343,7 +343,7 @@
   SetPolicyValue(&proto, policy_value, true);
   base::RunLoop run_loop;
   base::CallbackListSubscription subscription =
-      chromeos::CrosSettings::Get()->AddSettingsObserver(
+      ash::CrosSettings::Get()->AddSettingsObserver(
           chromeos::kDeviceDisplayResolution, run_loop.QuitClosure());
   device_policy->SetDefaultSigningKey();
   device_policy->Build();
diff --git a/chrome/browser/chromeos/policy/display_rotation_default_handler.cc b/chrome/browser/chromeos/policy/display_rotation_default_handler.cc
index 6b14c67..187f7de 100644
--- a/chrome/browser/chromeos/policy/display_rotation_default_handler.cc
+++ b/chrome/browser/chromeos/policy/display_rotation_default_handler.cc
@@ -64,7 +64,7 @@
 // |display_rotation_default_| and |policy_enabled_|.
 void DisplayRotationDefaultHandler::OnSettingUpdate() {
   int new_rotation;
-  bool new_policy_enabled = chromeos::CrosSettings::Get()->GetInteger(
+  bool new_policy_enabled = ash::CrosSettings::Get()->GetInteger(
       chromeos::kDisplayRotationDefault, &new_rotation);
   display::Display::Rotation new_display_rotation_default =
       display::Display::ROTATE_0;
diff --git a/chrome/browser/chromeos/policy/display_rotation_default_handler_browsertest.cc b/chrome/browser/chromeos/policy/display_rotation_default_handler_browsertest.cc
index 1f7bdd9..7fe940f 100644
--- a/chrome/browser/chromeos/policy/display_rotation_default_handler_browsertest.cc
+++ b/chrome/browser/chromeos/policy/display_rotation_default_handler_browsertest.cc
@@ -84,7 +84,7 @@
 
   SetRotationPolicy(policy_rotation);
   int settings_rotation;
-  EXPECT_TRUE(chromeos::CrosSettings::Get()->GetInteger(
+  EXPECT_TRUE(ash::CrosSettings::Get()->GetInteger(
       chromeos::kDisplayRotationDefault, &settings_rotation));
   EXPECT_EQ(policy_rotation, settings_rotation)
       << "Value of CrosSettings after policy value changed";
@@ -216,7 +216,7 @@
       static_cast<em::DisplayRotationDefaultProto::Rotation>(policy_rotation));
   base::RunLoop run_loop;
   base::CallbackListSubscription subscription =
-      chromeos::CrosSettings::Get()->AddSettingsObserver(
+      ash::CrosSettings::Get()->AddSettingsObserver(
           chromeos::kDisplayRotationDefault, run_loop.QuitClosure());
   device_policy->SetDefaultSigningKey();
   device_policy->Build();
diff --git a/chrome/browser/chromeos/policy/display_settings_handler.cc b/chrome/browser/chromeos/policy/display_settings_handler.cc
index a437d69..5c0ced3b 100644
--- a/chrome/browser/chromeos/policy/display_settings_handler.cc
+++ b/chrome/browser/chromeos/policy/display_settings_handler.cc
@@ -45,7 +45,7 @@
   // Register observers for all settings
   for (const auto& handler : handlers_) {
     settings_subscriptions_.push_back(
-        chromeos::CrosSettings::Get()->AddSettingsObserver(
+        ash::CrosSettings::Get()->AddSettingsObserver(
             handler->SettingName(),
             base::BindRepeating(&DisplaySettingsHandler::OnSettingUpdate,
                                 base::Unretained(this),
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_content_manager.cc b/chrome/browser/chromeos/policy/dlp/dlp_content_manager.cc
index dd1b5c1..ff6541d 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_content_manager.cc
+++ b/chrome/browser/chromeos/policy/dlp/dlp_content_manager.cc
@@ -313,7 +313,6 @@
 
 void DlpContentManager::MaybeChangeOnScreenRestrictions() {
   DlpContentRestrictionSet new_restriction_set;
-  // TODO(crbug/1111860): Recalculate more effectively.
   for (const auto& entry : confidential_web_contents_) {
     if (entry.first->GetVisibility() == content::Visibility::VISIBLE) {
       new_restriction_set.UnionWith(entry.second);
diff --git a/chrome/browser/chromeos/policy/dm_token_storage.cc b/chrome/browser/chromeos/policy/dm_token_storage.cc
index 49cd182..d6cbdd0 100644
--- a/chrome/browser/chromeos/policy/dm_token_storage.cc
+++ b/chrome/browser/chromeos/policy/dm_token_storage.cc
@@ -18,13 +18,13 @@
 
 std::string EncryptToken(const std::string& system_salt,
                          const std::string& dm_token) {
-  chromeos::CryptohomeTokenEncryptor encryptor(system_salt);
+  ash::CryptohomeTokenEncryptor encryptor(system_salt);
   return encryptor.EncryptWithSystemSalt(dm_token);
 }
 
 std::string DecryptToken(const std::string& system_salt,
                          const std::string encrypted_dm_token) {
-  chromeos::CryptohomeTokenEncryptor encryptor(system_salt);
+  ash::CryptohomeTokenEncryptor encryptor(system_salt);
   return encryptor.DecryptWithSystemSalt(encrypted_dm_token);
 }
 
diff --git a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc
index b1c1a89..72f4abe 100644
--- a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc
+++ b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc
@@ -725,7 +725,7 @@
     CHECK(install_attributes_->IsActiveDirectoryManaged());
     // Update device settings so that in case of Active Directory unsigned
     // policy is accepted.
-    chromeos::DeviceSettingsService::Get()->SetDeviceMode(
+    ash::DeviceSettingsService::Get()->SetDeviceMode(
         install_attributes_->GetMode());
     chromeos::AuthPolicyClient::Get()->RefreshDevicePolicy(base::BindOnce(
         &EnrollmentHandlerChromeOS::HandleActiveDirectoryPolicyRefreshed,
diff --git a/chrome/browser/chromeos/policy/extension_cache_unittest.cc b/chrome/browser/chromeos/policy/extension_cache_unittest.cc
index 50b4ff7..098ff8e 100644
--- a/chrome/browser/chromeos/policy/extension_cache_unittest.cc
+++ b/chrome/browser/chromeos/policy/extension_cache_unittest.cc
@@ -59,7 +59,7 @@
 class ExtensionCacheTest : public testing::Test {
  protected:
   content::BrowserTaskEnvironment task_environment_;
-  chromeos::ScopedTestingCrosSettings scoped_testing_cros_settings_;
+  ash::ScopedTestingCrosSettings scoped_testing_cros_settings_;
 };
 
 TEST_F(ExtensionCacheTest, SizePolicy) {
diff --git a/chrome/browser/chromeos/policy/extension_install_event_log_collector.cc b/chrome/browser/chromeos/policy/extension_install_event_log_collector.cc
index 10e22f75..334abb16 100644
--- a/chrome/browser/chromeos/policy/extension_install_event_log_collector.cc
+++ b/chrome/browser/chromeos/policy/extension_install_event_log_collector.cc
@@ -518,12 +518,12 @@
 void ExtensionInstallEventLogCollector::OnLoginInternal() {
   std::unique_ptr<em::ExtensionInstallReportLogEvent> event =
       CreateSessionChangeEvent(em::ExtensionInstallReportLogEvent::LOGIN);
-  if (chromeos::ProfileHelper::Get()->GetUserByProfile(profile_)) {
     extensions::InstallStageTracker::UserInfo user_info =
         extensions::InstallStageTracker::GetUserInfo(profile_);
-    event->set_user_type(ConvertUserTypeToProto(user_info.user_type));
-    event->set_is_new_user(user_info.is_new_user);
-  }
+    if (user_info.is_user_present) {
+      event->set_user_type(ConvertUserTypeToProto(user_info.user_type));
+      event->set_is_new_user(user_info.is_new_user);
+    }
   event->set_online(online_);
   delegate_->AddForAllExtensions(std::move(event));
 }
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/crostini_ansible_playbook_external_data_handler.cc b/chrome/browser/chromeos/policy/external_data_handlers/crostini_ansible_playbook_external_data_handler.cc
index b785e1d..d34fdb3 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/crostini_ansible_playbook_external_data_handler.cc
+++ b/chrome/browser/chromeos/policy/external_data_handlers/crostini_ansible_playbook_external_data_handler.cc
@@ -16,7 +16,7 @@
 
 CrostiniAnsiblePlaybookExternalDataHandler::
     CrostiniAnsiblePlaybookExternalDataHandler(
-        chromeos::CrosSettings* cros_settings,
+        ash::CrosSettings* cros_settings,
         DeviceLocalAccountPolicyService* policy_service)
     : crostini_ansible_observer_(cros_settings,
                                  policy_service,
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/crostini_ansible_playbook_external_data_handler.h b/chrome/browser/chromeos/policy/external_data_handlers/crostini_ansible_playbook_external_data_handler.h
index 79b54f5..255eed4 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/crostini_ansible_playbook_external_data_handler.h
+++ b/chrome/browser/chromeos/policy/external_data_handlers/crostini_ansible_playbook_external_data_handler.h
@@ -10,9 +10,9 @@
 
 #include "chrome/browser/chromeos/policy/external_data_handlers/cloud_external_data_policy_handler.h"
 
-namespace chromeos {
+namespace ash {
 class CrosSettings;
-}  // namespace chromeos
+}  // namespace ash
 
 namespace policy {
 
@@ -22,7 +22,7 @@
     : public CloudExternalDataPolicyHandler {
  public:
   CrostiniAnsiblePlaybookExternalDataHandler(
-      chromeos::CrosSettings* cros_settings,
+      ash::CrosSettings* cros_settings,
       DeviceLocalAccountPolicyService* policy_service);
   ~CrostiniAnsiblePlaybookExternalDataHandler() override;
 
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/print_servers_external_data_handler.cc b/chrome/browser/chromeos/policy/external_data_handlers/print_servers_external_data_handler.cc
index 53148c7..ec67f65 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/print_servers_external_data_handler.cc
+++ b/chrome/browser/chromeos/policy/external_data_handlers/print_servers_external_data_handler.cc
@@ -25,7 +25,7 @@
 }  // namespace
 
 PrintServersExternalDataHandler::PrintServersExternalDataHandler(
-    chromeos::CrosSettings* cros_settings,
+    ash::CrosSettings* cros_settings,
     DeviceLocalAccountPolicyService* policy_service)
     : print_servers_observer_(cros_settings,
                               policy_service,
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/print_servers_external_data_handler.h b/chrome/browser/chromeos/policy/external_data_handlers/print_servers_external_data_handler.h
index 18c6b1e4..e68b211c 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/print_servers_external_data_handler.h
+++ b/chrome/browser/chromeos/policy/external_data_handlers/print_servers_external_data_handler.h
@@ -10,9 +10,9 @@
 
 #include "chrome/browser/chromeos/policy/external_data_handlers/cloud_external_data_policy_handler.h"
 
-namespace chromeos {
+namespace ash {
 class CrosSettings;
-}  // namespace chromeos
+}  // namespace ash
 
 namespace policy {
 
@@ -23,7 +23,7 @@
 class PrintServersExternalDataHandler : public CloudExternalDataPolicyHandler {
  public:
   PrintServersExternalDataHandler(
-      chromeos::CrosSettings* cros_settings,
+      ash::CrosSettings* cros_settings,
       DeviceLocalAccountPolicyService* policy_service);
   ~PrintServersExternalDataHandler() override;
 
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/printers_external_data_handler.cc b/chrome/browser/chromeos/policy/external_data_handlers/printers_external_data_handler.cc
index 0a83378..8e7d7b65 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/printers_external_data_handler.cc
+++ b/chrome/browser/chromeos/policy/external_data_handlers/printers_external_data_handler.cc
@@ -29,7 +29,7 @@
 }  // namespace
 
 PrintersExternalDataHandler::PrintersExternalDataHandler(
-    chromeos::CrosSettings* cros_settings,
+    ash::CrosSettings* cros_settings,
     DeviceLocalAccountPolicyService* policy_service)
     : printers_observer_(cros_settings,
                          policy_service,
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/printers_external_data_handler.h b/chrome/browser/chromeos/policy/external_data_handlers/printers_external_data_handler.h
index ba5181c..995176b6 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/printers_external_data_handler.h
+++ b/chrome/browser/chromeos/policy/external_data_handlers/printers_external_data_handler.h
@@ -10,9 +10,9 @@
 
 #include "chrome/browser/chromeos/policy/external_data_handlers/cloud_external_data_policy_handler.h"
 
-namespace chromeos {
+namespace ash {
 class CrosSettings;
-}  // namespace chromeos
+}  // namespace ash
 
 namespace policy {
 
@@ -20,7 +20,7 @@
 
 class PrintersExternalDataHandler : public CloudExternalDataPolicyHandler {
  public:
-  PrintersExternalDataHandler(chromeos::CrosSettings* cros_settings,
+  PrintersExternalDataHandler(ash::CrosSettings* cros_settings,
                               DeviceLocalAccountPolicyService* policy_service);
   ~PrintersExternalDataHandler() override;
 
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/user_avatar_image_external_data_handler.cc b/chrome/browser/chromeos/policy/external_data_handlers/user_avatar_image_external_data_handler.cc
index 9951603a..53d3d51 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/user_avatar_image_external_data_handler.cc
+++ b/chrome/browser/chromeos/policy/external_data_handlers/user_avatar_image_external_data_handler.cc
@@ -23,7 +23,7 @@
 }  // namespace
 
 UserAvatarImageExternalDataHandler::UserAvatarImageExternalDataHandler(
-    chromeos::CrosSettings* cros_settings,
+    ash::CrosSettings* cros_settings,
     DeviceLocalAccountPolicyService* policy_service)
     : user_avatar_image_observer_(cros_settings,
                                   policy_service,
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/user_avatar_image_external_data_handler.h b/chrome/browser/chromeos/policy/external_data_handlers/user_avatar_image_external_data_handler.h
index 69c43d7..c77a1895 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/user_avatar_image_external_data_handler.h
+++ b/chrome/browser/chromeos/policy/external_data_handlers/user_avatar_image_external_data_handler.h
@@ -10,9 +10,9 @@
 
 #include "chrome/browser/chromeos/policy/external_data_handlers/cloud_external_data_policy_handler.h"
 
-namespace chromeos {
+namespace ash {
 class CrosSettings;
-}  // namespace chromeos
+}  // namespace ash
 
 namespace policy {
 
@@ -22,7 +22,7 @@
     : public CloudExternalDataPolicyHandler {
  public:
   UserAvatarImageExternalDataHandler(
-      chromeos::CrosSettings* cros_settings,
+      ash::CrosSettings* cros_settings,
       DeviceLocalAccountPolicyService* policy_service);
   ~UserAvatarImageExternalDataHandler() override;
 
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/wallpaper_image_external_data_handler.cc b/chrome/browser/chromeos/policy/external_data_handlers/wallpaper_image_external_data_handler.cc
index 1289a34..4ad64ce8 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/wallpaper_image_external_data_handler.cc
+++ b/chrome/browser/chromeos/policy/external_data_handlers/wallpaper_image_external_data_handler.cc
@@ -13,7 +13,7 @@
 namespace policy {
 
 WallpaperImageExternalDataHandler::WallpaperImageExternalDataHandler(
-    chromeos::CrosSettings* cros_settings,
+    ash::CrosSettings* cros_settings,
     DeviceLocalAccountPolicyService* policy_service)
     : wallpaper_image_observer_(cros_settings,
                                 policy_service,
diff --git a/chrome/browser/chromeos/policy/external_data_handlers/wallpaper_image_external_data_handler.h b/chrome/browser/chromeos/policy/external_data_handlers/wallpaper_image_external_data_handler.h
index dd1550c..b7d4742 100644
--- a/chrome/browser/chromeos/policy/external_data_handlers/wallpaper_image_external_data_handler.h
+++ b/chrome/browser/chromeos/policy/external_data_handlers/wallpaper_image_external_data_handler.h
@@ -10,9 +10,9 @@
 
 #include "chrome/browser/chromeos/policy/external_data_handlers/cloud_external_data_policy_handler.h"
 
-namespace chromeos {
+namespace ash {
 class CrosSettings;
-}  // namespace chromeos
+}  // namespace ash
 
 namespace policy {
 
@@ -22,7 +22,7 @@
     : public CloudExternalDataPolicyHandler {
  public:
   WallpaperImageExternalDataHandler(
-      chromeos::CrosSettings* cros_settings,
+      ash::CrosSettings* cros_settings,
       DeviceLocalAccountPolicyService* policy_service);
   ~WallpaperImageExternalDataHandler() override;
 
diff --git a/chrome/browser/chromeos/policy/fuzzer/policy_fuzzer.cc b/chrome/browser/chromeos/policy/fuzzer/policy_fuzzer.cc
index 6564e7e..28a04ebf 100644
--- a/chrome/browser/chromeos/policy/fuzzer/policy_fuzzer.cc
+++ b/chrome/browser/chromeos/policy/fuzzer/policy_fuzzer.cc
@@ -78,7 +78,7 @@
   ~PerInputEnvironment() {
     chromeos::ShutdownDBus();
     chromeos::InstallAttributes::Shutdown();
-    chromeos::DeviceSettingsService::Shutdown();
+    ash::DeviceSettingsService::Shutdown();
   }
 
   base::test::TaskEnvironment task_environment;
@@ -99,12 +99,12 @@
     const enterprise_management::ChromeDeviceSettingsProto&
         chrome_device_settings) {
   PrefValueMap cros_settings_prefs;
-  chromeos::DeviceSettingsProvider::DecodePolicies(chrome_device_settings,
-                                                   &cros_settings_prefs);
+  ash::DeviceSettingsProvider::DecodePolicies(chrome_device_settings,
+                                              &cros_settings_prefs);
 
   for (const auto& it : cros_settings_prefs) {
     const std::string& pref_name = it.first;
-    CHECK(chromeos::DeviceSettingsProvider::IsDeviceSetting(pref_name));
+    CHECK(ash::DeviceSettingsProvider::IsDeviceSetting(pref_name));
   }
 }
 
diff --git a/chrome/browser/chromeos/policy/heartbeat_scheduler.cc b/chrome/browser/chromeos/policy/heartbeat_scheduler.cc
index bfd81ba3..58ea24e 100644
--- a/chrome/browser/chromeos/policy/heartbeat_scheduler.cc
+++ b/chrome/browser/chromeos/policy/heartbeat_scheduler.cc
@@ -73,9 +73,6 @@
 const base::TimeDelta HeartbeatScheduler::kDefaultHeartbeatInterval =
     base::TimeDelta::FromMinutes(2);
 
-const char* const HeartbeatScheduler::kHeartbeatSignalHistogram =
-    "Enterprise.HeartbeatSignalSuccess";
-
 // Helper class used to manage GCM registration (handles retrying after
 // errors, etc).
 class HeartbeatRegistrationHelper {
@@ -191,13 +188,13 @@
     return;
 
   heartbeat_frequency_subscription_ =
-      chromeos::CrosSettings::Get()->AddSettingsObserver(
+      ash::CrosSettings::Get()->AddSettingsObserver(
           chromeos::kHeartbeatFrequency,
           base::BindRepeating(&HeartbeatScheduler::RefreshHeartbeatSettings,
                               base::Unretained(this)));
 
   heartbeat_enabled_subscription_ =
-      chromeos::CrosSettings::Get()->AddSettingsObserver(
+      ash::CrosSettings::Get()->AddSettingsObserver(
           chromeos::kHeartbeatEnabled,
           base::BindRepeating(&HeartbeatScheduler::RefreshHeartbeatSettings,
                               base::Unretained(this)));
@@ -215,7 +212,7 @@
   // Attempt to fetch the current value of the reporting settings.
   // If trusted values are not available, register this function to be called
   // back when they are available.
-  chromeos::CrosSettings* settings = chromeos::CrosSettings::Get();
+  ash::CrosSettings* settings = ash::CrosSettings::Get();
   if (chromeos::CrosSettingsProvider::TRUSTED !=
       settings->PrepareTrustedValues(
           base::BindOnce(&HeartbeatScheduler::RefreshHeartbeatSettings,
@@ -397,9 +394,6 @@
   DLOG_IF(ERROR, result != gcm::GCMClient::SUCCESS) <<
       "Error sending monitoring heartbeat: " << result;
 
-  UMA_HISTOGRAM_BOOLEAN(kHeartbeatSignalHistogram,
-                        result == gcm::GCMClient::SUCCESS);
-
   last_heartbeat_ = base::Time::NowFromSystemTime();
   ScheduleNextHeartbeat();
 }
diff --git a/chrome/browser/chromeos/policy/heartbeat_scheduler.h b/chrome/browser/chromeos/policy/heartbeat_scheduler.h
index ffd7e50..02f50a7 100644
--- a/chrome/browser/chromeos/policy/heartbeat_scheduler.h
+++ b/chrome/browser/chromeos/policy/heartbeat_scheduler.h
@@ -42,9 +42,6 @@
   // Default interval for how often we send up a heartbeat.
   static const base::TimeDelta kDefaultHeartbeatInterval;
 
-  // UMA histogram name.
-  static const char* const kHeartbeatSignalHistogram;
-
   // Constructor. |cloud_policy_client| will be used to send registered GCM id
   // to DM server, and can be null. |driver| can be null for tests.
   HeartbeatScheduler(
diff --git a/chrome/browser/chromeos/policy/heartbeat_scheduler_unittest.cc b/chrome/browser/chromeos/policy/heartbeat_scheduler_unittest.cc
index 2b7f1ff..ddc3051 100644
--- a/chrome/browser/chromeos/policy/heartbeat_scheduler_unittest.cc
+++ b/chrome/browser/chromeos/policy/heartbeat_scheduler_unittest.cc
@@ -11,7 +11,6 @@
 #include "base/macros.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/test/gmock_move_support.h"
-#include "base/test/metrics/histogram_tester.h"
 #include "base/test/test_simple_task_runner.h"
 #include "chrome/browser/ash/settings/scoped_testing_cros_settings.h"
 #include "chrome/browser/ash/settings/stub_cros_settings_provider.h"
@@ -172,7 +171,7 @@
 
   content::BrowserTaskEnvironment task_environment_;
   MockGCMDriver gcm_driver_;
-  chromeos::ScopedTestingCrosSettings scoped_testing_cros_settings_;
+  ash::ScopedTestingCrosSettings scoped_testing_cros_settings_;
   testing::NiceMock<policy::MockCloudPolicyClient> cloud_policy_client_;
   testing::NiceMock<policy::MockCloudPolicyStore> cloud_policy_store_;
 
@@ -181,8 +180,6 @@
 
   // The HeartbeatScheduler instance under test.
   policy::HeartbeatScheduler scheduler_;
-
-  base::HistogramTester histogram_tester_;
 };
 
 TEST_F(HeartbeatSchedulerTest, Basic) {
@@ -254,8 +251,6 @@
   EXPECT_EQ(1U, task_runner_->NumPendingTasks());
   task_runner_->RunPendingTasks();
   testing::Mock::VerifyAndClearExpectations(&gcm_driver_);
-  histogram_tester_.ExpectTotalCount(
-      policy::HeartbeatScheduler::kHeartbeatSignalHistogram, 0);
 }
 
 TEST_F(HeartbeatSchedulerTest, StoreResetAfterRegistration) {
@@ -324,9 +319,6 @@
   gcm_driver_.CompleteSend(
       kHeartbeatGCMAppID, message.id, gcm::GCMClient::SERVER_ERROR);
   EXPECT_EQ(1U, task_runner_->NumPendingTasks());
-  histogram_tester_.ExpectUniqueSample(
-      policy::HeartbeatScheduler::kHeartbeatSignalHistogram, /*failure*/ false,
-      /*amount*/ 1);
   CheckPendingTaskDelay(scheduler_.last_heartbeat(),
                         base::TimeDelta::FromMilliseconds(new_delay));
 }
@@ -350,9 +342,6 @@
   // Complete sending a message - we should queue up the next heartbeat.
   gcm_driver_.CompleteSend(
       kHeartbeatGCMAppID, message.id, gcm::GCMClient::SUCCESS);
-  histogram_tester_.ExpectUniqueSample(
-      policy::HeartbeatScheduler::kHeartbeatSignalHistogram, /*success*/ true,
-      /*amount*/ 1);
 
   // Should have a new heartbeat task posted.
   ASSERT_EQ(1U, task_runner_->NumPendingTasks());
diff --git a/chrome/browser/chromeos/policy/hostname_handler.cc b/chrome/browser/chromeos/policy/hostname_handler.cc
index 7b616ef6..2898b18 100644
--- a/chrome/browser/chromeos/policy/hostname_handler.cc
+++ b/chrome/browser/chromeos/policy/hostname_handler.cc
@@ -48,7 +48,7 @@
 
 namespace policy {
 
-HostnameHandler::HostnameHandler(chromeos::CrosSettings* cros_settings)
+HostnameHandler::HostnameHandler(ash::CrosSettings* cros_settings)
     : cros_settings_(cros_settings) {
   policy_subscription_ = cros_settings_->AddSettingsObserver(
       chromeos::kDeviceHostnameTemplate,
diff --git a/chrome/browser/chromeos/policy/hostname_handler.h b/chrome/browser/chromeos/policy/hostname_handler.h
index dc451fd8..14b5b37 100644
--- a/chrome/browser/chromeos/policy/hostname_handler.h
+++ b/chrome/browser/chromeos/policy/hostname_handler.h
@@ -21,7 +21,7 @@
 // setting.
 class HostnameHandler : public chromeos::NetworkStateHandlerObserver {
  public:
-  explicit HostnameHandler(chromeos::CrosSettings* cros_settings);
+  explicit HostnameHandler(ash::CrosSettings* cros_settings);
   ~HostnameHandler() override;
 
   // NetworkStateHandlerObserver overrides
@@ -50,7 +50,7 @@
 
   void OnDeviceHostnamePropertyChangedAndMachineStatisticsLoaded();
 
-  chromeos::CrosSettings* cros_settings_;
+  ash::CrosSettings* cros_settings_;
   base::CallbackListSubscription policy_subscription_;
   std::string hostname_;
   base::WeakPtrFactory<HostnameHandler> weak_factory_{this};
diff --git a/chrome/browser/chromeos/policy/lock_to_single_user_manager.cc b/chrome/browser/chromeos/policy/lock_to_single_user_manager.cc
index 56938e12..4829c7ed 100644
--- a/chrome/browser/chromeos/policy/lock_to_single_user_manager.cc
+++ b/chrome/browser/chromeos/policy/lock_to_single_user_manager.cc
@@ -68,7 +68,7 @@
     return;
 
   int policy_value = -1;
-  if (!chromeos::CrosSettings::Get()->GetInteger(
+  if (!ash::CrosSettings::Get()->GetInteger(
           chromeos::kDeviceRebootOnUserSignout, &policy_value)) {
     return;
   }
diff --git a/chrome/browser/chromeos/policy/lock_to_single_user_manager_unittest.cc b/chrome/browser/chromeos/policy/lock_to_single_user_manager_unittest.cc
index f5a4db5..1a1125fe 100644
--- a/chrome/browser/chromeos/policy/lock_to_single_user_manager_unittest.cc
+++ b/chrome/browser/chromeos/policy/lock_to_single_user_manager_unittest.cc
@@ -132,7 +132,7 @@
   }
 
  private:
-  chromeos::ScopedCrosSettingsTestHelper settings_helper_{
+  ash::ScopedCrosSettingsTestHelper settings_helper_{
       /* create_settings_service= */ false};
   chromeos::FakeChromeUserManager* fake_user_manager_{
       new chromeos::FakeChromeUserManager()};
diff --git a/chrome/browser/chromeos/policy/minimum_version_policy_handler.cc b/chrome/browser/chromeos/policy/minimum_version_policy_handler.cc
index f1c68ca..c1a26b86d 100644
--- a/chrome/browser/chromeos/policy/minimum_version_policy_handler.cc
+++ b/chrome/browser/chromeos/policy/minimum_version_policy_handler.cc
@@ -154,7 +154,7 @@
 
 MinimumVersionPolicyHandler::MinimumVersionPolicyHandler(
     Delegate* delegate,
-    chromeos::CrosSettings* cros_settings)
+    ash::CrosSettings* cros_settings)
     : delegate_(delegate),
       cros_settings_(cros_settings),
       clock_(base::DefaultClock::GetInstance()) {
diff --git a/chrome/browser/chromeos/policy/minimum_version_policy_handler.h b/chrome/browser/chromeos/policy/minimum_version_policy_handler.h
index d06ca40..7a30cd07 100644
--- a/chrome/browser/chromeos/policy/minimum_version_policy_handler.h
+++ b/chrome/browser/chromeos/policy/minimum_version_policy_handler.h
@@ -132,7 +132,7 @@
   };
 
   explicit MinimumVersionPolicyHandler(Delegate* delegate,
-                                       chromeos::CrosSettings* cros_settings);
+                                       ash::CrosSettings* cros_settings);
   ~MinimumVersionPolicyHandler() override;
 
   // BuildStateObserver:
@@ -295,7 +295,7 @@
 
   // Non-owning reference to CrosSettings. This class have shorter lifetime than
   // CrosSettings.
-  chromeos::CrosSettings* cros_settings_;
+  ash::CrosSettings* cros_settings_;
 
   base::Clock* const clock_;
 
diff --git a/chrome/browser/chromeos/policy/minimum_version_policy_handler_unittest.cc b/chrome/browser/chromeos/policy/minimum_version_policy_handler_unittest.cc
index 26325df..5225551 100644
--- a/chrome/browser/chromeos/policy/minimum_version_policy_handler_unittest.cc
+++ b/chrome/browser/chromeos/policy/minimum_version_policy_handler_unittest.cc
@@ -93,7 +93,7 @@
   bool user_managed_ = true;
   ScopedTestingLocalState local_state_;
   base::test::ScopedFeatureList feature_list_;
-  chromeos::ScopedTestingCrosSettings scoped_testing_cros_settings_;
+  ash::ScopedTestingCrosSettings scoped_testing_cros_settings_;
   chromeos::ScopedStubInstallAttributes scoped_stub_install_attributes_;
   chromeos::FakeUpdateEngineClient* fake_update_engine_client_;
   std::unique_ptr<base::Version> current_version_;
@@ -136,7 +136,7 @@
 
 void MinimumVersionPolicyHandlerTest::CreateMinimumVersionHandler() {
   minimum_version_policy_handler_.reset(
-      new MinimumVersionPolicyHandler(this, chromeos::CrosSettings::Get()));
+      new MinimumVersionPolicyHandler(this, ash::CrosSettings::Get()));
 }
 
 const MinimumVersionRequirement* MinimumVersionPolicyHandlerTest::GetState()
diff --git a/chrome/browser/chromeos/policy/network_configuration_updater_unittest.cc b/chrome/browser/chromeos/policy/network_configuration_updater_unittest.cc
index 741684e..603d32d3 100644
--- a/chrome/browser/chromeos/policy/network_configuration_updater_unittest.cc
+++ b/chrome/browser/chromeos/policy/network_configuration_updater_unittest.cc
@@ -438,7 +438,7 @@
     network_configuration_updater_ =
         DeviceNetworkConfigurationUpdater::CreateForDevicePolicy(
             policy_service_.get(), &network_config_handler_,
-            &network_device_handler_, chromeos::CrosSettings::Get(),
+            &network_device_handler_, ash::CrosSettings::Get(),
             testing_device_asset_id_getter);
     return network_configuration_updater_.get();
   }
@@ -450,8 +450,8 @@
       network_config_handler_;
   FakeNetworkDeviceHandler network_device_handler_;
   chromeos::ScopedStubInstallAttributes scoped_stub_install_attributes_;
-  chromeos::ScopedTestDeviceSettingsService scoped_device_settings_service_;
-  chromeos::ScopedTestingCrosSettings scoped_testing_cros_settings_;
+  ash::ScopedTestDeviceSettingsService scoped_device_settings_service_;
+  ash::ScopedTestingCrosSettings scoped_testing_cros_settings_;
   chromeos::system::ScopedFakeStatisticsProvider fake_statistics_provider_;
 
   // Ownership of client_certificate_importer_owned_ is passed to the
diff --git a/chrome/browser/chromeos/policy/off_hours/device_off_hours_controller.cc b/chrome/browser/chromeos/policy/off_hours/device_off_hours_controller.cc
index 0204fff..e11d6bb 100644
--- a/chrome/browser/chromeos/policy/off_hours/device_off_hours_controller.cc
+++ b/chrome/browser/chromeos/policy/off_hours/device_off_hours_controller.cc
@@ -112,7 +112,7 @@
 
 void DeviceOffHoursController::OffHoursModeIsChanged() const {
   VLOG(1) << "OffHours mode is changed to " << off_hours_mode_;
-  chromeos::DeviceSettingsService::Get()->Load();
+  ash::DeviceSettingsService::Get()->Load();
 }
 
 void DeviceOffHoursController::UpdateOffHoursMode() {
diff --git a/chrome/browser/chromeos/policy/off_hours/device_off_hours_controller_unittest.cc b/chrome/browser/chromeos/policy/off_hours/device_off_hours_controller_unittest.cc
index c73212b..132f6b0 100644
--- a/chrome/browser/chromeos/policy/off_hours/device_off_hours_controller_unittest.cc
+++ b/chrome/browser/chromeos/policy/off_hours/device_off_hours_controller_unittest.cc
@@ -99,16 +99,15 @@
 
 }  // namespace
 
-class DeviceOffHoursControllerSimpleTest
-    : public chromeos::DeviceSettingsTestBase {
+class DeviceOffHoursControllerSimpleTest : public ash::DeviceSettingsTestBase {
  protected:
   DeviceOffHoursControllerSimpleTest()
-      : chromeos::DeviceSettingsTestBase(
+      : ash::DeviceSettingsTestBase(
             base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
   ~DeviceOffHoursControllerSimpleTest() override = default;
 
   void SetUp() override {
-    chromeos::DeviceSettingsTestBase::SetUp();
+    ash::DeviceSettingsTestBase::SetUp();
     chromeos::SystemClockClient::InitializeFake();
     system_clock_client()->SetServiceIsAvailable(false);
 
@@ -120,7 +119,7 @@
 
   void TearDown() override {
     chromeos::SystemClockClient::Shutdown();
-    chromeos::DeviceSettingsTestBase::TearDown();
+    ash::DeviceSettingsTestBase::TearDown();
   }
 
   void UpdateDeviceSettings() {
diff --git a/chrome/browser/chromeos/policy/powerwash_requirements_checker.cc b/chrome/browser/chromeos/policy/powerwash_requirements_checker.cc
index 0cdb18cb..77691623 100644
--- a/chrome/browser/chromeos/policy/powerwash_requirements_checker.cc
+++ b/chrome/browser/chromeos/policy/powerwash_requirements_checker.cc
@@ -143,7 +143,7 @@
 
 bool PowerwashRequirementsChecker::IsPolicySet() const {
   int policy_value = RebootOnSignOutPolicy::NEVER;
-  if (!chromeos::CrosSettings::Get()->GetInteger(
+  if (!ash::CrosSettings::Get()->GetInteger(
           chromeos::kDeviceRebootOnUserSignout, &policy_value)) {
     return false;
   }
diff --git a/chrome/browser/chromeos/policy/powerwash_requirements_checker_unittest.cc b/chrome/browser/chromeos/policy/powerwash_requirements_checker_unittest.cc
index b5ef4d6..1c629ea4 100644
--- a/chrome/browser/chromeos/policy/powerwash_requirements_checker_unittest.cc
+++ b/chrome/browser/chromeos/policy/powerwash_requirements_checker_unittest.cc
@@ -67,7 +67,7 @@
   }
 
  private:
-  chromeos::ScopedCrosSettingsTestHelper settings_helper_{
+  ash::ScopedCrosSettingsTestHelper settings_helper_{
       /* create_settings_service=*/false};
   chromeos::FakeChromeUserManager* fake_user_manager_;
   user_manager::ScopedUserManager scoped_user_manager_;
diff --git a/chrome/browser/chromeos/policy/rsu/lookup_key_uploader_unittest.cc b/chrome/browser/chromeos/policy/rsu/lookup_key_uploader_unittest.cc
index 313ccb2f..2393afd 100644
--- a/chrome/browser/chromeos/policy/rsu/lookup_key_uploader_unittest.cc
+++ b/chrome/browser/chromeos/policy/rsu/lookup_key_uploader_unittest.cc
@@ -37,12 +37,12 @@
 const char kValidRsuDeviceIdEncoded[] =
     "MTIz";  // base::Base64Encode(kValidRsuDeviceId, kValidRsuDeviceencoded)
 }
-class LookupKeyUploaderTest : public chromeos::DeviceSettingsTestBase {
+class LookupKeyUploaderTest : public ash::DeviceSettingsTestBase {
  protected:
   LookupKeyUploaderTest() = default;
 
   void SetUp() override {
-    chromeos::DeviceSettingsTestBase::SetUp();
+    ash::DeviceSettingsTestBase::SetUp();
     pref_service_.registry()->RegisterStringPref(
         prefs::kLastRsuDeviceIdUploaded, std::string());
     lookup_key_uploader_ = std::make_unique<LookupKeyUploader>(
diff --git a/chrome/browser/chromeos/policy/scheduled_update_checker/device_scheduled_update_checker.cc b/chrome/browser/chromeos/policy/scheduled_update_checker/device_scheduled_update_checker.cc
index b983879..8e1b0c8 100644
--- a/chrome/browser/chromeos/policy/scheduled_update_checker/device_scheduled_update_checker.cc
+++ b/chrome/browser/chromeos/policy/scheduled_update_checker/device_scheduled_update_checker.cc
@@ -266,7 +266,7 @@
 // |os_and_policies_update_checker_| will be destroyed as part of this object,
 // so it's safe to use "this" with any callbacks.
 DeviceScheduledUpdateChecker::DeviceScheduledUpdateChecker(
-    chromeos::CrosSettings* cros_settings,
+    ash::CrosSettings* cros_settings,
     chromeos::NetworkStateHandler* network_state_handler)
     : cros_settings_(cros_settings),
       cros_settings_subscription_(cros_settings_->AddSettingsObserver(
diff --git a/chrome/browser/chromeos/policy/scheduled_update_checker/device_scheduled_update_checker.h b/chrome/browser/chromeos/policy/scheduled_update_checker/device_scheduled_update_checker.h
index 3e2cf88d..aa082a3d 100644
--- a/chrome/browser/chromeos/policy/scheduled_update_checker/device_scheduled_update_checker.h
+++ b/chrome/browser/chromeos/policy/scheduled_update_checker/device_scheduled_update_checker.h
@@ -31,7 +31,7 @@
     : public chromeos::system::TimezoneSettings::Observer {
  public:
   DeviceScheduledUpdateChecker(
-      chromeos::CrosSettings* cros_settings,
+      ash::CrosSettings* cros_settings,
       chromeos::NetworkStateHandler* network_state_handler);
   ~DeviceScheduledUpdateChecker() override;
 
@@ -127,7 +127,7 @@
   virtual const icu::TimeZone& GetTimeZone();
 
   // Used to retrieve Chrome OS settings. Not owned.
-  chromeos::CrosSettings* const cros_settings_;
+  ash::CrosSettings* const cros_settings_;
 
   // Subscription for callback when settings change.
   base::CallbackListSubscription cros_settings_subscription_;
diff --git a/chrome/browser/chromeos/policy/scheduled_update_checker/device_scheduled_update_checker_unittest.cc b/chrome/browser/chromeos/policy/scheduled_update_checker/device_scheduled_update_checker_unittest.cc
index d3b4165..f1cdfd2 100644
--- a/chrome/browser/chromeos/policy/scheduled_update_checker/device_scheduled_update_checker_unittest.cc
+++ b/chrome/browser/chromeos/policy/scheduled_update_checker/device_scheduled_update_checker_unittest.cc
@@ -221,7 +221,7 @@
     : public DeviceScheduledUpdateChecker {
  public:
   DeviceScheduledUpdateCheckerForTest(
-      chromeos::CrosSettings* cros_settings,
+      ash::CrosSettings* cros_settings,
       chromeos::NetworkStateHandler* network_state_handler,
       const base::Clock* clock,
       const base::TickClock* tick_clock)
@@ -328,7 +328,7 @@
 
     device_scheduled_update_checker_ =
         std::make_unique<DeviceScheduledUpdateCheckerForTest>(
-            chromeos::CrosSettings::Get(),
+            ash::CrosSettings::Get(),
             network_state_test_helper_->network_state_handler(),
             task_environment_.GetMockClock(),
             task_environment_.GetMockTickClock());
@@ -586,7 +586,7 @@
   base::test::TaskEnvironment task_environment_;
   std::unique_ptr<DeviceScheduledUpdateCheckerForTest>
       device_scheduled_update_checker_;
-  chromeos::ScopedTestingCrosSettings cros_settings_;
+  ash::ScopedTestingCrosSettings cros_settings_;
   chromeos::FakeUpdateEngineClient* fake_update_engine_client_;
   std::unique_ptr<chromeos::NetworkStateTestHelper> network_state_test_helper_;
   device::TestWakeLockProvider wake_lock_provider_;
diff --git a/chrome/browser/chromeos/policy/status_collector/child_status_collector.cc b/chrome/browser/chromeos/policy/status_collector/child_status_collector.cc
index 7bf556d..32f72f27 100644
--- a/chrome/browser/chromeos/policy/status_collector/child_status_collector.cc
+++ b/chrome/browser/chromeos/policy/status_collector/child_status_collector.cc
@@ -121,7 +121,7 @@
     chromeos::system::StatisticsProvider* provider,
     const AndroidStatusFetcher& android_status_fetcher,
     TimeDelta activity_day_start)
-    : StatusCollector(provider, chromeos::CrosSettings::Get()),
+    : StatusCollector(provider, ash::CrosSettings::Get()),
       pref_service_(pref_service),
       profile_(profile),
       android_status_fetcher_(android_status_fetcher) {
diff --git a/chrome/browser/chromeos/policy/status_collector/child_status_collector_browsertest.cc b/chrome/browser/chromeos/policy/status_collector/child_status_collector_browsertest.cc
index 07ad343..62ec3bb 100644
--- a/chrome/browser/chromeos/policy/status_collector/child_status_collector_browsertest.cc
+++ b/chrome/browser/chromeos/policy/status_collector/child_status_collector_browsertest.cc
@@ -424,7 +424,7 @@
   ChromeContentBrowserClient browser_content_client_;
   chromeos::system::ScopedFakeStatisticsProvider fake_statistics_provider_;
   chromeos::ScopedStubInstallAttributes scoped_stub_install_attributes_;
-  chromeos::ScopedTestingCrosSettings scoped_testing_cros_settings_;
+  ash::ScopedTestingCrosSettings scoped_testing_cros_settings_;
   base::test::ScopedFeatureList scoped_feature_list_;
   chromeos::FakeOwnerSettingsService owner_settings_service_{
       scoped_testing_cros_settings_.device_settings(), nullptr};
diff --git a/chrome/browser/chromeos/policy/status_collector/device_status_collector.cc b/chrome/browser/chromeos/policy/status_collector/device_status_collector.cc
index 46c3209..1aec9292 100644
--- a/chrome/browser/chromeos/policy/status_collector/device_status_collector.cc
+++ b/chrome/browser/chromeos/policy/status_collector/device_status_collector.cc
@@ -1323,7 +1323,7 @@
     const GraphicsStatusFetcher& graphics_status_fetcher,
     const CrashReportInfoFetcher& crash_report_info_fetcher,
     base::Clock* clock)
-    : StatusCollector(provider, chromeos::CrosSettings::Get(), clock),
+    : StatusCollector(provider, ash::CrosSettings::Get(), clock),
       pref_service_(pref_service),
       firmware_fetch_error_(kFirmwareNotInitialized),
       volume_info_fetcher_(volume_info_fetcher),
diff --git a/chrome/browser/chromeos/policy/status_collector/device_status_collector_browsertest.cc b/chrome/browser/chromeos/policy/status_collector/device_status_collector_browsertest.cc
index d6947409..3e9a8186 100644
--- a/chrome/browser/chromeos/policy/status_collector/device_status_collector_browsertest.cc
+++ b/chrome/browser/chromeos/policy/status_collector/device_status_collector_browsertest.cc
@@ -1085,7 +1085,7 @@
   chromeos::system::ScopedFakeStatisticsProvider fake_statistics_provider_;
   DiskMountManager::MountPointMap mount_point_map_;
   chromeos::ScopedStubInstallAttributes scoped_stub_install_attributes_;
-  chromeos::ScopedTestingCrosSettings scoped_testing_cros_settings_;
+  ash::ScopedTestingCrosSettings scoped_testing_cros_settings_;
   chromeos::FakeOwnerSettingsService owner_settings_service_{
       scoped_testing_cros_settings_.device_settings(), nullptr};
   // local_state_ should be destructed after TestingProfile.
diff --git a/chrome/browser/chromeos/policy/status_collector/status_collector.cc b/chrome/browser/chromeos/policy/status_collector/status_collector.cc
index 03773bd0..0890ef2 100644
--- a/chrome/browser/chromeos/policy/status_collector/status_collector.cc
+++ b/chrome/browser/chromeos/policy/status_collector/status_collector.cc
@@ -28,7 +28,7 @@
 // session has been removed from policy since the session started, in which
 // case we won't report its status).
 std::unique_ptr<DeviceLocalAccount> GetCurrentKioskDeviceLocalAccount(
-    chromeos::CrosSettings* settings) {
+    ash::CrosSettings* settings) {
   if (!user_manager::UserManager::Get()->IsLoggedInAsAnyKioskApp()) {
     return nullptr;
   }
@@ -102,7 +102,7 @@
 }
 
 StatusCollector::StatusCollector(chromeos::system::StatisticsProvider* provider,
-                                 chromeos::CrosSettings* cros_settings,
+                                 ash::CrosSettings* cros_settings,
                                  base::Clock* clock)
     : statistics_provider_(provider),
       cros_settings_(cros_settings),
@@ -113,7 +113,7 @@
 std::unique_ptr<DeviceLocalAccount>
 StatusCollector::GetAutoLaunchedKioskSessionInfo() {
   std::unique_ptr<DeviceLocalAccount> account =
-      GetCurrentKioskDeviceLocalAccount(chromeos::CrosSettings::Get());
+      GetCurrentKioskDeviceLocalAccount(ash::CrosSettings::Get());
   if (!account) {
     // No auto-launched kiosk session active.
     return nullptr;
diff --git a/chrome/browser/chromeos/policy/status_collector/status_collector.h b/chrome/browser/chromeos/policy/status_collector/status_collector.h
index 33dd6d44..4d976fdd 100644
--- a/chrome/browser/chromeos/policy/status_collector/status_collector.h
+++ b/chrome/browser/chromeos/policy/status_collector/status_collector.h
@@ -20,11 +20,14 @@
 class PrefRegistrySimple;
 class Profile;
 
-namespace chromeos {
+namespace ash {
 class CrosSettings;
+}  // namespace ash
+
+namespace chromeos {
 namespace system {
 class StatisticsProvider;
-}
+}  // namespace system
 }  // namespace chromeos
 
 namespace policy {
@@ -85,7 +88,7 @@
       chromeos::system::StatisticsProvider* statistics_provider);
 
   StatusCollector(chromeos::system::StatisticsProvider* provider,
-                  chromeos::CrosSettings* cros_settings,
+                  ash::CrosSettings* cros_settings,
                   base::Clock* clock = base::DefaultClock::GetInstance());
   virtual ~StatusCollector();
 
@@ -128,7 +131,7 @@
 
   chromeos::system::StatisticsProvider* const statistics_provider_;
 
-  chromeos::CrosSettings* const cros_settings_;
+  ash::CrosSettings* const cros_settings_;
 
   // Cached values of the reporting settings.
   bool report_version_info_ = false;
diff --git a/chrome/browser/chromeos/policy/status_uploader.cc b/chrome/browser/chromeos/policy/status_uploader.cc
index a437e26..a9ddf9e 100644
--- a/chrome/browser/chromeos/policy/status_uploader.cc
+++ b/chrome/browser/chromeos/policy/status_uploader.cc
@@ -55,7 +55,7 @@
   // Listen for changes to the upload delay, and start sending updates to the
   // server.
   upload_frequency_subscription_ =
-      chromeos::CrosSettings::Get()->AddSettingsObserver(
+      ash::CrosSettings::Get()->AddSettingsObserver(
           chromeos::kReportUploadFrequency,
           base::BindRepeating(&StatusUploader::RefreshUploadFrequency,
                               base::Unretained(this)));
@@ -106,7 +106,7 @@
   // Attempt to fetch the current value of the reporting settings.
   // If trusted values are not available, register this function to be called
   // back when they are available.
-  chromeos::CrosSettings* settings = chromeos::CrosSettings::Get();
+  ash::CrosSettings* settings = ash::CrosSettings::Get();
   if (chromeos::CrosSettingsProvider::TRUSTED !=
       settings->PrepareTrustedValues(
           base::BindOnce(&StatusUploader::RefreshUploadFrequency,
diff --git a/chrome/browser/chromeos/policy/status_uploader_unittest.cc b/chrome/browser/chromeos/policy/status_uploader_unittest.cc
index 9885ec9..9710d030 100644
--- a/chrome/browser/chromeos/policy/status_uploader_unittest.cc
+++ b/chrome/browser/chromeos/policy/status_uploader_unittest.cc
@@ -177,7 +177,7 @@
 
   content::BrowserTaskEnvironment task_environment_;
   scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
-  chromeos::ScopedTestingCrosSettings scoped_testing_cros_settings_;
+  ash::ScopedTestingCrosSettings scoped_testing_cros_settings_;
   std::unique_ptr<MockDeviceStatusCollector> collector_;
   MockDeviceStatusCollector* collector_ptr_;
   ui::UserActivityDetector detector_;
diff --git a/chrome/browser/chromeos/policy/system_log_uploader.cc b/chrome/browser/chromeos/policy/system_log_uploader.cc
index 3d5b4853..6a0f4629 100644
--- a/chrome/browser/chromeos/policy/system_log_uploader.cc
+++ b/chrome/browser/chromeos/policy/system_log_uploader.cc
@@ -333,11 +333,10 @@
   SYSLOG(INFO) << "Creating system log uploader.";
 
   // Watch for policy changes.
-  upload_enabled_subscription_ =
-      chromeos::CrosSettings::Get()->AddSettingsObserver(
-          chromeos::kSystemLogUploadEnabled,
-          base::BindRepeating(&SystemLogUploader::RefreshUploadSettings,
-                              base::Unretained(this)));
+  upload_enabled_subscription_ = ash::CrosSettings::Get()->AddSettingsObserver(
+      chromeos::kSystemLogUploadEnabled,
+      base::BindRepeating(&SystemLogUploader::RefreshUploadSettings,
+                          base::Unretained(this)));
 
   // Fetch the current value of the policy.
   RefreshUploadSettings();
@@ -410,7 +409,7 @@
   // Attempt to fetch the current value of the reporting settings.
   // If trusted values are not available, register this function to be called
   // back when they are available.
-  chromeos::CrosSettings* settings = chromeos::CrosSettings::Get();
+  ash::CrosSettings* settings = ash::CrosSettings::Get();
   auto trust_status = settings->PrepareTrustedValues(base::BindOnce(
       &SystemLogUploader::RefreshUploadSettings, weak_factory_.GetWeakPtr()));
   if (trust_status != chromeos::CrosSettingsProvider::TRUSTED)
diff --git a/chrome/browser/chromeos/policy/system_log_uploader_unittest.cc b/chrome/browser/chromeos/policy/system_log_uploader_unittest.cc
index 4f47e48..11a13c2 100644
--- a/chrome/browser/chromeos/policy/system_log_uploader_unittest.cc
+++ b/chrome/browser/chromeos/policy/system_log_uploader_unittest.cc
@@ -284,7 +284,7 @@
 
  protected:
   content::BrowserTaskEnvironment task_environment_;
-  chromeos::ScopedCrosSettingsTestHelper settings_helper_;
+  ash::ScopedCrosSettingsTestHelper settings_helper_;
   scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
   bool is_zipped_upload_;
   base::test::ScopedFeatureList feature_list;
diff --git a/chrome/browser/chromeos/policy/system_proxy_manager.cc b/chrome/browser/chromeos/policy/system_proxy_manager.cc
index c1ca746c..a40f6dc 100644
--- a/chrome/browser/chromeos/policy/system_proxy_manager.cc
+++ b/chrome/browser/chromeos/policy/system_proxy_manager.cc
@@ -87,7 +87,7 @@
 
 namespace policy {
 
-SystemProxyManager::SystemProxyManager(chromeos::CrosSettings* cros_settings,
+SystemProxyManager::SystemProxyManager(ash::CrosSettings* cros_settings,
                                        PrefService* local_state)
     : cros_settings_(cros_settings),
       system_proxy_subscription_(cros_settings_->AddSettingsObserver(
diff --git a/chrome/browser/chromeos/policy/system_proxy_manager.h b/chrome/browser/chromeos/policy/system_proxy_manager.h
index ac93d44..72ac491 100644
--- a/chrome/browser/chromeos/policy/system_proxy_manager.h
+++ b/chrome/browser/chromeos/policy/system_proxy_manager.h
@@ -57,7 +57,7 @@
 // managed network changes to another class.
 class SystemProxyManager : public chromeos::NetworkStateHandlerObserver {
  public:
-  SystemProxyManager(chromeos::CrosSettings* cros_settings,
+  SystemProxyManager(ash::CrosSettings* cros_settings,
                      PrefService* local_state);
   SystemProxyManager(const SystemProxyManager&) = delete;
 
@@ -194,7 +194,7 @@
   // Closes the authentication notification or dialog if shown.
   void CloseAuthenticationUI();
 
-  chromeos::CrosSettings* cros_settings_;
+  ash::CrosSettings* cros_settings_;
   base::CallbackListSubscription system_proxy_subscription_;
 
   bool system_proxy_enabled_ = false;
diff --git a/chrome/browser/chromeos/policy/system_proxy_manager_unittest.cc b/chrome/browser/chromeos/policy/system_proxy_manager_unittest.cc
index 9eb240c..71e0ee1 100644
--- a/chrome/browser/chromeos/policy/system_proxy_manager_unittest.cc
+++ b/chrome/browser/chromeos/policy/system_proxy_manager_unittest.cc
@@ -113,7 +113,7 @@
     profile_ = std::make_unique<TestingProfile>();
     chromeos::SystemProxyClient::InitializeFake();
     system_proxy_manager_ = std::make_unique<SystemProxyManager>(
-        chromeos::CrosSettings::Get(), local_state_.Get());
+        ash::CrosSettings::Get(), local_state_.Get());
     // Listen for pref changes for the primary profile.
     system_proxy_manager_->StartObservingPrimaryProfilePrefs(profile_.get());
     chromeos::NetworkHandler::Get()->InitializePrefServices(
@@ -150,10 +150,10 @@
 
   content::BrowserTaskEnvironment task_environment_;
   ScopedTestingLocalState local_state_;
-  chromeos::ScopedTestingCrosSettings scoped_testing_cros_settings_;
+  ash::ScopedTestingCrosSettings scoped_testing_cros_settings_;
   std::unique_ptr<SystemProxyManager> system_proxy_manager_;
   std::unique_ptr<TestingProfile> profile_;
-  chromeos::ScopedDeviceSettingsTestHelper device_settings_test_helper_;
+  ash::ScopedDeviceSettingsTestHelper device_settings_test_helper_;
   chromeos::ScopedStubInstallAttributes test_install_attributes_;
 };
 
diff --git a/chrome/browser/chromeos/policy/tpm_auto_update_mode_policy_handler.cc b/chrome/browser/chromeos/policy/tpm_auto_update_mode_policy_handler.cc
index d255c4e1..2e230c0 100644
--- a/chrome/browser/chromeos/policy/tpm_auto_update_mode_policy_handler.cc
+++ b/chrome/browser/chromeos/policy/tpm_auto_update_mode_policy_handler.cc
@@ -37,7 +37,7 @@
 // are available and AutoUpdateMode::kNever will be returned. This value is set
 // via the device policy TPMFirmwareUpdateSettings.
 policy::AutoUpdateMode GetTPMAutoUpdateModeSetting(
-    const chromeos::CrosSettings* cros_settings,
+    const ash::CrosSettings* cros_settings,
     const base::RepeatingClosure callback) {
   if (!g_browser_process->platform_part()
            ->browser_policy_connector_chromeos()
@@ -81,7 +81,7 @@
 namespace policy {
 
 TPMAutoUpdateModePolicyHandler::TPMAutoUpdateModePolicyHandler(
-    chromeos::CrosSettings* cros_settings,
+    ash::CrosSettings* cros_settings,
     PrefService* local_state)
     : cros_settings_(cros_settings), local_state_(local_state) {
   DCHECK(local_state_);
diff --git a/chrome/browser/chromeos/policy/tpm_auto_update_mode_policy_handler.h b/chrome/browser/chromeos/policy/tpm_auto_update_mode_policy_handler.h
index fb38df1..f14b7092 100644
--- a/chrome/browser/chromeos/policy/tpm_auto_update_mode_policy_handler.h
+++ b/chrome/browser/chromeos/policy/tpm_auto_update_mode_policy_handler.h
@@ -52,7 +52,7 @@
   using ShowNotificationCallback = base::RepeatingCallback<void(
       chromeos::TpmAutoUpdateUserNotification notification_type)>;
 
-  TPMAutoUpdateModePolicyHandler(chromeos::CrosSettings* cros_settings,
+  TPMAutoUpdateModePolicyHandler(ash::CrosSettings* cros_settings,
                                  PrefService* local_state);
   ~TPMAutoUpdateModePolicyHandler();
 
@@ -96,7 +96,7 @@
 
   void ShowTPMUpdateOnNextRebootNotification();
 
-  chromeos::CrosSettings* cros_settings_;
+  ash::CrosSettings* cros_settings_;
 
   PrefService* local_state_;
 
diff --git a/chrome/browser/chromeos/policy/tpm_auto_update_mode_policy_handler_unittest.cc b/chrome/browser/chromeos/policy/tpm_auto_update_mode_policy_handler_unittest.cc
index 9a8ad33..1218d9d 100644
--- a/chrome/browser/chromeos/policy/tpm_auto_update_mode_policy_handler_unittest.cc
+++ b/chrome/browser/chromeos/policy/tpm_auto_update_mode_policy_handler_unittest.cc
@@ -82,7 +82,7 @@
   chromeos::ScopedStubInstallAttributes test_install_attributes_{
       chromeos::StubInstallAttributes::CreateCloudManaged("example.com",
                                                           "fake-id")};
-  chromeos::ScopedTestingCrosSettings scoped_testing_cros_settings_;
+  ash::ScopedTestingCrosSettings scoped_testing_cros_settings_;
 
   base::WeakPtrFactory<TPMAutoUpdateModePolicyHandlerTest> weak_factory_{this};
 };
@@ -91,7 +91,7 @@
 // policy option TPMFirmwareUpdateSettings.AutoUpdateMode.
 TEST_F(TPMAutoUpdateModePolicyHandlerTest, PolicyUpdatesTriggered) {
   TPMAutoUpdateModePolicyHandler tpm_update_policy_handler(
-      chromeos::CrosSettings::Get(), local_state_.Get());
+      ash::CrosSettings::Get(), local_state_.Get());
   tpm_update_policy_handler.SetUpdateCheckerCallbackForTesting(
       base::BindRepeating(&TPMAutoUpdateModePolicyHandlerTest::CheckForUpdate,
                           weak_factory_.GetWeakPtr()));
@@ -129,7 +129,7 @@
 // state preserving update is not available.
 TEST_F(TPMAutoUpdateModePolicyHandlerTest, NoUpdatesAvailable) {
   TPMAutoUpdateModePolicyHandler tpm_update_policy_handler(
-      chromeos::CrosSettings::Get(), local_state_.Get());
+      ash::CrosSettings::Get(), local_state_.Get());
   tpm_update_policy_handler.SetUpdateCheckerCallbackForTesting(
       base::BindRepeating(&TPMAutoUpdateModePolicyHandlerTest::CheckForUpdate,
                           weak_factory_.GetWeakPtr()));
@@ -146,7 +146,7 @@
 // after 24 hours is shown.
 TEST_F(TPMAutoUpdateModePolicyHandlerTest, ShowPlannedUpdateNotification) {
   TPMAutoUpdateModePolicyHandler tpm_update_policy_handler(
-      chromeos::CrosSettings::Get(), local_state_.Get());
+      ash::CrosSettings::Get(), local_state_.Get());
   tpm_update_policy_handler.SetUpdateCheckerCallbackForTesting(
       base::BindRepeating(&TPMAutoUpdateModePolicyHandlerTest::CheckForUpdate,
                           weak_factory_.GetWeakPtr()));
@@ -180,7 +180,7 @@
 TEST_F(TPMAutoUpdateModePolicyHandlerTest,
        ShowUpdateOnRebootNotificationNoTimer) {
   TPMAutoUpdateModePolicyHandler tpm_update_policy_handler(
-      chromeos::CrosSettings::Get(), local_state_.Get());
+      ash::CrosSettings::Get(), local_state_.Get());
   tpm_update_policy_handler.SetUpdateCheckerCallbackForTesting(
       base::BindRepeating(&TPMAutoUpdateModePolicyHandlerTest::CheckForUpdate,
                           weak_factory_.GetWeakPtr()));
@@ -218,7 +218,7 @@
 TEST_F(TPMAutoUpdateModePolicyHandlerTest,
        ShowUpdateOnRebootNotificationTimer) {
   TPMAutoUpdateModePolicyHandler tpm_update_policy_handler(
-      chromeos::CrosSettings::Get(), local_state_.Get());
+      ash::CrosSettings::Get(), local_state_.Get());
   tpm_update_policy_handler.SetUpdateCheckerCallbackForTesting(
       base::BindRepeating(&TPMAutoUpdateModePolicyHandlerTest::CheckForUpdate,
                           weak_factory_.GetWeakPtr()));
@@ -258,7 +258,7 @@
 // TPM update with user acknowlegment triggered.
 TEST_F(TPMAutoUpdateModePolicyHandlerTest, UpdateWithUserAcknowlegment) {
   TPMAutoUpdateModePolicyHandler tpm_update_policy_handler(
-      chromeos::CrosSettings::Get(), local_state_.Get());
+      ash::CrosSettings::Get(), local_state_.Get());
   tpm_update_policy_handler.SetUpdateCheckerCallbackForTesting(
       base::BindRepeating(&TPMAutoUpdateModePolicyHandlerTest::CheckForUpdate,
                           weak_factory_.GetWeakPtr()));
diff --git a/chrome/browser/chromeos/policy/unaffiliated_arc_allowed_browsertest.cc b/chrome/browser/chromeos/policy/unaffiliated_arc_allowed_browsertest.cc
index bf83441..a0d880d 100644
--- a/chrome/browser/chromeos/policy/unaffiliated_arc_allowed_browsertest.cc
+++ b/chrome/browser/chromeos/policy/unaffiliated_arc_allowed_browsertest.cc
@@ -76,7 +76,7 @@
   void RefreshPolicyAndWaitUntilDeviceSettingsUpdated() {
     base::RunLoop run_loop;
     base::CallbackListSubscription subscription =
-        chromeos::CrosSettings::Get()->AddSettingsObserver(
+        ash::CrosSettings::Get()->AddSettingsObserver(
             chromeos::kUnaffiliatedArcAllowed, run_loop.QuitClosure());
     RefreshDevicePolicy();
     run_loop.Run();
diff --git a/chrome/browser/chromeos/policy/user_policy_manager_builder_chromeos.cc b/chrome/browser/chromeos/policy/user_policy_manager_builder_chromeos.cc
index 8b7346b..1cb7497 100644
--- a/chrome/browser/chromeos/policy/user_policy_manager_builder_chromeos.cc
+++ b/chrome/browser/chromeos/policy/user_policy_manager_builder_chromeos.cc
@@ -286,7 +286,7 @@
 
     bool wildcard_match = false;
     if (connector->IsEnterpriseManaged() &&
-        chromeos::CrosSettings::Get()->IsUserAllowlisted(
+        ash::CrosSettings::Get()->IsUserAllowlisted(
             account_id.GetUserEmail(), &wildcard_match, user->GetType()) &&
         wildcard_match &&
         !connector->IsNonEnterpriseUser(account_id.GetUserEmail())) {
diff --git a/chrome/browser/chromeos/printing/calculators_policies_binder.h b/chrome/browser/chromeos/printing/calculators_policies_binder.h
index 6e0b6ea..2b509b9 100644
--- a/chrome/browser/chromeos/printing/calculators_policies_binder.h
+++ b/chrome/browser/chromeos/printing/calculators_policies_binder.h
@@ -17,9 +17,11 @@
 class PrefService;
 class PrefRegistrySimple;
 
-namespace chromeos {
-
+namespace ash {
 class CrosSettings;
+}  // namespace ash
+
+namespace chromeos {
 
 // Observes device settings & user profile modifications and propagates them to
 // BulkPrintersCalculator objects associated with given device context and user
@@ -30,7 +32,7 @@
 
   // Binds events from |settings| to the appropriate fields in |calculator|.
   static std::unique_ptr<CalculatorsPoliciesBinder> DeviceBinder(
-      CrosSettings* settings,
+      ash::CrosSettings* settings,
       base::WeakPtr<BulkPrintersCalculator> calculator);
 
   // Binds events from |profile| to the appropriate fields in |calculator|.
diff --git a/chrome/browser/chromeos/printing/enterprise_printers_provider.cc b/chrome/browser/chromeos/printing/enterprise_printers_provider.cc
index 708c0f9..6aa8ab5 100644
--- a/chrome/browser/chromeos/printing/enterprise_printers_provider.cc
+++ b/chrome/browser/chromeos/printing/enterprise_printers_provider.cc
@@ -52,7 +52,7 @@
 class EnterprisePrintersProviderImpl : public EnterprisePrintersProvider,
                                        public BulkPrintersCalculator::Observer {
  public:
-  EnterprisePrintersProviderImpl(CrosSettings* settings, Profile* profile)
+  EnterprisePrintersProviderImpl(ash::CrosSettings* settings, Profile* profile)
       : profile_(profile) {
     // initialization of pref_change_registrar
     pref_change_registrar_.Init(profile->GetPrefs());
@@ -287,7 +287,7 @@
 
 // static
 std::unique_ptr<EnterprisePrintersProvider> EnterprisePrintersProvider::Create(
-    CrosSettings* settings,
+    ash::CrosSettings* settings,
     Profile* profile) {
   return std::make_unique<EnterprisePrintersProviderImpl>(settings, profile);
 }
diff --git a/chrome/browser/chromeos/printing/enterprise_printers_provider.h b/chrome/browser/chromeos/printing/enterprise_printers_provider.h
index 649cc15..23213172 100644
--- a/chrome/browser/chromeos/printing/enterprise_printers_provider.h
+++ b/chrome/browser/chromeos/printing/enterprise_printers_provider.h
@@ -12,13 +12,16 @@
 #include "base/macros.h"
 #include "chrome/browser/profiles/profile.h"
 
+namespace ash {
+class CrosSettings;
+}  // namespace ash
+
 namespace user_prefs {
 class PrefRegistrySyncable;
 }
 
 namespace chromeos {
 
-class CrosSettings;
 class Printer;
 
 // Uses classes BulkPrintersCalculator and CalculatorsPoliciesBinder to track
@@ -44,7 +47,7 @@
 
   // |settings| is the source of device policies. |profile| is a user profile.
   static std::unique_ptr<EnterprisePrintersProvider> Create(
-      CrosSettings* settings,
+      ash::CrosSettings* settings,
       Profile* profile);
   virtual ~EnterprisePrintersProvider() = default;
 
diff --git a/chrome/browser/chromeos/tpm_firmware_update.h b/chrome/browser/chromeos/tpm_firmware_update.h
index 1469189..50d6fb2 100644
--- a/chrome/browser/chromeos/tpm_firmware_update.h
+++ b/chrome/browser/chromeos/tpm_firmware_update.h
@@ -66,4 +66,12 @@
 }  // namespace tpm_firmware_update
 }  // namespace chromeos
 
+// TODO(https://crbug.com/1164001): remove when Chrome OS code migration is
+// done.
+namespace ash {
+namespace tpm_firmware_update {
+using ::chromeos::tpm_firmware_update::DecodeSettingsProto;
+}  // namespace tpm_firmware_update
+}  // namespace ash
+
 #endif  // CHROME_BROWSER_CHROMEOS_TPM_FIRMWARE_UPDATE_H_
diff --git a/chrome/browser/chromeos/virtual_machines/virtual_machines_util.cc b/chrome/browser/chromeos/virtual_machines/virtual_machines_util.cc
index cf9ef53b3..b45c43d 100644
--- a/chrome/browser/chromeos/virtual_machines/virtual_machines_util.cc
+++ b/chrome/browser/chromeos/virtual_machines/virtual_machines_util.cc
@@ -11,8 +11,8 @@
 
 bool AreVirtualMachinesAllowedByPolicy() {
   bool virtual_machines_allowed;
-  if (chromeos::CrosSettings::Get()->GetBoolean(
-          chromeos::kVirtualMachinesAllowed, &virtual_machines_allowed)) {
+  if (ash::CrosSettings::Get()->GetBoolean(chromeos::kVirtualMachinesAllowed,
+                                           &virtual_machines_allowed)) {
     return virtual_machines_allowed;
   }
   // If device policy is not set, allow virtual machines.
diff --git a/chrome/browser/device/android/java/src/org/chromium/chrome/browser/device/DeviceConditions.java b/chrome/browser/device/android/java/src/org/chromium/chrome/browser/device/DeviceConditions.java
index 3c0a5b03..a68752f 100644
--- a/chrome/browser/device/android/java/src/org/chromium/chrome/browser/device/DeviceConditions.java
+++ b/chrome/browser/device/android/java/src/org/chromium/chrome/browser/device/DeviceConditions.java
@@ -18,6 +18,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
 
+import org.chromium.base.compat.ApiHelperForM;
 import org.chromium.net.ConnectionType;
 import org.chromium.net.NetworkChangeNotifier;
 
@@ -134,8 +135,8 @@
 
     @TargetApi(Build.VERSION_CODES.M)
     private static boolean isCurrentlyInIdleModeM(Context context) {
-        PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
-        return powerManager.isDeviceIdleMode();
+        return ApiHelperForM.isDeviceIdleMode(
+                (PowerManager) context.getSystemService(Context.POWER_SERVICE));
     }
 
     /**
diff --git a/chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos_unittest.cc b/chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos_unittest.cc
index ad3e0f4..5432586 100644
--- a/chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos_unittest.cc
+++ b/chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos_unittest.cc
@@ -77,13 +77,13 @@
         new ownership::MockOwnerKeyUtil());
     owner_key_util_->SetPublicKeyFromPrivateKey(
         *device_policy_.GetSigningKey());
-    chromeos::DeviceSettingsService::Get()->SetSessionManager(
+    ash::DeviceSettingsService::Get()->SetSessionManager(
         &session_manager_client_, owner_key_util_);
   }
 
   void TearDown() override {
     base::ThreadPoolInstance::Get()->FlushForTesting();
-    chromeos::DeviceSettingsService::Get()->UnsetSessionManager();
+    ash::DeviceSettingsService::Get()->UnsetSessionManager();
     chromeos::SystemSaltGetter::Shutdown();
     chromeos::CryptohomeClient::Shutdown();
   }
@@ -122,7 +122,7 @@
     device_policy_.policy_data().set_service_account_identity(account_id);
     device_policy_.Build();
     session_manager_client_.set_device_policy(device_policy_.GetBlob());
-    chromeos::DeviceSettingsService::Get()->Load();
+    ash::DeviceSettingsService::Get()->Load();
     content::RunAllTasksUntilIdle();
   }
 
@@ -135,8 +135,8 @@
   content::BrowserTaskEnvironment task_environment_;
   ScopedTestingLocalState scoped_testing_local_state_;
   chromeos::ScopedStubInstallAttributes scoped_stub_install_attributes_;
-  chromeos::ScopedTestDeviceSettingsService scoped_device_settings_service_;
-  chromeos::ScopedTestCrosSettings scoped_test_cros_settings_{
+  ash::ScopedTestDeviceSettingsService scoped_device_settings_service_;
+  ash::ScopedTestCrosSettings scoped_test_cros_settings_{
       scoped_testing_local_state_.Get()};
   chromeos::FakeSessionManagerClient session_manager_client_;
   policy::DevicePolicyBuilder device_policy_;
diff --git a/chrome/browser/enterprise/reporting/android_app_info_generator_unittest.cc b/chrome/browser/enterprise/reporting/android_app_info_generator_unittest.cc
index 5392b61e..83b94da 100644
--- a/chrome/browser/enterprise/reporting/android_app_info_generator_unittest.cc
+++ b/chrome/browser/enterprise/reporting/android_app_info_generator_unittest.cc
@@ -112,12 +112,12 @@
   EXPECT_EQ(app_info->permissions_size(), 2);
 
   em::AndroidAppPermission permission0 = app_info->permissions(0);
-  EXPECT_EQ(permission0.name(), "AppPermission::CAMERA");
+  EXPECT_EQ(permission0.name(), "CAMERA");
   EXPECT_FALSE(permission0.granted());
   EXPECT_FALSE(permission0.managed());
 
   em::AndroidAppPermission permission1 = app_info->permissions(1);
-  EXPECT_EQ(permission1.name(), "AppPermission::LOCATION");
+  EXPECT_EQ(permission1.name(), "LOCATION");
   EXPECT_TRUE(permission1.granted());
   EXPECT_TRUE(permission1.managed());
 }
diff --git a/chrome/browser/extensions/activity_log/counting_policy_unittest.cc b/chrome/browser/extensions/activity_log/counting_policy_unittest.cc
index f1e7ceb..96bc6fe1 100644
--- a/chrome/browser/extensions/activity_log/counting_policy_unittest.cc
+++ b/chrome/browser/extensions/activity_log/counting_policy_unittest.cc
@@ -388,7 +388,7 @@
   content::BrowserTaskEnvironment task_environment_;
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  chromeos::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
+  ash::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
   std::unique_ptr<chromeos::ScopedTestUserManager> test_user_manager_;
 #endif
 };
diff --git a/chrome/browser/extensions/activity_log/fullstream_ui_policy_unittest.cc b/chrome/browser/extensions/activity_log/fullstream_ui_policy_unittest.cc
index ea55134..a773136 100644
--- a/chrome/browser/extensions/activity_log/fullstream_ui_policy_unittest.cc
+++ b/chrome/browser/extensions/activity_log/fullstream_ui_policy_unittest.cc
@@ -333,7 +333,7 @@
   content::BrowserTaskEnvironment task_environment_;
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  chromeos::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
+  ash::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
   std::unique_ptr<chromeos::ScopedTestUserManager> test_user_manager_;
 #endif
 };
diff --git a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_apitest_chromeos.cc b/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_apitest_chromeos.cc
index 1be6797..7e589bf 100644
--- a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_apitest_chromeos.cc
+++ b/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_apitest_chromeos.cc
@@ -69,7 +69,7 @@
   chromeos::FakeChromeUserManager* fake_user_manager_;
   std::unique_ptr<user_manager::ScopedUserManager> user_manager_enabler_;
 
-  chromeos::ScopedCrosSettingsTestHelper settings_helper_;
+  ash::ScopedCrosSettingsTestHelper settings_helper_;
   std::unique_ptr<chromeos::FakeOwnerSettingsService> owner_settings_service_;
 };
 
diff --git a/chrome/browser/extensions/api/chrome_extensions_api_client.cc b/chrome/browser/extensions/api/chrome_extensions_api_client.cc
index 8380ebe4..5b3b09d 100644
--- a/chrome/browser/extensions/api/chrome_extensions_api_client.cc
+++ b/chrome/browser/extensions/api/chrome_extensions_api_client.cc
@@ -326,8 +326,8 @@
 bool ChromeExtensionsAPIClient::ShouldAllowDetachingUsb(int vid,
                                                         int pid) const {
   const base::ListValue* policy_list;
-  if (chromeos::CrosSettings::Get()->GetList(chromeos::kUsbDetachableAllowlist,
-                                             &policy_list)) {
+  if (ash::CrosSettings::Get()->GetList(chromeos::kUsbDetachableAllowlist,
+                                        &policy_list)) {
     for (const auto& entry : *policy_list) {
       if (entry.FindIntKey(chromeos::kUsbDetachableAllowlistKeyVid) == vid &&
           entry.FindIntKey(chromeos::kUsbDetachableAllowlistKeyPid) == pid) {
diff --git a/chrome/browser/extensions/api/declarative_content/content_action.cc b/chrome/browser/extensions/api/declarative_content/content_action.cc
index bc33886..cce1e79 100644
--- a/chrome/browser/extensions/api/declarative_content/content_action.cc
+++ b/chrome/browser/extensions/api/declarative_content/content_action.cc
@@ -18,12 +18,12 @@
 #include "chrome/browser/profiles/profile.h"
 #include "components/sessions/content/session_tab_helper.h"
 #include "content/public/browser/invalidate_type.h"
-#include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
 #include "extensions/browser/extension_action.h"
 #include "extensions/browser/extension_action_manager.h"
 #include "extensions/browser/extension_system.h"
 #include "extensions/browser/extension_user_script_loader.h"
+#include "extensions/browser/extension_web_contents_observer.h"
 #include "extensions/browser/user_script_manager.h"
 #include "extensions/common/api/declarative/declarative_constants.h"
 #include "extensions/common/extension.h"
@@ -356,11 +356,11 @@
 void RequestContentScript::InstructRenderProcessToInject(
     content::WebContents* contents,
     const Extension* extension) const {
-  content::RenderFrameHost* render_frame_host = contents->GetMainFrame();
-  render_frame_host->Send(new ExtensionMsg_ExecuteDeclarativeScript(
-      render_frame_host->GetRoutingID(),
-      sessions::SessionTabHelper::IdForTab(contents).id(), extension->id(),
-      script_.id(), contents->GetLastCommittedURL()));
+  ExtensionWebContentsObserver::GetForWebContents(contents)
+      ->GetLocalFrame(contents->GetMainFrame())
+      ->ExecuteDeclarativeScript(
+          sessions::SessionTabHelper::IdForTab(contents).id(), extension->id(),
+          script_.id(), contents->GetLastCommittedURL());
 }
 
 // static
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc
index 820b5b3..289062a 100644
--- a/chrome/browser/extensions/api/settings_private/prefs_util.cc
+++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -80,7 +80,7 @@
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 bool IsPrivilegedCrosSetting(const std::string& pref_name) {
-  if (!chromeos::CrosSettings::IsCrosSettings(pref_name))
+  if (!ash::CrosSettings::IsCrosSettings(pref_name))
     return false;
   if (!ash::system::PerUserTimezoneEnabled()) {
     // kSystemTimezone should be changeable by all users.
@@ -97,7 +97,7 @@
   if (!profile->IsChild())
     return false;
 
-  return chromeos::CrosSettings::Get()
+  return ash::CrosSettings::Get()
       ->supervised_user_cros_settings_provider()
       ->HandlesSetting(pref_name);
 }
@@ -109,7 +109,7 @@
   // pre-set.
   DCHECK(IsRestrictedCrosSettingForChildUser(profile, pref_name));
 
-  return chromeos::CrosSettings::Get()
+  return ash::CrosSettings::Get()
       ->supervised_user_cros_settings_provider()
       ->Get(pref_name);
 }
diff --git a/chrome/browser/extensions/api/settings_private/settings_private_apitest.cc b/chrome/browser/extensions/api/settings_private/settings_private_apitest.cc
index a6a1fa5..dc80a33 100644
--- a/chrome/browser/extensions/api/settings_private/settings_private_apitest.cc
+++ b/chrome/browser/extensions/api/settings_private/settings_private_apitest.cc
@@ -78,7 +78,7 @@
   testing::NiceMock<policy::MockConfigurationPolicyProvider> provider_;
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  chromeos::ScopedTestingCrosSettings scoped_testing_cros_settings_;
+  ash::ScopedTestingCrosSettings scoped_testing_cros_settings_;
 #endif
 
   DISALLOW_COPY_AND_ASSIGN(SettingsPrivateApiTest);
diff --git a/chrome/browser/extensions/api/settings_private/settings_private_event_router.cc b/chrome/browser/extensions/api/settings_private/settings_private_event_router.cc
index 76c8b6b..903a5c9 100644
--- a/chrome/browser/extensions/api/settings_private/settings_private_event_router.cc
+++ b/chrome/browser/extensions/api/settings_private/settings_private_event_router.cc
@@ -101,7 +101,7 @@
       if (prefs_util_->IsCrosSetting(pref_name)) {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
         base::CallbackListSubscription subscription =
-            chromeos::CrosSettings::Get()->AddSettingsObserver(
+            ash::CrosSettings::Get()->AddSettingsObserver(
                 pref_name.c_str(),
                 base::BindRepeating(
                     &SettingsPrivateEventRouter::OnPreferenceChanged,
diff --git a/chrome/browser/extensions/app_background_page_apitest.cc b/chrome/browser/extensions/app_background_page_apitest.cc
index 35b6880..8455388 100644
--- a/chrome/browser/extensions/app_background_page_apitest.cc
+++ b/chrome/browser/extensions/app_background_page_apitest.cc
@@ -467,7 +467,8 @@
 }
 
 // TODO(https://crbug.com/1124033): Fails on LaCrOS bot.
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
+// TODO(https://crbug.com/1186442): Fails on linux-ozone-rel bot.
+#if BUILDFLAG(IS_CHROMEOS_LACROS) || defined(OS_LINUX)
 #define MAYBE_OpenPopupFromBGPage DISABLED_OpenPopupFromBGPage
 #else
 #define MAYBE_OpenPopupFromBGPage OpenPopupFromBGPage
diff --git a/chrome/browser/extensions/extension_action_icon_factory_unittest.cc b/chrome/browser/extensions/extension_action_icon_factory_unittest.cc
index bd6f403..8819a0f5 100644
--- a/chrome/browser/extensions/extension_action_icon_factory_unittest.cc
+++ b/chrome/browser/extensions/extension_action_icon_factory_unittest.cc
@@ -167,7 +167,7 @@
   ExtensionService* extension_service_;
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  chromeos::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
+  ash::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
   chromeos::ScopedTestUserManager test_user_manager_;
 #endif
 
diff --git a/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc b/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc
index 06d7bf4..c321ddc8 100644
--- a/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc
+++ b/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc
@@ -415,7 +415,7 @@
 
   // This is needed to create extension service under CrOS.
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  chromeos::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
+  ash::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
   std::unique_ptr<chromeos::ScopedTestUserManager> test_user_manager_;
 #endif
 
diff --git a/chrome/browser/extensions/extension_service_test_base.h b/chrome/browser/extensions/extension_service_test_base.h
index d7b6a6f25..7a352c1f 100644
--- a/chrome/browser/extensions/extension_service_test_base.h
+++ b/chrome/browser/extensions/extension_service_test_base.h
@@ -211,7 +211,7 @@
   extensions::ExtensionRegistry* registry_;
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  chromeos::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
+  ash::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
   chromeos::ScopedTestUserManager test_user_manager_;
 #endif
 
diff --git a/chrome/browser/extensions/extension_web_ui_unittest.cc b/chrome/browser/extensions/extension_web_ui_unittest.cc
index 40bf362..29c025fd2 100644
--- a/chrome/browser/extensions/extension_web_ui_unittest.cc
+++ b/chrome/browser/extensions/extension_web_ui_unittest.cc
@@ -68,7 +68,7 @@
   content::BrowserTaskEnvironment task_environment_;
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  chromeos::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
+  ash::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
   chromeos::ScopedTestUserManager test_user_manager_;
 #endif
 };
diff --git a/chrome/browser/extensions/forced_extensions/force_installed_metrics.cc b/chrome/browser/extensions/forced_extensions/force_installed_metrics.cc
index 6b100af9..5ebee36c 100644
--- a/chrome/browser/extensions/forced_extensions/force_installed_metrics.cc
+++ b/chrome/browser/extensions/forced_extensions/force_installed_metrics.cc
@@ -278,6 +278,30 @@
             ->extensions_enabled());
   }
 }
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+// Report type of user in case Force Installed Extensions fail to
+// install only if there is a user corresponding to given profile.
+void ReportUserType(Profile* profile, bool is_stuck_in_initial_creation_stage) {
+  InstallStageTracker::UserInfo user_info =
+      InstallStageTracker::GetUserInfo(profile);
+  // There can be extensions on the login screen. There is no user on the login
+  // screen and thus we would not report in that case.
+  if (!user_info.is_user_present)
+    return;
+
+  ForceInstalledMetrics::UserType user_type = ConvertUserType(user_info);
+  base::UmaHistogramEnumeration("Extensions.ForceInstalledFailureSessionType",
+                                user_type);
+  if (is_stuck_in_initial_creation_stage) {
+    base::UmaHistogramEnumeration(
+        "Extensions.ForceInstalledFailureSessionType."
+        "ExtensionStuckInCreatedStage",
+        user_type);
+  }
+}
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+
 }  // namespace
 
 ForceInstalledMetrics::ForceInstalledMetrics(
@@ -412,26 +436,13 @@
     }
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-    // Report type of user in case Force Installed Extensions fail to
-    // install only if there is a user corresponding to given profile. There can
-    // be extensions on the login screen. There is no user on the login screen
-    // and thus we would not report in that case.
-    if (chromeos::ProfileHelper::Get()->GetUserByProfile(profile_)) {
-      InstallStageTracker::UserInfo user_info =
-          InstallStageTracker::GetUserInfo(profile_);
-      ForceInstalledMetrics::UserType user_type = ConvertUserType(user_info);
-      base::UmaHistogramEnumeration(
-          "Extensions.ForceInstalledFailureSessionType", user_type);
-      if (failure_reason == FailureReason::IN_PROGRESS &&
-          installation.install_creation_stage ==
-              InstallStageTracker::InstallCreationStage::
-                  NOTIFIED_FROM_MANAGEMENT_INITIAL_CREATION_FORCED) {
-        base::UmaHistogramEnumeration(
-            "Extensions.ForceInstalledFailureSessionType."
-            "ExtensionStuckInCreatedStage",
-            user_type);
-      }
-    }
+    bool is_stuck_in_initial_creation_stage =
+        failure_reason == FailureReason::IN_PROGRESS &&
+        installation.install_stage == InstallStageTracker::Stage::CREATED &&
+        installation.install_creation_stage ==
+            InstallStageTracker::InstallCreationStage::
+                NOTIFIED_FROM_MANAGEMENT_INITIAL_CREATION_FORCED;
+    ReportUserType(profile_, is_stuck_in_initial_creation_stage);
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
     VLOG(2) << "Forced extension " << extension_id
             << " failed to install with data="
diff --git a/chrome/browser/extensions/forced_extensions/install_stage_tracker.cc b/chrome/browser/extensions/forced_extensions/install_stage_tracker.cc
index ac6bd05..de19e6d0 100644
--- a/chrome/browser/extensions/forced_extensions/install_stage_tracker.cc
+++ b/chrome/browser/extensions/forced_extensions/install_stage_tracker.cc
@@ -36,10 +36,14 @@
 }  // namespace
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+InstallStageTracker::UserInfo::UserInfo() = default;
 InstallStageTracker::UserInfo::UserInfo(const UserInfo&) = default;
 InstallStageTracker::UserInfo::UserInfo(user_manager::UserType user_type,
-                                        bool is_new_user)
-    : user_type(user_type), is_new_user(is_new_user) {}
+                                        bool is_new_user,
+                                        bool is_user_present)
+    : user_type(user_type),
+      is_new_user(is_new_user),
+      is_user_present(is_user_present) {}
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 // InstallStageTracker::InstallationData implementation.
@@ -131,10 +135,12 @@
     Profile* profile) {
   const user_manager::User* user =
       chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
-  DCHECK(user);
+  if (!user)
+    return UserInfo();
+
   bool is_new_user = user_manager::UserManager::Get()->IsCurrentUserNew() ||
                      profile->IsNewProfile();
-  UserInfo current_user(user->GetType(), is_new_user);
+  UserInfo current_user(user->GetType(), is_new_user, /*is_user_present=*/true);
   return current_user;
 }
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/extensions/forced_extensions/install_stage_tracker.h b/chrome/browser/extensions/forced_extensions/install_stage_tracker.h
index 1597574..ab085931 100644
--- a/chrome/browser/extensions/forced_extensions/install_stage_tracker.h
+++ b/chrome/browser/extensions/forced_extensions/install_stage_tracker.h
@@ -280,11 +280,15 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   // Contains information about the current user.
   struct UserInfo {
+    UserInfo();
     UserInfo(const UserInfo&);
-    UserInfo(user_manager::UserType user_type, bool is_new_user);
+    UserInfo(user_manager::UserType user_type,
+             bool is_new_user,
+             bool is_user_present);
 
     user_manager::UserType user_type = user_manager::USER_TYPE_REGULAR;
-    bool is_new_user = false;
+    const bool is_new_user = false;
+    const bool is_user_present = false;
   };
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
@@ -403,8 +407,7 @@
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   // Returns user type of the user associated with the |profile| and whether the
-  // user is new or not. This method should be used only if there is a user
-  // associated with the profile.
+  // user is new or not if there is an active user.
   static UserInfo GetUserInfo(Profile* profile);
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
diff --git a/chrome/browser/extensions/test_extension_environment.cc b/chrome/browser/extensions/test_extension_environment.cc
index f0578ab..60ffc59 100644
--- a/chrome/browser/extensions/test_extension_environment.cc
+++ b/chrome/browser/extensions/test_extension_environment.cc
@@ -79,7 +79,7 @@
   ChromeOSEnv() {}
 
  private:
-  chromeos::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
+  ash::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
   chromeos::ScopedTestUserManager test_user_manager_;
 
   DISALLOW_COPY_AND_ASSIGN(ChromeOSEnv);
@@ -101,7 +101,7 @@
               ? std::make_unique<content::BrowserTaskEnvironment>()
               : nullptr),
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-      chromeos_env_(chromeos::DeviceSettingsService::IsInitialized()
+      chromeos_env_(ash::DeviceSettingsService::IsInitialized()
                         ? nullptr
                         : std::make_unique<ChromeOSEnv>()),
 #endif
diff --git a/chrome/browser/extensions/updater/chromeos_extension_cache_delegate.cc b/chrome/browser/extensions/updater/chromeos_extension_cache_delegate.cc
index d47ca49..3ed876e 100644
--- a/chrome/browser/extensions/updater/chromeos_extension_cache_delegate.cc
+++ b/chrome/browser/extensions/updater/chromeos_extension_cache_delegate.cc
@@ -37,8 +37,8 @@
 
   size_t max_size = kDefaultCacheSizeLimit;
   int policy_size = 0;
-  if (chromeos::CrosSettings::Get()->GetInteger(chromeos::kExtensionCacheSize,
-                                                &policy_size) &&
+  if (ash::CrosSettings::Get()->GetInteger(chromeos::kExtensionCacheSize,
+                                           &policy_size) &&
       policy_size >= static_cast<int>(GetMinimumCacheSize())) {
     max_size = policy_size;
   }
diff --git a/chrome/browser/extensions/updater/extension_updater_unittest.cc b/chrome/browser/extensions/updater/extension_updater_unittest.cc
index 06cdda22..63fab2c 100644
--- a/chrome/browser/extensions/updater/extension_updater_unittest.cc
+++ b/chrome/browser/extensions/updater/extension_updater_unittest.cc
@@ -2432,7 +2432,7 @@
   ScopedTestingLocalState testing_local_state_;
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  chromeos::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
+  ash::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
   chromeos::ScopedTestUserManager test_user_manager_;
 #endif
 };
diff --git a/chrome/browser/extensions/zipfile_installer_unittest.cc b/chrome/browser/extensions/zipfile_installer_unittest.cc
index 60a15c39..4c93615 100644
--- a/chrome/browser/extensions/zipfile_installer_unittest.cc
+++ b/chrome/browser/extensions/zipfile_installer_unittest.cc
@@ -169,7 +169,7 @@
   MockExtensionRegistryObserver observer_;
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  chromeos::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
+  ash::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
   // ChromeOS needs a user manager to instantiate an extension service.
   chromeos::ScopedTestUserManager test_user_manager_;
 #endif
diff --git a/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc b/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
index f4604ce..a2a34742 100644
--- a/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
+++ b/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
@@ -241,8 +241,8 @@
   // If the device is receiving LTS updates, add a prefix to the version string.
   // The value of the policy is ignored here.
   std::string value;
-  const bool is_lts = chromeos::CrosSettings::Get()->GetString(
-      chromeos::kReleaseLtsTag, &value);
+  const bool is_lts =
+      ash::CrosSettings::Get()->GetString(chromeos::kReleaseLtsTag, &value);
   if (is_lts)
     browser_version = kLTSChromeVersionPrefix + browser_version;
 
diff --git a/chrome/browser/lifetime/application_lifetime.cc b/chrome/browser/lifetime/application_lifetime.cc
index b6abdbc..67dbba0 100644
--- a/chrome/browser/lifetime/application_lifetime.cc
+++ b/chrome/browser/lifetime/application_lifetime.cc
@@ -92,7 +92,7 @@
 // policy or the owner's locale.  Returns true if any pref has been modified.
 bool SetLocaleForNextStart(PrefService* local_state) {
   // If a policy mandates the login screen locale, use it.
-  chromeos::CrosSettings* cros_settings = chromeos::CrosSettings::Get();
+  ash::CrosSettings* cros_settings = ash::CrosSettings::Get();
   const base::ListValue* login_screen_locales = nullptr;
   std::string login_screen_locale;
   if (cros_settings->GetList(chromeos::kDeviceLoginScreenLocales,
diff --git a/chrome/browser/lookalikes/lookalike_url_navigation_throttle.cc b/chrome/browser/lookalikes/lookalike_url_navigation_throttle.cc
index f7c74dc..10c17d1 100644
--- a/chrome/browser/lookalikes/lookalike_url_navigation_throttle.cc
+++ b/chrome/browser/lookalikes/lookalike_url_navigation_throttle.cc
@@ -256,11 +256,15 @@
 
 ThrottleCheckResult LookalikeUrlNavigationThrottle::PerformChecks(
     const std::vector<DomainInfo>& engaged_sites) {
-  DCHECK_EQ(
+  // The last URL in the redirect chain must be the same as the commit URL,
+  // or the navigation is a loadData navigation (where the base URL is saved in
+  // the redirect chain, instead of the commit URL).
+  const GURL& last_url_in_redirect_chain =
       navigation_handle()
           ->GetRedirectChain()[navigation_handle()->GetRedirectChain().size() -
-                               1],
-      navigation_handle()->GetURL());
+                               1];
+  DCHECK(last_url_in_redirect_chain == navigation_handle()->GetURL() ||
+         !navigation_handle()->GetBaseURLForDataURL().is_empty());
 
   // Check for two lookalikes -- at the beginning and end of the redirect chain.
   const GURL& first_url = navigation_handle()->GetRedirectChain()[0];
diff --git a/chrome/browser/media/chromeos_login_media_access_handler.cc b/chrome/browser/media/chromeos_login_media_access_handler.cc
index 2d7d047..29cf37ed 100644
--- a/chrome/browser/media/chromeos_login_media_access_handler.cc
+++ b/chrome/browser/media/chromeos_login_media_access_handler.cc
@@ -44,7 +44,7 @@
   if (security_origin.spec() == chrome::kChromeUIOobeURL)
     return true;
 
-  const chromeos::CrosSettings* const settings = chromeos::CrosSettings::Get();
+  const ash::CrosSettings* const settings = ash::CrosSettings::Get();
   if (!settings)
     return false;
 
diff --git a/chrome/browser/media/platform_verification_impl.cc b/chrome/browser/media/platform_verification_impl.cc
index a62c441..cfc7435 100644
--- a/chrome/browser/media/platform_verification_impl.cc
+++ b/chrome/browser/media/platform_verification_impl.cc
@@ -177,7 +177,7 @@
   }
 
   bool enabled_for_device = false;
-  if (!chromeos::CrosSettings::Get()->GetBoolean(
+  if (!ash::CrosSettings::Get()->GetBoolean(
           chromeos::kAttestationForContentProtectionEnabled,
           &enabled_for_device)) {
     LOG(ERROR) << "Failed to get device setting.";
diff --git a/chrome/browser/media/protected_media_identifier_permission_context.cc b/chrome/browser/media/protected_media_identifier_permission_context.cc
index b4bdbe68..9b053756 100644
--- a/chrome/browser/media/protected_media_identifier_permission_context.cc
+++ b/chrome/browser/media/protected_media_identifier_permission_context.cc
@@ -202,7 +202,7 @@
 
   // This could be disabled by the device policy or by user's master switch.
   bool enabled_for_device = false;
-  if (!chromeos::CrosSettings::Get()->GetBoolean(
+  if (!ash::CrosSettings::Get()->GetBoolean(
           chromeos::kAttestationForContentProtectionEnabled,
           &enabled_for_device) ||
       !enabled_for_device ||
diff --git a/chrome/browser/media/webrtc/current_tab_desktop_media_list_unittest.cc b/chrome/browser/media/webrtc/current_tab_desktop_media_list_unittest.cc
index 8c5ac612..cd5d2d7 100644
--- a/chrome/browser/media/webrtc/current_tab_desktop_media_list_unittest.cc
+++ b/chrome/browser/media/webrtc/current_tab_desktop_media_list_unittest.cc
@@ -184,7 +184,7 @@
   std::unique_ptr<base::RunLoop> run_loop_;
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  chromeos::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
+  ash::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
   chromeos::ScopedTestUserManager test_user_manager_;
 #endif
 
diff --git a/chrome/browser/media/webrtc/tab_desktop_media_list_unittest.cc b/chrome/browser/media/webrtc/tab_desktop_media_list_unittest.cc
index 2955d59..285f3d7c 100644
--- a/chrome/browser/media/webrtc/tab_desktop_media_list_unittest.cc
+++ b/chrome/browser/media/webrtc/tab_desktop_media_list_unittest.cc
@@ -249,7 +249,7 @@
   content::BrowserTaskEnvironment task_environment_;
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  chromeos::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
+  ash::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
   chromeos::ScopedTestUserManager test_user_manager_;
 #endif
 
diff --git a/chrome/browser/media/webrtc/webrtc_text_log_handler.cc b/chrome/browser/media/webrtc/webrtc_text_log_handler.cc
index ac22f09..21056ada 100644
--- a/chrome/browser/media/webrtc/webrtc_text_log_handler.cc
+++ b/chrome/browser/media/webrtc/webrtc_text_log_handler.cc
@@ -450,7 +450,8 @@
 
   // Chrome version
   LogToCircularBuffer("Chrome version: " + version_info::GetVersionNumber() +
-                      " " + chrome::GetChannelName());
+                      " " +
+                      chrome::GetChannelName(chrome::WithExtendedStable(true)));
 
   // OS
   LogToCircularBuffer(base::SysInfo::OperatingSystemName() + " " +
diff --git a/chrome/browser/media_galleries/gallery_watch_manager_unittest.cc b/chrome/browser/media_galleries/gallery_watch_manager_unittest.cc
index d55c80d..5c214b5 100644
--- a/chrome/browser/media_galleries/gallery_watch_manager_unittest.cc
+++ b/chrome/browser/media_galleries/gallery_watch_manager_unittest.cc
@@ -200,7 +200,7 @@
   EnsureMediaDirectoriesExists mock_gallery_locations_;
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  chromeos::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
+  ash::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
   std::unique_ptr<chromeos::ScopedTestUserManager> test_user_manager_;
 #endif
 
diff --git a/chrome/browser/media_galleries/media_file_system_registry_unittest.cc b/chrome/browser/media_galleries/media_file_system_registry_unittest.cc
index fd81bdfc..3e34275 100644
--- a/chrome/browser/media_galleries/media_file_system_registry_unittest.cc
+++ b/chrome/browser/media_galleries/media_file_system_registry_unittest.cc
@@ -393,7 +393,7 @@
   // Needed for extension service & friends to work.
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  chromeos::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
+  ash::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
 #endif
 
   MockProfileSharedRenderProcessHostFactory rph_factory_;
diff --git a/chrome/browser/media_galleries/media_galleries_permission_controller_unittest.cc b/chrome/browser/media_galleries/media_galleries_permission_controller_unittest.cc
index 8bb1ca4..a0930fc 100644
--- a/chrome/browser/media_galleries/media_galleries_permission_controller_unittest.cc
+++ b/chrome/browser/media_galleries/media_galleries_permission_controller_unittest.cc
@@ -151,7 +151,7 @@
   scoped_refptr<extensions::Extension> extension_;
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  chromeos::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
+  ash::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
   chromeos::ScopedTestUserManager test_user_manager_;
 #endif
 
diff --git a/chrome/browser/media_galleries/media_galleries_preferences_unittest.cc b/chrome/browser/media_galleries/media_galleries_preferences_unittest.cc
index 716c5b5a..9f420de4a 100644
--- a/chrome/browser/media_galleries/media_galleries_preferences_unittest.cc
+++ b/chrome/browser/media_galleries/media_galleries_preferences_unittest.cc
@@ -360,7 +360,7 @@
   EnsureMediaDirectoriesExists mock_gallery_locations_;
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  chromeos::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
+  ash::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
   chromeos::ScopedTestUserManager test_user_manager_;
 #endif
 
diff --git a/chrome/browser/metrics/chrome_feature_list_creator.cc b/chrome/browser/metrics/chrome_feature_list_creator.cc
index 730b164..51e3027df3 100644
--- a/chrome/browser/metrics/chrome_feature_list_creator.cc
+++ b/chrome/browser/metrics/chrome_feature_list_creator.cc
@@ -154,8 +154,8 @@
   // from signed device settings, while flags for user session are stored in
   // preferences and applied via a chrome restart upon user login, see
   // UserSessionManager::RestartToApplyPerSessionFlagsIfNeed for the latter.
-  chromeos::about_flags::ReadOnlyFlagsStorage flags_storage(
-      chromeos::about_flags::ParseFlagsFromCommandLine());
+  ash::about_flags::ReadOnlyFlagsStorage flags_storage(
+      ash::about_flags::ParseFlagsFromCommandLine());
 #else
   flags_ui::PrefServiceFlagsStorage flags_storage(local_state_.get());
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/metrics/chrome_metrics_services_manager_client.cc b/chrome/browser/metrics/chrome_metrics_services_manager_client.cc
index 0ea86d5d..c1f2ce7 100644
--- a/chrome/browser/metrics/chrome_metrics_services_manager_client.cc
+++ b/chrome/browser/metrics/chrome_metrics_services_manager_client.cc
@@ -103,7 +103,7 @@
 // Callback to update the metrics reporting state when the Chrome OS metrics
 // reporting setting changes.
 void OnCrosMetricsReportingSettingChange() {
-  bool enable_metrics = chromeos::StatsReportingController::Get()->IsEnabled();
+  bool enable_metrics = ash::StatsReportingController::Get()->IsEnabled();
   ChangeMetricsReportingState(enable_metrics);
 }
 #endif
@@ -219,7 +219,7 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 void ChromeMetricsServicesManagerClient::OnCrosSettingsCreated() {
   reporting_setting_subscription_ =
-      chromeos::StatsReportingController::Get()->AddObserver(
+      ash::StatsReportingController::Get()->AddObserver(
           base::BindRepeating(&OnCrosMetricsReportingSettingChange));
   // Invoke the callback once initially to set the metrics reporting state.
   OnCrosMetricsReportingSettingChange();
diff --git a/chrome/browser/metrics/testing/metrics_reporting_pref_helper.cc b/chrome/browser/metrics/testing/metrics_reporting_pref_helper.cc
index 96a89b8..23888fa 100644
--- a/chrome/browser/metrics/testing/metrics_reporting_pref_helper.cc
+++ b/chrome/browser/metrics/testing/metrics_reporting_pref_helper.cc
@@ -34,7 +34,7 @@
   policy_data.set_policy_value(device_settings_proto.SerializeAsString());
   local_state_dict->SetString(
       prefs::kDeviceSettingsCache,
-      chromeos::device_settings_cache::PolicyDataToString(policy_data));
+      ash::device_settings_cache::PolicyDataToString(policy_data));
 }
 
 }  // namespace
diff --git a/chrome/browser/metrics/variations/chrome_variations_service_client.cc b/chrome/browser/metrics/variations/chrome_variations_service_client.cc
index fcd7d898..d9a788956 100644
--- a/chrome/browser/metrics/variations/chrome_variations_service_client.cc
+++ b/chrome/browser/metrics/variations/chrome_variations_service_client.cc
@@ -72,8 +72,8 @@
 bool ChromeVariationsServiceClient::OverridesRestrictParameter(
     std::string* parameter) {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  chromeos::CrosSettings::Get()->GetString(
-      chromeos::kVariationsRestrictParameter, parameter);
+  ash::CrosSettings::Get()->GetString(chromeos::kVariationsRestrictParameter,
+                                      parameter);
   return true;
 #else
   return false;
diff --git a/chrome/browser/nearby_sharing/mock_nearby_sharing_service.h b/chrome/browser/nearby_sharing/mock_nearby_sharing_service.h
index 5819faa..1e5795c 100644
--- a/chrome/browser/nearby_sharing/mock_nearby_sharing_service.h
+++ b/chrome/browser/nearby_sharing/mock_nearby_sharing_service.h
@@ -61,6 +61,10 @@
               Cancel,
               (const ShareTarget&, StatusCodesCallback),
               (override));
+  MOCK_METHOD(bool,
+              DidLocalUserCancelTransfer,
+              (const ShareTarget&),
+              (override));
   MOCK_METHOD(void,
               Open,
               (const ShareTarget&, StatusCodesCallback),
diff --git a/chrome/browser/nearby_sharing/nearby_notification_manager.cc b/chrome/browser/nearby_sharing/nearby_notification_manager.cc
index 955eff8c..dd75261c 100644
--- a/chrome/browser/nearby_sharing/nearby_notification_manager.cc
+++ b/chrome/browser/nearby_sharing/nearby_notification_manager.cc
@@ -614,9 +614,14 @@
       ShowProgress(share_target, transfer_metadata);
       break;
     case TransferMetadata::Status::kRejected:
+    case TransferMetadata::Status::kCancelled:
+      // Only show the notification if the remote Receiver rejected
+      // or the remote Sender cancelled.
+      if (!nearby_service_->DidLocalUserCancelTransfer(share_target))
+        ShowCancelled(share_target);
+      break;
     case TransferMetadata::Status::kAwaitingRemoteAcceptanceFailed:
     case TransferMetadata::Status::kExternalProviderLaunched:
-    case TransferMetadata::Status::kCancelled:
       // Any previous notifications have been closed with the status change
       // check above that called CloseTransfer(). No notification is currently
       // shown for these statuses, so break.
@@ -871,6 +876,26 @@
       /*metadata=*/nullptr);
 }
 
+void NearbyNotificationManager::ShowCancelled(const ShareTarget& share_target) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  message_center::Notification notification =
+      CreateNearbyNotification(kNearbyNotificationId);
+
+  notification.set_title(base::ReplaceStringPlaceholders(
+      l10n_util::GetStringUTF16(
+          share_target.is_incoming
+              ? IDS_NEARBY_NOTIFICATION_SENDER_CANCELLED
+              : IDS_NEARBY_NOTIFICATION_RECEIVER_CANCELLED),
+      {base::ASCIIToUTF16(share_target.device_name)}, /*offsets=*/nullptr));
+
+  delegate_map_.erase(kNearbyNotificationId);
+
+  notification_display_service_->Display(
+      NotificationHandler::Type::NEARBY_SHARE, notification,
+      /*metadata=*/nullptr);
+}
+
 void NearbyNotificationManager::CloseTransfer() {
   delegate_map_.erase(kNearbyNotificationId);
   notification_display_service_->Close(NotificationHandler::Type::NEARBY_SHARE,
diff --git a/chrome/browser/nearby_sharing/nearby_notification_manager.h b/chrome/browser/nearby_sharing/nearby_notification_manager.h
index 559fa7c..ea8cad7 100644
--- a/chrome/browser/nearby_sharing/nearby_notification_manager.h
+++ b/chrome/browser/nearby_sharing/nearby_notification_manager.h
@@ -91,6 +91,9 @@
   void ShowFailure(const ShareTarget& share_target,
                    const TransferMetadata& transfer_metadata);
 
+  // Shows a notification for send or receive cancellation.
+  void ShowCancelled(const ShareTarget& share_target);
+
   // Closes any currently shown transfer notification (e.g. progress or
   // connection).
   void CloseTransfer();
diff --git a/chrome/browser/nearby_sharing/nearby_notification_manager_unittest.cc b/chrome/browser/nearby_sharing/nearby_notification_manager_unittest.cc
index 51387e2b..c60fae4 100644
--- a/chrome/browser/nearby_sharing/nearby_notification_manager_unittest.cc
+++ b/chrome/browser/nearby_sharing/nearby_notification_manager_unittest.cc
@@ -820,8 +820,8 @@
                         .set_status(TransferMetadata::Status::kCancelled)
                         .build());
 
-  // Notification should be closed.
-  EXPECT_EQ(0u, GetDisplayedNotifications().size());
+  // Cancelled notification should be shown.
+  EXPECT_EQ(1u, GetDisplayedNotifications().size());
 }
 
 TEST_F(NearbyNotificationManagerTest, ConnectionRequest_Accept) {
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service.h b/chrome/browser/nearby_sharing/nearby_sharing_service.h
index 795522fa..54483ee 100644
--- a/chrome/browser/nearby_sharing/nearby_sharing_service.h
+++ b/chrome/browser/nearby_sharing/nearby_sharing_service.h
@@ -147,10 +147,14 @@
   virtual void Reject(const ShareTarget& share_target,
                       StatusCodesCallback status_codes_callback) = 0;
 
-  // Cancels outoing shares to the remote |share_target|.
+  // Cancels outgoing shares to the remote |share_target|.
   virtual void Cancel(const ShareTarget& share_target,
                       StatusCodesCallback status_codes_callback) = 0;
 
+  // Returns true if the local user cancelled the transfer to remote
+  // |share_target|.
+  virtual bool DidLocalUserCancelTransfer(const ShareTarget& share_target) = 0;
+
   // Opens attachments from the remote |share_target|.
   virtual void Open(const ShareTarget& share_target,
                     StatusCodesCallback status_codes_callback) = 0;
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
index af24007..ea1fe60e 100644
--- a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
+++ b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
@@ -786,6 +786,7 @@
     const ShareTarget& share_target,
     StatusCodesCallback status_codes_callback) {
   NS_LOG(INFO) << __func__ << ": User canceled transfer";
+  locally_cancelled_share_target_ids_.insert(share_target.id);
   DoCancel(share_target, std::move(status_codes_callback),
            /*write_cancel_frame=*/true);
 }
@@ -806,7 +807,7 @@
   }
 
   // For metrics.
-  cancelled_share_target_ids_.insert(share_target.id);
+  all_cancelled_share_target_ids_.insert(share_target.id);
 
   // Cancel all ongoing payload transfers before invoking the transfer update
   // callback. Invoking the transfer update callback first could result in
@@ -862,6 +863,11 @@
   std::move(status_codes_callback).Run(StatusCodes::kOk);
 }
 
+bool NearbySharingServiceImpl::DidLocalUserCancelTransfer(
+    const ShareTarget& share_target) {
+  return base::Contains(locally_cancelled_share_target_ids_, share_target.id);
+}
+
 void NearbySharingServiceImpl::Open(const ShareTarget& share_target,
                                     StatusCodesCallback status_codes_callback) {
   std::move(status_codes_callback).Run(StatusCodes::kOk);
@@ -938,6 +944,7 @@
   last_incoming_metadata_.reset();
   last_outgoing_metadata_.reset();
   attachment_info_map_.clear();
+  locally_cancelled_share_target_ids_.clear();
 
   mutual_acceptance_timeout_alarm_.Cancel();
   disconnection_timeout_alarms_.clear();
@@ -2276,7 +2283,7 @@
   bool success = info && info->endpoint_id() && connection;
   RecordNearbyShareEstablishConnectionMetrics(
       success, /*cancelled=*/
-      base::Contains(cancelled_share_target_ids_, share_target.id),
+      base::Contains(all_cancelled_share_target_ids_, share_target.id),
       base::TimeTicks::Now() - connect_start_time);
 
   if (!success) {
@@ -2484,7 +2491,7 @@
       GetBluetoothMacAddressForShareTarget(share_target);
 
   // For metrics.
-  cancelled_share_target_ids_.clear();
+  all_cancelled_share_target_ids_.clear();
 
   // TODO(crbug.com/1111458): Add preferred transfer type.
   nearby_connections_manager_->Connect(
@@ -3776,7 +3783,7 @@
                   << share_target.id;
 
   // For metrics.
-  cancelled_share_target_ids_.erase(share_target.id);
+  all_cancelled_share_target_ids_.erase(share_target.id);
 
   if (share_target.is_incoming) {
     if (last_incoming_metadata_ &&
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.h b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.h
index 7b8a49d..3e42929a 100644
--- a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.h
+++ b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.h
@@ -115,6 +115,7 @@
               StatusCodesCallback status_codes_callback) override;
   void Cancel(const ShareTarget& share_target,
               StatusCodesCallback status_codes_callback) override;
+  bool DidLocalUserCancelTransfer(const ShareTarget& share_target) override;
   void Open(const ShareTarget& share_target,
             StatusCodesCallback status_codes_callback) override;
   void OpenURL(GURL url) override;
@@ -446,7 +447,9 @@
       outgoing_share_target_info_map_;
   // For metrics. The IDs of ShareTargets that are cancelled while trying to
   // establish an outgoing connection.
-  base::flat_set<base::UnguessableToken> cancelled_share_target_ids_;
+  base::flat_set<base::UnguessableToken> all_cancelled_share_target_ids_;
+  // The IDs of ShareTargets that we cancelled the transfer to.
+  base::flat_set<base::UnguessableToken> locally_cancelled_share_target_ids_;
   // A map from endpoint ID to endpoint info from discovered, contact-based
   // advertisements that could not decrypt any available public certificates.
   // During discovery, if certificates are downloaded, we revist this map and
diff --git a/chrome/browser/net/nss_context.h b/chrome/browser/net/nss_context.h
index 1b8e918..b8b34db 100644
--- a/chrome/browser/net/nss_context.h
+++ b/chrome/browser/net/nss_context.h
@@ -21,7 +21,6 @@
 
 namespace content {
 class BrowserContext;
-class ResourceContext;
 }  // namespace content
 
 // NssCertDatabaseGetter is a callback that MUST only be invoked on the IO
@@ -41,20 +40,6 @@
 NssCertDatabaseGetter CreateNSSCertDatabaseGetter(
     content::BrowserContext* browser_context);
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-// Sets the |username_hash| associated with |context|.
-// Must be called only on the IO thread, once for each ResourceContext.
-void SetNSSCertDatabaseUsernameHash(content::ResourceContext* context,
-                                    const std::string& username_hash);
-
-// Enables the system key slot in the NSSCertDatabase for the user associated
-// with |context|.
-// Must be called only on the IO thread. SetNSSCertDatabaseUsernameHash() must
-// already have been called on |context|.
-void EnableNSSSystemKeySlotForResourceContext(
-    content::ResourceContext* context);
-#endif
-
 // Gets a pointer to the NSSCertDatabase for the user associated with |context|.
 // It's a wrapper around |GetNSSCertDatabaseForResourceContext| which makes
 // sure it's called on IO thread (with |profile|'s resource context). The
diff --git a/chrome/browser/net/nss_context_chromeos.cc b/chrome/browser/net/nss_context_chromeos.cc
index a5d05ca66..91770a8 100644
--- a/chrome/browser/net/nss_context_chromeos.cc
+++ b/chrome/browser/net/nss_context_chromeos.cc
@@ -4,166 +4,14 @@
 
 #include "chrome/browser/net/nss_context.h"
 
-#include <utility>
-
 #include "base/bind.h"
-#include "base/callback_list.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/memory/weak_ptr.h"
-#include "base/supports_user_data.h"
-#include "content/public/browser/browser_context.h"
+#include "chrome/browser/net/nss_service_chromeos.h"
+#include "chrome/browser/net/nss_service_chromeos_factory.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/resource_context.h"
-#include "crypto/nss_util_internal.h"
-#include "net/cert/nss_cert_database_chromeos.h"
-
-namespace {
-
-void* kDatabaseManagerKey = &kDatabaseManagerKey;
-void* kUsernameHashKey = &kUsernameHashKey;
-
-class NSSUsernameHash : public base::SupportsUserData::Data {
- public:
-  explicit NSSUsernameHash(const std::string& username_hash)
-      : username_hash_(username_hash) {}
-  NSSUsernameHash(const NSSUsernameHash&) = delete;
-  NSSUsernameHash& operator=(const NSSUsernameHash&) = delete;
-  ~NSSUsernameHash() override = default;
-
-  const std::string& username_hash() { return username_hash_; }
-
- private:
-  const std::string username_hash_;
-};
-
-class NSSCertDatabaseChromeOSManager : public base::SupportsUserData::Data {
- public:
-  typedef base::OnceCallback<void(net::NSSCertDatabaseChromeOS*)>
-      GetNSSCertDatabaseCallback;
-  explicit NSSCertDatabaseChromeOSManager(const std::string& username_hash)
-      : username_hash_(username_hash) {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-    crypto::ScopedPK11Slot private_slot(crypto::GetPrivateSlotForChromeOSUser(
-        username_hash,
-        base::BindOnce(&NSSCertDatabaseChromeOSManager::DidGetPrivateSlot,
-                       weak_ptr_factory_.GetWeakPtr())));
-    if (private_slot)
-      DidGetPrivateSlot(std::move(private_slot));
-  }
-
-  ~NSSCertDatabaseChromeOSManager() override {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-  }
-
-  net::NSSCertDatabaseChromeOS* GetNSSCertDatabase(
-      GetNSSCertDatabaseCallback callback) {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-
-    if (nss_cert_database_)
-      return nss_cert_database_.get();
-
-    ready_callback_list_.AddUnsafe(std::move(callback));
-    return NULL;
-  }
-
- private:
-  using ReadyCallbackList =
-      base::OnceCallbackList<GetNSSCertDatabaseCallback::RunType>;
-
-  void DidGetPrivateSlot(crypto::ScopedPK11Slot private_slot) {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-    nss_cert_database_.reset(new net::NSSCertDatabaseChromeOS(
-        crypto::GetPublicSlotForChromeOSUser(username_hash_),
-        std::move(private_slot)));
-
-    ready_callback_list_.Notify(nss_cert_database_.get());
-  }
-
-  std::string username_hash_;
-  std::unique_ptr<net::NSSCertDatabaseChromeOS> nss_cert_database_;
-  ReadyCallbackList ready_callback_list_;
-  base::WeakPtrFactory<NSSCertDatabaseChromeOSManager> weak_ptr_factory_{this};
-
-  DISALLOW_COPY_AND_ASSIGN(NSSCertDatabaseChromeOSManager);
-};
-
-net::NSSCertDatabaseChromeOS* GetNSSCertDatabaseChromeOS(
-    content::ResourceContext* context,
-    NSSCertDatabaseChromeOSManager::GetNSSCertDatabaseCallback callback) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-  NSSCertDatabaseChromeOSManager* manager =
-      static_cast<NSSCertDatabaseChromeOSManager*>(
-          context->GetUserData(kDatabaseManagerKey));
-  if (!manager) {
-    NSSUsernameHash* username_hash =
-        static_cast<NSSUsernameHash*>(context->GetUserData(kUsernameHashKey));
-    // |username_hash| should not be null here, but handle it just in case it
-    // is, to avoid a crash.
-    // TODO(https://cbug.com/1018972): This check will be removed as part of
-    // removing the ResourceContext dependency of this code.
-    manager = new NSSCertDatabaseChromeOSManager(
-        username_hash ? username_hash->username_hash() : std::string());
-    context->SetUserData(kDatabaseManagerKey, base::WrapUnique(manager));
-  }
-  return manager->GetNSSCertDatabase(std::move(callback));
-}
-
-void CallWithNSSCertDatabase(
-    base::OnceCallback<void(net::NSSCertDatabase*)> callback,
-    net::NSSCertDatabaseChromeOS* db) {
-  std::move(callback).Run(db);
-}
-
-void SetSystemSlot(crypto::ScopedPK11Slot system_slot,
-                   net::NSSCertDatabaseChromeOS* db) {
-  db->SetSystemSlot(std::move(system_slot));
-}
-
-void SetSystemSlotOfDBForResourceContext(content::ResourceContext* context,
-                                         crypto::ScopedPK11Slot system_slot) {
-  base::RepeatingCallback<void(net::NSSCertDatabaseChromeOS*)> callback =
-      base::BindRepeating(&SetSystemSlot, base::Passed(&system_slot));
-
-  net::NSSCertDatabaseChromeOS* db =
-      GetNSSCertDatabaseChromeOS(context, callback);
-  if (db)
-    callback.Run(db);
-}
-
-net::NSSCertDatabase* GetNSSCertDatabaseForResourceContext(
-    content::ResourceContext* context,
-    base::OnceCallback<void(net::NSSCertDatabase*)> callback) {
-  return GetNSSCertDatabaseChromeOS(
-      context, base::BindOnce(&CallWithNSSCertDatabase, std::move(callback)));
-}
-
-}  // namespace
 
 NssCertDatabaseGetter CreateNSSCertDatabaseGetter(
     content::BrowserContext* browser_context) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  DCHECK(browser_context);
-  return base::BindOnce(
-      &GetNSSCertDatabaseForResourceContext,
-      base::Unretained(browser_context->GetResourceContext()));
-}
-
-void SetNSSCertDatabaseUsernameHash(content::ResourceContext* context,
-                                    const std::string& username_hash) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-
-  DCHECK(!context->GetUserData(kUsernameHashKey));
-  context->SetUserData(kUsernameHashKey,
-                       std::make_unique<NSSUsernameHash>(username_hash));
-}
-
-void EnableNSSSystemKeySlotForResourceContext(
-    content::ResourceContext* context) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-  base::RepeatingCallback<void(crypto::ScopedPK11Slot)> callback =
-      base::BindRepeating(&SetSystemSlotOfDBForResourceContext, context);
-  crypto::ScopedPK11Slot system_slot = crypto::GetSystemNSSKeySlot(callback);
-  if (system_slot)
-    callback.Run(std::move(system_slot));
+  return NssServiceChromeOSFactory::GetForContext(browser_context)
+      ->CreateNSSCertDatabaseGetterForIOThread();
 }
diff --git a/chrome/browser/net/nss_service_chromeos.cc b/chrome/browser/net/nss_service_chromeos.cc
index f252ad4..859974c 100644
--- a/chrome/browser/net/nss_service_chromeos.cc
+++ b/chrome/browser/net/nss_service_chromeos.cc
@@ -5,11 +5,15 @@
 #include "chrome/browser/net/nss_service_chromeos.h"
 
 #include <memory>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/callback_list.h"
 #include "base/logging.h"
+#include "base/memory/weak_ptr.h"
 #include "base/single_thread_task_runner.h"
+#include "base/supports_user_data.h"
 #include "chrome/browser/ash/login/startup_utils.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/net/nss_context.h"
@@ -20,10 +24,12 @@
 #include "chromeos/tpm/tpm_token_info_getter.h"
 #include "components/user_manager/user.h"
 #include "components/user_manager/user_manager.h"
+#include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "crypto/nss_util.h"
 #include "crypto/nss_util_internal.h"
+#include "net/cert/nss_cert_database_chromeos.h"
 
 using content::BrowserThread;
 
@@ -140,17 +146,133 @@
   }
 }
 
-void EnableNSSSystemKeySlotOnIOThread(
-    content::ResourceContext* resource_context,
-    const std::string& username_hash,
-    bool user_is_affiliated) {
-  SetNSSCertDatabaseUsernameHash(resource_context, username_hash);
-  if (user_is_affiliated)
-    EnableNSSSystemKeySlotForResourceContext(resource_context);
+// Used to convert a callback that takes a net::NSSCertDatabase to one that
+// takes a net::NSSCertDatabaseChromeOS.
+void CallWithNSSCertDatabase(
+    base::OnceCallback<void(net::NSSCertDatabase*)> callback,
+    net::NSSCertDatabaseChromeOS* db) {
+  std::move(callback).Run(db);
 }
 
 }  // namespace
 
+// Creates and manages a NSSCertDatabaseChromeOS.  Created on the UI thread, but
+// all other calls are made on the IO thread.
+class NssServiceChromeOS::NSSCertDatabaseChromeOSManager {
+ public:
+  typedef base::OnceCallback<void(net::NSSCertDatabaseChromeOS*)>
+      GetNSSCertDatabaseCallback;
+
+  NSSCertDatabaseChromeOSManager(std::string username_hash,
+                                 bool user_is_affiliated)
+      : username_hash_(std::move(username_hash)) {
+    DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+    if (user_is_affiliated) {
+      content::GetIOThreadTaskRunner({})->PostTask(
+          FROM_HERE,
+          base::BindOnce(
+              &NSSCertDatabaseChromeOSManager::EnableNSSSystemKeySlot,
+              weak_ptr_factory_.GetWeakPtr()));
+    }
+  }
+
+  NSSCertDatabaseChromeOSManager(const NSSCertDatabaseChromeOSManager&) =
+      delete;
+  NSSCertDatabaseChromeOSManager& operator=(
+      const NSSCertDatabaseChromeOSManager&) = delete;
+
+  ~NSSCertDatabaseChromeOSManager() { DCHECK_CURRENTLY_ON(BrowserThread::IO); }
+
+  net::NSSCertDatabaseChromeOS* GetNSSCertDatabaseChromeOS(
+      NSSCertDatabaseChromeOSManager::GetNSSCertDatabaseCallback callback) {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+    if (nss_cert_database_)
+      return nss_cert_database_.get();
+
+    ready_callback_list_.AddUnsafe(std::move(callback));
+
+    // If database creation has already started, nothing else to do.
+    if (database_creation_started_)
+      return nullptr;
+
+    // Otherwise, start creating the database.
+    database_creation_started_ = true;
+    crypto::ScopedPK11Slot private_slot(crypto::GetPrivateSlotForChromeOSUser(
+        username_hash_,
+        base::BindOnce(&NSSCertDatabaseChromeOSManager::DidGetPrivateSlot,
+                       weak_ptr_factory_.GetWeakPtr())));
+    if (private_slot)
+      DidGetPrivateSlot(std::move(private_slot));
+
+    return nullptr;
+  }
+
+  // Just like GetNSSCertDatabaseChromeOS(), but uses net::NSSCertDatabase
+  // instead of net::NSSCertDatabaseChromeOS.
+  net::NSSCertDatabase* GetNSSCertDatabase(
+      base::OnceCallback<void(net::NSSCertDatabase*)> callback) {
+    return GetNSSCertDatabaseChromeOS(
+        base::BindOnce(&CallWithNSSCertDatabase, std::move(callback)));
+  }
+
+ private:
+  using ReadyCallbackList =
+      base::OnceCallbackList<GetNSSCertDatabaseCallback::RunType>;
+
+  void EnableNSSSystemKeySlot() {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+    // This should only be called once.
+    DCHECK(!pending_system_slot_);
+
+    crypto::ScopedPK11Slot system_slot = crypto::GetSystemNSSKeySlot(
+        base::BindOnce(&NSSCertDatabaseChromeOSManager::SetSystemSlotOfDB,
+                       weak_ptr_factory_.GetWeakPtr()));
+    if (system_slot)
+      SetSystemSlotOfDB(std::move(system_slot));
+  }
+
+  void SetSystemSlotOfDB(crypto::ScopedPK11Slot system_slot) {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+    DCHECK(system_slot);
+
+    pending_system_slot_ = std::move(system_slot);
+
+    base::RepeatingCallback<void(net::NSSCertDatabaseChromeOS*)> callback =
+        base::BindRepeating(&NSSCertDatabaseChromeOSManager::SetSystemSlot,
+                            weak_ptr_factory_.GetWeakPtr());
+
+    net::NSSCertDatabaseChromeOS* db = GetNSSCertDatabaseChromeOS(callback);
+    if (db)
+      SetSystemSlot(db);
+  }
+
+  void SetSystemSlot(net::NSSCertDatabaseChromeOS* db) {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+    db->SetSystemSlot(std::move(pending_system_slot_));
+  }
+
+  void DidGetPrivateSlot(crypto::ScopedPK11Slot private_slot) {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+    nss_cert_database_ = std::make_unique<net::NSSCertDatabaseChromeOS>(
+        crypto::GetPublicSlotForChromeOSUser(username_hash_),
+        std::move(private_slot));
+
+    ready_callback_list_.Notify(nss_cert_database_.get());
+  }
+
+  const std::string username_hash_;
+  bool database_creation_started_ = false;
+
+  crypto::ScopedPK11Slot pending_system_slot_;
+
+  std::unique_ptr<net::NSSCertDatabaseChromeOS> nss_cert_database_;
+  ReadyCallbackList ready_callback_list_;
+
+  base::WeakPtrFactory<NSSCertDatabaseChromeOSManager> weak_ptr_factory_{this};
+};
+
 NssServiceChromeOS::NssServiceChromeOS(Profile* profile) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
@@ -172,17 +294,21 @@
     user_is_affiliated = user->IsAffiliated();
   }
 
-  // We need to make sure that content initializes its own data structures that
-  // are associated with each ResourceContext because we might post this
-  // object to the IO thread after this function.
-  content::BrowserContext::EnsureResourceContextInitialized(profile);
-
   DCHECK(!(username_hash.empty() && user_is_affiliated));
 
-  content::GetIOThreadTaskRunner({})->PostTask(
-      FROM_HERE, base::BindOnce(&EnableNSSSystemKeySlotOnIOThread,
-                                profile->GetResourceContext(), username_hash,
-                                user_is_affiliated));
+  nss_cert_database_manager_ = std::make_unique<NSSCertDatabaseChromeOSManager>(
+      std::move(username_hash), user_is_affiliated);
 }
 
-NssServiceChromeOS::~NssServiceChromeOS() = default;
+NssServiceChromeOS::~NssServiceChromeOS() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  content::GetIOThreadTaskRunner({})->DeleteSoon(
+      FROM_HERE, std::move(nss_cert_database_manager_));
+}
+
+NssCertDatabaseGetter
+NssServiceChromeOS::CreateNSSCertDatabaseGetterForIOThread() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  return base::BindOnce(&NSSCertDatabaseChromeOSManager::GetNSSCertDatabase,
+                        base::Unretained(nss_cert_database_manager_.get()));
+}
diff --git a/chrome/browser/net/nss_service_chromeos.h b/chrome/browser/net/nss_service_chromeos.h
index 5f1d3c3..2299816b 100644
--- a/chrome/browser/net/nss_service_chromeos.h
+++ b/chrome/browser/net/nss_service_chromeos.h
@@ -5,12 +5,16 @@
 #ifndef CHROME_BROWSER_NET_NSS_SERVICE_CHROMEOS_H_
 #define CHROME_BROWSER_NET_NSS_SERVICE_CHROMEOS_H_
 
+#include <memory>
+
+#include "base/callback_forward.h"
+#include "chrome/browser/net/nss_context.h"
 #include "components/keyed_service/core/keyed_service.h"
 
 class Profile;
 
-// ChromeOS Ash service that manages initialization of NSS and the per-profile
-// certificate database.
+// ChromeOS Ash service that owns and initializates the per-Profile certificate
+// database.
 class NssServiceChromeOS : public KeyedService {
  public:
   explicit NssServiceChromeOS(Profile* profile);
@@ -18,9 +22,20 @@
   NssServiceChromeOS& operator=(const NssServiceChromeOS&) = delete;
   ~NssServiceChromeOS() override;
 
+  // Returns an NssCertDatabaseGetter that may only be invoked on the IO thread.
+  // To avoid UAF, the getter must be immediately posted to the IO thread and
+  // then invoked.  While the returned getter must be invoked on the IO thread,
+  // this method itself may only be invoked on the UI thread, where the
+  // NssServiceChromeOS lives.
+  NssCertDatabaseGetter CreateNSSCertDatabaseGetterForIOThread();
+
  private:
-  // TODO(https://cbug.com/1018972):  Move ownership of
-  // NSSCertDatabaseChromeOSManager to this class.
+  // Owns and manages access to the net::NSSCertDatabaseChromeOS.
+  class NSSCertDatabaseChromeOSManager;
+
+  // Created on the UI thread, but after that, initialized, accessed, and
+  // destroyed exclusively on the IO thread.
+  std::unique_ptr<NSSCertDatabaseChromeOSManager> nss_cert_database_manager_;
 };
 
 #endif  // CHROME_BROWSER_NET_NSS_SERVICE_CHROMEOS_H_
diff --git a/chrome/browser/optimization_guide/page_content_annotations_service_browsertest.cc b/chrome/browser/optimization_guide/page_content_annotations_service_browsertest.cc
index 30d0740..0e39640 100644
--- a/chrome/browser/optimization_guide/page_content_annotations_service_browsertest.cc
+++ b/chrome/browser/optimization_guide/page_content_annotations_service_browsertest.cc
@@ -15,6 +15,7 @@
 #include "components/optimization_guide/content/browser/page_content_annotations_service.h"
 #include "components/optimization_guide/core/optimization_guide_features.h"
 #include "components/optimization_guide/machine_learning_tflite_buildflags.h"
+#include "components/optimization_guide/proto/page_topics_model_metadata.pb.h"
 #include "content/public/test/browser_test.h"
 
 namespace {
@@ -89,6 +90,12 @@
         "chrome/test/data/optimization_guide");
     ASSERT_TRUE(embedded_test_server()->Start());
 
+    proto::Any any_metadata;
+    any_metadata.set_type_url(
+        "type.googleapis.com/com.foo.PageTopicsModelMetadata");
+    proto::PageTopicsModelMetadata page_topics_model_metadata;
+    page_topics_model_metadata.set_version(123);
+    page_topics_model_metadata.SerializeToString(any_metadata.mutable_value());
     base::FilePath source_root_dir;
     base::PathService::Get(base::DIR_SOURCE_ROOT, &source_root_dir);
     base::FilePath model_file_path =
@@ -99,8 +106,8 @@
             .AppendASCII("bert_page_topics_model.tflite");
     OptimizationGuideKeyedServiceFactory::GetForProfile(browser()->profile())
         ->OverrideTargetModelFileForTesting(
-            proto::OPTIMIZATION_TARGET_PAGE_TOPICS,
-            /*model_metadata=*/base::nullopt, model_file_path);
+            proto::OPTIMIZATION_TARGET_PAGE_TOPICS, any_metadata,
+            model_file_path);
     base::RunLoop().RunUntilIdle();
   }
 
@@ -137,9 +144,13 @@
   PageContentAnnotationsService* service =
       PageContentAnnotationsServiceFactory::GetForProfile(browser()->profile());
 
-  // TODO(crbug/1177102): Make sure this propagates from model if building with
-  // TFLite.
+#if BUILDFLAG(BUILD_WITH_TFLITE_LIB)
+  base::Optional<int64_t> model_version = service->GetPageTopicsModelVersion();
+  EXPECT_TRUE(model_version.has_value());
+  EXPECT_EQ(123, *model_version);
+#else
   EXPECT_FALSE(service->GetPageTopicsModelVersion().has_value());
+#endif
 }
 
 }  // namespace optimization_guide
diff --git a/chrome/browser/payments/secure_payment_confirmation_browsertest.cc b/chrome/browser/payments/secure_payment_confirmation_browsertest.cc
index ea536c19..4fc53ea3 100644
--- a/chrome/browser/payments/secure_payment_confirmation_browsertest.cc
+++ b/chrome/browser/payments/secure_payment_confirmation_browsertest.cc
@@ -586,7 +586,7 @@
   confirm_payment_ = true;
 
   // EvalJs waits for JavaScript promise to resolve.
-  EXPECT_EQ("Authenticator returned AuthenticatorStatus::NOT_ALLOWED_ERROR.",
+  EXPECT_EQ("Authenticator returned NOT_ALLOWED_ERROR.",
             content::EvalJs(GetActiveWebContents(),
                             content::JsReplace("getChallenge($1, $2);",
                                                credentialIdentifier, "0.01")));
diff --git a/chrome/browser/policy/chrome_policy_conversions_client.cc b/chrome/browser/policy/chrome_policy_conversions_client.cc
index 7264e27..df73caa 100644
--- a/chrome/browser/policy/chrome_policy_conversions_client.cc
+++ b/chrome/browser/policy/chrome_policy_conversions_client.cc
@@ -201,7 +201,7 @@
   DCHECK(device_local_account_policy_service);  // always non null for
                                                 // affiliated users.
   std::vector<DeviceLocalAccount> device_local_accounts =
-      GetDeviceLocalAccounts(chromeos::CrosSettings::Get());
+      GetDeviceLocalAccounts(ash::CrosSettings::Get());
   for (const auto& account : device_local_accounts) {
     const std::string user_id = account.user_id;
 
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index bc11c59..04163af 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -546,6 +546,12 @@
 const char kCartModuleRemoved[] = "cart_module_removed";
 #endif
 
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+// Deprecated 03/2021
+const char kPinnedExtensionsMigrationComplete[] =
+    "extensions.pinned_extension_migration";
+#endif
+
 // Register local state used only for migration (clearing or moving to a new
 // key).
 void RegisterLocalStatePrefsForMigration(PrefRegistrySimple* registry) {
@@ -576,6 +582,10 @@
   registry->RegisterIntegerPref(kStabilityBreakpadRegistrationSuccess, 0);
   registry->RegisterIntegerPref(kStabilityDebuggerPresent, 0);
   registry->RegisterIntegerPref(kStabilityDebuggerNotPresent, 0);
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+  registry->RegisterBooleanPref(kPinnedExtensionsMigrationComplete, false);
+#endif
 }
 
 // Register prefs used only for migration (clearing or moving to a new key).
@@ -751,7 +761,7 @@
   chromeos::DemoSetupController::RegisterLocalStatePrefs(registry);
   chromeos::DeviceNameStore::RegisterLocalStatePrefs(registry);
   chromeos::DeviceOAuth2TokenStoreChromeOS::RegisterPrefs(registry);
-  chromeos::device_settings_cache::RegisterPrefs(registry);
+  ash::device_settings_cache::RegisterPrefs(registry);
   chromeos::EasyUnlockService::RegisterPrefs(registry);
   chromeos::echo_offer::RegisterPrefs(registry);
   chromeos::EnableAdbSideloadingScreen::RegisterPrefs(registry);
@@ -780,7 +790,7 @@
   chromeos::ServicesCustomizationDocument::RegisterPrefs(registry);
   chromeos::SigninScreenHandler::RegisterPrefs(registry);
   chromeos::StartupUtils::RegisterPrefs(registry);
-  chromeos::StatsReportingController::RegisterLocalStatePrefs(registry);
+  ash::StatsReportingController::RegisterLocalStatePrefs(registry);
   ash::system::AutomaticRebootManager::RegisterPrefs(registry);
   chromeos::TimeZoneResolver::RegisterPrefs(registry);
   chromeos::UserImageManager::RegisterPrefs(registry);
@@ -1198,6 +1208,11 @@
   local_state->ClearPref(kStabilityDebuggerPresent);
   local_state->ClearPref(kStabilityDebuggerNotPresent);
 
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+  // Added 03/2021
+  local_state->ClearPref(kPinnedExtensionsMigrationComplete);
+#endif
+
   // Please don't delete the following line. It is used by PRESUBMIT.py.
   // END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS
 }
diff --git a/chrome/browser/profiles/off_the_record_profile_impl.cc b/chrome/browser/profiles/off_the_record_profile_impl.cc
index 8303598..8c6d06b 100644
--- a/chrome/browser/profiles/off_the_record_profile_impl.cc
+++ b/chrome/browser/profiles/off_the_record_profile_impl.cc
@@ -86,6 +86,7 @@
 #endif  // defined(OS_ANDROID)
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/chromeos/preferences.h"
 #endif
 
@@ -225,6 +226,12 @@
   // other profile-related destroy notifications are dispatched.
   ShutdownStoragePartitions();
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  // Bypass profile lifetime recording for ChromeOS helper profiles (sign-in,
+  // lockscreen, etc).
+  if (!chromeos::ProfileHelper::IsRegularProfile(profile_))
+    return;
+#endif
   // Store incognito lifetime and navigations count histogram.
   if (IsIncognitoProfile()) {
     auto duration = base::Time::Now() - start_time_;
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index 1961497..8054553 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -599,7 +599,7 @@
   policy::UserCloudPolicyManager* user_cloud_policy_manager;
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   if (force_immediate_policy_load)
-    chromeos::DeviceSettingsService::Get()->LoadImmediately();
+    ash::DeviceSettingsService::Get()->LoadImmediately();
 
   policy::CreateConfigurationPolicyProvider(
       this, force_immediate_policy_load, io_task_runner_,
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index db023c1..c879241 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.cc
@@ -35,17 +35,13 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  // This triggers ResourceContext creation and initializes the per-profile NSS
-  // database.
-  //
   // TODO(https://crbug.com/1018972): Remove this line once NSS initialization
   // no longer depends on the ResourceContext.
   NssServiceChromeOSFactory::GetForContext(profile);
-#else  // !BUILDFLAG(IS_CHROMEOS_ASH)
+#endif  // #if BUILDFLAG(IS_CHROMEOS_ASH)
   // Make sure the ResourceContext is initialized.  It's unclear if this is
   // still needed.
   content::BrowserContext::EnsureResourceContextInitialized(profile);
-#endif
 }
 
 ProfileIOData::ProfileIOData()
diff --git a/chrome/browser/profiles/profile_manager_unittest.cc b/chrome/browser/profiles/profile_manager_unittest.cc
index ac251938..a222457 100644
--- a/chrome/browser/profiles/profile_manager_unittest.cc
+++ b/chrome/browser/profiles/profile_manager_unittest.cc
@@ -243,7 +243,7 @@
         profile_helper->GetProfilePathByUserIdHash(user_id_hash));
   }
 
-  chromeos::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
+  ash::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
 #endif
 
   // The path to temporary directory used to contain the test operations. These
diff --git a/chrome/browser/profiles/profile_window_browsertest.cc b/chrome/browser/profiles/profile_window_browsertest.cc
index 95f5874..9bbc995 100644
--- a/chrome/browser/profiles/profile_window_browsertest.cc
+++ b/chrome/browser/profiles/profile_window_browsertest.cc
@@ -155,7 +155,14 @@
   Profile* profile_ = nullptr;
 };
 
-IN_PROC_BROWSER_TEST_P(ProfileWindowCountBrowserTest, CountProfileWindows) {
+// TODO(crbug.com/1186994): Test is flaky on Linux Dbg.
+#if defined(OS_LINUX) && !defined(NDEBUG)
+#define MAYBE_CountProfileWindows DISABLED_CountProfileWindows
+#else
+#define MAYBE_CountProfileWindows CountProfileWindows
+#endif
+IN_PROC_BROWSER_TEST_P(ProfileWindowCountBrowserTest,
+                       MAYBE_CountProfileWindows) {
   DCHECK_EQ(0, GetWindowCount());
 
   // Create a browser and check the count.
diff --git a/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_gu.xtb b/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_gu.xtb
index b4393eef..542dec8 100644
--- a/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_gu.xtb
+++ b/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_gu.xtb
@@ -989,7 +989,7 @@
 <translation id="8378855320830505539">પ્રદેશ</translation>
 <translation id="8382679411218029383">સ્વતઃપૂર્ણ ઇનલાઇન અને સૂચિ</translation>
 <translation id="8394908167088220973">મીડિયા ચલાવો/થોભાવો</translation>
-<translation id="8428213095426709021">સેટિંગ્સ</translation>
+<translation id="8428213095426709021">સેટિંગ</translation>
 <translation id="8428603554127842284">સ્તર <ph name="DEPTH" /></translation>
 <translation id="8430049249787218991">mnubr</translation>
 <translation id="8446884382197647889">વધુ જાણો</translation>
diff --git a/chrome/browser/resources/chromeos/crostini_installer/app.js b/chrome/browser/resources/chromeos/crostini_installer/app.js
index d45e80f..8a0ba7c 100644
--- a/chrome/browser/resources/chromeos/crostini_installer/app.js
+++ b/chrome/browser/resources/chromeos/crostini_installer/app.js
@@ -459,6 +459,10 @@
     let messageId = null;
     switch (error) {
       case InstallerError.kErrorLoadingTermina:
+      case InstallerError.kNeedReboot:
+        // TODO(sidereal) kNeedReboot should really have it's own error message,
+        // but that has to go through UX. Previously these failures would have
+        // been reported as kErrorLoadingTermina so use that message for now.
         messageId = 'loadTerminaError';
         break;
       case InstallerError.kErrorCreatingDiskImage:
diff --git a/chrome/browser/resources/chromeos/emoji_picker/BUILD.gn b/chrome/browser/resources/chromeos/emoji_picker/BUILD.gn
index 10ba19a0..fde1bc9 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/BUILD.gn
+++ b/chrome/browser/resources/chromeos/emoji_picker/BUILD.gn
@@ -29,6 +29,7 @@
 generate_grd("build_grd") {
   deps = [
     ":build_fuse_grdp",
+    ":build_mojo_grdp",
     ":build_preprocessed_grdp",
     ":emoji_data",
   ]
@@ -40,14 +41,28 @@
     "index.html",
     "store.js",
     "types.js",
+    "emoji_picker_api_proxy.js",
   ]
   grdp_files = [
     preprocessed_grdp_file,
     fuse_grdp_file,
+    "$target_gen_dir/mojo_resources.grdp",
   ]
   input_files_base_dir = rebase_path(".", "//")
 }
 
+generate_grd("build_mojo_grdp") {
+  grd_prefix = "emoji_picker"
+  out_grd = "$target_gen_dir/mojo_resources.grdp"
+  deps = [ "//chrome/browser/ui/webui/chromeos/emoji:mojo_bindings_webui_js" ]
+  input_files = [ "emoji_picker.mojom-webui.js" ]
+  input_files_base_dir =
+      rebase_path(
+          "${root_gen_dir}/mojom-webui/chrome/browser/ui/webui/chromeos/emoji",
+          "$root_build_dir")
+  resource_path_rewrites = [ "emoji-picker.mojom-webui.js|chrome/browser/ui/webui/chromeos/emoji/emoji-picker.mojom-webui.js" ]
+}
+
 generate_grd("build_preprocessed_grdp") {
   deps = [ ":web_components" ]
   grd_prefix = "emoji_picker"
@@ -111,6 +126,7 @@
     ":constants",
     ":emoji_group",
     ":emoji_group_button",
+    ":emoji_picker_api_proxy",
     ":emoji_search",
     ":events",
     ":store",
@@ -121,6 +137,13 @@
   externs_list = [ "$externs_path/chrome_send.js" ]
 }
 
+js_library("emoji_picker_api_proxy") {
+  deps = [
+    "//chrome/browser/ui/webui/chromeos/emoji:mojo_bindings_webui_js",
+    "//ui/webui/resources/js:cr.m",
+  ]
+}
+
 js_library("emoji_group_button") {
   deps = [
     ":events",
@@ -185,12 +208,19 @@
 
 js_type_check("closure_compile") {
   is_polymer3 = true
+  closure_flags = default_closure_args + mojom_js_args + [
+                    "js_module_root=" + rebase_path(".", root_build_dir),
+                    "js_module_root=" + rebase_path(
+                            "$root_gen_dir/mojom-webui/chrome/browser/ui/webui/chromeos/emoji",
+                            root_build_dir),
+                  ]
   deps = [
     ":constants",
     ":emoji_button",
     ":emoji_group",
     ":emoji_group_button",
     ":emoji_picker",
+    ":emoji_picker_api_proxy",
     ":emoji_search",
     ":emoji_variants",
     ":events",
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.js b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.js
index 0b31861..f1a9ce0f 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.js
+++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.js
@@ -13,6 +13,7 @@
 
 import {EMOJI_ICON_SIZE, EMOJI_PER_ROW, EMOJI_PICKER_HEIGHT_PX, EMOJI_PICKER_PADDING_PX, EMOJI_PICKER_WIDTH_PX, EMOJI_SIZE_PX, GROUP_ICON_SIZE, GROUP_PER_ROW} from './constants.js';
 import {EmojiButton} from './emoji_button.js';
+import {EmojiPickerApiProxy, EmojiPickerApiProxyImpl} from './emoji_picker_api_proxy.js';
 import {createCustomEvent, EMOJI_BUTTON_CLICK, EMOJI_DATA_LOADED, EMOJI_VARIANTS_SHOWN, EmojiVariantsShownEvent, GROUP_BUTTON_CLICK} from './events.js';
 import {RecentEmojiStore} from './store.js';
 import {Emoji, EmojiGroup, EmojiGroupData, EmojiVariants} from './types.js';
@@ -140,6 +141,9 @@
     /** @private {?EmojiButton} */
     this.activeVariant = null;
 
+    /** @private {!EmojiPickerApiProxy} */
+    this.apiProxy_ = EmojiPickerApiProxyImpl.getInstance();
+
     /** @private {boolean} */
     this.autoScrollingToGroup = false;
 
@@ -156,6 +160,7 @@
         ev => this.onShowEmojiVariants(
             /** @type {!EmojiVariantsShownEvent} */ (ev)));
     this.addEventListener('click', () => this.hideEmojiVariants());
+    this.apiProxy_.showUI();
   }
 
   ready() {
@@ -183,12 +188,11 @@
    * @param {!string} emoji
    */
   insertEmoji(emoji, isVariant) {
-    chrome.send('insertEmoji', [emoji, isVariant]);
+    this.$.message.textContent = emoji + ' inserted.';
     this.recentEmojiStore.bumpEmoji(emoji);
     this.set(
         ['history', 'emoji'], makeRecentlyUsed(this.recentEmojiStore.data));
-
-    this.$.message.textContent = emoji + ' inserted.';
+    this.apiProxy_.insertEmoji(emoji, isVariant);
   }
 
   /**
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker_api_proxy.js b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker_api_proxy.js
new file mode 100644
index 0000000..b9218096
--- /dev/null
+++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker_api_proxy.js
@@ -0,0 +1,39 @@
+// Copyright 2021 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 {addSingletonGetter} from 'chrome://resources/js/cr.m.js';
+
+
+import {PageHandlerFactory, PageHandlerRemote} from './emoji_picker.mojom-webui.js';
+
+/** @interface */
+export class EmojiPickerApiProxy {
+  showUI() {}
+  /**
+   *
+   * @param {string} emoji
+   * @param {boolean} isVariant
+   */
+  insertEmoji(emoji, isVariant) {}
+}
+/** @implements {EmojiPickerApiProxy} */
+export class EmojiPickerApiProxyImpl {
+  constructor() {
+    /** @type {!PageHandlerRemote} */
+    this.handler = new PageHandlerRemote();
+
+    const factory = PageHandlerFactory.getRemote();
+    factory.createPageHandler(this.handler.$.bindNewPipeAndPassReceiver());
+  }
+
+  /** @override */
+  showUI() {
+    this.handler.showUI();
+  }
+  /** @override */
+  insertEmoji(emoji, isVariant) {
+    this.handler.insertEmoji(emoji, isVariant);
+  }
+}
+
+addSingletonGetter(EmojiPickerApiProxyImpl);
\ No newline at end of file
diff --git a/chrome/browser/resources/new_tab_page/BUILD.gn b/chrome/browser/resources/new_tab_page/BUILD.gn
index e6c75abb1..c731aab4 100644
--- a/chrome/browser/resources/new_tab_page/BUILD.gn
+++ b/chrome/browser/resources/new_tab_page/BUILD.gn
@@ -365,7 +365,6 @@
 
   grdp_files = [
     "$target_gen_dir/icons/resources.grdp",
-    "$target_gen_dir/modules/drive/icons/resources.grdp",
     "$target_gen_dir/new_tab_page_mojo_resources.grdp",
     "$target_gen_dir/promo_browser_command_mojo_resources.grdp",
     "$target_gen_dir/realbox/realbox_mojo_resources.grdp",
@@ -381,7 +380,6 @@
     ":build_promo_browser_command_mojo_grdp",
     ":build_task_module_mojo_grdp",
     "icons:build_grdp",
-    "modules/drive/icons:build_grdp",
     "realbox:build_realbox_mojo_grdp",
     "realbox:build_search_mojo_grdp",
   ]
diff --git a/chrome/browser/resources/new_tab_page/modules/drive/icons/BUILD.gn b/chrome/browser/resources/new_tab_page/modules/drive/icons/BUILD.gn
deleted file mode 100644
index b9fe918..0000000
--- a/chrome/browser/resources/new_tab_page/modules/drive/icons/BUILD.gn
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright 2021 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("//ui/webui/resources/tools/generate_grd.gni")
-
-generate_grd("build_grdp") {
-  grd_prefix = "drive"
-  out_grd = "$target_gen_dir/resources.grdp"
-  input_files = [
-    "google_docs_logo.svg",
-    "google_sheets_logo.svg",
-    "google_slides_logo.svg",
-  ]
-  input_files_base_dir = rebase_path(".", "//")
-  resource_path_prefix = "modules/drive/icons"
-}
diff --git a/chrome/browser/resources/new_tab_page/modules/drive/icons/google_docs_logo.svg b/chrome/browser/resources/new_tab_page/modules/drive/icons/google_docs_logo.svg
deleted file mode 100644
index 1cec678..0000000
--- a/chrome/browser/resources/new_tab_page/modules/drive/icons/google_docs_logo.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg width="26" height="36" viewBox="0 0 26 36" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M20.719 18.41H5.281v2.863H20.72v-2.864zm-4.062 4.908H5.28v2.864h11.376v-2.864z" fill="#fff"/><path d="M17.063 9l4.188.205L26 9l-8.938-9-.203 5.494L17.062 9z" fill="#0066DA"/><path d="M20.719 13.5H5.281v2.864H20.72V13.5z" fill="#fff"/><path d="M17.063 9V0H2.438A2.445 2.445 0 0 0 0 2.455v31.09A2.445 2.445 0 0 0 2.438 36h21.125A2.445 2.445 0 0 0 26 33.545V9h-8.938zm-.813 16.773H5.687v-2.046H16.25v2.046zm4.063-4.91H5.688v-2.045h14.625v2.046zm0-4.909H5.688V13.91h14.625v2.045z" fill="#2684FC"/></svg>
\ No newline at end of file
diff --git a/chrome/browser/resources/new_tab_page/modules/drive/icons/google_sheets_logo.svg b/chrome/browser/resources/new_tab_page/modules/drive/icons/google_sheets_logo.svg
deleted file mode 100644
index 9c7b0cc..0000000
--- a/chrome/browser/resources/new_tab_page/modules/drive/icons/google_sheets_logo.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg width="26" height="36" viewBox="0 0 26 36" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M23.563 36H2.438A2.445 2.445 0 0 1 0 33.545V2.455A2.445 2.445 0 0 1 2.438 0h14.624L26 9v24.545A2.445 2.445 0 0 1 23.562 36z" fill="#00AC47"/><path d="M17.063 0L26 9h-8.938V0z" fill="#00832D"/><path d="M19.094 13.91H4.875v11.862h16.25V13.909h-2.031zM6.906 15.954h5.078v2.863H6.906v-2.863zm0 7.772v-2.863h5.078v2.863H6.906zm12.188 0h-5.078v-2.863h5.078v2.863zm0-4.909h-5.078v-2.863h5.078v2.863z" fill="#fff"/></svg>
\ No newline at end of file
diff --git a/chrome/browser/resources/new_tab_page/modules/drive/icons/google_slides_logo.svg b/chrome/browser/resources/new_tab_page/modules/drive/icons/google_slides_logo.svg
deleted file mode 100644
index 6ea313f..0000000
--- a/chrome/browser/resources/new_tab_page/modules/drive/icons/google_slides_logo.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg width="52" height="72" viewBox="0 0 52 72" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M47.125 72H4.875C2.18 72 0 69.803 0 67.091V4.91C0 2.197 2.18 0 4.875 0h29.25L52 18v49.091c0 2.713-2.182 4.91-4.875 4.91z" fill="#FFBA00"/><path d="M34.125 0L52 18H34.125V0z" fill="#FF9500"/><path d="M38.187 27.819H9.75v22.09h32.5V27.82h-4.063zm0 18H13.812v-13.91h24.375v13.91z" fill="#fff"/></svg>
\ No newline at end of file
diff --git a/chrome/browser/resources/new_tab_page/modules/drive/module.html b/chrome/browser/resources/new_tab_page/modules/drive/module.html
index cec9cb10..82af37e 100644
--- a/chrome/browser/resources/new_tab_page/modules/drive/module.html
+++ b/chrome/browser/resources/new_tab_page/modules/drive/module.html
@@ -51,9 +51,10 @@
         on-auxclick="onFileClick_">
       <div class="file-icon-container">
         <img
+            is="ntp-img"
             class="file-icon"
             draggable="false"
-            src="[[getImageSrc_(item)]]">
+            auto-src="[[getImageSrc_(item)]]">
         </img>
       </div>
       <div class="file-title">[[item.title]]</div>
diff --git a/chrome/browser/resources/new_tab_page/modules/drive/module.js b/chrome/browser/resources/new_tab_page/modules/drive/module.js
index 1d1956d4..9302580 100644
--- a/chrome/browser/resources/new_tab_page/modules/drive/module.js
+++ b/chrome/browser/resources/new_tab_page/modules/drive/module.js
@@ -60,19 +60,8 @@
    * @private
    */
   getImageSrc_(file) {
-    switch (file.type) {
-      case (drive.mojom.FileType.kDoc):
-        return 'modules/drive/icons/google_docs_logo.svg';
-      case (drive.mojom.FileType.kSheet):
-        return 'modules/drive/icons/google_sheets_logo.svg';
-      case (drive.mojom.FileType.kSlide):
-        return 'modules/drive/icons/google_slides_logo.svg';
-      default:
-        // TODO(crbug/1176982): Need to return an image
-        // in the case we don't know the type of
-        // drive item.
-        return '';
-    }
+    return 'https://drive-thirdparty.googleusercontent.com/128/type/' +
+        file.mimeType;
   }
 
   /** @private */
diff --git a/chrome/browser/safe_browsing/incident_reporting/extension_data_collection_unittest.cc b/chrome/browser/safe_browsing/incident_reporting/extension_data_collection_unittest.cc
index cdaaa70e..11aad28 100644
--- a/chrome/browser/safe_browsing/incident_reporting/extension_data_collection_unittest.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/extension_data_collection_unittest.cc
@@ -191,7 +191,7 @@
   int profile_number_;
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  chromeos::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
+  ash::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
   std::unique_ptr<chromeos::ScopedTestUserManager> test_user_manager_;
 #endif
 };
diff --git a/chrome/browser/search/drive/drive.mojom b/chrome/browser/search/drive/drive.mojom
index af05c96..8f822743 100644
--- a/chrome/browser/search/drive/drive.mojom
+++ b/chrome/browser/search/drive/drive.mojom
@@ -6,26 +6,16 @@
 
 import "url/mojom/url.mojom";
 
-// The types of documents available within Google Drive.
-// TODO(crbug/1176927): Verify prioritized types from
-// Item Suggest.
-enum FileType {
-  kDoc,
-  kSlide,
-  kSheet,
-  kOther,
-};
-
 // A Google Drive File.
 struct File {
   // The ID of the Drive Item.
   string id;
   // Information on why the Drive Item was returned.
   string justification_text;
+  // The mime type of the Drive Item.
+  string mime_type;
   // The name of the Drive Item.
   string title;
-  // The type of the Drive Item.
-  FileType type;
   // The URL to navigate to the Drive Item.
   url.mojom.Url url;
 };
diff --git a/chrome/browser/search/drive/drive_service.cc b/chrome/browser/search/drive/drive_service.cc
index ce8c0ba0..c0eb96b 100644
--- a/chrome/browser/search/drive/drive_service.cc
+++ b/chrome/browser/search/drive/drive_service.cc
@@ -192,15 +192,7 @@
       }
       auto mojo_drive_doc = drive::mojom::File::New();
       mojo_drive_doc->title = *title;
-      if (*mime_type == "application/vnd.google-apps.document") {
-        mojo_drive_doc->type = drive::mojom::FileType::kDoc;
-      } else if (*mime_type == "application/vnd.google-apps.spreadsheet") {
-        mojo_drive_doc->type = drive::mojom::FileType::kSheet;
-      } else if (*mime_type == "application/vnd.google-apps.presentation") {
-        mojo_drive_doc->type = drive::mojom::FileType::kSlide;
-      } else {
-        mojo_drive_doc->type = drive::mojom::FileType::kOther;
-      }
+      mojo_drive_doc->mime_type = *mime_type;
       mojo_drive_doc->justification_text = justification_text;
       mojo_drive_doc->id = *id;
       mojo_drive_doc->url = GURL(*url);
diff --git a/chrome/browser/search/drive/drive_service_unittest.cc b/chrome/browser/search/drive/drive_service_unittest.cc
index fde3aaa..b455807c 100644
--- a/chrome/browser/search/drive/drive_service_unittest.cc
+++ b/chrome/browser/search/drive/drive_service_unittest.cc
@@ -66,7 +66,7 @@
               "url":"https://google.com/foo",
               "driveItem": {
                 "title": "Foo foo",
-                "mimeType": "Foo foo foo"
+                "mimeType": "application/vnd.google-apps.spreadsheet"
               },
               "justification": {
                 "displayText": {
@@ -110,12 +110,14 @@
 
   EXPECT_EQ(2u, actual_documents.size());
   EXPECT_EQ("Foo foo", actual_documents.at(0)->title);
-  EXPECT_EQ(drive::mojom::FileType::kOther, actual_documents.at(0)->type);
+  EXPECT_EQ("application/vnd.google-apps.spreadsheet",
+            actual_documents.at(0)->mime_type);
   EXPECT_EQ("Foo foo", actual_documents.at(0)->justification_text);
   EXPECT_EQ("https://google.com/foo", actual_documents.at(0)->url.spec());
   EXPECT_EQ("Bar", actual_documents.at(1)->title);
   EXPECT_EQ("123", actual_documents.at(1)->id);
-  EXPECT_EQ(drive::mojom::FileType::kDoc, actual_documents.at(1)->type);
+  EXPECT_EQ("application/vnd.google-apps.document",
+            actual_documents.at(1)->mime_type);
   EXPECT_EQ("Foo bar foo bar", actual_documents.at(1)->justification_text);
   EXPECT_EQ("https://google.com/bar", actual_documents.at(1)->url.spec());
 }
@@ -195,19 +197,23 @@
   EXPECT_EQ(1u, response3.size());
   EXPECT_EQ(1u, response4.size());
   EXPECT_EQ("Foo foo", response1.at(0)->title);
-  EXPECT_EQ(drive::mojom::FileType::kSheet, response1.at(0)->type);
+  EXPECT_EQ("application/vnd.google-apps.spreadsheet",
+            response1.at(0)->mime_type);
   EXPECT_EQ("Foo foo", response1.at(0)->justification_text);
   EXPECT_EQ("234", response1.at(0)->id);
   EXPECT_EQ("Foo foo", response2.at(0)->title);
-  EXPECT_EQ(drive::mojom::FileType::kSheet, response2.at(0)->type);
+  EXPECT_EQ("application/vnd.google-apps.spreadsheet",
+            response2.at(0)->mime_type);
   EXPECT_EQ("Foo foo", response2.at(0)->justification_text);
   EXPECT_EQ("234", response2.at(0)->id);
   EXPECT_EQ("Foo foo", response3.at(0)->title);
-  EXPECT_EQ(drive::mojom::FileType::kSheet, response3.at(0)->type);
+  EXPECT_EQ("application/vnd.google-apps.spreadsheet",
+            response3.at(0)->mime_type);
   EXPECT_EQ("Foo foo", response3.at(0)->justification_text);
   EXPECT_EQ("234", response3.at(0)->id);
   EXPECT_EQ("Foo foo", response4.at(0)->title);
-  EXPECT_EQ(drive::mojom::FileType::kSheet, response4.at(0)->type);
+  EXPECT_EQ("application/vnd.google-apps.spreadsheet",
+            response4.at(0)->mime_type);
   EXPECT_EQ("Foo foo", response4.at(0)->justification_text);
   EXPECT_EQ("234", response4.at(0)->id);
 }
diff --git a/chrome/browser/speech/network_speech_recognizer.cc b/chrome/browser/speech/network_speech_recognizer.cc
index a048c021..48a93e7 100644
--- a/chrome/browser/speech/network_speech_recognizer.cc
+++ b/chrome/browser/speech/network_speech_recognizer.cc
@@ -125,10 +125,19 @@
       locale_(locale),
       session_(kInvalidSessionId) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  NotifyRecognitionStateChanged(SPEECH_RECOGNIZER_READY);
 }
 
 NetworkSpeechRecognizer::EventListener::~EventListener() {
+  // No more callbacks when we are deleting.
+  delegate_.reset();
   DCHECK(!speech_timeout_.IsRunning());
+  if (session_ != kInvalidSessionId) {
+    // Ensure the session is aborted.
+    int session = session_;
+    session_ = kInvalidSessionId;
+    content::SpeechRecognitionManager::GetInstance()->AbortSession(session);
+  }
 }
 
 void NetworkSpeechRecognizer::EventListener::StartOnIOThread(
@@ -177,6 +186,9 @@
   StopSpeechTimeout();
   content::SpeechRecognitionManager::GetInstance()->StopAudioCaptureForSession(
       session);
+  // Since we no longer have access to this session ID, end the session
+  // associated with it.
+  content::SpeechRecognitionManager::GetInstance()->AbortSession(session);
   weak_factory_.InvalidateWeakPtrs();
 }
 
@@ -253,7 +265,7 @@
     const blink::mojom::SpeechRecognitionError& error) {
   StopOnIOThread();
   if (error.code == blink::mojom::SpeechRecognitionErrorCode::kNetwork) {
-    NotifyRecognitionStateChanged(SPEECH_RECOGNIZER_NETWORK_ERROR);
+    NotifyRecognitionStateChanged(SPEECH_RECOGNIZER_ERROR);
   }
   NotifyRecognitionStateChanged(SPEECH_RECOGNIZER_READY);
 }
@@ -310,6 +322,8 @@
 
 NetworkSpeechRecognizer::~NetworkSpeechRecognizer() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  // Reset the delegate before calling Stop() to avoid any additional callbacks.
+  delegate().reset();
   Stop();
 }
 
diff --git a/chrome/browser/speech/network_speech_recognizer_browsertest.cc b/chrome/browser/speech/network_speech_recognizer_browsertest.cc
index a8b359c8..aa1f33ec 100644
--- a/chrome/browser/speech/network_speech_recognizer_browsertest.cc
+++ b/chrome/browser/speech/network_speech_recognizer_browsertest.cc
@@ -26,8 +26,8 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using ::testing::DoDefault;
 using ::testing::InvokeWithoutArgs;
-using ::testing::Return;
 
 class MockSpeechRecognizerDelegate : public SpeechRecognizerDelegate {
  public:
@@ -86,13 +86,26 @@
           ->GetURLLoaderFactoryForBrowserProcessIOThread(),
       "en" /* accept_language */, "en" /* locale */);
 
+  testing::InSequence seq;
+
   base::RunLoop run_loop;
   EXPECT_CALL(*mock_speech_delegate_,
+              OnSpeechRecognitionStateChanged(SPEECH_RECOGNIZER_READY))
+      .Times(1)
+      .RetiresOnSaturation();
+  EXPECT_CALL(*mock_speech_delegate_,
+              OnSpeechRecognitionStateChanged(SPEECH_RECOGNIZER_RECOGNIZING))
+      .Times(1);
+  EXPECT_CALL(*mock_speech_delegate_,
+              OnSpeechRecognitionStateChanged(SPEECH_RECOGNIZER_IN_SPEECH))
+      .Times(1);
+  EXPECT_CALL(*mock_speech_delegate_,
               OnSpeechResult(base::ASCIIToUTF16("Pictures of the moon"), true,
                              testing::_));
   EXPECT_CALL(*mock_speech_delegate_,
               OnSpeechRecognitionStateChanged(SPEECH_RECOGNIZER_READY))
-      .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
+      .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit))
+      .RetiresOnSaturation();
   recognizer.Start();
   run_loop.Run();
 }
diff --git a/chrome/browser/speech/on_device_speech_recognizer.cc b/chrome/browser/speech/on_device_speech_recognizer.cc
index 0a5513d..d723597 100644
--- a/chrome/browser/speech/on_device_speech_recognizer.cc
+++ b/chrome/browser/speech/on_device_speech_recognizer.cc
@@ -4,20 +4,104 @@
 
 #include "chrome/browser/speech/on_device_speech_recognizer.h"
 
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/accessibility/soda_installer.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/speech/cros_speech_recognition_service.h"
+#include "chrome/browser/speech/cros_speech_recognition_service_factory.h"
 #include "chrome/browser/speech/speech_recognizer_delegate.h"
+#include "content/public/browser/audio_service.h"
+#include "content/public/browser/browser_thread.h"
+#include "media/base/bind_to_current_loop.h"
+#include "media/base/media_switches.h"
 
 bool OnDeviceSpeechRecognizer::IsOnDeviceSpeechRecognizerAvailable() {
-  return false;
+  // IsSodaInstalled will DCHECK if kUseSodaForLiveCaption is disabled.
+  // kUseSodaForLiveCaption is used to track SODA availability on-device.
+  return base::FeatureList::IsEnabled(media::kUseSodaForLiveCaption) &&
+         speech::SodaInstaller::GetInstance()->IsSodaInstalled();
 }
 
 OnDeviceSpeechRecognizer::OnDeviceSpeechRecognizer(
-    const base::WeakPtr<SpeechRecognizerDelegate>& delegate)
-    : SpeechRecognizer(delegate) {}
+    const base::WeakPtr<SpeechRecognizerDelegate>& delegate,
+    Profile* profile)
+    : SpeechRecognizer(delegate),
+      state_(SpeechRecognizerStatus::SPEECH_RECOGNIZER_OFF) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-OnDeviceSpeechRecognizer::~OnDeviceSpeechRecognizer() {
-  Stop();
+  // Connect the SpeechRecognitionContext.
+  mojo::PendingReceiver<media::mojom::SpeechRecognitionContext>
+      speech_recognition_context_receiver =
+          speech_recognition_context_.BindNewPipeAndPassReceiver();
+
+  // Bind to an AudioSourceFetcher in the Speech Recognition service,
+  // passing the stream factory so it can listen to mic audio.
+  // TODO(crbug.com/1173135): Get input stream parameters from
+  // content::CreateAudioSystemForAudioService() if possible, and pass this
+  // and device_id to the AudioSourceFetcher in BindAudioSourceFetcher().
+  mojo::PendingRemote<media::mojom::AudioStreamFactory> stream_factory;
+  content::GetAudioServiceStreamFactoryBinder().Run(
+      stream_factory.InitWithNewPipeAndPassReceiver());
+  speech_recognition_context_->BindAudioSourceFetcher(
+      audio_source_fetcher_.BindNewPipeAndPassReceiver(),
+      speech_recognition_client_receiver_.BindNewPipeAndPassRemote(),
+      std::move(stream_factory),
+      media::BindToCurrentLoop(
+          base::BindOnce(&OnDeviceSpeechRecognizer::OnRecognizerBound,
+                         weak_factory_.GetWeakPtr())));
+
+  CrosSpeechRecognitionServiceFactory::GetForProfile(profile)->Create(
+      std::move(speech_recognition_context_receiver));
+
+  speech_recognition_context_.set_disconnect_handler(media::BindToCurrentLoop(
+      base::BindOnce(&OnDeviceSpeechRecognizer::OnRecognizerDisconnected,
+                     weak_factory_.GetWeakPtr())));
 }
 
-void OnDeviceSpeechRecognizer::Start() {}
+OnDeviceSpeechRecognizer::~OnDeviceSpeechRecognizer() {
+  audio_source_fetcher_->Stop();
+  audio_source_fetcher_.reset();
+  speech_recognition_client_receiver_.reset();
+  speech_recognition_context_.reset();
+}
 
-void OnDeviceSpeechRecognizer::Stop() {}
+void OnDeviceSpeechRecognizer::Start() {
+  // TODO(crbug.com/1173135): Call audio_source_fetcher_->Start();
+  UpdateStatus(SpeechRecognizerStatus::SPEECH_RECOGNIZER_RECOGNIZING);
+}
+
+void OnDeviceSpeechRecognizer::Stop() {
+  audio_source_fetcher_->Stop();
+  UpdateStatus(SpeechRecognizerStatus::SPEECH_RECOGNIZER_READY);
+}
+
+void OnDeviceSpeechRecognizer::OnSpeechRecognitionRecognitionEvent(
+    media::mojom::SpeechRecognitionResultPtr result) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  if (!result->transcription.size())
+    return;
+  UpdateStatus(SpeechRecognizerStatus::SPEECH_RECOGNIZER_IN_SPEECH);
+  delegate()->OnSpeechResult(base::UTF8ToUTF16(result->transcription),
+                             result->is_final, base::nullopt);
+}
+
+void OnDeviceSpeechRecognizer::OnSpeechRecognitionError() {
+  UpdateStatus(SpeechRecognizerStatus::SPEECH_RECOGNIZER_ERROR);
+}
+
+void OnDeviceSpeechRecognizer::OnRecognizerBound(bool success) {
+  if (success)
+    UpdateStatus(SpeechRecognizerStatus::SPEECH_RECOGNIZER_READY);
+}
+
+void OnDeviceSpeechRecognizer::OnRecognizerDisconnected() {
+  UpdateStatus(SpeechRecognizerStatus::SPEECH_RECOGNIZER_ERROR);
+}
+
+void OnDeviceSpeechRecognizer::UpdateStatus(SpeechRecognizerStatus state) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  if (state_ == state)
+    return;
+  delegate()->OnSpeechRecognitionStateChanged(state);
+  state_ = state;
+}
diff --git a/chrome/browser/speech/on_device_speech_recognizer.h b/chrome/browser/speech/on_device_speech_recognizer.h
index 34c139d..5b11081 100644
--- a/chrome/browser/speech/on_device_speech_recognizer.h
+++ b/chrome/browser/speech/on_device_speech_recognizer.h
@@ -5,22 +5,33 @@
 #ifndef CHROME_BROWSER_SPEECH_ON_DEVICE_SPEECH_RECOGNIZER_H_
 #define CHROME_BROWSER_SPEECH_ON_DEVICE_SPEECH_RECOGNIZER_H_
 
-#include "chrome/browser/speech/speech_recognizer.h"
+#include <memory>
 
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/speech/speech_recognizer.h"
+#include "chrome/browser/speech/speech_recognizer_delegate.h"
+#include "media/mojo/mojom/speech_recognition_service.mojom.h"
+
+class Profile;
 class SpeechRecognizerDelegate;
 
 // OnDeviceSpeechRecognizer is a wrapper around the on-device speech recognition
 // engine that simplifies its use from the browser process.
-class OnDeviceSpeechRecognizer : public SpeechRecognizer {
+class OnDeviceSpeechRecognizer
+    : public SpeechRecognizer,
+      public media::mojom::SpeechRecognitionRecognizerClient {
  public:
   // Returns true if on-device speech recognition is available and installed
   // on-device.
-  // TODO(katie): Might need to take a language/locale parameter once we know
-  // how to check for per-language downloads.
+  // TODO(crbug.com/1173135): Language pack availability is based on the current
+  // profile language settings, and currently based on kLiveCaptionLanguageCode
+  // which is hard-coded to en-us. IsOnDeviceSpeechRecognizerAvailable should
+  // take a language code to check.
   static bool IsOnDeviceSpeechRecognizerAvailable();
 
-  explicit OnDeviceSpeechRecognizer(
-      const base::WeakPtr<SpeechRecognizerDelegate>& delegate);
+  OnDeviceSpeechRecognizer(
+      const base::WeakPtr<SpeechRecognizerDelegate>& delegate,
+      Profile* profile);
   ~OnDeviceSpeechRecognizer() override;
   OnDeviceSpeechRecognizer(const OnDeviceSpeechRecognizer&) = delete;
   OnDeviceSpeechRecognizer& operator=(const OnDeviceSpeechRecognizer&) = delete;
@@ -29,6 +40,29 @@
   // Start and Stop must be called on the UI thread.
   void Start() override;
   void Stop() override;
+
+  // media::mojom::SpeechRecognitionRecognizerClient:
+  void OnSpeechRecognitionRecognitionEvent(
+      media::mojom::SpeechRecognitionResultPtr result) override;
+  void OnSpeechRecognitionError() override;
+
+ private:
+  void OnRecognizerBound(bool success);
+  void OnRecognizerDisconnected();
+
+  // Helper function to send the delegate updates to SpeechRecognizerStatus
+  // only when the status has changed.
+  void UpdateStatus(SpeechRecognizerStatus state);
+
+  SpeechRecognizerStatus state_;
+
+  mojo::Remote<media::mojom::SpeechRecognitionContext>
+      speech_recognition_context_;
+  mojo::Remote<media::mojom::AudioSourceFetcher> audio_source_fetcher_;
+  mojo::Receiver<media::mojom::SpeechRecognitionRecognizerClient>
+      speech_recognition_client_receiver_{this};
+
+  base::WeakPtrFactory<OnDeviceSpeechRecognizer> weak_factory_{this};
 };
 
 #endif  // CHROME_BROWSER_SPEECH_ON_DEVICE_SPEECH_RECOGNIZER_H_
diff --git a/chrome/browser/speech/speech_recognition_service_browsertest.cc b/chrome/browser/speech/speech_recognition_service_browsertest.cc
index 8ef4915..709e586 100644
--- a/chrome/browser/speech/speech_recognition_service_browsertest.cc
+++ b/chrome/browser/speech/speech_recognition_service_browsertest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/files/file_util.h"
+#include "base/notreached.h"
 #include "base/path_service.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
@@ -57,6 +58,7 @@
   // media::mojom::SpeechRecognitionRecognizerClient
   void OnSpeechRecognitionRecognitionEvent(
       media::mojom::SpeechRecognitionResultPtr result) override;
+  void OnSpeechRecognitionError() override;
 
   void SetUpCommandLine(base::CommandLine* command_line) override {
     // Required for the utility process to access the directory containing the
@@ -98,6 +100,10 @@
   recognition_results_.push_back(std::move(result->transcription));
 }
 
+void SpeechRecognitionServiceTest::OnSpeechRecognitionError() {
+  NOTREACHED();
+}
+
 void SpeechRecognitionServiceTest::LaunchService() {
   // Launch the Speech Recognition service.
   auto* browser_context =
@@ -264,10 +270,11 @@
   profile_prefs->SetBoolean(prefs::kLiveCaptionEnabled, true);
   LaunchServiceWithAudioSourceFetcher();
 
-  // TODO(crbug.com/1173135): Test mock audio input for AudioSourceFetcher.
-  // Currently a sanity check as nothing happens yet.
-  audio_source_fetcher_->Start();
+  // Ensure no crashes.
+  // TODO(crbug.com/1173135): Try to mock audio input, maybe with
+  // FakeStreamFactory, to test end-to-end.
   audio_source_fetcher_->Stop();
+
   base::RunLoop().RunUntilIdle();
 }
 
diff --git a/chrome/browser/speech/speech_recognizer_delegate.h b/chrome/browser/speech/speech_recognizer_delegate.h
index dc24ec7..f6f3e98b 100644
--- a/chrome/browser/speech/speech_recognizer_delegate.h
+++ b/chrome/browser/speech/speech_recognizer_delegate.h
@@ -14,11 +14,14 @@
 // Requires cleanup. See crbug.com/800374.
 enum SpeechRecognizerStatus {
   SPEECH_RECOGNIZER_OFF = 0,
+  // Ready for SpeechRecognizer::Start() to be called.
   SPEECH_RECOGNIZER_READY,
+  // Beginning to listen for speech, but have not received any yet.
   SPEECH_RECOGNIZER_RECOGNIZING,
+  // Sounds are being recognized.
   SPEECH_RECOGNIZER_IN_SPEECH,
-  SPEECH_RECOGNIZER_STOPPING,
-  SPEECH_RECOGNIZER_NETWORK_ERROR,
+  // There was an error.
+  SPEECH_RECOGNIZER_ERROR,
 };
 
 // Delegate for speech recognizer. All methods are called from the thread on
diff --git a/chrome/browser/sync/test/integration/single_client_nigori_sync_test.cc b/chrome/browser/sync/test/integration/single_client_nigori_sync_test.cc
index a560a5b2..99c60d9 100644
--- a/chrome/browser/sync/test/integration/single_client_nigori_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_nigori_sync_test.cc
@@ -1116,8 +1116,9 @@
 // Device registration attempt should be taken upon sign in into primary
 // profile. It should be successful when security domain server allows device
 // registration with constant key.
+// Disabled due to flakiness. See crbug.com/1186919.
 IN_PROC_BROWSER_TEST_F(SingleClientNigoriSyncTestWithSecurityDomainsServer,
-                       ShouldRegisterDeviceWithConstantKey) {
+                       DISABLED_ShouldRegisterDeviceWithConstantKey) {
   ASSERT_TRUE(SetupSync());
   // TODO(crbug.com/1113599): consider checking member public key (requires
   // either ability to overload key generator in the test or exposing public key
diff --git a/chrome/browser/themes/theme_helper.cc b/chrome/browser/themes/theme_helper.cc
index d06630e..e17ad78 100644
--- a/chrome/browser/themes/theme_helper.cc
+++ b/chrome/browser/themes/theme_helper.cc
@@ -389,14 +389,29 @@
           GetColor(TP::COLOR_NTP_TEXT, incognito, theme_supplier), 0.40);
     case TP::COLOR_TAB_THROBBER_SPINNING:
     case TP::COLOR_TAB_THROBBER_WAITING: {
-      SkColor base_color =
-          ui::GetAuraColor(id == TP::COLOR_TAB_THROBBER_SPINNING
-                               ? ui::NativeTheme::kColorId_ThrobberSpinningColor
-                               : ui::NativeTheme::kColorId_ThrobberWaitingColor,
-                           ui::NativeTheme::GetInstanceForNativeUi());
-      color_utils::HSL hsl =
-          GetTint(TP::TINT_BUTTONS, incognito, theme_supplier);
-      return color_utils::HSLShift(base_color, hsl);
+      // Similar to the code in BrowserThemeProvider::HasCustomColor(), here we
+      // decide the toolbar button icon has a custom color if the theme supplier
+      // has explicitly specified it or a TINT_BUTTONS value. Unlike that code,
+      // this does not consider TINT_BUTTONS to have been customized just
+      // because it differs from {-1, -1, -1}. The effect is that for the
+      // default light/dark/incognito themes, or custom themes which use the
+      // default toolbar button colors, the default throbber colors will be
+      // used; otherwise the throbber will be colored to match the toolbar
+      // buttons to guarantee visibility.
+      bool has_custom_color = false;
+      const SkColor button_color =
+          GetColor(TP::COLOR_TOOLBAR_BUTTON_ICON, incognito, theme_supplier,
+                   &has_custom_color);
+      color_utils::HSL hsl;
+      return (has_custom_color ||
+              (theme_supplier &&
+               theme_supplier->GetTint(TP::TINT_BUTTONS, &hsl)))
+                 ? button_color
+                 : ui::GetAuraColor(
+                       id == TP::COLOR_TAB_THROBBER_SPINNING
+                           ? ui::NativeTheme::kColorId_ThrobberSpinningColor
+                           : ui::NativeTheme::kColorId_ThrobberWaitingColor,
+                       ui::NativeTheme::GetInstanceForNativeUi());
     }
   }
 
diff --git a/chrome/browser/themes/theme_syncable_service_unittest.cc b/chrome/browser/themes/theme_syncable_service_unittest.cc
index 953325c7..6d391c0e 100644
--- a/chrome/browser/themes/theme_syncable_service_unittest.cc
+++ b/chrome/browser/themes/theme_syncable_service_unittest.cc
@@ -254,7 +254,7 @@
   content::BrowserTaskEnvironment task_environment_;
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  chromeos::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
+  ash::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
   chromeos::ScopedTestUserManager test_user_manager_;
 #endif
 
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index b43506b8..2fdf130 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -638,6 +638,7 @@
       "//components/query_tiles",
       "//components/resources:android_resources",
       "//components/security_state/content/android",
+      "//url:gurl_android",
     ]
   } else {
     # !is_android
@@ -2275,12 +2276,10 @@
       "webui/chromeos/edu_coexistence/edu_coexistence_login_handler_chromeos.h",
       "webui/chromeos/edu_coexistence/edu_coexistence_state_tracker.cc",
       "webui/chromeos/edu_coexistence/edu_coexistence_state_tracker.h",
-      "webui/chromeos/emoji/emoji_dialog.cc",
-      "webui/chromeos/emoji/emoji_dialog.h",
-      "webui/chromeos/emoji/emoji_handler.cc",
-      "webui/chromeos/emoji/emoji_handler.h",
-      "webui/chromeos/emoji/emoji_picker.cc",
-      "webui/chromeos/emoji/emoji_picker.h",
+      "webui/chromeos/emoji/emoji_page_handler.cc",
+      "webui/chromeos/emoji/emoji_page_handler.h",
+      "webui/chromeos/emoji/emoji_ui.cc",
+      "webui/chromeos/emoji/emoji_ui.h",
       "webui/chromeos/image_source.cc",
       "webui/chromeos/image_source.h",
       "webui/chromeos/in_session_password_change/confirm_password_change_handler.cc",
@@ -2689,6 +2688,7 @@
       "//chrome/browser/ui/webui/chromeos/add_supervision:mojo_bindings",
       "//chrome/browser/ui/webui/chromeos/crostini_installer:mojo_bindings",
       "//chrome/browser/ui/webui/chromeos/crostini_upgrader:mojo_bindings",
+      "//chrome/browser/ui/webui/chromeos/emoji:mojo_bindings",
       "//chrome/browser/ui/webui/chromeos/machine_learning:mojo_bindings",
       "//chrome/browser/ui/webui/nearby_share:mojom",
       "//chrome/browser/ui/webui/nearby_share/public/mojom",
diff --git a/chrome/browser/ui/android/infobars/autofill_offer_notification_infobar.cc b/chrome/browser/ui/android/infobars/autofill_offer_notification_infobar.cc
index 3f79838c..f1c6b10b 100644
--- a/chrome/browser/ui/android/infobars/autofill_offer_notification_infobar.cc
+++ b/chrome/browser/ui/android/infobars/autofill_offer_notification_infobar.cc
@@ -17,6 +17,7 @@
 #include "components/autofill/core/browser/payments/legal_message_line.h"
 #include "ui/gfx/android/java_bitmap.h"
 #include "ui/gfx/image/image.h"
+#include "url/android/gurl_android.h"
 #include "url/gurl.h"
 
 using base::android::ScopedJavaLocalRef;
@@ -28,11 +29,12 @@
 
 AutofillOfferNotificationInfoBar::~AutofillOfferNotificationInfoBar() {}
 
-void AutofillOfferNotificationInfoBar::OnOfferDeepLinkClicked(JNIEnv* env,
-                                                              jobject obj,
-                                                              jstring url) {
+void AutofillOfferNotificationInfoBar::OnOfferDeepLinkClicked(
+    JNIEnv* env,
+    jobject obj,
+    const base::android::JavaParamRef<jobject>& url) {
   GetOfferNotificationDelegate()->OnOfferDeepLinkClicked(
-      GURL(base::android::ConvertJavaStringToUTF16(env, url)));
+      *url::GURLAndroid::ToNativeGURL(env, url));
 }
 
 base::android::ScopedJavaLocalRef<jobject>
@@ -50,8 +52,7 @@
                                                   delegate->GetMessageText()),
           base::android::ConvertUTF16ToJavaString(
               env, GetTextFor(ConfirmInfoBarDelegate::BUTTON_OK)),
-          base::android::ConvertUTF16ToJavaString(env,
-                                                  delegate->deep_link_url()));
+          url::GURLAndroid::FromNativeGURL(env, delegate->deep_link_url()));
 
   Java_AutofillOfferNotificationInfoBar_setCreditCardDetails(
       env, java_delegate,
diff --git a/chrome/browser/ui/android/infobars/autofill_offer_notification_infobar.h b/chrome/browser/ui/android/infobars/autofill_offer_notification_infobar.h
index a1fde3a..0740c4a 100644
--- a/chrome/browser/ui/android/infobars/autofill_offer_notification_infobar.h
+++ b/chrome/browser/ui/android/infobars/autofill_offer_notification_infobar.h
@@ -11,7 +11,6 @@
 
 #include "base/macros.h"
 #include "chrome/browser/ui/android/infobars/chrome_confirm_infobar.h"
-
 namespace autofill {
 class AutofillOfferNotificationInfoBarDelegateMobile;
 }
@@ -32,7 +31,9 @@
       const AutofillOfferNotificationInfoBar&) = delete;
 
   // Called when a link in the legal message text was clicked.
-  void OnOfferDeepLinkClicked(JNIEnv* env, jobject obj, jstring url);
+  void OnOfferDeepLinkClicked(JNIEnv* env,
+                              jobject obj,
+                              const base::android::JavaParamRef<jobject>& url);
 
  private:
   // ChromeConfirmInfoBar:
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_as.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_as.xtb
index 0b6ffe9..8c84487 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_as.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_as.xtb
@@ -608,6 +608,7 @@
 <translation id="5210365745912300556">টেব বন্ধ কৰক</translation>
 <translation id="5213672942202814946">কণ্ঠধ্বনিৰদ্বাৰা সন্ধানৰ সুবিধাটো ব্যৱহাৰ কৰক</translation>
 <translation id="5222676887888702881">ছাইন আউট কৰক</translation>
+<translation id="5227554086496586518">সন্ধানৰ ফলাফল চাবলৈ টিপক</translation>
 <translation id="5230560987958996918"><ph name="SITE" />এ নিকটৱৰ্তী ব্লুটুথ ডিভাইচবোৰ বিচাৰি স্কেন কৰিব বিচাৰে। এই ডিভাইচকেইটা বিচাৰি পোৱা গৈছে:</translation>
 <translation id="5233638681132016545">নতুন টেব</translation>
 <translation id="5250483651202458397">স্ক্ৰীনশ্বট। বন্ধ কৰিবলৈ টিপক।</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_az.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_az.xtb
index 72741856..8f265b7 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_az.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_az.xtb
@@ -608,6 +608,7 @@
 <translation id="5210365745912300556">Paneli qapadın</translation>
 <translation id="5213672942202814946">Səsli axtarışdan istifadə edin</translation>
 <translation id="5222676887888702881">Hesabdan çıxın</translation>
+<translation id="5227554086496586518">Axtarış nəticələrini görmək üçün toxunun</translation>
 <translation id="5230560987958996918"><ph name="SITE" /> yaxınlıqdakı Bluetooth cihazlarını axtarmaq istəyir. Aşağıdakı cihazlar tapıldı:</translation>
 <translation id="5233638681132016545">Yeni panel</translation>
 <translation id="5250483651202458397">Skrinşot. Bağlamaq üçün toxunun.</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_be.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_be.xtb
index b331840..b1d9970d 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_be.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_be.xtb
@@ -608,6 +608,7 @@
 <translation id="5210365745912300556">Закрыць укладку</translation>
 <translation id="5213672942202814946">Як працуе галасавы пошук</translation>
 <translation id="5222676887888702881">Выйсці</translation>
+<translation id="5227554086496586518">Націсніце, каб праглядзець вынікі пошуку</translation>
 <translation id="5230560987958996918"><ph name="SITE" /> запытвае пошук прылад Bluetooth паблізу. Знойдзены наступныя прылады:</translation>
 <translation id="5233638681132016545">Новая ўкладка</translation>
 <translation id="5250483651202458397">Здымак экрана. Дакраніцеся, каб закрыць.</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_bn.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_bn.xtb
index c03720bd..6920026 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_bn.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_bn.xtb
@@ -610,6 +610,7 @@
 <translation id="5210365745912300556">ট্যাব বন্ধ করুন</translation>
 <translation id="5213672942202814946">ভয়েস সার্চ ব্যবহার করুন</translation>
 <translation id="5222676887888702881">সাইন-আউট করুন</translation>
+<translation id="5227554086496586518">সার্চ ফলাফল দেখতে ট্যাপ করুন</translation>
 <translation id="5230560987958996918">কাছাকাছি থাকা ব্লুটুথ ডিভাইসগুলিকে <ph name="SITE" /> স্ক্যান করতে চায়, এই ডিভাইসগুলি পাওয়া গেছে:</translation>
 <translation id="5233638681132016545">নতুন ট্যাব</translation>
 <translation id="5250483651202458397">স্ক্রিনশট। বন্ধ করতে ট্যাপ করুন।</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_de.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_de.xtb
index d364bf1..c223e473 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_de.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_de.xtb
@@ -608,6 +608,7 @@
 <translation id="5210365745912300556">Schließen</translation>
 <translation id="5213672942202814946">Sprachsuche verwenden</translation>
 <translation id="5222676887888702881">Abmelden</translation>
+<translation id="5227554086496586518">Tippen, um Suchergebnisse zu sehen</translation>
 <translation id="5230560987958996918"><ph name="SITE" /> möchte nach Bluetooth-Geräten in der Nähe suchen. Die folgenden Geräte wurden gefunden:</translation>
 <translation id="5233638681132016545">Neuer Tab</translation>
 <translation id="5250483651202458397">Screenshot. Zum Schließen tippen.</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_fil.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_fil.xtb
index 13abef1..065f4db 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_fil.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_fil.xtb
@@ -608,6 +608,7 @@
 <translation id="5210365745912300556">Isara ang tab</translation>
 <translation id="5213672942202814946">Gamitin ang paghahanap gamit ang boses</translation>
 <translation id="5222676887888702881">Mag-sign out</translation>
+<translation id="5227554086496586518">I-tap para makita ang mga resulta ng paghahanap</translation>
 <translation id="5230560987958996918">Gustong mag-scan ng <ph name="SITE" /> para sa mga Bluetooth device na nasa malapit. Nahanap ang mga sumusunod na device:</translation>
 <translation id="5233638681132016545">Bagong tab</translation>
 <translation id="5250483651202458397">Screenshot. I-tap para isara.</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_gu.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_gu.xtb
index 38400a9df..bd125c8e 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_gu.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_gu.xtb
@@ -262,7 +262,7 @@
 <translation id="2779651927720337254">નિષ્ફળ થયું</translation>
 <translation id="2781151931089541271">1 સેકંડ બાકી</translation>
 <translation id="2801022321632964776">Chromeના એકદમ નવા વર્ઝનમાં તમારી ભાષા મેળવવા માટે અપડેટ કરો</translation>
-<translation id="2805756323405976993">એપ્સ</translation>
+<translation id="2805756323405976993">ઍપ</translation>
 <translation id="281504910091592009">સાચવેલા પાસવર્ડ તમારા <ph name="BEGIN_LINK" />Google એકાઉન્ટ<ph name="END_LINK" />માં જુઓ અને મેનેજ કરો</translation>
 <translation id="2818669890320396765">તમારા બધા ઉપકરણો પર તમારા બુકમાર્ક મેળવવા માટે, સાઇન ઇન કરો અને સિંક કરવાનું ચાલુ કરો</translation>
 <translation id="2827278682606527653">Feed card menu half height</translation>
@@ -608,6 +608,7 @@
 <translation id="5210365745912300556">ટૅબ બંધ કરો</translation>
 <translation id="5213672942202814946">વૉઇસ શોધનો ઉપયોગ કરો</translation>
 <translation id="5222676887888702881">સાઇન આઉટ</translation>
+<translation id="5227554086496586518">શોધ પરિણામો જોવા માટે ટૅપ કરો</translation>
 <translation id="5230560987958996918"><ph name="SITE" /> નજીકના બ્લૂટૂથ ડિવાઇસ માટે સ્કૅન કરવા માગે છે. નીચે મુજબના ડિવાઇસ મળ્યા છે:</translation>
 <translation id="5233638681132016545">નવું ટૅબ</translation>
 <translation id="5250483651202458397">સ્ક્રીનશૉટ. બંધ કરવા માટે ટૅપ કરો.</translation>
@@ -1096,7 +1097,7 @@
 <translation id="8410695015584479363">કિંમત ટ્રૅક કરો</translation>
 <translation id="8413126021676339697">પૂર્ણ ઇતિહાસ બતાવો</translation>
 <translation id="8427875596167638501">પ્રીવ્યૂ ટૅબ અડધી ઊંચાઈએ ખુલી</translation>
-<translation id="8428213095426709021">સેટિંગ્સ</translation>
+<translation id="8428213095426709021">સેટિંગ</translation>
 <translation id="8438566539970814960">શોધ અને બ્રાઉઝિંગ વધુ સારું બનાવો</translation>
 <translation id="8442258441309440798">કોઈ સ્ટોરી ઉપલબ્ધ નથી</translation>
 <translation id="8443209985646068659">Chrome અપડેટ કરી શકતા નથી</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_iw.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_iw.xtb
index 5179f10..a0537a3f 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_iw.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_iw.xtb
@@ -608,6 +608,7 @@
 <translation id="5210365745912300556">סגירת כרטיסייה</translation>
 <translation id="5213672942202814946">שימוש בחיפוש קולי</translation>
 <translation id="5222676887888702881">יציאה</translation>
+<translation id="5227554086496586518">יש להקיש כדי להציג את תוצאות החיפוש</translation>
 <translation id="5230560987958996918">‏<ph name="SITE" /> מבקש לבצע סריקה כדי לאתר מכשירי Bluetooth בקרבת מקום. המכשירים הבאים נמצאו:</translation>
 <translation id="5233638681132016545">כרטיסייה חדשה</translation>
 <translation id="5250483651202458397">צילום מסך. אפשר להקיש כדי לסגור.</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_kk.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_kk.xtb
index a04e6ae..31e63e8c 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_kk.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_kk.xtb
@@ -608,6 +608,7 @@
 <translation id="5210365745912300556">Қойындыны жабу</translation>
 <translation id="5213672942202814946">Дауыспен іздеу функциясын пайдалану</translation>
 <translation id="5222676887888702881">Шығу</translation>
+<translation id="5227554086496586518">Іздеу нәтижелерін көру үшін түртіңіз.</translation>
 <translation id="5230560987958996918"><ph name="SITE" /> маңайдағы Bluetooth құрылғыларын іздеуде. Мына құрылғылар табылды:</translation>
 <translation id="5233638681132016545">Жаңа қойынды</translation>
 <translation id="5250483651202458397">Скриншот. Жабу үшін түртіңіз.</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_km.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_km.xtb
index 0bc60549..12050f09 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_km.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_km.xtb
@@ -608,6 +608,7 @@
 <translation id="5210365745912300556">បិទផ្ទាំង</translation>
 <translation id="5213672942202814946">ប្រើការស្វែងរកតាមសំឡេង</translation>
 <translation id="5222676887888702881">ចាកចេញ</translation>
+<translation id="5227554086496586518">ចុច​ដើម្បី​មើល​លទ្ធផល​ស្វែងរក</translation>
 <translation id="5230560987958996918"><ph name="SITE" /> ចង់ស្កេនរក​ឧបករណ៍ប៊្លូធូស​នៅជិត។ បានរកឃើញ​ឧបករណ៍​ខាងក្រោម៖</translation>
 <translation id="5233638681132016545">ផ្ទាំងថ្មី</translation>
 <translation id="5250483651202458397">រូបថត​អេក្រង់។ ចុចដើម្បីបិទ។</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_ko.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_ko.xtb
index 198d24b2..7ccbd9e 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_ko.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_ko.xtb
@@ -608,6 +608,7 @@
 <translation id="5210365745912300556">탭 닫기</translation>
 <translation id="5213672942202814946">음성 검색 사용하기</translation>
 <translation id="5222676887888702881">로그아웃</translation>
+<translation id="5227554086496586518">검색결과를 보려면 탭하세요.</translation>
 <translation id="5230560987958996918"><ph name="SITE" />에서 주변 블루투스 기기를 검색하려고 합니다. 다음 기기가 발견되었습니다.</translation>
 <translation id="5233638681132016545">새 탭</translation>
 <translation id="5250483651202458397">스크린샷입니다. 닫으려면 탭하세요.</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_ky.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_ky.xtb
index f4a1d68..ad42d3d 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_ky.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_ky.xtb
@@ -608,6 +608,7 @@
 <translation id="5210365745912300556">Өтмөктү жабуу</translation>
 <translation id="5213672942202814946">"Үн менен издөөнү" колдонуу</translation>
 <translation id="5222676887888702881">Чыгуу</translation>
+<translation id="5227554086496586518">Издөө натыйжаларын көрүү үчүн таптап коюңуз</translation>
 <translation id="5230560987958996918"><ph name="SITE" /> сайты жакын жердеги Bluetooth түзмөктөрүн скандаганы жатат. Төмөнкү түзмөктөр табылды:</translation>
 <translation id="5233638681132016545">Жаңы өтмөк</translation>
 <translation id="5250483651202458397">Скриншот. Жабуу үчүн таптаңыз.</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_lv.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_lv.xtb
index 1ce5be6..2e25016 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_lv.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_lv.xtb
@@ -608,6 +608,7 @@
 <translation id="5210365745912300556">Aizvērt cilni</translation>
 <translation id="5213672942202814946">Meklēšana ar balsi</translation>
 <translation id="5222676887888702881">Izrakstīties</translation>
+<translation id="5227554086496586518">Pieskarieties, lai skatītu meklēšanas rezultātus</translation>
 <translation id="5230560987958996918"><ph name="SITE" /> vēlas meklēt tuvumā esošas Bluetooth ierīces. Ir atrastas šīs ierīces:</translation>
 <translation id="5233638681132016545">Jauna cilne</translation>
 <translation id="5250483651202458397">Ekrānuzņēmums. Pieskarieties, lai to aizvērtu.</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_ml.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_ml.xtb
index a483f0e..9d9628da 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_ml.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_ml.xtb
@@ -608,6 +608,7 @@
 <translation id="5210365745912300556">ടാബ് അടയ്ക്കൂക</translation>
 <translation id="5213672942202814946">ശബ്ദ തിരയൽ ഉപയോഗിക്കൂ</translation>
 <translation id="5222676887888702881">സൈൻ ഔട്ട് ചെയ്യുക</translation>
+<translation id="5227554086496586518">തിരയൽ ഫലങ്ങൾ കാണാൻ ടാപ്പ് ചെയ്യുക</translation>
 <translation id="5230560987958996918"><ph name="SITE" /> എന്നതിന് സമീപമുള്ള Bluetooth ഉപകരണങ്ങൾ സ്‌കാൻ ചെയ്യണമെന്നുണ്ട്. ഇനിപ്പറയുന്ന ഉപകരണങ്ങൾ കണ്ടെത്തി:</translation>
 <translation id="5233638681132016545">പുതിയ ടാബ്</translation>
 <translation id="5250483651202458397">സ്‌ക്രീൻഷോട്ട്. അടയ്ക്കാൻ ടാപ്പ് ചെയ്യുക.</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_ta.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_ta.xtb
index d185b6c..4899046 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_ta.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_ta.xtb
@@ -608,6 +608,7 @@
 <translation id="5210365745912300556">தாவலை மூடுக</translation>
 <translation id="5213672942202814946">குரல் தேடலைப் பயன்படுத்துதல்</translation>
 <translation id="5222676887888702881">வெளியேறு</translation>
+<translation id="5227554086496586518">தேடல் முடிவுகளைப் பார்க்க தட்டுக</translation>
 <translation id="5230560987958996918">அருகிலுள்ள புளூடூத் சாதனங்களை <ph name="SITE" /> ஸ்கேன் செய்ய விரும்புகிறது. இவை கண்டறியப்பட்டுள்ளன:</translation>
 <translation id="5233638681132016545">புதிய தாவல்</translation>
 <translation id="5250483651202458397">ஸ்கிரீன்ஷாட். மூடுவதற்குத் தட்டவும்.</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_te.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_te.xtb
index 640756f..7d26bee 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_te.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_te.xtb
@@ -608,6 +608,7 @@
 <translation id="5210365745912300556">ట్యాబ్‌ను మూసివేయి</translation>
 <translation id="5213672942202814946">వాయిస్ సెర్చ్‌ను ఉపయోగించండి</translation>
 <translation id="5222676887888702881">సైన్ ఔట్</translation>
+<translation id="5227554086496586518">సెర్చ్ ఫలితాలను చూడటానికి ట్యాప్ చేయండి</translation>
 <translation id="5230560987958996918"><ph name="SITE" /> సమీపంలోని బ్లూటూత్ పరికరాల కోసం స్కాన్ చేయాలనుకుంటోంది. కింది పరికరాలు కనుగొనబడ్డాయి:</translation>
 <translation id="5233638681132016545">కొత్త‌ టాబ్</translation>
 <translation id="5250483651202458397">స్క్రీన్‌షాట్. మూసివేయడానికి ట్యాప్ చేయండి.</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_ur.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_ur.xtb
index 5be37a0..8debe9f 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_ur.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_ur.xtb
@@ -608,6 +608,7 @@
 <translation id="5210365745912300556">ٹیب بند کریں</translation>
 <translation id="5213672942202814946">صوتی تلاش استعمال کریں</translation>
 <translation id="5222676887888702881">سائن آؤٹ</translation>
+<translation id="5227554086496586518">تلاش کے نتائج دیکھنے کیلئے تھپتھپائیں</translation>
 <translation id="5230560987958996918"><ph name="SITE" /> قریبی بلوٹوتھ آلات کے لیے اسکین کرنا چاہتی ہے، مندرجہ ذیل آلات ملے ہیں:</translation>
 <translation id="5233638681132016545">نیا ٹیب</translation>
 <translation id="5250483651202458397">اسکرین شاٹ۔ بند کرنے کے لئے تھپتھپائیں۔</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_zh-TW.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_zh-TW.xtb
index b069141..54bae76 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_zh-TW.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_zh-TW.xtb
@@ -608,6 +608,7 @@
 <translation id="5210365745912300556">關閉分頁</translation>
 <translation id="5213672942202814946">Use voice search</translation>
 <translation id="5222676887888702881">登出</translation>
+<translation id="5227554086496586518">輕觸即可查看搜尋結果</translation>
 <translation id="5230560987958996918"><ph name="SITE" /> 要求掃描附近的藍牙裝置。已找到下列裝置:</translation>
 <translation id="5233638681132016545">新增分頁</translation>
 <translation id="5250483651202458397">螢幕截圖。輕觸即可關閉。</translation>
diff --git a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc
index e8cde6f..8dd93e2 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc
@@ -1772,13 +1772,12 @@
                                     const std::string& package_name,
                                     const std::string& activity,
                                     const base::Optional<std::string>& name,
-                                    const base::Optional<std::string>& intent) {
+                                    const base::Optional<std::string>& intent,
+                                    int32_t session_id) {
   HandleTaskCreated(name, package_name, activity);
   for (auto& observer : observer_list_) {
-    observer.OnTaskCreated(task_id,
-                           package_name,
-                           activity,
-                           intent.value_or(std::string()));
+    observer.OnTaskCreated(task_id, package_name, activity,
+                           intent.value_or(std::string()), session_id);
   }
 }
 
diff --git a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.h b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.h
index 69a3245..8047e19 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.h
+++ b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.h
@@ -181,7 +181,8 @@
     virtual void OnTaskCreated(int32_t task_id,
                                const std::string& package_name,
                                const std::string& activity,
-                               const std::string& intent) {}
+                               const std::string& intent,
+                               int32_t session_id) {}
     // Notifies that task description has been updated.
     virtual void OnTaskDescriptionChanged(
         int32_t task_id,
@@ -432,7 +433,8 @@
                      const std::string& package_name,
                      const std::string& activity,
                      const base::Optional<std::string>& name,
-                     const base::Optional<std::string>& intent) override;
+                     const base::Optional<std::string>& intent,
+                     int32_t session_id) override;
   // This interface is deprecated and will soon be replaced by
   // OnTaskDescriptionChanged().
   void OnTaskDescriptionUpdated(
diff --git a/chrome/browser/ui/app_list/arc/arc_app_unittest.cc b/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
index 2bde877..937958c 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
@@ -3205,7 +3205,8 @@
       .Times(1);
   EXPECT_CALL(observer,
               OnTaskCreated(1 /* task_id */, app_runtime.package_name,
-                            app_runtime.activity, std::string() /* name */))
+                            app_runtime.activity, std::string() /* name */,
+                            0 /* session_id */))
       .Times(1);
 
   app_instance()->SendTaskCreated(1, app_runtime, std::string());
diff --git a/chrome/browser/ui/app_list/arc/mock_arc_app_list_prefs_observer.h b/chrome/browser/ui/app_list/arc/mock_arc_app_list_prefs_observer.h
index dcf220e..3efa0002 100644
--- a/chrome/browser/ui/app_list/arc/mock_arc_app_list_prefs_observer.h
+++ b/chrome/browser/ui/app_list/arc/mock_arc_app_list_prefs_observer.h
@@ -29,11 +29,12 @@
   MOCK_METHOD2(OnAppNameUpdated,
                void(const std::string& id, const std::string& name));
   MOCK_METHOD1(OnAppLastLaunchTimeUpdated, void(const std::string& app_id));
-  MOCK_METHOD4(OnTaskCreated,
+  MOCK_METHOD5(OnTaskCreated,
                void(int32_t task_id,
                     const std::string& package_name,
                     const std::string& activity,
-                    const std::string& intent));
+                    const std::string& intent,
+                    int32_t session_id));
   MOCK_METHOD3(OnTaskDescriptionChanged,
                void(int32_t task_id,
                     const std::string& label,
diff --git a/chrome/browser/ui/ash/launcher/app_service/app_service_app_window_arc_tracker.cc b/chrome/browser/ui/ash/launcher/app_service/app_service_app_window_arc_tracker.cc
index d0e3dd5..77ac67f 100644
--- a/chrome/browser/ui/ash/launcher/app_service/app_service_app_window_arc_tracker.cc
+++ b/chrome/browser/ui/ash/launcher/app_service/app_service_app_window_arc_tracker.cc
@@ -121,10 +121,11 @@
 }
 
 void AppServiceAppWindowArcTracker::OnTaskCreated(
-    int task_id,
+    int32_t task_id,
     const std::string& package_name,
     const std::string& activity_name,
-    const std::string& intent) {
+    const std::string& intent,
+    int32_t session_id) {
   DCHECK(task_id_to_arc_app_window_info_.find(task_id) ==
          task_id_to_arc_app_window_info_.end());
 
@@ -181,7 +182,7 @@
   }
 }
 
-void AppServiceAppWindowArcTracker::OnTaskDestroyed(int task_id) {
+void AppServiceAppWindowArcTracker::OnTaskDestroyed(int32_t task_id) {
   auto it = task_id_to_arc_app_window_info_.find(task_id);
   if (it == task_id_to_arc_app_window_info_.end())
     return;
diff --git a/chrome/browser/ui/ash/launcher/app_service/app_service_app_window_arc_tracker.h b/chrome/browser/ui/ash/launcher/app_service/app_service_app_window_arc_tracker.h
index 7aeb8f3f..f130163 100644
--- a/chrome/browser/ui/ash/launcher/app_service/app_service_app_window_arc_tracker.h
+++ b/chrome/browser/ui/ash/launcher/app_service/app_service_app_window_arc_tracker.h
@@ -66,15 +66,16 @@
   void OnAppStatesChanged(const std::string& app_id,
                           const ArcAppListPrefs::AppInfo& app_info) override;
   void OnAppRemoved(const std::string& app_id) override;
-  void OnTaskCreated(int task_id,
+  void OnTaskCreated(int32_t task_id,
                      const std::string& package_name,
                      const std::string& activity,
-                     const std::string& intent) override;
+                     const std::string& intent,
+                     int32_t session_id) override;
   void OnTaskDescriptionChanged(
       int32_t task_id,
       const std::string& label,
       const arc::mojom::RawIconPngData& icon) override;
-  void OnTaskDestroyed(int task_id) override;
+  void OnTaskDestroyed(int32_t task_id) override;
   void OnTaskSetActive(int32_t task_id) override;
 
   // Attaches controller and sets window's property when |window| is an ARC
diff --git a/chrome/browser/ui/ash/launcher/app_service/app_service_app_window_browsertest.cc b/chrome/browser/ui/ash/launcher/app_service/app_service_app_window_browsertest.cc
index beaaae69..ca7d96b 100644
--- a/chrome/browser/ui/ash/launcher/app_service/app_service_app_window_browsertest.cc
+++ b/chrome/browser/ui/ash/launcher/app_service/app_service_app_window_browsertest.cc
@@ -675,7 +675,7 @@
   // Simulate task creation so the app is marked as running/open.
   std::unique_ptr<ArcAppListPrefs::AppInfo> info = app_prefs()->GetApp(app_id1);
   app_host()->OnTaskCreated(1, info->package_name, info->activity, info->name,
-                            info->intent_uri);
+                            info->intent_uri, /*session_id=*/0);
   EXPECT_TRUE(controller_->GetItem(ash::ShelfID(app_id1)));
 
   // Check the window state in instance for app1
@@ -698,7 +698,7 @@
   const std::string app_id2 = GetTestApp2Id(kTestAppPackage);
   info = app_prefs()->GetApp(app_id2);
   app_host()->OnTaskCreated(2, info->package_name, info->activity, info->name,
-                            info->intent_uri);
+                            info->intent_uri, /*session_id=*/0);
   views::Widget* arc_window2 = CreateExoWindow("org.chromium.arc.2");
   EXPECT_TRUE(controller_->GetItem(ash::ShelfID(app_id2)));
 
@@ -766,10 +766,12 @@
   std::unique_ptr<ArcAppListPrefs::AppInfo> info = app_prefs()->GetApp(app_id);
   app_host()->OnTaskCreated(1, info->package_name, info->activity, info->name,
                             CreateIntentUriWithShelfGroupAndLogicalWindow(
-                                "shelf_group_1", "logical_window_1"));
+                                "shelf_group_1", "logical_window_1"),
+                            /*session_id=*/0);
   app_host()->OnTaskCreated(2, info->package_name, info->activity, info->name,
                             CreateIntentUriWithShelfGroupAndLogicalWindow(
-                                "shelf_group_1", "logical_window_1"));
+                                "shelf_group_1", "logical_window_1"),
+                            /*session_id=*/0);
 
   // Both windows should show up in the instance registry.
   auto windows = app_service_proxy_->InstanceRegistry().GetWindows(app_id);
diff --git a/chrome/browser/ui/ash/launcher/arc_app_launcher_browsertest.cc b/chrome/browser/ui/ash/launcher/arc_app_launcher_browsertest.cc
index 27b7c9a..3a56332 100644
--- a/chrome/browser/ui/ash/launcher/arc_app_launcher_browsertest.cc
+++ b/chrome/browser/ui/ash/launcher/arc_app_launcher_browsertest.cc
@@ -562,7 +562,7 @@
   // Simulate task creation so the app is marked as running/open.
   std::unique_ptr<ArcAppListPrefs::AppInfo> info = app_prefs()->GetApp(app_id);
   app_host()->OnTaskCreated(0, info->package_name, info->activity, info->name,
-                            info->intent_uri);
+                            info->intent_uri, 0 /* session_id */);
   EXPECT_TRUE(delegate->IsAppOpen(app_id));
 }
 
@@ -589,27 +589,31 @@
 
   // 1 task for group 1
   app_host()->OnTaskCreated(1, info->package_name, info->activity, info->name,
-                            CreateIntentUriWithShelfGroup(kTestShelfGroup));
+                            CreateIntentUriWithShelfGroup(kTestShelfGroup),
+                            0 /* session_id */);
 
   ash::ShelfItemDelegate* delegate1 = GetShelfItemDelegate(shelf_id1);
   ASSERT_TRUE(delegate1);
 
   // 2 tasks for group 2
   app_host()->OnTaskCreated(2, info->package_name, info->activity, info->name,
-                            CreateIntentUriWithShelfGroup(kTestShelfGroup2));
+                            CreateIntentUriWithShelfGroup(kTestShelfGroup2),
+                            0 /* session_id */);
 
   ash::ShelfItemDelegate* delegate2 = GetShelfItemDelegate(shelf_id2);
   ASSERT_TRUE(delegate2);
   ASSERT_NE(delegate1, delegate2);
 
   app_host()->OnTaskCreated(3, info->package_name, info->activity, info->name,
-                            CreateIntentUriWithShelfGroup(kTestShelfGroup2));
+                            CreateIntentUriWithShelfGroup(kTestShelfGroup2),
+                            0 /* session_id */);
 
   ASSERT_EQ(delegate2, GetShelfItemDelegate(shelf_id2));
 
   // 2 tasks for group 3 which does not have shortcut.
   app_host()->OnTaskCreated(4, info->package_name, info->activity, info->name,
-                            CreateIntentUriWithShelfGroup(kTestShelfGroup3));
+                            CreateIntentUriWithShelfGroup(kTestShelfGroup3),
+                            0 /* session_id */);
 
   ash::ShelfItemDelegate* delegate3 = GetShelfItemDelegate(shelf_id3);
   ASSERT_TRUE(delegate3);
@@ -617,7 +621,8 @@
   ASSERT_NE(delegate2, delegate3);
 
   app_host()->OnTaskCreated(5, info->package_name, info->activity, info->name,
-                            CreateIntentUriWithShelfGroup(kTestShelfGroup3));
+                            CreateIntentUriWithShelfGroup(kTestShelfGroup3),
+                            0 /* session_id */);
 
   ASSERT_EQ(delegate3, GetShelfItemDelegate(shelf_id3));
 
@@ -716,7 +721,8 @@
   // First logical window
   app_host()->OnTaskCreated(1, info->package_name, info->activity, info->name,
                             CreateIntentUriWithShelfGroupAndLogicalWindow(
-                                kTestShelfGroups[1], kTestLogicalWindows[1]));
+                                kTestShelfGroups[1], kTestLogicalWindows[1]),
+                            0 /* session_id */);
   arc_instance()->set_icon_response_type(
       arc::FakeAppInstance::IconResponseType::ICON_RESPONSE_SEND_EMPTY);
   app_host()->OnTaskDescriptionChanged(
@@ -732,7 +738,8 @@
 
   app_host()->OnTaskCreated(2, info->package_name, info->activity, info->name,
                             CreateIntentUriWithShelfGroupAndLogicalWindow(
-                                kTestShelfGroups[2], kTestLogicalWindows[2]));
+                                kTestShelfGroups[2], kTestLogicalWindows[2]),
+                            0 /* session_id */);
   app_host()->OnTaskDescriptionChanged(
       2, kTestWindowTitles[2],
       arc_instance()->GenerateIconResponse(kGeneratedIconSize,
@@ -748,7 +755,8 @@
     app_host()->OnTaskCreated(
         task_id, info->package_name, info->activity, info->name,
         CreateIntentUriWithShelfGroupAndLogicalWindow(
-            kTestShelfGroups[task_id], kTestLogicalWindows[task_id]));
+            kTestShelfGroups[task_id], kTestLogicalWindows[task_id]),
+        0 /* session_id */);
     app_host()->OnTaskDescriptionChanged(
         task_id, kTestWindowTitles[task_id],
         arc_instance()->GenerateIconResponse(kGeneratedIconSize,
@@ -764,7 +772,8 @@
   // tasks 1 and 2, but different group.
   app_host()->OnTaskCreated(6, info->package_name, info->activity, info->name,
                             CreateIntentUriWithShelfGroupAndLogicalWindow(
-                                kTestShelfGroups[6], kTestLogicalWindows[6]));
+                                kTestShelfGroups[6], kTestLogicalWindows[6]),
+                            0 /* session_id */);
   app_host()->OnTaskDescriptionChanged(
       6, kTestWindowTitles[6],
       arc_instance()->GenerateIconResponse(kGeneratedIconSize,
@@ -779,7 +788,8 @@
 
   app_host()->OnTaskCreated(7, info->package_name, info->activity, info->name,
                             CreateIntentUriWithShelfGroupAndLogicalWindow(
-                                kTestShelfGroups[7], kTestLogicalWindows[7]));
+                                kTestShelfGroups[7], kTestLogicalWindows[7]),
+                            0 /* session_id */);
   app_host()->OnTaskDescriptionChanged(
       7, kTestWindowTitles[7],
       arc_instance()->GenerateIconResponse(kGeneratedIconSize,
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
index 54a60b9..6597af5 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
@@ -972,7 +972,7 @@
                            int32_t task_id) {
     ArcAppListPrefs* const prefs = arc_test_.arc_app_list_prefs();
     prefs->OnTaskCreated(task_id, appinfo.package_name, appinfo.activity,
-                         appinfo.name, std::string());
+                         appinfo.name, std::string(), /*session_id=*/0);
   }
 
   // Creates a window with TYPE_APP shelf item type and the given app_id.
diff --git a/chrome/browser/ui/ash/multi_user/multi_profile_support_unittest.cc b/chrome/browser/ui/ash/multi_user/multi_profile_support_unittest.cc
index bf9a96f5..7beefb2 100644
--- a/chrome/browser/ui/ash/multi_user/multi_profile_support_unittest.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_profile_support_unittest.cc
@@ -293,8 +293,8 @@
 };
 
 void MultiProfileSupportTest::SetUp() {
-  chromeos::DeviceSettingsService::Initialize();
-  chromeos::CrosSettings::Initialize(
+  ash::DeviceSettingsService::Initialize();
+  ash::CrosSettings::Initialize(
       TestingBrowserProcess::GetGlobal()->local_state());
   ChromeAshTestBase::SetUp(std::make_unique<TestShellDelegateChromeOS>());
   ash_test_helper()
@@ -367,8 +367,8 @@
   ChromeAshTestBase::TearDown();
   wallpaper_controller_client_.reset();
   profile_manager_.reset();
-  chromeos::CrosSettings::Shutdown();
-  chromeos::DeviceSettingsService::Shutdown();
+  ash::CrosSettings::Shutdown();
+  ash::DeviceSettingsService::Shutdown();
 }
 
 std::string MultiProfileSupportTest::GetStatusImpl(bool follow_transients) {
diff --git a/chrome/browser/ui/ash/projector/projector_client_impl.cc b/chrome/browser/ui/ash/projector/projector_client_impl.cc
index 98f00102..c891b0c8 100644
--- a/chrome/browser/ui/ash/projector/projector_client_impl.cc
+++ b/chrome/browser/ui/ash/projector/projector_client_impl.cc
@@ -7,6 +7,7 @@
 #include "ash/public/cpp/projector/projector_controller.h"
 #include "base/optional.h"
 #include "chrome/browser/accessibility/soda_installer.h"
+#include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/speech/on_device_speech_recognizer.h"
 
 ProjectorClientImpl::ProjectorClientImpl() {
@@ -28,7 +29,7 @@
   DCHECK(OnDeviceSpeechRecognizer::IsOnDeviceSpeechRecognizerAvailable());
   DCHECK_EQ(speech_recognizer_.get(), nullptr);
   speech_recognizer_ = std::make_unique<OnDeviceSpeechRecognizer>(
-      weak_ptr_factory_.GetWeakPtr());
+      weak_ptr_factory_.GetWeakPtr(), ProfileManager::GetPrimaryUserProfile());
   speech_recognizer_->Start();
 }
 
diff --git a/chrome/browser/ui/ash/session_controller_client_impl.cc b/chrome/browser/ui/ash/session_controller_client_impl.cc
index ab533b8..e431b2a 100644
--- a/chrome/browser/ui/ash/session_controller_client_impl.cc
+++ b/chrome/browser/ui/ash/session_controller_client_impl.cc
@@ -157,9 +157,8 @@
       prefs::kSessionLengthLimit,
       base::BindRepeating(&SessionControllerClientImpl::SendSessionLengthLimit,
                           base::Unretained(this)));
-  chromeos::DeviceSettingsService::Get()
-      ->device_off_hours_controller()
-      ->AddObserver(this);
+  ash::DeviceSettingsService::Get()->device_off_hours_controller()->AddObserver(
+      this);
   DCHECK(!g_session_controller_client_instance);
   g_session_controller_client_instance = this;
 }
@@ -180,7 +179,7 @@
   SessionManager::Get()->RemoveObserver(this);
   UserManager::Get()->RemoveObserver(this);
   UserManager::Get()->RemoveSessionStateObserver(this);
-  chromeos::DeviceSettingsService::Get()
+  ash::DeviceSettingsService::Get()
       ->device_off_hours_controller()
       ->RemoveObserver(this);
 }
@@ -602,7 +601,7 @@
   }
 
   policy::off_hours::DeviceOffHoursController* off_hours_controller =
-      chromeos::DeviceSettingsService::Get()->device_off_hours_controller();
+      ash::DeviceSettingsService::Get()->device_off_hours_controller();
   base::Time off_hours_session_end_time;
   // Use "OffHours" end time only if the session will be actually terminated.
   if (off_hours_controller->IsCurrentSessionAllowedOnlyForOffHours())
diff --git a/chrome/browser/ui/ash/system_tray_client_browsertest.cc b/chrome/browser/ui/ash/system_tray_client_browsertest.cc
index cb20eea..dbdd4d3 100644
--- a/chrome/browser/ui/ash/system_tray_client_browsertest.cc
+++ b/chrome/browser/ui/ash/system_tray_client_browsertest.cc
@@ -180,7 +180,7 @@
   }
 
  protected:
-  chromeos::ScopedTestingCrosSettings scoped_testing_cros_settings_;
+  ash::ScopedTestingCrosSettings scoped_testing_cros_settings_;
   chromeos::LocalStateMixin local_state_{&mixin_host_, this};
 };
 
diff --git a/chrome/browser/ui/ash/wallpaper_controller_client.cc b/chrome/browser/ui/ash/wallpaper_controller_client.cc
index 65405df60..69335d50 100644
--- a/chrome/browser/ui/ash/wallpaper_controller_client.cc
+++ b/chrome/browser/ui/ash/wallpaper_controller_client.cc
@@ -121,7 +121,7 @@
 WallpaperControllerClient::WallpaperControllerClient() {
   local_state_ = g_browser_process->local_state();
   show_user_names_on_signin_subscription_ =
-      chromeos::CrosSettings::Get()->AddSettingsObserver(
+      ash::CrosSettings::Get()->AddSettingsObserver(
           chromeos::kAccountsPrefShowUserNamesOnSignIn,
           base::BindRepeating(
               &WallpaperControllerClient::ShowWallpaperOnLoginScreen,
@@ -522,7 +522,7 @@
 
 bool WallpaperControllerClient::ShouldShowUserNamesOnLogin() const {
   bool show_user_names = true;
-  chromeos::CrosSettings::Get()->GetBoolean(
+  ash::CrosSettings::Get()->GetBoolean(
       chromeos::kAccountsPrefShowUserNamesOnSignIn, &show_user_names);
   return show_user_names;
 }
diff --git a/chrome/browser/ui/ash/wallpaper_controller_client_unittest.cc b/chrome/browser/ui/ash/wallpaper_controller_client_unittest.cc
index f3c212e..86239f1 100644
--- a/chrome/browser/ui/ash/wallpaper_controller_client_unittest.cc
+++ b/chrome/browser/ui/ash/wallpaper_controller_client_unittest.cc
@@ -21,7 +21,7 @@
 
  private:
   ScopedTestingLocalState local_state_;
-  chromeos::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
+  ash::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
   base::test::TaskEnvironment task_environment_;
 
   DISALLOW_COPY_AND_ASSIGN(WallpaperControllerClientTest);
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc
index 372b3ca38..c307f04 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.cc
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -649,11 +649,13 @@
 
 void ChromeAutofillClient::ShowOfferNotificationIfApplicable(
     const std::vector<GURL>& domains_to_display_bubble,
+    const GURL& offer_details_url,
     const CreditCard* card) {
 #if defined(OS_ANDROID)
   std::unique_ptr<OfferNotificationInfoBarControllerImpl> controller =
       std::make_unique<OfferNotificationInfoBarControllerImpl>(web_contents());
-  controller->ShowIfNecessary(domains_to_display_bubble, card);
+  controller->ShowIfNecessary(domains_to_display_bubble, offer_details_url,
+                              card);
 #else
   OfferNotificationBubbleControllerImpl::CreateForWebContents(web_contents());
   OfferNotificationBubbleControllerImpl* controller =
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.h b/chrome/browser/ui/autofill/chrome_autofill_client.h
index 9980d682..2c9adf3 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.h
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.h
@@ -148,6 +148,7 @@
   void HideAutofillPopup(PopupHidingReason reason) override;
   void ShowOfferNotificationIfApplicable(
       const std::vector<GURL>& domains_to_display_bubble,
+      const GURL& offer_details_url,
       const CreditCard* card) override;
   bool IsAutocompleteEnabled() override;
   void PropagateAutofillPredictions(
diff --git a/chrome/browser/ui/autofill/payments/offer_notification_infobar_controller_impl.cc b/chrome/browser/ui/autofill/payments/offer_notification_infobar_controller_impl.cc
index 16842bc..679a4bf 100644
--- a/chrome/browser/ui/autofill/payments/offer_notification_infobar_controller_impl.cc
+++ b/chrome/browser/ui/autofill/payments/offer_notification_infobar_controller_impl.cc
@@ -19,6 +19,7 @@
 
 void OfferNotificationInfoBarControllerImpl::ShowIfNecessary(
     const std::vector<GURL>& origins_to_display_infobar,
+    const GURL& offer_details_url,
     const CreditCard* card) {
   OfferNotificationHelper::CreateForWebContents(web_contents_);
   OfferNotificationHelper* offer_notification_helper =
@@ -29,7 +30,7 @@
     InfoBarService::FromWebContents(web_contents_)
         ->AddInfoBar(std::make_unique<AutofillOfferNotificationInfoBar>(
             std::make_unique<AutofillOfferNotificationInfoBarDelegateMobile>(
-                *card)));
+                offer_details_url, *card)));
     offer_notification_helper->OnDisplayOfferNotification(
         origins_to_display_infobar);
   }
diff --git a/chrome/browser/ui/autofill/payments/offer_notification_infobar_controller_impl.h b/chrome/browser/ui/autofill/payments/offer_notification_infobar_controller_impl.h
index 8a52bb37..8d835e5 100644
--- a/chrome/browser/ui/autofill/payments/offer_notification_infobar_controller_impl.h
+++ b/chrome/browser/ui/autofill/payments/offer_notification_infobar_controller_impl.h
@@ -28,6 +28,7 @@
   // Show the infobar unless it was already shown in the same tab with the same
   // origin.
   void ShowIfNecessary(const std::vector<GURL>& origins_to_display_infobar,
+                       const GURL& offer_details_url,
                        const CreditCard* card);
 
  private:
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc
index eece7b2..ee9475b 100644
--- a/chrome/browser/ui/browser_commands.cc
+++ b/chrome/browser/ui/browser_commands.cc
@@ -1087,6 +1087,10 @@
   model->AddEntry(url, base::UTF16ToUTF8(title),
                   reading_list::EntrySource::ADDED_VIA_CURRENT_APP);
   MaybeShowBookmarkBarForReadLater(browser);
+  if (browser->bookmark_bar_state() == BookmarkBar::SHOW) {
+    browser->window()->GetFeaturePromoController()->MaybeShowPromo(
+        feature_engagement::kIPHReadingListDiscoveryFeature);
+  }
   base::UmaHistogramEnumeration(
       "ReadingList.BookmarkBarState.OnEveryAddToReadingList",
       browser->bookmark_bar_state());
@@ -1133,8 +1137,6 @@
         browser->bookmark_bar_state());
     if (browser->bookmark_bar_state() == BookmarkBar::HIDDEN)
       ToggleBookmarkBar(browser);
-    browser->window()->GetFeaturePromoController()->MaybeShowPromo(
-        feature_engagement::kIPHReadingListDiscoveryFeature);
   }
 #endif  // defined(OS_ANDROID)
 }
diff --git a/chrome/browser/ui/sync/profile_signin_confirmation_helper_unittest.cc b/chrome/browser/ui/sync/profile_signin_confirmation_helper_unittest.cc
index 1faad1a..94174af 100644
--- a/chrome/browser/ui/sync/profile_signin_confirmation_helper_unittest.cc
+++ b/chrome/browser/ui/sync/profile_signin_confirmation_helper_unittest.cc
@@ -181,7 +181,7 @@
   BookmarkModel* model_;
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  chromeos::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
+  ash::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
   chromeos::ScopedTestUserManager test_user_manager_;
 #endif
 };
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_model.cc b/chrome/browser/ui/toolbar/toolbar_actions_model.cc
index c53e4af2..961352a 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_model.cc
+++ b/chrome/browser/ui/toolbar/toolbar_actions_model.cc
@@ -521,14 +521,6 @@
     Populate();
 
   if (base::FeatureList::IsEnabled(features::kExtensionsToolbarMenu)) {
-    if (!extension_prefs_->IsPinnedExtensionsMigrationComplete() &&
-        !profile_->IsOffTheRecord()) {
-      // Migrate extensions visible in the toolbar to pinned extensions.
-      auto new_pinned_action_ids = std::vector<ActionId>(
-          action_ids_.begin(), action_ids_.begin() + visible_icon_count());
-      extension_prefs_->SetPinnedExtensions(new_pinned_action_ids);
-      extension_prefs_->MarkPinnedExtensionsMigrationComplete();
-    }
     // Set |pinned_action_ids_| directly to avoid notifying observers that they
     // have changed even though they haven't.
     pinned_action_ids_ = GetFilteredPinnedActionIds();
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_model_unittest.cc b/chrome/browser/ui/toolbar/toolbar_actions_model_unittest.cc
index a6727d21..03d5058b 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_model_unittest.cc
+++ b/chrome/browser/ui/toolbar/toolbar_actions_model_unittest.cc
@@ -1478,52 +1478,6 @@
                            browser_action_b()->id()));
 }
 
-TEST_F(ToolbarActionsModelUnitTest,
-       VisibleExtensionsMigrateToPinnedExtensions) {
-  InitializeEmptyExtensionService();
-
-  // Add the three browser action extensions.
-  ASSERT_TRUE(AddBrowserActionExtensions());
-
-  extensions::ExtensionPrefs* const extension_prefs =
-      extensions::ExtensionPrefs::Get(profile());
-  EXPECT_FALSE(extension_prefs->IsPinnedExtensionsMigrationComplete());
-
-  // Initialization of the toolbar model triggers migration of the visible
-  // extensions to pinned extensions.
-  InitToolbarModelAndObserver();
-
-  // Verify that the extensions that were visible are now the pinned extensions.
-  EXPECT_TRUE(extension_prefs->IsPinnedExtensionsMigrationComplete());
-  EXPECT_THAT(
-      extension_prefs->GetPinnedExtensions(),
-      testing::ElementsAre(browser_action_a()->id(), browser_action_b()->id(),
-                           browser_action_c()->id()));
-}
-
-TEST_F(ToolbarActionsModelUnitTest,
-       VisibleExtensionsOfConstrainedToolbarMigrateToPinnedExtensions) {
-  InitializeEmptyExtensionService();
-
-  profile()->GetPrefs()->SetInteger(extensions::pref_names::kToolbarSize, 2);
-  // Add the three browser action extensions.
-  ASSERT_TRUE(AddBrowserActionExtensions());
-
-  extensions::ExtensionPrefs* const extension_prefs =
-      extensions::ExtensionPrefs::Get(profile());
-  EXPECT_FALSE(extension_prefs->IsPinnedExtensionsMigrationComplete());
-
-  // Initialization of the toolbar model triggers migration of the visible
-  // extensions to pinned extensions.
-  InitToolbarModelAndObserver();
-
-  // Verify that the extensions that were visible are now the pinned extensions.
-  EXPECT_TRUE(extension_prefs->IsPinnedExtensionsMigrationComplete());
-  EXPECT_THAT(
-      extension_prefs->GetPinnedExtensions(),
-      testing::ElementsAre(browser_action_a()->id(), browser_action_b()->id()));
-}
-
 TEST_F(ToolbarActionsModelUnitTest, PinStateErasedOnUninstallation) {
   Init();
 
diff --git a/chrome/browser/ui/views/accessibility/caption_bubble.cc b/chrome/browser/ui/views/accessibility/caption_bubble.cc
index acb8429f..2812584 100644
--- a/chrome/browser/ui/views/accessibility/caption_bubble.cc
+++ b/chrome/browser/ui/views/accessibility/caption_bubble.cc
@@ -680,8 +680,7 @@
   DCHECK(GetWidget());
   // If there is no model set, do not show the bubble.
   if (!model_) {
-    if (GetWidget()->IsVisible())
-      GetWidget()->Hide();
+    Hide();
     return;
   }
 
@@ -690,8 +689,7 @@
   // the speech service or user interacting with the bubble through focus,
   // pressing buttons, or dragging.
   if (!can_layout_ || model_->IsClosed() || !HasActivity()) {
-    if (GetWidget()->IsVisible())
-      GetWidget()->Hide();
+    Hide();
     return;
   }
 
@@ -707,8 +705,7 @@
   }
 
   // No text and no error. Hide it.
-  if (GetWidget()->IsVisible())
-    GetWidget()->Hide();
+  Hide();
 }
 
 void CaptionBubble::OnWidgetVisibilityChanged(views::Widget* widget,
@@ -798,10 +795,15 @@
   SizeToContents();
 }
 
-void CaptionBubble::OnInactivityTimeout() {
-  LogSessionEvent(SessionEvent::kStreamEnded);
-  if (GetWidget()->IsVisible())
+void CaptionBubble::Hide() {
+  if (GetWidget()->IsVisible()) {
     GetWidget()->Hide();
+    LogSessionEvent(SessionEvent::kStreamEnded);
+  }
+}
+
+void CaptionBubble::OnInactivityTimeout() {
+  Hide();
 
   // Clear the partial and final text in the caption bubble model and the label.
   // Does not affect the speech service. The speech service will emit a final
diff --git a/chrome/browser/ui/views/accessibility/caption_bubble.h b/chrome/browser/ui/views/accessibility/caption_bubble.h
index 7d06ce8..3e5eef1 100644
--- a/chrome/browser/ui/views/accessibility/caption_bubble.h
+++ b/chrome/browser/ui/views/accessibility/caption_bubble.h
@@ -135,6 +135,7 @@
   void UpdateTextSize();
   void UpdateContentSize();
   void Redraw();
+  void Hide();
   std::unique_ptr<views::ImageButton> BuildImageButton(
       views::Button::PressedCallback callback,
       const gfx::VectorIcon& icon,
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_view_browsertest.cc b/chrome/browser/ui/views/extensions/extensions_menu_view_browsertest.cc
index 3900963..da8bd702 100644
--- a/chrome/browser/ui/views/extensions/extensions_menu_view_browsertest.cc
+++ b/chrome/browser/ui/views/extensions/extensions_menu_view_browsertest.cc
@@ -757,136 +757,6 @@
   // https://crbug.com/1070305 is fixed.
 }
 
-namespace {
-constexpr char kExtensionAId[] = "ldnnhddmnhbkjipkidpdiheffobcpfmf";
-constexpr char kExtensionBId[] = "mockepjebcnmhmhcahfddgfcdgkdifnc";
-constexpr char kExtensionCId[] = "dpfmafkdlbmopmcepgpjkpldjbghdibm";
-
-bool TestShouldEnableToolbarMenuExperiment() {
-  std::string test_name =
-      testing::UnitTest::GetInstance()->current_test_info()->name();
-  // This PRE_PRE_ step sets up pre-migration extension prefs. The experiment
-  // triggers migration so it needs to be off during pre-condition setup.
-  return test_name.find(
-             "PRE_PRE_PostExtensionMigrationChangesPersistAfterRestart") ==
-         std::string::npos;
-}
-
-}  // namespace
-
-class ExtensionsToolbarMigrationBrowserTest
-    : public ExtensionsToolbarBrowserTest {
- protected:
-  ExtensionsToolbarMigrationBrowserTest()
-      : ExtensionsToolbarBrowserTest(TestShouldEnableToolbarMenuExperiment()) {}
-
-  void ShowUi(const std::string& name) override {
-    // Intentionally empty, this tests UI in the toolbar.
-  }
-
- private:
-  extensions::ScopedInstallVerifierBypassForTest ignore_install_verification_;
-};
-
-// Add and verify extensions with extensions toolbar menu feature turned off.
-// TODO(corising): Remove this series of tests and the |enable_flag| parameter
-// from initialization of ExtensionsToolbarBrowserTest once the extensions
-// toolbar menu experiment has been launched for a couple milestones.
-IN_PROC_BROWSER_TEST_F(
-    ExtensionsToolbarMigrationBrowserTest,
-    PRE_PRE_PostExtensionMigrationChangesPersistAfterRestart) {
-  // Add three extensions.
-  LoadTestExtension("extensions/good.crx");
-  LoadTestExtension("extensions/trivial_extension/extension.crx");
-  LoadTestExtension("extensions/page_action.crx");
-
-  // Verify all extensions have been added.
-  EXPECT_EQ(3u, extensions().size());
-  EXPECT_EQ(extensions()[0]->id(), kExtensionAId);
-  EXPECT_EQ(extensions()[1]->id(), kExtensionBId);
-  EXPECT_EQ(extensions()[2]->id(), kExtensionCId);
-
-  BrowserActionsContainer* browser_actions =
-      BrowserView::GetBrowserViewForBrowser(browser())
-          ->toolbar()
-          ->browser_actions();
-
-  // Hide the last extension and verify that only the first two of the three are
-  // visible.
-  ToolbarActionsModel::Get(profile())->SetActionVisibility(kExtensionCId,
-                                                           false);
-  EXPECT_TRUE(browser_actions->GetViewForId(kExtensionAId)->GetVisible());
-  EXPECT_TRUE(browser_actions->GetViewForId(kExtensionBId)->GetVisible());
-  EXPECT_FALSE(browser_actions->GetViewForId(kExtensionCId)->GetVisible());
-}
-
-// Test visible extensions migrate to pinned extensions after Chrome restart and
-// that any further changes are reflected in the extension prefs.
-IN_PROC_BROWSER_TEST_F(ExtensionsToolbarMigrationBrowserTest,
-                       PRE_PostExtensionMigrationChangesPersistAfterRestart) {
-  // Wait for any animations to finish.
-  views::test::WaitForAnimatingLayoutManager(GetExtensionsToolbarContainer());
-
-  auto* toolbar_model = ToolbarActionsModel::Get(profile());
-
-  // Verify that the extensions that were visible are now the pinned extensions
-  // in the extension prefs.
-  extensions::ExtensionPrefs* const extension_prefs =
-      extensions::ExtensionPrefs::Get(profile());
-  EXPECT_THAT(extension_prefs->GetPinnedExtensions(),
-              testing::ElementsAre(kExtensionAId, kExtensionBId));
-  // Verify that the extensions that were visible are now the pinned extensions
-  // in the toolbar model.
-  EXPECT_TRUE(toolbar_model->IsActionPinned(kExtensionAId));
-  EXPECT_TRUE(toolbar_model->IsActionPinned(kExtensionBId));
-  EXPECT_FALSE(toolbar_model->IsActionPinned(kExtensionCId));
-  // Verify that the extensions that were visible are now visible in the toolbar
-  // container.
-  ExtensionsToolbarContainer* extensions_container =
-      GetExtensionsToolbarContainer();
-  EXPECT_TRUE(extensions_container->GetViewForId(kExtensionAId)->GetVisible());
-  EXPECT_TRUE(extensions_container->GetViewForId(kExtensionBId)->GetVisible());
-  EXPECT_FALSE(extensions_container->GetViewForId(kExtensionCId)->GetVisible());
-
-  // Verify that pinning/unpinning action is reflected in preferences.
-  toolbar_model->SetActionVisibility(kExtensionAId, false);
-  EXPECT_THAT(extension_prefs->GetPinnedExtensions(),
-              testing::ElementsAre(kExtensionBId));
-  toolbar_model->SetActionVisibility(kExtensionCId, true);
-  EXPECT_THAT(extension_prefs->GetPinnedExtensions(),
-              testing::ElementsAre(kExtensionBId, kExtensionCId));
-
-  // Verify that moving an action is reflected in preferences.
-  toolbar_model->MovePinnedAction(kExtensionCId, 0);
-  EXPECT_THAT(extension_prefs->GetPinnedExtensions(),
-              testing::ElementsAre(kExtensionCId, kExtensionBId));
-}
-
-// Test that any post-migration extension changes are persisent after Chrome
-// restarts.
-IN_PROC_BROWSER_TEST_F(ExtensionsToolbarMigrationBrowserTest,
-                       PostExtensionMigrationChangesPersistAfterRestart) {
-  // Wait for any animations to finish.
-  views::test::WaitForAnimatingLayoutManager(GetExtensionsToolbarContainer());
-
-  extensions::ExtensionPrefs* const extension_prefs =
-      extensions::ExtensionPrefs::Get(profile());
-  EXPECT_THAT(extension_prefs->GetPinnedExtensions(),
-              testing::ElementsAre(kExtensionCId, kExtensionBId));
-  // Verify that these extensions are also pinned extensions in the toolbar
-  // model.
-  auto* toolbar_model = ToolbarActionsModel::Get(profile());
-  EXPECT_FALSE(toolbar_model->IsActionPinned(kExtensionAId));
-  EXPECT_TRUE(toolbar_model->IsActionPinned(kExtensionBId));
-  EXPECT_TRUE(toolbar_model->IsActionPinned(kExtensionCId));
-  // Verify that these extensions are visible in the toolbar container.
-  ExtensionsToolbarContainer* extensions_container =
-      GetExtensionsToolbarContainer();
-  EXPECT_FALSE(extensions_container->GetViewForId(kExtensionAId)->GetVisible());
-  EXPECT_TRUE(extensions_container->GetViewForId(kExtensionBId)->GetVisible());
-  EXPECT_TRUE(extensions_container->GetViewForId(kExtensionCId)->GetVisible());
-}
-
 class ActivateWithReloadExtensionsMenuBrowserTest
     : public ExtensionsMenuViewBrowserTest,
       public ::testing::WithParamInterface<bool> {};
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_browsertest.cc b/chrome/browser/ui/views/extensions/extensions_toolbar_browsertest.cc
index e378ea09..5817f18c 100644
--- a/chrome/browser/ui/views/extensions/extensions_toolbar_browsertest.cc
+++ b/chrome/browser/ui/views/extensions/extensions_toolbar_browsertest.cc
@@ -9,7 +9,6 @@
 #include "chrome/browser/extensions/chrome_test_extension_loader.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/extensions/extensions_toolbar_container.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
@@ -18,14 +17,7 @@
 #include "ui/views/layout/animating_layout_manager_test_util.h"
 #include "ui/views/view_utils.h"
 
-ExtensionsToolbarBrowserTest::ExtensionsToolbarBrowserTest(bool enable_flag) {
-  if (enable_flag) {
-    scoped_feature_list_.InitAndEnableFeature(features::kExtensionsToolbarMenu);
-  } else {
-    scoped_feature_list_.InitAndDisableFeature(
-        features::kExtensionsToolbarMenu);
-  }
-}
+ExtensionsToolbarBrowserTest::ExtensionsToolbarBrowserTest() = default;
 
 ExtensionsToolbarBrowserTest::~ExtensionsToolbarBrowserTest() = default;
 
@@ -44,12 +36,10 @@
       loader.LoadExtension(test_data_dir.AppendASCII(path));
   AppendExtension(extension);
 
-  if (base::FeatureList::IsEnabled(features::kExtensionsToolbarMenu)) {
-    // Loading an extension can result in the container changing visibility.
-    // Allow it to finish laying out appropriately.
-    auto* container = GetExtensionsToolbarContainer();
-    container->GetWidget()->LayoutRootViewIfNecessary();
-  }
+  // Loading an extension can result in the container changing visibility.
+  // Allow it to finish laying out appropriately.
+  auto* container = GetExtensionsToolbarContainer();
+  container->GetWidget()->LayoutRootViewIfNecessary();
 
   return extension;
 }
@@ -66,8 +56,7 @@
 void ExtensionsToolbarBrowserTest::SetUpOnMainThread() {
   DialogBrowserTest::SetUpOnMainThread();
   host_resolver()->AddRule("*", "127.0.0.1");
-  if (base::FeatureList::IsEnabled(features::kExtensionsToolbarMenu))
-    views::test::ReduceAnimationDuration(GetExtensionsToolbarContainer());
+  views::test::ReduceAnimationDuration(GetExtensionsToolbarContainer());
 }
 
 ExtensionsToolbarContainer*
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_browsertest.h b/chrome/browser/ui/views/extensions/extensions_toolbar_browsertest.h
index 54b8e0b..89edd9a0 100644
--- a/chrome/browser/ui/views/extensions/extensions_toolbar_browsertest.h
+++ b/chrome/browser/ui/views/extensions/extensions_toolbar_browsertest.h
@@ -8,7 +8,6 @@
 #include <string>
 #include <vector>
 
-#include "base/test/scoped_feature_list.h"
 #include "chrome/browser/ui/test/test_browser_dialog.h"
 #include "extensions/common/extension.h"
 
@@ -34,10 +33,7 @@
       delete;
 
  protected:
-  // Note the |enable_flag| parameter exists to test migration of extensions
-  // triggered by the experiment. Pre-migration setup must be done with the flag
-  // disabled.
-  explicit ExtensionsToolbarBrowserTest(bool enable_flag = true);
+  ExtensionsToolbarBrowserTest();
   ~ExtensionsToolbarBrowserTest() override;
 
   void SetUpOnMainThread() override;
@@ -75,7 +71,6 @@
   std::vector<ToolbarActionView*> GetVisibleToolbarActionViews() const;
 
  private:
-  base::test::ScopedFeatureList scoped_feature_list_;
   Browser* incognito_browser_ = nullptr;
   std::vector<scoped_refptr<const extensions::Extension>> extensions_;
 };
diff --git a/chrome/browser/ui/views/intent_picker_bubble_view_browsertest.cc b/chrome/browser/ui/views/intent_picker_bubble_view_browsertest.cc
index 9566a2b..480ab0fc 100644
--- a/chrome/browser/ui/views/intent_picker_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/intent_picker_bubble_view_browsertest.cc
@@ -4,6 +4,7 @@
 
 #include "base/bind.h"
 #include "base/test/scoped_feature_list.h"
+#include "build/build_config.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_list.h"
@@ -136,9 +137,17 @@
 // Tests that clicking a link from an app browser to either within or outside
 // the scope of an installed app does not show the intent picker, even when an
 // outside of scope link is opened within the context of the PWA.
+// Flaky on Linux: https://crbug.com/1186613
+#if defined(OS_LINUX)
+#define MAYBE_NavigationInAppWindowToInScopeLinkDoesNotShowIntentPicker \
+  DISABLED_NavigationInAppWindowToInScopeLinkDoesNotShowIntentPicker
+#else
+#define MAYBE_NavigationInAppWindowToInScopeLinkDoesNotShowIntentPicker \
+  NavigationInAppWindowToInScopeLinkDoesNotShowIntentPicker
+#endif
 IN_PROC_BROWSER_TEST_P(
     IntentPickerBubbleViewBrowserTest,
-    NavigationInAppWindowToInScopeLinkDoesNotShowIntentPicker) {
+    MAYBE_NavigationInAppWindowToInScopeLinkDoesNotShowIntentPicker) {
   InstallTestWebApp();
 
   // No intent picker should be seen when first opening the web app.
diff --git a/chrome/browser/ui/views/location_bar/star_view.cc b/chrome/browser/ui/views/location_bar/star_view.cc
index 6e5ac9f8..b6adf5d 100644
--- a/chrome/browser/ui/views/location_bar/star_view.cc
+++ b/chrome/browser/ui/views/location_bar/star_view.cc
@@ -17,12 +17,14 @@
 #include "chrome/browser/ui/bookmarks/bookmark_stats.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/view_ids.h"
 #include "chrome/browser/ui/views/bookmarks/bookmark_bubble_view.h"
 #include "chrome/browser/ui/views/location_bar/star_menu_model.h"
 #include "chrome/browser/ui/views/user_education/feature_promo_bubble_view.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/bookmarks/common/bookmark_pref_names.h"
+#include "components/feature_engagement/public/feature_constants.h"
 #include "components/omnibox/browser/vector_icons.h"
 #include "components/reading_list/features/reading_list_switches.h"
 #include "components/strings/grit/components_strings.h"
@@ -99,6 +101,15 @@
 void StarView::ExecuteCommand(ExecuteSource source) {
   OnExecuting(source);
   if (base::FeatureList::IsEnabled(reading_list::switches::kReadLater)) {
+    FeaturePromoController* feature_promo_controller =
+        browser_->window()->GetFeaturePromoController();
+    if (feature_promo_controller &&
+        feature_promo_controller->BubbleIsShowing(
+            feature_engagement::kIPHReadingListEntryPointFeature)) {
+      reading_list_entry_point_promo_handle_ =
+          feature_promo_controller->CloseBubbleAndContinuePromo(
+              feature_engagement::kIPHReadingListEntryPointFeature);
+    }
     menu_model_ = std::make_unique<StarMenuModel>(
         this, GetActive(), chrome::CanMoveActiveTabToReadLater(browser_),
         chrome::IsCurrentTabUnreadInReadLater(browser_));
@@ -157,8 +168,14 @@
       !GetBubble()->GetWidget()->IsVisible()) {
     SetHighlighted(false);
   }
+  reading_list_entry_point_promo_handle_.reset();
   menu_runner_.reset();
 }
 
+bool StarView::IsCommandIdAlerted(int command_id) const {
+  return command_id == StarMenuModel::CommandMoveToReadLater &&
+         reading_list_entry_point_promo_handle_;
+}
+
 BEGIN_METADATA(StarView, PageActionIconView)
 END_METADATA
diff --git a/chrome/browser/ui/views/location_bar/star_view.h b/chrome/browser/ui/views/location_bar/star_view.h
index d79156d0..420fe748 100644
--- a/chrome/browser/ui/views/location_bar/star_view.h
+++ b/chrome/browser/ui/views/location_bar/star_view.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 
+#include "chrome/browser/ui/user_education/feature_promo_controller.h"
 #include "chrome/browser/ui/views/page_action/page_action_icon_view.h"
 #include "components/prefs/pref_member.h"
 #include "ui/base/models/simple_menu_model.h"
@@ -51,6 +52,7 @@
   // ui::SimpleMenuModel::Delegate:
   void ExecuteCommand(int command_id, int event_flags) override;
   void MenuClosed(ui::SimpleMenuModel* source) override;
+  bool IsCommandIdAlerted(int command_id) const override;
 
   Browser* const browser_;
 
@@ -58,6 +60,9 @@
   std::unique_ptr<StarMenuModel> menu_model_;
 
   BooleanPrefMember edit_bookmarks_enabled_;
+
+  base::Optional<FeaturePromoController::PromoHandle>
+      reading_list_entry_point_promo_handle_;
 };
 
 #endif  // CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_STAR_VIEW_H_
diff --git a/chrome/browser/ui/views/plugin_vm/plugin_vm_installer_view_browsertest.cc b/chrome/browser/ui/views/plugin_vm/plugin_vm_installer_view_browsertest.cc
index d4ad7ab..6f6d2e7 100644
--- a/chrome/browser/ui/views/plugin_vm/plugin_vm_installer_view_browsertest.cc
+++ b/chrome/browser/ui/views/plugin_vm/plugin_vm_installer_view_browsertest.cc
@@ -142,7 +142,7 @@
                                      IDS_PLUGIN_VM_INSTALLER_FINISHED_TITLE));
   }
 
-  chromeos::ScopedTestingCrosSettings scoped_testing_cros_settings_;
+  ash::ScopedTestingCrosSettings scoped_testing_cros_settings_;
   chromeos::ScopedStubInstallAttributes scoped_stub_install_attributes_;
 
   std::unique_ptr<network::TestNetworkConnectionTracker>
diff --git a/chrome/browser/ui/views/read_later/read_later_button.cc b/chrome/browser/ui/views/read_later/read_later_button.cc
index a5e606d..e5e30089 100644
--- a/chrome/browser/ui/views/read_later/read_later_button.cc
+++ b/chrome/browser/ui/views/read_later/read_later_button.cc
@@ -11,6 +11,7 @@
 #include "base/strings/string16.h"
 #include "base/time/time.h"
 #include "chrome/app/vector_icons/vector_icons.h"
+#include "chrome/browser/feature_engagement/tracker_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/ui/browser.h"
@@ -25,6 +26,8 @@
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/bookmarks/common/bookmark_pref_names.h"
+#include "components/feature_engagement/public/event_constants.h"
+#include "components/feature_engagement/public/tracker.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/pointer/touch_ui_controller.h"
@@ -279,6 +282,10 @@
     } else {
       base::RecordAction(
           base::UserMetricsAction("DesktopReadingList.OpenReadingList"));
+      feature_engagement::Tracker* tracker =
+          feature_engagement::TrackerFactory::GetForBrowserContext(
+              browser_->profile());
+      tracker->NotifyEvent(feature_engagement::events::kReadingListMenuOpened);
       RecordBookmarkBarState(browser_);
       webui_bubble_manager_->ShowBubble();
       reading_list_model_->MarkAllSeen();
diff --git a/chrome/browser/ui/views/user_education/feature_promo_registry.cc b/chrome/browser/ui/views/user_education/feature_promo_registry.cc
index fd2c8bae..ecf359f 100644
--- a/chrome/browser/ui/views/user_education/feature_promo_registry.cc
+++ b/chrome/browser/ui/views/user_education/feature_promo_registry.cc
@@ -198,7 +198,7 @@
     // kIPHReadingListEntryPointFeature:
     FeaturePromoBubbleParams params;
     params.body_string_specifier = IDS_READING_LIST_ENTRY_POINT_PROMO;
-    params.arrow = views::BubbleBorder::TOP_LEFT;
+    params.arrow = views::BubbleBorder::TOP_RIGHT;
 
     RegisterFeature(feature_engagement::kIPHReadingListEntryPointFeature,
                     params, base::BindRepeating(GetReadingListStarView));
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index 59f0bb1..7a2fb07 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -188,7 +188,7 @@
 #include "chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_ui.h"
 #include "chrome/browser/ui/webui/chromeos/cryptohome_ui.h"
 #include "chrome/browser/ui/webui/chromeos/drive_internals_ui.h"
-#include "chrome/browser/ui/webui/chromeos/emoji/emoji_picker.h"
+#include "chrome/browser/ui/webui/chromeos/emoji/emoji_ui.h"
 #include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_start_reauth_ui.h"
 #include "chrome/browser/ui/webui/chromeos/in_session_password_change/password_change_ui.h"
 #include "chrome/browser/ui/webui/chromeos/internet_config_dialog.h"
@@ -837,7 +837,7 @@
   }
   if (url.host_piece() == chrome::kChromeUIEmojiPickerHost &&
       base::FeatureList::IsEnabled(chromeos::features::kImeSystemEmojiPicker)) {
-    return &NewWebUI<chromeos::EmojiPicker>;
+    return &NewWebUI<chromeos::EmojiUI>;
   }
   if (url.host_piece() == chromeos::eche_app::kChromeUIEcheAppHost &&
       base::FeatureList::IsEnabled(chromeos::features::kEcheSWA)) {
diff --git a/chrome/browser/ui/webui/chromeos/emoji/BUILD.gn b/chrome/browser/ui/webui/chromeos/emoji/BUILD.gn
new file mode 100644
index 0000000..882968d
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/emoji/BUILD.gn
@@ -0,0 +1,11 @@
+# Copyright 2021 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("mojo_bindings") {
+  sources = [ "emoji_picker.mojom" ]
+  public_deps = [ "//mojo/public/mojom/base" ]
+  webui_module_path = "/"
+}
diff --git a/chrome/browser/ui/webui/chromeos/emoji/OWNERS b/chrome/browser/ui/webui/chromeos/emoji/OWNERS
index 4e1c393d..e38bf15 100644
--- a/chrome/browser/ui/webui/chromeos/emoji/OWNERS
+++ b/chrome/browser/ui/webui/chromeos/emoji/OWNERS
@@ -1,2 +1,5 @@
 jopalmer@chromium.org
 keithlee@chromium.org
+
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
\ No newline at end of file
diff --git a/chrome/browser/ui/webui/chromeos/emoji/emoji_dialog.cc b/chrome/browser/ui/webui/chromeos/emoji/emoji_dialog.cc
deleted file mode 100644
index 8cc74fd..0000000
--- a/chrome/browser/ui/webui/chromeos/emoji/emoji_dialog.cc
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright 2021 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/emoji/emoji_dialog.h"
-
-#include "base/strings/utf_string_conversions.h"
-
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/ui/browser_dialogs.h"
-#include "chrome/browser/ui/webui/constrained_web_dialog_ui.h"
-#include "chrome/common/url_constants.h"
-
-#include "ui/aura/window.h"
-#include "ui/base/ime/chromeos/ime_bridge.h"
-
-namespace chromeos {
-
-constexpr gfx::Size kDefaultWindowSize(340, 390);
-
-gfx::NativeWindow EmojiPickerDialog::window = nullptr;
-
-EmojiPickerDialog::EmojiPickerDialog() {
-  set_can_resize(false);
-}
-
-void EmojiPickerDialog::Show() {
-  if (window) {
-    window->Focus();
-    return;
-  }
-  ui::InputMethod* input_method =
-      ui::IMEBridge::Get()->GetInputContextHandler()->GetInputMethod();
-  const ui::TextInputClient* input_client =
-      input_method ? input_method->GetTextInputClient() : nullptr;
-  const gfx::Rect caret_bounds =
-      input_client ? input_client->GetCaretBounds() : gfx::Rect();
-  window = chrome::ShowWebDialog(
-      nullptr, ProfileManager::GetActiveUserProfile(), new EmojiPickerDialog());
-  // For now, this can overflow the screen.
-  if (input_client) {
-    window->SetBounds(gfx::Rect(caret_bounds.x(), caret_bounds.bottom(),
-                                kDefaultWindowSize.width(),
-                                kDefaultWindowSize.height()));
-  }
-}
-
-ui::ModalType EmojiPickerDialog::GetDialogModalType() const {
-  return ui::MODAL_TYPE_NONE;
-}
-
-base::string16 EmojiPickerDialog::GetDialogTitle() const {
-  return base::UTF8ToUTF16("Emoji Picker");
-}
-
-GURL EmojiPickerDialog::GetDialogContentURL() const {
-  return GURL(chrome::kChromeUIEmojiPickerURL);
-}
-
-void EmojiPickerDialog::GetWebUIMessageHandlers(
-    std::vector<content::WebUIMessageHandler*>* handlers) const {}
-
-void EmojiPickerDialog::GetDialogSize(gfx::Size* size) const {
-  *size = kDefaultWindowSize;
-}
-
-std::string EmojiPickerDialog::GetDialogArgs() const {
-  return "";
-}
-
-void EmojiPickerDialog::OnDialogShown(content::WebUI* webui) {
-  webui_ = webui;
-}
-
-void EmojiPickerDialog::OnDialogClosed(const std::string& json_retval) {
-  window = nullptr;
-  delete this;
-}
-
-void EmojiPickerDialog::OnCloseContents(content::WebContents* source,
-                                        bool* out_close_dialog) {
-  *out_close_dialog = true;
-}
-
-bool EmojiPickerDialog::ShouldShowDialogTitle() const {
-  return true;
-}
-
-EmojiPickerDialog::~EmojiPickerDialog() = default;
-}  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/emoji/emoji_dialog.h b/chrome/browser/ui/webui/chromeos/emoji/emoji_dialog.h
deleted file mode 100644
index 9109609..0000000
--- a/chrome/browser/ui/webui/chromeos/emoji/emoji_dialog.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2021 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_EMOJI_EMOJI_DIALOG_H_
-#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_EMOJI_EMOJI_DIALOG_H_
-
-#include "base/macros.h"
-#include "ui/base/ime/text_input_client.h"
-#include "ui/web_dialogs/web_dialog_delegate.h"
-
-#include "chrome/browser/ui/webui/chromeos/emoji/emoji_handler.h"
-
-namespace chromeos {
-
-class EmojiPickerDialog : public ui::WebDialogDelegate {
- public:
-  static void Show();
-  ~EmojiPickerDialog() override;
-
- private:
-  EmojiPickerDialog();
-  // ui::WebDialogDelegate:
-  ui::ModalType GetDialogModalType() const override;
-  base::string16 GetDialogTitle() const override;
-  GURL GetDialogContentURL() const override;
-  void GetWebUIMessageHandlers(
-      std::vector<content::WebUIMessageHandler*>* handlers) const override;
-  void GetDialogSize(gfx::Size* size) const override;
-  std::string GetDialogArgs() const override;
-  void OnDialogShown(content::WebUI* webui) override;
-  void OnDialogClosed(const std::string& json_retval) override;
-  void OnCloseContents(content::WebContents* source,
-                       bool* out_close_dialog) override;
-  bool ShouldShowDialogTitle() const override;
-
-  content::WebUI* webui_ = nullptr;
-
-  // Window for the emoji picker.  Used by the handler to close the window.
-  static gfx::NativeWindow window;
-  friend class EmojiHandler;
-
-  DISALLOW_COPY_AND_ASSIGN(EmojiPickerDialog);
-};
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_EMOJI_EMOJI_DIALOG_H_
diff --git a/chrome/browser/ui/webui/chromeos/emoji/emoji_handler.cc b/chrome/browser/ui/webui/chromeos/emoji/emoji_handler.cc
deleted file mode 100644
index d8f935b..0000000
--- a/chrome/browser/ui/webui/chromeos/emoji/emoji_handler.cc
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2021 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/emoji/emoji_handler.h"
-
-#include "base/logging.h"
-#include "base/metrics/histogram_functions.h"
-#include "base/strings/utf_string_conversions.h"
-
-#include "chrome/browser/ui/webui/chromeos/emoji/emoji_dialog.h"
-#include "ui/aura/window.h"
-#include "ui/base/ime/chromeos/ime_bridge.h"
-
-namespace chromeos {
-
-EmojiHandler::EmojiHandler() {}
-EmojiHandler::~EmojiHandler() = default;
-
-// Keep in sync with entry in enums.xml.
-enum class EmojiVariantType {
-  // smaller entries only used by Chrome OS VK
-  kEmojiPickerBase = 4,
-  kEmojiPickerVariant = 5,
-  kMaxValue = kEmojiPickerVariant,
-};
-
-void LogInsertEmoji(bool isVariant) {
-  EmojiVariantType insertValue = isVariant
-                                     ? EmojiVariantType::kEmojiPickerVariant
-                                     : EmojiVariantType::kEmojiPickerBase;
-  base::UmaHistogramEnumeration("InputMethod.VirtualKeyboard.Emoji.TriggerType",
-                                insertValue);
-}
-
-void EmojiHandler::RegisterMessages() {
-  web_ui()->RegisterMessageCallback(
-      "insertEmoji", base::BindRepeating(&EmojiHandler::HandleInsertEmoji,
-                                         base::Unretained(this)));
-}
-
-void EmojiHandler::HandleInsertEmoji(const base::ListValue* args) {
-  if (args->GetSize() != 2) {
-    DLOG(WARNING)
-        << "insertEmoji called with incorrect number of arguments (expected 2)";
-    return;
-  }
-
-  const std::string& emoji = args->GetList()[0].GetString();
-  LogInsertEmoji(args->GetList()[1].GetBool());
-
-  // Hide emoji picker window to restore focus to original text field
-  if (EmojiPickerDialog::window) {
-    EmojiPickerDialog::window->Hide();
-    EmojiPickerDialog::window = nullptr;
-  }
-
-  ui::InputMethod* input_method =
-      ui::IMEBridge::Get()->GetInputContextHandler()->GetInputMethod();
-  if (!input_method) {
-    LOG(WARNING) << "no input_method found";
-    return;
-  }
-
-  ui::TextInputClient* input_client = input_method->GetTextInputClient();
-
-  if (!input_client) {
-    LOG(WARNING) << "no input_client found";
-    return;
-  }
-
-  if (input_client->GetTextInputType() ==
-      ui::TextInputType::TEXT_INPUT_TYPE_NONE) {
-    LOG(WARNING) << "attempt to insert into input_client with type none";
-    return;
-  }
-
-  input_client->InsertText(
-      base::UTF8ToUTF16(emoji),
-      ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/emoji/emoji_handler.h b/chrome/browser/ui/webui/chromeos/emoji/emoji_handler.h
deleted file mode 100644
index 26f74ca7..0000000
--- a/chrome/browser/ui/webui/chromeos/emoji/emoji_handler.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2021 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_EMOJI_EMOJI_HANDLER_H_
-#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_EMOJI_EMOJI_HANDLER_H_
-
-#include "base/macros.h"
-#include "content/public/browser/web_ui_message_handler.h"
-
-namespace chromeos {
-
-// The WebUI message handler for chrome://emoji-picker
-class EmojiHandler : public content::WebUIMessageHandler {
- public:
-  EmojiHandler();
-  ~EmojiHandler() override;
-
- private:
-  // content::WebUIMessageHandler:
-  void RegisterMessages() override;
-
-  void HandleInsertEmoji(const base::ListValue* args);
-
-  DISALLOW_COPY_AND_ASSIGN(EmojiHandler);
-};
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_EMOJI_EMOJI_HANDLER_H_
diff --git a/chrome/browser/ui/webui/chromeos/emoji/emoji_page_handler.cc b/chrome/browser/ui/webui/chromeos/emoji/emoji_page_handler.cc
new file mode 100644
index 0000000..954baf0
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/emoji/emoji_page_handler.cc
@@ -0,0 +1,91 @@
+// 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/webui/chromeos/emoji/emoji_page_handler.h"
+
+#include "base/metrics/histogram_functions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+#include "base/trace_event/trace_event.h"
+#include "chrome/browser/ui/webui/chromeos/emoji/emoji_ui.h"
+#include "ui/base/ime/chromeos/ime_bridge.h"
+
+namespace chromeos {
+
+// Keep in sync with entry in enums.xml.
+enum class EmojiVariantType {
+  // smaller entries only used by Chrome OS VK
+  kEmojiPickerBase = 4,
+  kEmojiPickerVariant = 5,
+  kMaxValue = kEmojiPickerVariant,
+};
+
+void LogInsertEmoji(bool is_variant) {
+  EmojiVariantType insert_value = is_variant
+                                      ? EmojiVariantType::kEmojiPickerVariant
+                                      : EmojiVariantType::kEmojiPickerBase;
+  base::UmaHistogramEnumeration("InputMethod.VirtualKeyboard.Emoji.TriggerType",
+                                insert_value);
+}
+
+EmojiPageHandler::EmojiPageHandler(
+    mojo::PendingReceiver<emoji_picker::mojom::PageHandler> receiver,
+    content::WebUI* web_ui,
+    EmojiUI* webui_controller)
+    : receiver_(this, std::move(receiver)),
+      webui_controller_(webui_controller) {}
+
+EmojiPageHandler::~EmojiPageHandler() {}
+
+void EmojiPageHandler::ShowUI() {
+  auto embedder = webui_controller_->embedder();
+  // Embedder may not exist in some cases (e.g. user browses to
+  // chrome://emoji-picker directly rather than using right click on
+  // text field -> emoji).
+  if (embedder) {
+    embedder->ShowUI();
+  }
+}
+
+void EmojiPageHandler::InsertEmoji(const std::string& emoji_to_insert,
+                                   bool is_variant) {
+  // By hiding the emoji picker, we restore focus to the original text field so
+  // we can insert the text.
+  auto embedder = webui_controller_->embedder();
+  if (embedder) {
+    embedder->CloseUI();
+  }
+  LogInsertEmoji(is_variant);
+
+  // In theory, we are returning focus to the input field where the user
+  // originally selected emoji. However, the input field may not exist anymore
+  // e.g. JS has mutated the web page while emoji picker was open, so check that
+  // a valid input client is available as part of inserting the emoji.
+  ui::InputMethod* input_method =
+      ui::IMEBridge::Get()->GetInputContextHandler()->GetInputMethod();
+  if (!input_method) {
+    DLOG(WARNING) << "no input_method found";
+    return;
+  }
+
+  ui::TextInputClient* input_client = input_method->GetTextInputClient();
+
+  if (!input_client) {
+    DLOG(WARNING) << "no input_client found";
+    return;
+  }
+
+  if (input_client->GetTextInputType() ==
+      ui::TextInputType::TEXT_INPUT_TYPE_NONE) {
+    DLOG(WARNING) << "attempt to insert into input_client with type none";
+    return;
+  }
+
+  input_client->InsertText(
+      base::UTF8ToUTF16(emoji_to_insert),
+      ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/emoji/emoji_page_handler.h b/chrome/browser/ui/webui/chromeos/emoji/emoji_page_handler.h
new file mode 100644
index 0000000..4f05a8c
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/emoji/emoji_page_handler.h
@@ -0,0 +1,36 @@
+// Copyright 2021 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_EMOJI_EMOJI_PAGE_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_EMOJI_EMOJI_PAGE_HANDLER_H_
+
+#include "chrome/browser/ui/webui/chromeos/emoji/emoji_picker.mojom.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "ui/webui/mojo_bubble_web_ui_controller.h"
+
+namespace chromeos {
+class EmojiUI;
+
+class EmojiPageHandler : public emoji_picker::mojom::PageHandler {
+ public:
+  EmojiPageHandler(
+      mojo::PendingReceiver<emoji_picker::mojom::PageHandler> receiver,
+      content::WebUI* web_ui,
+      EmojiUI* webui_controller);
+  EmojiPageHandler(const EmojiPageHandler&) = delete;
+  EmojiPageHandler& operator=(const EmojiPageHandler&) = delete;
+  ~EmojiPageHandler() override;
+
+  // emoji_picker::mojom::PageHandler:
+  void ShowUI() override;
+  void InsertEmoji(const std::string& emoji_to_insert,
+                   bool is_variant) override;
+
+ private:
+  mojo::Receiver<emoji_picker::mojom::PageHandler> receiver_;
+  EmojiUI* const webui_controller_;
+};
+}  // namespace chromeos
+#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_EMOJI_EMOJI_PAGE_HANDLER_H_
diff --git a/chrome/browser/ui/webui/chromeos/emoji/emoji_picker.cc b/chrome/browser/ui/webui/chromeos/emoji/emoji_picker.cc
deleted file mode 100644
index 227a863..0000000
--- a/chrome/browser/ui/webui/chromeos/emoji/emoji_picker.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2021 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/emoji/emoji_picker.h"
-
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_list.h"
-#include "chrome/browser/ui/webui/webui_util.h"
-#include "chrome/common/url_constants.h"
-#include "chrome/grit/emoji_picker_resources.h"
-#include "chrome/grit/emoji_picker_resources_map.h"
-#include "content/public/browser/web_ui.h"
-#include "content/public/browser/web_ui_data_source.h"
-#include "ui/resources/grit/webui_generated_resources.h"
-
-#include "chrome/browser/ui/webui/chromeos/emoji/emoji_dialog.h"
-#include "chrome/browser/ui/webui/chromeos/emoji/emoji_handler.h"
-
-namespace chromeos {
-
-EmojiPicker::EmojiPicker(content::WebUI* web_ui)
-    : content::WebUIController(web_ui) {
-  // Set up the chrome://emoji-picker source.
-  std::unique_ptr<content::WebUIDataSource> html_source(
-      content::WebUIDataSource::Create(chrome::kChromeUIEmojiPickerHost));
-
-  // As a demonstration of passing a variable for JS to use we pass in some
-  // emoji.
-  html_source->AddString("emoji",
-                         "😀,😃,😄,😁,😆,😅,😂,🤣,😭");
-  html_source->UseStringsJs();
-
-  // Add required resources.
-  webui::SetupWebUIDataSource(
-      html_source.get(),
-      base::make_span(kEmojiPickerResources, kEmojiPickerResourcesSize),
-      IDR_EMOJI_PICKER_INDEX_HTML);
-
-  // Attach message handler to handle emoji click events.
-  web_ui->AddMessageHandler(std::make_unique<EmojiHandler>());
-
-  content::BrowserContext* browser_context =
-      web_ui->GetWebContents()->GetBrowserContext();
-  content::WebUIDataSource::Add(browser_context, html_source.release());
-}
-
-EmojiPicker::~EmojiPicker() {}
-
-}  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/emoji/emoji_picker.h b/chrome/browser/ui/webui/chromeos/emoji/emoji_picker.h
deleted file mode 100644
index 1b46281..0000000
--- a/chrome/browser/ui/webui/chromeos/emoji/emoji_picker.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2021 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_EMOJI_EMOJI_PICKER_H_
-#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_EMOJI_EMOJI_PICKER_H_
-
-#include "base/macros.h"
-#include "content/public/browser/web_ui_controller.h"
-#include "ui/web_dialogs/web_dialog_delegate.h"
-
-namespace chromeos {
-
-// The WebUI for chrome://emoji-picker
-class EmojiPicker : public content::WebUIController {
- public:
-  explicit EmojiPicker(content::WebUI* web_ui);
-  ~EmojiPicker() override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(EmojiPicker);
-};
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_EMOJI_EMOJI_PICKER_H_
diff --git a/chrome/browser/ui/webui/chromeos/emoji/emoji_picker.mojom b/chrome/browser/ui/webui/chromeos/emoji/emoji_picker.mojom
new file mode 100644
index 0000000..89b776b
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/emoji/emoji_picker.mojom
@@ -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.
+
+module emoji_picker.mojom;
+
+
+// Used by the WebUI page to bootstrap bidirectional communication.
+interface PageHandlerFactory {
+  // The WebUI calls this method when the page is first initialized.
+  CreatePageHandler(pending_receiver<PageHandler> handler);
+};
+
+// Browser-side handler for requests from WebUI page.
+interface PageHandler {
+
+  // Request the UI to be shown.  Using this interface, dialog can be invisible
+  // while rendering to avoid UI showing in incomplete state.
+  ShowUI();
+
+  // Request backend to insert emoji (will close the picker).
+  // emoji: The emoji to insert in string form e.g. "😂".
+  // is_variant: If the emoji is a variant / base emoji, used for metrics.
+  InsertEmoji(string emoji, bool is_variant);
+};
diff --git a/chrome/browser/ui/webui/chromeos/emoji/emoji_ui.cc b/chrome/browser/ui/webui/chromeos/emoji/emoji_ui.cc
new file mode 100644
index 0000000..98f1178e
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/emoji/emoji_ui.cc
@@ -0,0 +1,106 @@
+// 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/webui/chromeos/emoji/emoji_ui.h"
+
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/views/bubble/bubble_contents_wrapper.h"
+#include "chrome/browser/ui/views/bubble/bubble_contents_wrapper_service.h"
+#include "chrome/browser/ui/views/bubble/bubble_contents_wrapper_service_factory.h"
+#include "chrome/browser/ui/views/bubble/webui_bubble_dialog_view.h"
+#include "chrome/browser/ui/webui/webui_util.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/grit/emoji_picker_resources.h"
+#include "chrome/grit/emoji_picker_resources_map.h"
+#include "chrome/grit/generated_resources.h"
+#include "content/public/browser/url_data_source.h"
+#include "content/public/browser/web_ui.h"
+#include "content/public/browser/web_ui_data_source.h"
+#include "ui/base/ime/chromeos/ime_bridge.h"
+#include "ui/resources/grit/webui_generated_resources.h"
+
+#include <iostream>
+
+namespace {
+constexpr gfx::Size kDefaultWindowSize(340, 390);
+
+class EmojiiBubbleDialogView : public WebUIBubbleDialogView {
+ public:
+  EmojiiBubbleDialogView(
+      std::unique_ptr<BubbleContentsWrapper> contents_wrapper)
+      : WebUIBubbleDialogView(nullptr, contents_wrapper.get()),
+        contents_wrapper_(std::move(contents_wrapper)) {}
+
+ private:
+  std::unique_ptr<BubbleContentsWrapper> contents_wrapper_;
+};
+
+}  // namespace
+
+namespace chromeos {
+
+EmojiUI::EmojiUI(content::WebUI* web_ui)
+    : ui::MojoBubbleWebUIController(web_ui,
+                                    true /* Needed for webui browser tests */) {
+  content::WebUIDataSource* source =
+      content::WebUIDataSource::Create(chrome::kChromeUIEmojiPickerHost);
+  source->UseStringsJs();
+
+  // Add required resources.
+  webui::SetupWebUIDataSource(
+      source, base::make_span(kEmojiPickerResources, kEmojiPickerResourcesSize),
+      IDR_EMOJI_PICKER_INDEX_HTML);
+
+  content::WebUIDataSource::Add(web_ui->GetWebContents()->GetBrowserContext(),
+                                source);
+}
+
+EmojiUI::~EmojiUI() = default;
+
+void EmojiUI::Show(Profile* profile) {
+  ui::InputMethod* input_method =
+      ui::IMEBridge::Get()->GetInputContextHandler()->GetInputMethod();
+  const ui::TextInputClient* input_client =
+      input_method ? input_method->GetTextInputClient() : nullptr;
+  const gfx::Rect caret_bounds =
+      input_client ? input_client->GetCaretBounds() : gfx::Rect();
+
+  // This rect is used for positioning the emoji picker.  All that really
+  // matters is a position, so it has 0 height/width
+  auto anchor_rect = gfx::Rect(caret_bounds.x() + kDefaultWindowSize.width(),
+                               caret_bounds.bottom(), 0, 0);
+
+  // TODO(b/181703133): Refactor so that the webui_bubble_manager can be used
+  // here to reduce code duplication.
+
+  auto contents_wrapper = std::make_unique<BubbleContentsWrapperT<EmojiUI>>(
+      GURL(chrome::kChromeUIEmojiPickerURL), profile, IDS_ACCNAME_EMOJI_PICKER,
+      false /*enable_extension_apis*/);
+  // Need to reload the web contents here because the view isn't visible unless
+  // ShowUI is called from the JS side.  By reloading, we trigger the JS to
+  // eventually call ShowUI().
+  contents_wrapper->ReloadWebContents();
+
+  auto bubble_view =
+      std::make_unique<EmojiiBubbleDialogView>(std::move(contents_wrapper));
+  auto weak_ptr = bubble_view->GetWeakPtr();
+  views::BubbleDialogDelegateView::CreateBubble(std::move(bubble_view));
+  weak_ptr->SetAnchorRect(anchor_rect);
+}
+
+WEB_UI_CONTROLLER_TYPE_IMPL(EmojiUI)
+
+void EmojiUI::BindInterface(
+    mojo::PendingReceiver<emoji_picker::mojom::PageHandlerFactory> receiver) {
+  page_factory_receiver_.reset();
+  page_factory_receiver_.Bind(std::move(receiver));
+}
+
+void EmojiUI::CreatePageHandler(
+    mojo::PendingReceiver<emoji_picker::mojom::PageHandler> receiver) {
+  page_handler_ =
+      std::make_unique<EmojiPageHandler>(std::move(receiver), web_ui(), this);
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/emoji/emoji_ui.h b/chrome/browser/ui/webui/chromeos/emoji/emoji_ui.h
new file mode 100644
index 0000000..06bca90
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/emoji/emoji_ui.h
@@ -0,0 +1,52 @@
+// Copyright 2021 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_EMOJI_EMOJI_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_EMOJI_EMOJI_UI_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/timer/elapsed_timer.h"
+#include "chrome/browser/ui/webui/chromeos/emoji/emoji_page_handler.h"
+#include "chrome/browser/ui/webui/chromeos/emoji/emoji_picker.mojom.h"
+#include "chrome/browser/ui/webui/webui_load_timer.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "ui/webui/mojo_bubble_web_ui_controller.h"
+
+class Profile;
+
+namespace chromeos {
+
+class EmojiUI : public ui::MojoBubbleWebUIController,
+                public emoji_picker::mojom::PageHandlerFactory {
+ public:
+  explicit EmojiUI(content::WebUI* web_ui);
+  EmojiUI(const EmojiUI&) = delete;
+  EmojiUI& operator=(const EmojiUI&) = delete;
+  ~EmojiUI() override;
+
+  static void Show(Profile* profile);
+
+  // Instantiates the implementor of the mojom::PageHandlerFactory mojo
+  // interface passing the pending receiver that will be internally bound.
+  void BindInterface(
+      mojo::PendingReceiver<emoji_picker::mojom::PageHandlerFactory> receiver);
+
+  // emoji_picker::mojom::PageHandlerFactory
+  void CreatePageHandler(mojo::PendingReceiver<emoji_picker::mojom::PageHandler>
+                             receiver) override;
+
+ private:
+  std::unique_ptr<EmojiPageHandler> page_handler_;
+
+  mojo::Receiver<emoji_picker::mojom::PageHandlerFactory>
+      page_factory_receiver_{this};
+
+  WEB_UI_CONTROLLER_TYPE_DECL();
+};
+}  // namespace chromeos
+#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_EMOJI_EMOJI_UI_H_
diff --git a/chrome/browser/ui/webui/flags/flags_ui.cc b/chrome/browser/ui/webui/flags/flags_ui.cc
index 17b4eba..75d4266 100644
--- a/chrome/browser/ui/webui/flags/flags_ui.cc
+++ b/chrome/browser/ui/webui/flags/flags_ui.cc
@@ -78,7 +78,7 @@
       base::SysInfo::IsRunningOnChromeOS()) {
     // Set the string to show which user can actually change the flags.
     std::string owner;
-    chromeos::CrosSettings::Get()->GetString(chromeos::kDeviceOwner, &owner);
+    ash::CrosSettings::Get()->GetString(chromeos::kDeviceOwner, &owner);
     source->AddString("owner-warning",
                       l10n_util::GetStringFUTF16(IDS_FLAGS_UI_OWNER_WARNING,
                                                  base::UTF8ToUTF16(owner)));
diff --git a/chrome/browser/ui/webui/help/help_utils_chromeos.cc b/chrome/browser/ui/webui/help/help_utils_chromeos.cc
index cfddc576..b2a4f3ca 100644
--- a/chrome/browser/ui/webui/help/help_utils_chromeos.cc
+++ b/chrome/browser/ui/webui/help/help_utils_chromeos.cc
@@ -23,7 +23,7 @@
       interactive ? true : chromeos::switches::IsCellularFirstDevice();
 
   // Device Policy overrides the defaults.
-  chromeos::CrosSettings* settings = chromeos::CrosSettings::Get();
+  ash::CrosSettings* settings = ash::CrosSettings::Get();
   if (!settings)
     return default_update_over_cellular_allowed;
 
diff --git a/chrome/browser/ui/webui/help/version_updater_chromeos.cc b/chrome/browser/ui/webui/help/version_updater_chromeos.cc
index 1fe22853..dba49c73 100644
--- a/chrome/browser/ui/webui/help/version_updater_chromeos.cc
+++ b/chrome/browser/ui/webui/help/version_updater_chromeos.cc
@@ -67,7 +67,7 @@
 // Returns true if auto-update is disabled by the system administrator.
 bool IsAutoUpdateDisabled() {
   bool update_disabled = kDefaultAutoUpdateDisabled;
-  chromeos::CrosSettings* settings = chromeos::CrosSettings::Get();
+  ash::CrosSettings* settings = ash::CrosSettings::Get();
   if (!settings)
     return update_disabled;
   const base::Value* update_disabled_value =
diff --git a/chrome/browser/ui/webui/management/management_ui_handler.cc b/chrome/browser/ui/webui/management/management_ui_handler.cc
index f812f8e..e580230 100644
--- a/chrome/browser/ui/webui/management/management_ui_handler.cc
+++ b/chrome/browser/ui/webui/management/management_ui_handler.cc
@@ -638,8 +638,8 @@
                                  base::UTF8ToUTF16(GetDeviceManager()),
                                  ui::GetChromeOSDeviceName()));
   std::string eol_admin_message;
-  chromeos::CrosSettings::Get()->GetString(
-      chromeos::kDeviceMinimumVersionAueMessage, &eol_admin_message);
+  ash::CrosSettings::Get()->GetString(chromeos::kDeviceMinimumVersionAueMessage,
+                                      &eol_admin_message);
   response->SetStringPath("eolAdminMessage", eol_admin_message);
 }
 
diff --git a/chrome/browser/ui/webui/management/management_ui_handler_unittest.cc b/chrome/browser/ui/webui/management/management_ui_handler_unittest.cc
index dc2f507..4d8d02a 100644
--- a/chrome/browser/ui/webui/management/management_ui_handler_unittest.cc
+++ b/chrome/browser/ui/webui/management/management_ui_handler_unittest.cc
@@ -556,7 +556,7 @@
   std::unique_ptr<TestDeviceCloudPolicyManagerChromeOS> manager_;
   scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
   policy::ServerBackedStateKeysBroker state_keys_broker_;
-  chromeos::ScopedTestingCrosSettings settings_;
+  ash::ScopedTestingCrosSettings settings_;
   chromeos::system::ScopedFakeStatisticsProvider fake_statistics_provider_;
 #else
   content::BrowserTaskEnvironment task_environment_;
diff --git a/chrome/browser/ui/webui/policy/policy_ui_handler.cc b/chrome/browser/ui/webui/policy/policy_ui_handler.cc
index ab1750f..f6a9ba3b 100644
--- a/chrome/browser/ui/webui/policy/policy_ui_handler.cc
+++ b/chrome/browser/ui/webui/policy/policy_ui_handler.cc
@@ -236,7 +236,7 @@
 
 void GetOffHoursStatus(base::DictionaryValue* dict) {
   policy::off_hours::DeviceOffHoursController* off_hours_controller =
-      chromeos::DeviceSettingsService::Get()->device_off_hours_controller();
+      ash::DeviceSettingsService::Get()->device_off_hours_controller();
   if (off_hours_controller) {
     dict->SetBoolean("isOffHoursActive",
                      off_hours_controller->is_off_hours_mode());
diff --git a/chrome/browser/ui/webui/settings/about_handler.cc b/chrome/browser/ui/webui/settings/about_handler.cc
index 09b82022..c6d253e 100644
--- a/chrome/browser/ui/webui/settings/about_handler.cc
+++ b/chrome/browser/ui/webui/settings/about_handler.cc
@@ -123,8 +123,8 @@
     bool value = false;
     // On a managed machine we delegate this setting to the affiliated users
     // only if the policy value is true.
-    chromeos::CrosSettings::Get()->GetBoolean(
-        chromeos::kReleaseChannelDelegated, &value);
+    ash::CrosSettings::Get()->GetBoolean(chromeos::kReleaseChannelDelegated,
+                                         &value);
     if (!value)
       return false;
 
@@ -551,8 +551,8 @@
   // For the LTS pilot simply check whether the device policy is set and ignore
   // its value.
   std::string value;
-  bool is_lts = chromeos::CrosSettings::Get()->GetString(
-      chromeos::kReleaseLtsTag, &value);
+  bool is_lts =
+      ash::CrosSettings::Get()->GetString(chromeos::kReleaseLtsTag, &value);
   channel_info->SetBoolean("isLts", is_lts);
 
   ResolveJavascriptCallback(base::Value(callback_id), *channel_info);
diff --git a/chrome/browser/ui/webui/settings/chromeos/search/search_handler_unittest.cc b/chrome/browser/ui/webui/settings/chromeos/search/search_handler_unittest.cc
index 5d2bb644..0c0421f 100644
--- a/chrome/browser/ui/webui/settings/chromeos/search/search_handler_unittest.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/search/search_handler_unittest.cc
@@ -200,9 +200,8 @@
 
   // The URL should have bee modified according to the FakeOsSettingSection
   // scheme.
-  EXPECT_EQ(
-      std::string("Section::kPrinting::") + mojom::kPrintingDetailsSubpagePath,
-      search_results[0]->url_path_with_parameters);
+  EXPECT_EQ(std::string("kPrinting::") + mojom::kPrintingDetailsSubpagePath,
+            search_results[0]->url_path_with_parameters);
 }
 
 TEST_F(SearchHandlerTest, AltTagMatch) {
diff --git a/chrome/browser/ui/webui/signin/inline_login_ui.cc b/chrome/browser/ui/webui/signin/inline_login_ui.cc
index 9879153..da9cba3 100644
--- a/chrome/browser/ui/webui/signin/inline_login_ui.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_ui.cc
@@ -181,10 +181,10 @@
   source->AddResourcePaths(kResources);
 
   static constexpr webui::LocalizedString kLocalizedStrings[] = {
-    {"title", IDS_CHROME_SIGNIN_TITLE},
     {"accessibleCloseButtonLabel", IDS_SIGNIN_ACCESSIBLE_CLOSE_BUTTON},
     {"accessibleBackButtonLabel", IDS_SIGNIN_ACCESSIBLE_BACK_BUTTON},
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+    {"title", IDS_ACCOUNT_MANAGER_DIALOG_TITLE},
     {"ok", IDS_APP_OK},
     {"accountManagerDialogWelcomeTitle",
      IDS_ACCOUNT_MANAGER_DIALOG_WELCOME_TITLE},
@@ -198,6 +198,8 @@
      IDS_ACCOUNT_MANAGER_ERROR_CANNOT_ADD_ACCOUNT_TITLE},
     {"accountManagerErrorCannotAddAccountBody",
      IDS_ACCOUNT_MANAGER_ERROR_CANNOT_ADD_ACCOUNT_BODY},
+#else
+    {"title", IDS_CHROME_SIGNIN_TITLE},
 #endif
   };
   source->AddLocalizedStrings(kLocalizedStrings);
diff --git a/chrome/browser/video_tutorials/internal/android/java/res/layout/video_player_controls.xml b/chrome/browser/video_tutorials/internal/android/java/res/layout/video_player_controls.xml
index 966f496..7baaa3a 100644
--- a/chrome/browser/video_tutorials/internal/android/java/res/layout/video_player_controls.xml
+++ b/chrome/browser/video_tutorials/internal/android/java/res/layout/video_player_controls.xml
@@ -50,7 +50,7 @@
 
             <org.chromium.ui.widget.ButtonCompat
                 android:id="@+id/try_now"
-                android:layout_width="100dp"
+                android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_gravity="center_horizontal"
                 android:text="@string/video_tutorials_try_now"
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerMediator.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerMediator.java
index 13bf2a7..7564aeb 100644
--- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerMediator.java
+++ b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerMediator.java
@@ -8,6 +8,7 @@
 import android.text.TextUtils;
 
 import org.chromium.base.Callback;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.video_tutorials.LanguageInfoProvider;
 import org.chromium.chrome.browser.video_tutorials.PlaybackStateObserver;
 import org.chromium.chrome.browser.video_tutorials.PlaybackStateObserver.WatchStateInfo.State;
@@ -28,6 +29,9 @@
  * interaction events, and player state.
  */
 class VideoPlayerMediator implements PlaybackStateObserver.Observer {
+    private static final String VARIATION_ENABLE_SHARE_BUTTON = "enable_share";
+    public static Boolean sEnableShareForTesting;
+
     private final Context mContext;
     private final VideoTutorialService mVideoTutorialService;
     private final PropertyModel mModel;
@@ -64,6 +68,12 @@
         mModel.set(VideoPlayerProperties.CALLBACK_TRY_NOW, this::tryNow);
         mModel.set(VideoPlayerProperties.CALLBACK_SHARE, this::share);
         mModel.set(VideoPlayerProperties.CALLBACK_CLOSE, this::close);
+
+        boolean enableShare = sEnableShareForTesting == null
+                ? ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean(
+                        ChromeFeatureList.VIDEO_TUTORIALS, VARIATION_ENABLE_SHARE_BUTTON, false)
+                : sEnableShareForTesting;
+        mModel.set(VideoPlayerProperties.SHOW_SHARE, enableShare);
     }
 
     /** Called when the player is getting destroyed. */
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerMediatorUnitTest.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerMediatorUnitTest.java
index a854c4c..85b6de3 100644
--- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerMediatorUnitTest.java
+++ b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerMediatorUnitTest.java
@@ -83,6 +83,7 @@
         mModel = new PropertyModel(VideoPlayerProperties.ALL_KEYS);
         mModel.addObserver(mPropertyObserver);
 
+        VideoPlayerMediator.sEnableShareForTesting = true;
         mTestVideoTutorialService = new TestVideoTutorialService();
         mMediator = new VideoPlayerMediator(mContext, mModel, mTestVideoTutorialService,
                 mLanguagePicker, mLanguageProvider, mWebContents, mPlaybackStateObserver,
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerProperties.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerProperties.java
index 481a7745..741497e9 100644
--- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerProperties.java
+++ b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerProperties.java
@@ -19,6 +19,7 @@
     WritableBooleanPropertyKey SHOW_MEDIA_CONTROLS = new WritableBooleanPropertyKey();
     WritableBooleanPropertyKey SHOW_LANGUAGE_PICKER = new WritableBooleanPropertyKey();
     WritableBooleanPropertyKey SHOW_TRY_NOW = new WritableBooleanPropertyKey();
+    WritableBooleanPropertyKey SHOW_SHARE = new WritableBooleanPropertyKey();
     WritableBooleanPropertyKey SHOW_WATCH_NEXT = new WritableBooleanPropertyKey();
     WritableBooleanPropertyKey SHOW_CHANGE_LANGUAGE = new WritableBooleanPropertyKey();
     WritableObjectPropertyKey<String> CHANGE_LANGUAGE_BUTTON_TEXT =
@@ -32,7 +33,7 @@
     WritableObjectPropertyKey<State> WATCH_STATE_FOR_TRY_NOW = new WritableObjectPropertyKey<>();
 
     PropertyKey[] ALL_KEYS = new PropertyKey[] {SHOW_LOADING_SCREEN, SHOW_MEDIA_CONTROLS,
-            SHOW_LANGUAGE_PICKER, SHOW_TRY_NOW, SHOW_WATCH_NEXT, SHOW_CHANGE_LANGUAGE,
+            SHOW_LANGUAGE_PICKER, SHOW_TRY_NOW, SHOW_SHARE, SHOW_WATCH_NEXT, SHOW_CHANGE_LANGUAGE,
             CHANGE_LANGUAGE_BUTTON_TEXT, CALLBACK_WATCH_NEXT, CALLBACK_CHANGE_LANGUAGE,
             CALLBACK_TRY_NOW, CALLBACK_SHARE, CALLBACK_CLOSE, WATCH_STATE_FOR_TRY_NOW};
 }
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerViewBinder.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerViewBinder.java
index bbc0e920..0230058 100644
--- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerViewBinder.java
+++ b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerViewBinder.java
@@ -29,6 +29,11 @@
                     .findViewById(R.id.try_now)
                     .setVisibility(model.get(VideoPlayerProperties.SHOW_TRY_NOW) ? View.VISIBLE
                                                                                  : View.GONE);
+        } else if (propertyKey == VideoPlayerProperties.SHOW_SHARE) {
+            view.getView()
+                    .findViewById(R.id.share_button)
+                    .setVisibility(
+                            model.get(VideoPlayerProperties.SHOW_SHARE) ? View.VISIBLE : View.GONE);
         } else if (propertyKey == VideoPlayerProperties.SHOW_WATCH_NEXT) {
             view.getView()
                     .findViewById(R.id.watch_next)
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerViewBinderTest.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerViewBinderTest.java
index da581ab..1974c4a 100644
--- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerViewBinderTest.java
+++ b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerViewBinderTest.java
@@ -177,6 +177,8 @@
     @SmallTest
     public void testShareButton() {
         View shareButton = mControls.findViewById(R.id.share_button);
+        mModel.set(VideoPlayerProperties.SHOW_SHARE, true);
+        assertEquals(View.VISIBLE, shareButton.getVisibility());
         AtomicBoolean buttonClicked = new AtomicBoolean();
         mModel.set(VideoPlayerProperties.CALLBACK_SHARE, () -> buttonClicked.set(true));
         shareButton.performClick();
diff --git a/chrome/browser/video_tutorials/internal/config.cc b/chrome/browser/video_tutorials/internal/config.cc
index 31d395db..91790a3 100644
--- a/chrome/browser/video_tutorials/internal/config.cc
+++ b/chrome/browser/video_tutorials/internal/config.cc
@@ -11,8 +11,7 @@
 namespace video_tutorials {
 
 // Default base URL string for the server.
-constexpr char kDefaultBaseURL[] =
-    "https://staging-gsaprototype-pa.sandbox.googleapis.com";
+constexpr char kDefaultBaseURL[] = "https://chromeupboarding-pa.googleapis.com";
 
 // Default URL string for GetTutorials RPC.
 constexpr char kDefaultGetTutorialsPath[] = "/v1/videotutorials";
diff --git a/chrome/browser/video_tutorials/internal/config_unittest.cc b/chrome/browser/video_tutorials/internal/config_unittest.cc
index 2274f33..78c0d42 100644
--- a/chrome/browser/video_tutorials/internal/config_unittest.cc
+++ b/chrome/browser/video_tutorials/internal/config_unittest.cc
@@ -34,7 +34,7 @@
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(features::kVideoTutorials);
   EXPECT_EQ(Config::GetTutorialsServerURL().spec(),
-            "https://staging-gsaprototype-pa.sandbox.googleapis.com/v1/"
+            "https://chromeupboarding-pa.googleapis.com/v1/"
             "videotutorials");
   EXPECT_EQ(Config::GetDefaultPreferredLocale(), "en");
   EXPECT_EQ(Config::GetFetchFrequency(), base::TimeDelta::FromDays(15));
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 24f76a2..59140e4e 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-master-1615399152-ed68f34ecd63191647774b06c46e4357c6dae108.profdata
+chrome-linux-master-1615442232-362501ddc2ce39442e4e87db225c0e7a04e774f5.profdata
diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json
index 19475ba..7d256641 100644
--- a/chrome/common/extensions/api/_api_features.json
+++ b/chrome/common/extensions/api/_api_features.json
@@ -818,6 +818,7 @@
     "channel": "stable",
     "contexts": ["webui_untrusted"],
     "matches": [
+      "chrome-untrusted://crosh/*",
       "chrome-untrusted://terminal/*"
     ],
     "platforms": ["chromeos"]
@@ -969,6 +970,7 @@
     "channel": "stable",
     "contexts": ["webui_untrusted"],
     "matches": [
+      "chrome-untrusted://crosh/*",
       "chrome-untrusted://terminal/*"
     ],
     "platforms": ["chromeos"]
diff --git a/chrome/installer/util/shell_util.cc b/chrome/installer/util/shell_util.cc
index d33b1bcb..581e0e6 100644
--- a/chrome/installer/util/shell_util.cc
+++ b/chrome/installer/util/shell_util.cc
@@ -2498,6 +2498,9 @@
         base::SplitString(handled_file_extensions, std::wstring(L";"),
                           base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
 
+    const base::FilePath executable_name =
+        ShellUtil::GetApplicationPathForProgId(prog_id).BaseName();
+
     // Delete file-extension-handling registry entries for each file extension.
     for (const auto& file_extension : file_extensions) {
       std::wstring extension_path(kRegClasses);
@@ -2505,19 +2508,53 @@
       extension_path.append(file_extension);
 
       // Delete the default value at
-      // HKEY_CURRENT_USER\Software\Classes\.<extension> if set to |prog_id|;
-      // this unregisters |prog_id| as the default handler for |file_extension|.
+      // HKEY_CURRENT_USER\Software\Classes\|file_extension| if set to
+      // |prog_id|; this unregisters |prog_id| as the default handler for
+      // |file_extension|.
       InstallUtil::DeleteRegistryValueIf(
           HKEY_CURRENT_USER, extension_path.c_str(), WorkItem::kWow64Default,
           L"", InstallUtil::ValueEquals(prog_id));
 
       // Delete value |prog_id| at
-      // HKEY_CURRENT_USER\Software\Classes\.<extension>\OpenWithProgids;
+      // HKEY_CURRENT_USER\Software\Classes\|file_extension|\OpenWithProgids;
       // this removes |prog_id| from the list of handlers for |file_extension|.
       extension_path.push_back(base::FilePath::kSeparators[0]);
       extension_path.append(ShellUtil::kRegOpenWithProgids);
       InstallUtil::DeleteRegistryValue(HKEY_CURRENT_USER, extension_path,
                                        WorkItem::kWow64Default, prog_id);
+
+      // Delete values at
+      // HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\
+      // FileExts\|file_extension|. These are set by Windows the first time a
+      // user opens the Open With menu after installation.
+      // TODO(https://crbug.com/1177401): confirm that this is fixed in Windows
+      // version 10.0.19043, and delete these only on older versions if so.
+      std::wstring extension_cache_path(
+          L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts");
+      extension_cache_path.push_back(base::FilePath::kSeparators[0]);
+      extension_cache_path.append(file_extension);
+      extension_cache_path.push_back(base::FilePath::kSeparators[0]);
+      // Delete value |prog_id| at ...FileExts\|file_extension|\OpenWithProgids;
+      // this removes |prog_id| from the Open With menu for |file_extension|.
+      std::wstring extension_cache_progids_path(extension_cache_path);
+      extension_cache_progids_path.append(ShellUtil::kRegOpenWithProgids);
+      InstallUtil::DeleteRegistryValue(HKEY_CURRENT_USER,
+                                       extension_cache_progids_path,
+                                       WorkItem::kWow64Default, prog_id);
+      // Delete value containing |executable_name| at
+      // ...FileExts\|file_extension|\OpenWithList; this removes
+      // |executable_name| from the cache of file handlers for |file_extension|.
+      std::wstring extension_cache_list_path(extension_cache_path);
+      extension_cache_list_path.append(L"OpenWithList");
+      for (base::win::RegistryValueIterator iter(
+               HKEY_CURRENT_USER, extension_cache_list_path.c_str(),
+               WorkItem::kWow64Default);
+           iter.Valid(); ++iter) {
+        InstallUtil::DeleteRegistryValueIf(
+            HKEY_CURRENT_USER, extension_cache_list_path.c_str(),
+            WorkItem::kWow64Default, iter.Name(),
+            InstallUtil::ValueEquals(executable_name.value()));
+      }
     }
   }
 
diff --git a/chrome/installer/util/shell_util_unittest.cc b/chrome/installer/util/shell_util_unittest.cc
index 608fd05f..7d1e5860 100644
--- a/chrome/installer/util/shell_util_unittest.cc
+++ b/chrome/installer/util/shell_util_unittest.cc
@@ -941,12 +941,32 @@
   ASSERT_TRUE(ShellUtil::AddFileAssociations(
       kTestProgid, OpenCommand(), kTestApplicationName, kTestFileTypeName,
       base::FilePath(kTestIconPath), FileExtensions()));
+  // Create cached file-association entries. In practice, these are created by
+  // Windows when the Open With menu is first opened.
+  base::win::RegKey key;
+  constexpr wchar_t kExtensionCacheProgidsPath[] =
+      L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\"
+      L".test1\\OpenWithProgids";
+  constexpr wchar_t kExtensionCacheListPath[] =
+      L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\"
+      L".test1\\OpenWithList";
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Create(HKEY_CURRENT_USER, kExtensionCacheProgidsPath,
+                       KEY_ALL_ACCESS));
+  ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER,
+                                      kExtensionCacheListPath, KEY_ALL_ACCESS));
+  constexpr wchar_t kApplicationPath[] = L"test.exe";
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Open(HKEY_CURRENT_USER, kExtensionCacheProgidsPath, KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kTestProgid, L""));
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Open(HKEY_CURRENT_USER, kExtensionCacheListPath, KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(L"a", kApplicationPath));
 
   // Delete them.
   EXPECT_TRUE(ShellUtil::DeleteFileAssociations(kTestProgid));
 
   // The class key should have been completely deleted.
-  base::win::RegKey key;
   std::wstring value;
   ASSERT_NE(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER,
                                     L"Software\\Classes\\TestApp", KEY_READ));
@@ -971,6 +991,16 @@
                                     L"Software\\Classes\\.test2", KEY_READ));
   EXPECT_EQ(ERROR_SUCCESS, key.ReadValue(L"", &value));
   EXPECT_EQ(L"SomeOtherApp", value);
+
+  // Windows' cached file-association entries should have been deleted.
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Open(HKEY_CURRENT_USER, kExtensionCacheProgidsPath, KEY_READ));
+  EXPECT_FALSE(key.HasValue(kTestProgid));
+  for (base::win::RegistryValueIterator iter(
+           HKEY_CURRENT_USER, kExtensionCacheListPath, WorkItem::kWow64Default);
+       iter.Valid(); ++iter) {
+    EXPECT_NE(0, wcscmp(iter.Value(), kApplicationPath));
+  }
 }
 
 TEST_F(ShellUtilRegistryTest, AddApplicationClass) {
diff --git a/chrome/renderer/extensions/platform_keys_natives.cc b/chrome/renderer/extensions/platform_keys_natives.cc
index 22551ad..f1f6e46 100644
--- a/chrome/renderer/extensions/platform_keys_natives.cc
+++ b/chrome/renderer/extensions/platform_keys_natives.cc
@@ -68,7 +68,7 @@
             rsa_hashed_key_gen->PublicExponent();
         v8::Local<v8::ArrayBuffer> buffer =
             v8::ArrayBuffer::New(isolate, public_exponent.size());
-        memcpy(buffer->GetContents().Data(), public_exponent.Data(),
+        memcpy(buffer->GetBackingStore()->Data(), public_exponent.Data(),
                public_exponent.size());
         builder.Set("publicExponent", buffer);
 
diff --git a/chrome/renderer/media/chrome_speech_recognition_client.cc b/chrome/renderer/media/chrome_speech_recognition_client.cc
index ae38c3a8..3308dfe1 100644
--- a/chrome/renderer/media/chrome_speech_recognition_client.cc
+++ b/chrome/renderer/media/chrome_speech_recognition_client.cc
@@ -107,6 +107,10 @@
                      base::Unretained(this)));
 }
 
+void ChromeSpeechRecognitionClient::OnSpeechRecognitionError() {
+  caption_host_->OnError();
+}
+
 void ChromeSpeechRecognitionClient::SpeechRecognitionAvailabilityChanged(
     bool is_speech_recognition_available) {
   if (is_speech_recognition_available) {
diff --git a/chrome/renderer/media/chrome_speech_recognition_client.h b/chrome/renderer/media/chrome_speech_recognition_client.h
index 27f808e6..34526d7a 100644
--- a/chrome/renderer/media/chrome_speech_recognition_client.h
+++ b/chrome/renderer/media/chrome_speech_recognition_client.h
@@ -59,6 +59,7 @@
   // media::mojom::SpeechRecognitionRecognizerClient
   void OnSpeechRecognitionRecognitionEvent(
       media::mojom::SpeechRecognitionResultPtr result) override;
+  void OnSpeechRecognitionError() override;
 
   // media::mojom::SpeechRecognitionAvailabilityObserver
   void SpeechRecognitionAvailabilityChanged(
diff --git a/chrome/services/speech/soda/soda_client.cc b/chrome/services/speech/soda/soda_client.cc
index 8dfe3463..f56ec17d 100644
--- a/chrome/services/speech/soda/soda_client.cc
+++ b/chrome/services/speech/soda/soda_client.cc
@@ -5,6 +5,7 @@
 #include "chrome/services/speech/soda/soda_client.h"
 
 #include "base/logging.h"
+#include "base/metrics/histogram_functions.h"
 
 namespace soda {
 
@@ -32,16 +33,34 @@
   DCHECK(delete_soda_func_);
   DCHECK(add_audio_func_);
   DCHECK(soda_start_func_);
+
+  if (!lib_.is_valid()) {
+    load_soda_result_ = LoadSodaResultValue::kBinaryInvalid;
+  } else if (!(create_soda_func_ && delete_soda_func_ && add_audio_func_ &&
+               soda_start_func_)) {
+    load_soda_result_ = LoadSodaResultValue::kFunctionPointerInvalid;
+  } else {
+    load_soda_result_ = LoadSodaResultValue::kSuccess;
+  }
+
+  base::UmaHistogramEnumeration("Accessibility.LiveCaption.LoadSodaResult",
+                                load_soda_result_);
 }
 
 NO_SANITIZE("cfi-icall")
 SodaClient::~SodaClient() {
+  if (load_soda_result_ != LoadSodaResultValue::kSuccess)
+    return;
+
   if (IsInitialized())
     delete_soda_func_(soda_async_handle_);
 }
 
 NO_SANITIZE("cfi-icall")
 void SodaClient::AddAudio(const char* audio_buffer, int audio_buffer_size) {
+  if (load_soda_result_ != LoadSodaResultValue::kSuccess)
+    return;
+
   add_audio_func_(soda_async_handle_, audio_buffer, audio_buffer_size);
 }
 
@@ -53,6 +72,9 @@
 void SodaClient::Reset(const SerializedSodaConfig config,
                        int sample_rate,
                        int channel_count) {
+  if (load_soda_result_ != LoadSodaResultValue::kSuccess)
+    return;
+
   if (IsInitialized()) {
     delete_soda_func_(soda_async_handle_);
   }
diff --git a/chrome/services/speech/soda/soda_client.h b/chrome/services/speech/soda/soda_client.h
index d15ae08..a098982 100644
--- a/chrome/services/speech/soda/soda_client.h
+++ b/chrome/services/speech/soda/soda_client.h
@@ -10,6 +10,16 @@
 
 namespace soda {
 
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class LoadSodaResultValue {
+  kUnknown = 0,
+  kSuccess = 1,
+  kBinaryInvalid = 2,
+  kFunctionPointerInvalid = 3,
+  kMaxValue = kFunctionPointerInvalid,
+};
+
 // The client that wraps the plain C-style interface between Chrome and the
 // Speech On-Device API (SODA). Changes to the interface must be backwards
 // compatible and reflected in the Google3-side definition.
@@ -34,6 +44,10 @@
   // Returns a flag indicating whether the client has been initialized.
   bool IsInitialized() { return is_initialized_; }
 
+  bool BinaryLoadedSuccessfully() {
+    return load_soda_result_ == LoadSodaResultValue::kSuccess;
+  }
+
  private:
   base::ScopedNativeLibrary lib_;
 
@@ -52,6 +66,7 @@
   // An opaque handle to the SODA async instance.
   void* soda_async_handle_;
 
+  LoadSodaResultValue load_soda_result_ = LoadSodaResultValue::kUnknown;
   bool is_initialized_;
   int sample_rate_;
   int channel_count_;
diff --git a/chrome/services/speech/speech_recognition_recognizer_impl.cc b/chrome/services/speech/speech_recognition_recognizer_impl.cc
index 29141da7..844b67d 100644
--- a/chrome/services/speech/speech_recognition_recognizer_impl.cc
+++ b/chrome/services/speech/speech_recognition_recognizer_impl.cc
@@ -118,6 +118,9 @@
   if (enable_soda_) {
     DCHECK(base::PathExists(binary_path));
     soda_client_ = std::make_unique<::soda::SodaClient>(binary_path);
+    if (!soda_client_->BinaryLoadedSuccessfully()) {
+      client_remote_->OnSpeechRecognitionError();
+    }
   } else {
     cloud_client_ = std::make_unique<CloudSpeechRecognitionClient>(
         recognition_event_callback(),
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index e16f09fb..aed2b60 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -629,11 +629,11 @@
       "$root_gen_dir/components/components_resources.pak",
       "$root_gen_dir/components/dev_ui_components_resources.pak",
       "$root_out_dir/browser_tests.pak",
+      "//components/test/data/ads_observer/",
       "//components/test/data/payments/",
       "//chrome/test/data/android/customtabs/",
       "//chrome/test/data/banners/",
       "//chrome/test/data/ssl/",
-      "//chrome/test/data/ads_observer/",
       "//content/test/data/",
     ]
   }
@@ -943,6 +943,7 @@
       "//components/test/data/optimization_guide/",
       "//components/test/data/payments/",
       "//components/test/data/ad_tagging/",
+      "//components/test/data/ads_observer/",
       "//components/test/data/subresource_filter/",
       "//components/test/data/translate/",
       "//components/test/data/update_client/",
@@ -5009,6 +5010,7 @@
       "../browser/ui/window_sizer/window_sizer_unittest.cc",
     ]
     sources += [
+      "../browser/apps/app_service/intent_util_unittest.cc",
       "../browser/component_updater/cros_component_installer_chromeos_unittest.cc",
       "../browser/component_updater/metadata_table_chromeos_unittest.cc",
       "../browser/enterprise/reporting/android_app_info_generator_unittest.cc",
diff --git a/chrome/test/base/browser_with_test_window_test.cc b/chrome/test/base/browser_with_test_window_test.cc
index fd094fca..ef2797a5 100644
--- a/chrome/test/base/browser_with_test_window_test.cc
+++ b/chrome/test/base/browser_with_test_window_test.cc
@@ -209,7 +209,7 @@
 }
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-chromeos::ScopedCrosSettingsTestHelper*
+ash::ScopedCrosSettingsTestHelper*
 BrowserWithTestWindowTest::GetCrosSettingsHelper() {
   return &cros_settings_test_helper_;
 }
diff --git a/chrome/test/base/browser_with_test_window_test.h b/chrome/test/base/browser_with_test_window_test.h
index c1a4234..b43da6d 100644
--- a/chrome/test/base/browser_with_test_window_test.h
+++ b/chrome/test/base/browser_with_test_window_test.h
@@ -198,7 +198,7 @@
 #endif
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  chromeos::ScopedCrosSettingsTestHelper* GetCrosSettingsHelper();
+  ash::ScopedCrosSettingsTestHelper* GetCrosSettingsHelper();
   chromeos::StubInstallAttributes* GetInstallAttributes();
 #endif
 
@@ -214,7 +214,7 @@
   std::unique_ptr<content::BrowserTaskEnvironment> task_environment_;
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  chromeos::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
+  ash::ScopedCrosSettingsTestHelper cros_settings_test_helper_;
   chromeos::ScopedTestUserManager test_user_manager_;
 #endif
 
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc
index 349e3645..8aefa81 100644
--- a/chrome/test/base/testing_profile.cc
+++ b/chrome/test/base/testing_profile.cc
@@ -380,9 +380,9 @@
   account_manager->Initialize(profile_path_, GetURLLoaderFactory(),
                               immediate_callback_runner);
   account_manager->SetPrefService(GetPrefs());
-  if (!chromeos::CrosSettings::IsInitialized()) {
+  if (!ash::CrosSettings::IsInitialized()) {
     scoped_cros_settings_test_helper_.reset(
-        new chromeos::ScopedCrosSettingsTestHelper);
+        new ash::ScopedCrosSettingsTestHelper);
   }
   arc::ArcServiceLauncher* launcher = arc::ArcServiceLauncher::Get();
   if (launcher)
@@ -879,7 +879,7 @@
   requested_locale_ = locale;
 }
 
-chromeos::ScopedCrosSettingsTestHelper*
+ash::ScopedCrosSettingsTestHelper*
 TestingProfile::ScopedCrosSettingsTestHelper() {
   return scoped_cros_settings_test_helper_.get();
 }
diff --git a/chrome/test/base/testing_profile.h b/chrome/test/base/testing_profile.h
index cd6a28a..5f1040e 100644
--- a/chrome/test/base/testing_profile.h
+++ b/chrome/test/base/testing_profile.h
@@ -376,7 +376,7 @@
   void ChangeAppLocale(const std::string&, AppLocaleChangedVia) override;
   void OnLogin() override {}
   void InitChromeOSPreferences() override {}
-  chromeos::ScopedCrosSettingsTestHelper* ScopedCrosSettingsTestHelper();
+  ash::ScopedCrosSettingsTestHelper* ScopedCrosSettingsTestHelper();
 
   base::Optional<std::string> requested_locale() { return requested_locale_; }
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
@@ -506,7 +506,7 @@
   base::Optional<OTRProfileID> otr_profile_id_;
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  std::unique_ptr<chromeos::ScopedCrosSettingsTestHelper>
+  std::unique_ptr<ash::ScopedCrosSettingsTestHelper>
       scoped_cros_settings_test_helper_;
 
   base::Optional<std::string> requested_locale_;
diff --git a/chrome/test/data/ads_observer/ad_iframe_writer.js b/chrome/test/data/ads_observer/ad_iframe_writer.js
deleted file mode 100644
index eebd03d..0000000
--- a/chrome/test/data/ads_observer/ad_iframe_writer.js
+++ /dev/null
@@ -1,47 +0,0 @@
-// 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.
-
-// Creates and iframe and appends it to the body element. Make sure the caller
-// has a body element!
-function createAdIframe() {
-    let frame = document.createElement('iframe');
-    document.body.appendChild(frame);
-    return frame;
-}
-
-function createAdIframeWithSrc(src) {
-  let frame = document.createElement('iframe');
-  frame.src = src;
-  document.body.appendChild(frame);
-  return frame;
-}
-
-function createAdIframeAtRect(x, y, width, height) {
-  let frame = document.createElement('iframe');
-  frame.style.border = "0px none transparent";
-  frame.style.overflow = "hidden";
-  frame.style.position = "fixed";
-  frame.style.left = x;
-  frame.style.top = y;
-  frame.scrolling = "no";
-  frame.frameborder="0";
-  frame.allowTransparency="true";
-  frame.width = width;
-  frame.height = height;
-  document.body.appendChild(frame);
-  return frame;
-}
-
-function createStickyAdIframeAtBottomOfViewport(width, height) {
-  let frame = document.createElement('iframe');
-  frame.style.position = "fixed";
-  frame.style.bottom = "0px";
-  frame.scrolling = "no";
-  frame.width = width;
-  frame.height = height;
-  document.body.appendChild(frame);
-  return frame;
-}
-
-document.scriptExecuted = true;
diff --git a/chrome/test/data/extensions/platform_apps/web_view/speech_recognition_api/guest.js b/chrome/test/data/extensions/platform_apps/web_view/speech_recognition_api/guest.js
index c5c0be6..b54eb65b 100644
--- a/chrome/test/data/extensions/platform_apps/web_view/speech_recognition_api/guest.js
+++ b/chrome/test/data/extensions/platform_apps/web_view/speech_recognition_api/guest.js
@@ -20,7 +20,6 @@
     succeeded = true;
     LOG('r.onstart');
     notifyEmbedder(['recognition', 'onstart', '']);
-    r.abort();
   };
   r.onerror = function() {
     LOG('r.onerror');
diff --git a/chrome/test/data/pdf/test-beep-csp.pdf.mock-http-headers b/chrome/test/data/pdf/test-beep-csp.pdf.mock-http-headers
index c99d095..7a69d5d 100644
--- a/chrome/test/data/pdf/test-beep-csp.pdf.mock-http-headers
+++ b/chrome/test/data/pdf/test-beep-csp.pdf.mock-http-headers
@@ -1,3 +1,3 @@
 HTTP/1.1 200 OK
-content-security-policy: script-source *
+content-security-policy: script-src *
 content-type: application/pdf
diff --git a/chrome/test/data/pdf/test-nobeep-csp.pdf.mock-http-headers b/chrome/test/data/pdf/test-nobeep-csp.pdf.mock-http-headers
index 360f770..67c65be 100644
--- a/chrome/test/data/pdf/test-nobeep-csp.pdf.mock-http-headers
+++ b/chrome/test/data/pdf/test-nobeep-csp.pdf.mock-http-headers
@@ -1,3 +1,3 @@
 HTTP/1.1 200 OK
-content-security-policy: script-source none
+content-security-policy: script-src 'none'
 content-type: application/pdf
diff --git a/chrome/test/data/webui/chromeos/emoji_picker/BUILD.gn b/chrome/test/data/webui/chromeos/emoji_picker/BUILD.gn
index 0a4e90e..cc2a779 100644
--- a/chrome/test/data/webui/chromeos/emoji_picker/BUILD.gn
+++ b/chrome/test/data/webui/chromeos/emoji_picker/BUILD.gn
@@ -6,10 +6,16 @@
 
 js_type_check("closure_compile") {
   is_polymer3 = true
-  closure_flags = default_closure_args + [
+  closure_flags = default_closure_args + mojom_js_args + [
                     "browser_resolver_prefix_replacements=\"chrome://emoji-picker/=../../chrome/browser/resources/chromeos/emoji_picker/\"",
                     "js_module_root=../../chrome/test/data/webui/",
                     "js_module_root=./gen/chrome/test/data/webui/",
+                    "js_module_root=" + rebase_path(
+                            "//chrome/browser/resources/chromeos/emoji_picker/",
+                            root_build_dir),
+                    "js_module_root=" + rebase_path(
+                            "$root_gen_dir/mojom-webui/chrome/browser/ui/webui/chromeos/emoji",
+                            root_build_dir),
                   ]
   deps = [
     ":emoji_picker_store_test",
diff --git a/chrome/test/data/webui/cr_components/chromeos/network/network_config_test.js b/chrome/test/data/webui/cr_components/chromeos/network/network_config_test.js
index 9f7726e..605f0f1 100644
--- a/chrome/test/data/webui/cr_components/chromeos/network/network_config_test.js
+++ b/chrome/test/data/webui/cr_components/chromeos/network/network_config_test.js
@@ -137,6 +137,19 @@
         assertTrue(networkConfig.propertiesSent_);
       });
     });
+
+    test('Remove error text when input key is pressed', function() {
+      return flushAsync().then(() => {
+        networkConfig.error = 'bad-passphrase';
+        let passwordInput = networkConfig.$$('#wifi-passphrase');
+        assertTrue(!!passwordInput);
+        assertTrue(!!networkConfig.error);
+
+        passwordInput.fire('keypress');
+        Polymer.dom.flush();
+        assertFalse(!!networkConfig.error);
+      });
+    });
   });
 
   suite('Share', function() {
diff --git a/chrome/test/data/webui/new_tab_page/modules/drive/module_test.js b/chrome/test/data/webui/new_tab_page/modules/drive/module_test.js
index f2b67d1..1d54d2b8 100644
--- a/chrome/test/data/webui/new_tab_page/modules/drive/module_test.js
+++ b/chrome/test/data/webui/new_tab_page/modules/drive/module_test.js
@@ -28,21 +28,21 @@
           justificationText: 'Edited last week',
           title: 'Foo',
           id: '123',
-          type: drive.mojom.FileType.kDoc,
+          mimeType: 'application/vnd.google-apps.spreadsheet',
           url: {url: 'https://foo.com'},
         },
         {
           justificationText: 'Edited today',
           title: 'Bar',
           id: '234',
-          type: drive.mojom.FileType.kSheet,
+          mimeType: 'application/vnd.google-apps.document',
           url: {url: 'https://bar.com'},
         },
         {
           justificationText: 'Created today',
           title: 'Caz',
           id: '345',
-          type: drive.mojom.FileType.kOther,
+          mimeType: 'application/vnd.google-apps.presentation',
           url: {url: 'https://caz.com'},
         }
       ]
@@ -63,6 +63,15 @@
     assertEquals(
         'Edited today',
         items[1].querySelector('.file-description').textContent);
+    assertEquals(
+        'https://drive-thirdparty.googleusercontent.com/128/type/application/vnd.google-apps.spreadsheet',
+        items[0].querySelector('img').autoSrc);
+    assertEquals(
+        'https://drive-thirdparty.googleusercontent.com/128/type/application/vnd.google-apps.document',
+        items[1].querySelector('img').autoSrc);
+    assertEquals(
+        'https://drive-thirdparty.googleusercontent.com/128/type/application/vnd.google-apps.presentation',
+        items[2].querySelector('img').autoSrc);
     const urls = module.shadowRoot.querySelectorAll('.file');
     assertEquals('https://foo.com/', urls[0].href);
     assertEquals('https://bar.com/', urls[1].href);
@@ -76,7 +85,7 @@
                          justification: 'edited',
                          title: 'foo',
                          id: '123',
-                         type: drive.mojom.FileType.kDoc
+                         mimeType: 'application/vnd.google-apps.document',
                        }))
     }));
 
diff --git a/chromeos/components/camera_app_ui/resources/js/views/camera/mode/index.js b/chromeos/components/camera_app_ui/resources/js/views/camera/mode/index.js
index fc90a9f..7ef142c3 100644
--- a/chromeos/components/camera_app_ui/resources/js/views/camera/mode/index.js
+++ b/chromeos/components/camera_app_ui/resources/js/views/camera/mode/index.js
@@ -380,6 +380,7 @@
   async updateMode(mode, factory, stream, facing, deviceId, captureResolution) {
     if (this.current !== null) {
       await this.current.stopCapture();
+      await this.disableSaveMetadata_();
     }
     this.updateModeUI_(mode);
     this.current = factory.produce();
diff --git a/chromeos/components/camera_app_ui/resources/js/views/camera/preview.js b/chromeos/components/camera_app_ui/resources/js/views/camera/preview.js
index 40382058..3abbba7 100644
--- a/chromeos/components/camera_app_ui/resources/js/views/camera/preview.js
+++ b/chromeos/components/camera_app_ui/resources/js/views/camera/preview.js
@@ -257,6 +257,7 @@
     }
     // Pause video element to avoid black frames during transition.
     this.video_.pause();
+    this.disableShowMetadata_();
     if (this.stream_ !== null) {
       const track = this.stream_.getVideoTracks()[0];
       const {deviceId} = track.getSettings();
diff --git a/chromeos/components/camera_app_ui/resources/strings/camera_strings_gu.xtb b/chromeos/components/camera_app_ui/resources/strings/camera_strings_gu.xtb
index f8530c97..374a7ebb 100644
--- a/chromeos/components/camera_app_ui/resources/strings/camera_strings_gu.xtb
+++ b/chromeos/components/camera_app_ui/resources/strings/camera_strings_gu.xtb
@@ -88,7 +88,7 @@
 <translation id="8145038249676204903">ફોટો લેવા માટે સ્વિચ કરો</translation>
 <translation id="8239780215768881278">વીડિયો સ્નૅપશૉટ લો</translation>
 <translation id="8261506727792406068">ડિલીટ કરો</translation>
-<translation id="8428213095426709021">સેટિંગ્સ</translation>
+<translation id="8428213095426709021">સેટિંગ</translation>
 <translation id="8687491812650032292">HD <ph name="HEIGHT" />p (<ph name="WIDTH" />:<ph name="HEIGHT" />)</translation>
 <translation id="8732462232047530626">મેટાડેટાનું પ્રીવ્યૂ કરો</translation>
 <translation id="8815966864175525708">પોર્ટ્રેટ ફોટો લેવા માટે સ્વિચ કરો</translation>
diff --git a/chromeos/components/diagnostics_ui/backend/routine_log_unittest.cc b/chromeos/components/diagnostics_ui/backend/routine_log_unittest.cc
index d5d9921b..6a0be5f 100644
--- a/chromeos/components/diagnostics_ui/backend/routine_log_unittest.cc
+++ b/chromeos/components/diagnostics_ui/backend/routine_log_unittest.cc
@@ -61,7 +61,7 @@
       GetLogLineContents(first_line);
 
   ASSERT_EQ(3u, first_line_contents.size());
-  EXPECT_EQ("RoutineType::kCpuStress", first_line_contents[1]);
+  EXPECT_EQ("kCpuStress", first_line_contents[1]);
   EXPECT_EQ("Started", first_line_contents[2]);
 }
 
@@ -80,7 +80,7 @@
       GetLogLineContents(first_line);
 
   ASSERT_EQ(3u, first_line_contents.size());
-  EXPECT_EQ("RoutineType::kMemory", first_line_contents[1]);
+  EXPECT_EQ("kMemory", first_line_contents[1]);
   EXPECT_EQ("Started", first_line_contents[2]);
 
   const std::string second_line = log_lines[1];
@@ -88,8 +88,8 @@
       GetLogLineContents(second_line);
 
   ASSERT_EQ(3u, second_line_contents.size());
-  EXPECT_EQ("RoutineType::kMemory", second_line_contents[1]);
-  EXPECT_EQ("StandardRoutineResult::kTestPassed", second_line_contents[2]);
+  EXPECT_EQ("kMemory", second_line_contents[1]);
+  EXPECT_EQ("kTestPassed", second_line_contents[2]);
 }
 
 TEST_F(RoutineLogTest, Cancelled) {
diff --git a/chromeos/components/diagnostics_ui/backend/session_log_handler_unittest.cc b/chromeos/components/diagnostics_ui/backend/session_log_handler_unittest.cc
index e510136..8a9bb118 100644
--- a/chromeos/components/diagnostics_ui/backend/session_log_handler_unittest.cc
+++ b/chromeos/components/diagnostics_ui/backend/session_log_handler_unittest.cc
@@ -240,7 +240,7 @@
       GetLogLineContents(log_lines[11]);
   ASSERT_EQ(3u, first_routine_log_line_contents.size());
   // first_routine_log_line_contents[0] is ignored because it's a timestamp.
-  EXPECT_EQ("RoutineType::kCpuStress", first_routine_log_line_contents[1]);
+  EXPECT_EQ("kCpuStress", first_routine_log_line_contents[1]);
   EXPECT_EQ("Started", first_routine_log_line_contents[2]);
 }
 
@@ -284,4 +284,4 @@
 }
 
 }  // namespace diagnostics
-}  // namespace chromeos
\ No newline at end of file
+}  // namespace chromeos
diff --git a/chromeos/components/diagnostics_ui/backend/system_routine_controller_unittest.cc b/chromeos/components/diagnostics_ui/backend/system_routine_controller_unittest.cc
index bc03f4d0..f25fd4b 100644
--- a/chromeos/components/diagnostics_ui/backend/system_routine_controller_unittest.cc
+++ b/chromeos/components/diagnostics_ui/backend/system_routine_controller_unittest.cc
@@ -697,7 +697,7 @@
 
   std::vector<std::string> log_line_contents = GetLogLineContents(log_lines[0]);
   ASSERT_EQ(3u, log_line_contents.size());
-  EXPECT_EQ("RoutineType::kCpuStress", log_line_contents[1]);
+  EXPECT_EQ("kCpuStress", log_line_contents[1]);
   EXPECT_EQ("Started", log_line_contents[2]);
 
   // Update the status on cros_healthd.
@@ -717,8 +717,8 @@
 
   log_line_contents = GetLogLineContents(log_lines[1]);
   ASSERT_EQ(3u, log_line_contents.size());
-  EXPECT_EQ("RoutineType::kCpuStress", log_line_contents[1]);
-  EXPECT_EQ("StandardRoutineResult::kTestPassed", log_line_contents[2]);
+  EXPECT_EQ("kCpuStress", log_line_contents[1]);
+  EXPECT_EQ("kTestPassed", log_line_contents[2]);
 
   // Start another routine and cancel it and verify the cancellation appears in
   // logs. Use a unique_ptr for the RoutineRunner so we can easily destroy it.
diff --git a/chromeos/lacros/BUILD.gn b/chromeos/lacros/BUILD.gn
index d3f1fd4..69988aba 100644
--- a/chromeos/lacros/BUILD.gn
+++ b/chromeos/lacros/BUILD.gn
@@ -40,7 +40,8 @@
   lacros_tast_test(target_name) {
     # TODO(crbug.com/1158590): use --attr-expr instead of hard-coding the tests.
     tast_tests = [
-      "lacros.AudioPlay",
+      # TODO(crbug.com/1186917): Enable this test again.
+      # "lacros.AudioPlay",
       "lacros.AppLauncherLaunch",
       "lacros.Basic",
       "lacros.ShelfLaunch",
diff --git a/chromeos/services/assistant/public/cpp/migration/BUILD.gn b/chromeos/services/assistant/public/cpp/migration/BUILD.gn
index 994af38..bf78dc2 100644
--- a/chromeos/services/assistant/public/cpp/migration/BUILD.gn
+++ b/chromeos/services/assistant/public/cpp/migration/BUILD.gn
@@ -35,8 +35,6 @@
   sources = [
     "fake_assistant_manager_service_delegate.cc",
     "fake_assistant_manager_service_delegate.h",
-    "fake_platform_delegate.cc",
-    "fake_platform_delegate.h",
   ]
 
   deps = [
diff --git a/chromeos/services/libassistant/BUILD.gn b/chromeos/services/libassistant/BUILD.gn
index d51590e..5d04b0d 100644
--- a/chromeos/services/libassistant/BUILD.gn
+++ b/chromeos/services/libassistant/BUILD.gn
@@ -163,6 +163,8 @@
   testonly = true
 
   sources = [
+    "test_support/fake_platform_delegate.cc",
+    "test_support/fake_platform_delegate.h",
     "test_support/libassistant_service_tester.cc",
     "test_support/libassistant_service_tester.h",
   ]
diff --git a/chromeos/services/libassistant/audio_input_controller_unittest.cc b/chromeos/services/libassistant/audio_input_controller_unittest.cc
index acccf08..4dffead 100644
--- a/chromeos/services/libassistant/audio_input_controller_unittest.cc
+++ b/chromeos/services/libassistant/audio_input_controller_unittest.cc
@@ -8,9 +8,9 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "chromeos/services/assistant/public/cpp/features.h"
-#include "chromeos/services/assistant/public/cpp/migration/fake_platform_delegate.h"
 #include "chromeos/services/libassistant/audio/audio_input_impl.h"
 #include "chromeos/services/libassistant/public/mojom/audio_input_controller.mojom.h"
+#include "chromeos/services/libassistant/test_support/fake_platform_delegate.h"
 #include "media/audio/audio_device_description.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
diff --git a/chromeos/services/libassistant/network_provider_impl_unittest.cc b/chromeos/services/libassistant/network_provider_impl_unittest.cc
index 0df0449..29b1379 100644
--- a/chromeos/services/libassistant/network_provider_impl_unittest.cc
+++ b/chromeos/services/libassistant/network_provider_impl_unittest.cc
@@ -9,7 +9,7 @@
 
 #include "base/macros.h"
 #include "base/test/task_environment.h"
-#include "chromeos/services/assistant/public/cpp/migration/fake_platform_delegate.h"
+#include "chromeos/services/libassistant/test_support/fake_platform_delegate.h"
 #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom-forward.h"
 #include "chromeos/services/network_config/public/mojom/network_types.mojom-forward.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromeos/services/libassistant/power_manager_provider_impl_unittest.cc b/chromeos/services/libassistant/power_manager_provider_impl_unittest.cc
index 4b56fdb..6c3fb4a 100644
--- a/chromeos/services/libassistant/power_manager_provider_impl_unittest.cc
+++ b/chromeos/services/libassistant/power_manager_provider_impl_unittest.cc
@@ -7,7 +7,7 @@
 #include "base/run_loop.h"
 #include "base/test/task_environment.h"
 #include "chromeos/dbus/power/fake_power_manager_client.h"
-#include "chromeos/services/assistant/public/cpp/migration/fake_platform_delegate.h"
+#include "chromeos/services/libassistant/test_support/fake_platform_delegate.h"
 #include "services/device/public/cpp/test/test_wake_lock_provider.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/chromeos/services/libassistant/system_provider_impl_unittest.cc b/chromeos/services/libassistant/system_provider_impl_unittest.cc
index 9a84d195..9e97a23 100644
--- a/chromeos/services/libassistant/system_provider_impl_unittest.cc
+++ b/chromeos/services/libassistant/system_provider_impl_unittest.cc
@@ -8,8 +8,8 @@
 #include <utility>
 
 #include "base/test/task_environment.h"
-#include "chromeos/services/assistant/public/cpp/migration/fake_platform_delegate.h"
 #include "chromeos/services/libassistant/power_manager_provider_impl.h"
+#include "chromeos/services/libassistant/test_support/fake_platform_delegate.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "services/device/public/mojom/battery_monitor.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromeos/services/assistant/public/cpp/migration/fake_platform_delegate.cc b/chromeos/services/libassistant/test_support/fake_platform_delegate.cc
similarity index 89%
rename from chromeos/services/assistant/public/cpp/migration/fake_platform_delegate.cc
rename to chromeos/services/libassistant/test_support/fake_platform_delegate.cc
index c4e2aed..ab358d2 100644
--- a/chromeos/services/assistant/public/cpp/migration/fake_platform_delegate.cc
+++ b/chromeos/services/libassistant/test_support/fake_platform_delegate.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 "chromeos/services/assistant/public/cpp/migration/fake_platform_delegate.h"
+#include "chromeos/services/libassistant/test_support/fake_platform_delegate.h"
 
 namespace chromeos {
 namespace assistant {
diff --git a/chromeos/services/assistant/public/cpp/migration/fake_platform_delegate.h b/chromeos/services/libassistant/test_support/fake_platform_delegate.h
similarity index 84%
rename from chromeos/services/assistant/public/cpp/migration/fake_platform_delegate.h
rename to chromeos/services/libassistant/test_support/fake_platform_delegate.h
index 6c4bf63f..9433562 100644
--- a/chromeos/services/assistant/public/cpp/migration/fake_platform_delegate.h
+++ b/chromeos/services/libassistant/test_support/fake_platform_delegate.h
@@ -2,18 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMEOS_SERVICES_ASSISTANT_PUBLIC_CPP_MIGRATION_FAKE_PLATFORM_DELEGATE_H_
-#define CHROMEOS_SERVICES_ASSISTANT_PUBLIC_CPP_MIGRATION_FAKE_PLATFORM_DELEGATE_H_
+#ifndef CHROMEOS_SERVICES_LIBASSISTANT_TEST_SUPPORT_FAKE_PLATFORM_DELEGATE_H_
+#define CHROMEOS_SERVICES_LIBASSISTANT_TEST_SUPPORT_FAKE_PLATFORM_DELEGATE_H_
 
 #include "chromeos/services/libassistant/public/mojom/platform_delegate.mojom.h"
 
-#include "base/component_export.h"
-
 namespace chromeos {
 namespace assistant {
 
-class COMPONENT_EXPORT(ASSISTANT_SERVICE_MIGRATION_TEST_SUPPORT)
-    FakePlatformDelegate
+class FakePlatformDelegate
     : public chromeos::libassistant::mojom::PlatformDelegate {
  public:
   FakePlatformDelegate();
@@ -63,4 +60,4 @@
 }  // namespace assistant
 }  // namespace chromeos
 
-#endif  // CHROMEOS_SERVICES_ASSISTANT_PUBLIC_CPP_MIGRATION_FAKE_PLATFORM_DELEGATE_H_
+#endif  // CHROMEOS_SERVICES_LIBASSISTANT_TEST_SUPPORT_FAKE_PLATFORM_DELEGATE_H_
diff --git a/chromeos/settings/cros_settings_names.h b/chromeos/settings/cros_settings_names.h
index 8fd2fa2..4154ba5b 100644
--- a/chromeos/settings/cros_settings_names.h
+++ b/chromeos/settings/cros_settings_names.h
@@ -295,9 +295,12 @@
 
 // TODO(https://crbug.com/1164001): remove when migrated to ash/components/.
 namespace ash {
+using ::chromeos::kAccountsPrefAllowGuest;
+using ::chromeos::kAccountsPrefAllowNewUser;
 using ::chromeos::kAccountsPrefDeviceLocalAccountAutoLoginBailoutEnabled;
 using ::chromeos::kAccountsPrefDeviceLocalAccountAutoLoginDelay;
 using ::chromeos::kAccountsPrefDeviceLocalAccountAutoLoginId;
+using ::chromeos::kAccountsPrefDeviceLocalAccountPromptForNetworkWhenOffline;
 using ::chromeos::kAccountsPrefDeviceLocalAccounts;
 using ::chromeos::kAccountsPrefDeviceLocalAccountsKeyArcKioskAction;
 using ::chromeos::kAccountsPrefDeviceLocalAccountsKeyArcKioskClass;
@@ -305,12 +308,114 @@
 using ::chromeos::kAccountsPrefDeviceLocalAccountsKeyArcKioskPackage;
 using ::chromeos::kAccountsPrefDeviceLocalAccountsKeyId;
 using ::chromeos::kAccountsPrefDeviceLocalAccountsKeyKioskAppId;
+using ::chromeos::kAccountsPrefDeviceLocalAccountsKeyKioskAppUpdateURL;
 using ::chromeos::kAccountsPrefDeviceLocalAccountsKeyType;
+using ::chromeos::kAccountsPrefDeviceLocalAccountsKeyWebKioskIconUrl;
+using ::chromeos::kAccountsPrefDeviceLocalAccountsKeyWebKioskTitle;
+using ::chromeos::kAccountsPrefDeviceLocalAccountsKeyWebKioskUrl;
+using ::chromeos::kAccountsPrefEphemeralUsersEnabled;
+using ::chromeos::kAccountsPrefFamilyLinkAccountsAllowed;
+using ::chromeos::kAccountsPrefLoginScreenDomainAutoComplete;
+using ::chromeos::kAccountsPrefShowUserNamesOnSignIn;
+using ::chromeos::kAccountsPrefSupervisedUsersEnabled;
+using ::chromeos::kAccountsPrefTransferSAMLCookies;
+using ::chromeos::kAccountsPrefUsers;
+using ::chromeos::kAllowBluetooth;
+using ::chromeos::kAllowedConnectionTypesForUpdate;
+using ::chromeos::kAllowRedeemChromeOsRegistrationOffers;
+using ::chromeos::kAttestationForContentProtectionEnabled;
+using ::chromeos::kBorealisAllowedForDevice;
+using ::chromeos::kCastReceiverName;
+using ::chromeos::kCrosSettingsPrefix;
+using ::chromeos::kDeviceAttestationEnabled;
+using ::chromeos::kDeviceAutoUpdateTimeRestrictions;
+using ::chromeos::kDeviceChannelDowngradeBehavior;
+using ::chromeos::kDeviceCrostiniArcAdbSideloadingAllowed;
 using ::chromeos::kDeviceDisabled;
 using ::chromeos::kDeviceDisabledMessage;
+using ::chromeos::kDeviceDisplayResolution;
+using ::chromeos::kDeviceDockMacAddressSource;
+using ::chromeos::kDeviceHostnameTemplate;
+using ::chromeos::kDeviceLoginScreenInputMethods;
+using ::chromeos::kDeviceLoginScreenLocales;
+using ::chromeos::kDeviceLoginScreenSystemInfoEnforced;
+using ::chromeos::kDeviceMinimumVersion;
+using ::chromeos::kDeviceMinimumVersionAueMessage;
+using ::chromeos::kDeviceOffHours;
+using ::chromeos::kDeviceOwner;
+using ::chromeos::kDevicePeripheralDataAccessEnabled;
+using ::chromeos::kDevicePowerwashAllowed;
+using ::chromeos::kDevicePrintersAccessMode;
+using ::chromeos::kDevicePrintersAllowlist;
+using ::chromeos::kDevicePrintersBlocklist;
+using ::chromeos::kDeviceQuirksDownloadEnabled;
+using ::chromeos::kDeviceRebootOnUserSignout;
+using ::chromeos::kDeviceScheduledUpdateCheck;
+using ::chromeos::kDeviceSecondFactorAuthenticationMode;
+using ::chromeos::kDeviceShowLowDiskSpaceNotification;
+using ::chromeos::kDeviceShowNumericKeyboardForPassword;
+using ::chromeos::kDeviceUnaffiliatedCrostiniAllowed;
+using ::chromeos::kDeviceWebBasedAttestationAllowedUrls;
+using ::chromeos::kDeviceWiFiAllowed;
+using ::chromeos::kDeviceWilcoDtcAllowed;
+using ::chromeos::kDisplayRotationDefault;
+using ::chromeos::kExtensionCacheSize;
+using ::chromeos::kFeatureFlags;
+using ::chromeos::kHeartbeatEnabled;
+using ::chromeos::kHeartbeatFrequency;
+using ::chromeos::kLoginAuthenticationBehavior;
+using ::chromeos::kLoginVideoCaptureAllowedUrls;
+using ::chromeos::kPluginVmAllowed;
+using ::chromeos::kPluginVmLicenseKey;
+using ::chromeos::kPolicyMissingMitigationMode;
+using ::chromeos::kRebootOnShutdown;
+using ::chromeos::kReleaseChannel;
+using ::chromeos::kReleaseChannelDelegated;
+using ::chromeos::kReleaseLtsTag;
+using ::chromeos::kReportDeviceActivityTimes;
+using ::chromeos::kReportDeviceAppInfo;
+using ::chromeos::kReportDeviceBacklightInfo;
+using ::chromeos::kReportDeviceBluetoothInfo;
+using ::chromeos::kReportDeviceBoardStatus;
+using ::chromeos::kReportDeviceBootMode;
+using ::chromeos::kReportDeviceCpuInfo;
+using ::chromeos::kReportDeviceCrashReportInfo;
+using ::chromeos::kReportDeviceFanInfo;
+using ::chromeos::kReportDeviceGraphicsStatus;
+using ::chromeos::kReportDeviceHardwareStatus;
+using ::chromeos::kReportDeviceLocation;
+using ::chromeos::kReportDeviceMemoryInfo;
+using ::chromeos::kReportDeviceNetworkInterfaces;
+using ::chromeos::kReportDevicePowerStatus;
+using ::chromeos::kReportDevicePrintJobs;
+using ::chromeos::kReportDeviceSessionStatus;
+using ::chromeos::kReportDeviceStorageStatus;
+using ::chromeos::kReportDeviceSystemInfo;
+using ::chromeos::kReportDeviceTimezoneInfo;
+using ::chromeos::kReportDeviceUsers;
+using ::chromeos::kReportDeviceVersionInfo;
+using ::chromeos::kReportDeviceVpdInfo;
+using ::chromeos::kReportOsUpdateStatus;
+using ::chromeos::kReportRunningKioskApp;
+using ::chromeos::kReportUploadFrequency;
+using ::chromeos::kSamlLoginAuthenticationType;
+using ::chromeos::kServiceAccountIdentity;
+using ::chromeos::kSignedDataRoamingEnabled;
+using ::chromeos::kStatsReportingPref;
+using ::chromeos::kSystemLogUploadEnabled;
+using ::chromeos::kSystemProxySettings;
 using ::chromeos::kSystemTimezone;
 using ::chromeos::kSystemTimezonePolicy;
 using ::chromeos::kSystemUse24HourClock;
+using ::chromeos::kTargetVersionPrefix;
+using ::chromeos::kTPMFirmwareUpdateSettings;
+using ::chromeos::kUnaffiliatedArcAllowed;
+using ::chromeos::kUpdateDisabled;
+using ::chromeos::kUsbDetachableAllowlist;
+using ::chromeos::kUsbDetachableAllowlistKeyPid;
+using ::chromeos::kUsbDetachableAllowlistKeyVid;
+using ::chromeos::kVariationsRestrictParameter;
+using ::chromeos::kVirtualMachinesAllowed;
 }  // namespace ash
 
 #endif  // CHROMEOS_SETTINGS_CROS_SETTINGS_NAMES_H_
diff --git a/chromeos/settings/system_settings_provider.h b/chromeos/settings/system_settings_provider.h
index 258904f..977f9d8 100644
--- a/chromeos/settings/system_settings_provider.h
+++ b/chromeos/settings/system_settings_provider.h
@@ -50,4 +50,9 @@
 
 }  // namespace chromeos
 
+// TODO(https://crbug.com/1164001): remove when moved to ash.
+namespace ash {
+using ::chromeos::SystemSettingsProvider;
+}  // namespace ash
+
 #endif  // CHROMEOS_SETTINGS_SYSTEM_SETTINGS_PROVIDER_H_
diff --git a/chromeos/strings/chromeos_strings_ar.xtb b/chromeos/strings/chromeos_strings_ar.xtb
index af1ac57..0d757fb 100644
--- a/chromeos/strings/chromeos_strings_ar.xtb
+++ b/chromeos/strings/chromeos_strings_ar.xtb
@@ -253,7 +253,7 @@
 <translation id="6472207088655375767">‏كلمة المرور لمرة واحدة (OTP)</translation>
 <translation id="6480327114083866287">تتم الإدارة من خلال <ph name="MANAGER" /></translation>
 <translation id="649050271426829538">توقّفت الطابعة - الورق مكدّس</translation>
-<translation id="6516990319416533844">لاختبار معدّل شحن البطارية، عليك استهلاك طاقتها في فترة قصيرة.</translation>
+<translation id="6516990319416533844">لاختبار معدّل شحن البطارية، عليك استهلاك نسبة من طاقتها في فترة قصيرة.</translation>
 <translation id="6517239166834772319">استكشاف</translation>
 <translation id="6527081081771465939">‏بروتوكول حماية شبكة Wi-Fi غير معروف.</translation>
 <translation id="65587193855025101">المسطَّح</translation>
diff --git a/chromeos/strings/chromeos_strings_de.xtb b/chromeos/strings/chromeos_strings_de.xtb
index 22b920f..a577db6 100644
--- a/chromeos/strings/chromeos_strings_de.xtb
+++ b/chromeos/strings/chromeos_strings_de.xtb
@@ -253,6 +253,7 @@
 <translation id="6472207088655375767">OTP</translation>
 <translation id="6480327114083866287">Verwaltet von <ph name="MANAGER" /></translation>
 <translation id="649050271426829538">Angehalten – Papierstau</translation>
+<translation id="6516990319416533844">Wenn Sie die Aufladegeschwindigkeit Ihres Akkus testen möchten, warten Sie zuerst, bis er ein wenig entladen ist</translation>
 <translation id="6517239166834772319">Entdecken</translation>
 <translation id="6527081081771465939">Unbekanntes WLAN-Sicherheitsprotokoll</translation>
 <translation id="65587193855025101">Flachbett</translation>
diff --git a/chromeos/strings/chromeos_strings_gu.xtb b/chromeos/strings/chromeos_strings_gu.xtb
index eaedcf8..efe1cfd 100644
--- a/chromeos/strings/chromeos_strings_gu.xtb
+++ b/chromeos/strings/chromeos_strings_gu.xtb
@@ -75,7 +75,7 @@
 <translation id="2740531572673183784">બરાબર, સમજાઇ ગયું</translation>
 <translation id="2751739896257479635">EAP તબક્કા 2 માટેનું પ્રમાણીકરણ</translation>
 <translation id="2789486458103222910">બરાબર, સમજાઇ ગયું</translation>
-<translation id="2805756323405976993">એપ્સ</translation>
+<translation id="2805756323405976993">ઍપ</translation>
 <translation id="2862104018715411648">તમારા દસ્તાવેજને સ્કૅનર પર મૂકો અને શરૂ કરવા માટે સ્કૅન કરો પસંદ કરો</translation>
 <translation id="2872961005593481000">શટ ડાઉન કરો</translation>
 <translation id="2878387241690264070"><ph name="NUM_SECONDS" /> સેકન્ડમાં <ph name="RATE" /> ડિસ્ચાર્જ.</translation>
diff --git a/chromeos/strings/chromeos_strings_pa.xtb b/chromeos/strings/chromeos_strings_pa.xtb
index 08389ec3..5bc07bef 100644
--- a/chromeos/strings/chromeos_strings_pa.xtb
+++ b/chromeos/strings/chromeos_strings_pa.xtb
@@ -252,6 +252,7 @@
 <translation id="6472207088655375767">OTP</translation>
 <translation id="6480327114083866287"><ph name="MANAGER" /> ਵੱਲੋਂ ਪ੍ਰਬੰਧਨ ਕੀਤਾ ਗਿਆ</translation>
 <translation id="649050271426829538">ਬੰਦ ਹੋ ਗਿਆ - ਕਾਗਜ਼ ਫਸ ਗਿਆ ਹੈ</translation>
+<translation id="6516990319416533844">ਬੈਟਰੀ ਚਾਰਜਿੰਗ ਦਰ ਦੀ ਜਾਂਚ ਕਰਨ ਲਈ, ਥੋੜ੍ਹੇ ਸਮੇਂ ਲਈ ਆਪਣੀ ਬੈਟਰੀ ਦੀ ਖਪਤ ਹੋਣ ਦਿਓ</translation>
 <translation id="6517239166834772319">ਪੜਚੋਲ ਕਰੋ</translation>
 <translation id="6527081081771465939">ਅਗਿਆਤ ਵਾਈ-ਫਾਈ ਦੀ ਸੁਰੱਖਿਆ ਸੰਬੰਧੀ ਪ੍ਰੋਟੋਕੋਲ</translation>
 <translation id="65587193855025101">ਫਲੈਟਬੈੱਡ</translation>
diff --git a/chromeos/strings/chromeos_strings_zh-CN.xtb b/chromeos/strings/chromeos_strings_zh-CN.xtb
index 42d2673..c15a4c6 100644
--- a/chromeos/strings/chromeos_strings_zh-CN.xtb
+++ b/chromeos/strings/chromeos_strings_zh-CN.xtb
@@ -253,6 +253,7 @@
 <translation id="6472207088655375767">一次性密码</translation>
 <translation id="6480327114083866287">由 <ph name="MANAGER" /> 管理</translation>
 <translation id="649050271426829538">已停止 - 卡纸了</translation>
+<translation id="6516990319416533844">若要测试电池充电速率,请先耗掉少许电池电量</translation>
 <translation id="6517239166834772319">探索</translation>
 <translation id="6527081081771465939">未知的 Wi-Fi 安全协议</translation>
 <translation id="65587193855025101">平台式</translation>
diff --git a/components/arc/mojom/app.mojom b/components/arc/mojom/app.mojom
index 17ab818..d1c7c0e 100644
--- a/components/arc/mojom/app.mojom
+++ b/components/arc/mojom/app.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.
 //
-// Next MinVersion: 48
+// Next MinVersion: 49
 
 module arc.mojom;
 
@@ -352,12 +352,14 @@
 
   // Sends information about newly created task |package_name| and |activity|
   // specifies launch activity and |intent| is initial intent used to start
-  // new task.
+  // new task. |session_id| is the window_id of |window_info| from app launch
+  // parameters. |session_id| is -1 if the window_id is not set.
   [MinVersion=4] OnTaskCreated@4(int32 task_id@0,
                                  string package_name@1,
                                  string activity@2,
                                  [MinVersion=13] string? name@3,
-                                 [MinVersion=15] string? intent@4);
+                                 [MinVersion=15] string? intent@4,
+                                 [MinVersion=48] int32 session_id@5);
 
   // Sends task label and icon. This is deprecated and will soon be replaced by
   // OnTaskDescriptionChanged().
diff --git a/components/arc/mojom/sensor_service.mojom b/components/arc/mojom/sensor_service.mojom
index 414ef26..abf361b 100644
--- a/components/arc/mojom/sensor_service.mojom
+++ b/components/arc/mojom/sensor_service.mojom
@@ -19,7 +19,7 @@
   GetDeviceNames@0() => (array<string> names);
 
   // Binds the request to the specified device.
-  GetDeviceByName@1(string name, SensorDevice& request);
+  GetDeviceByName@1(string name, pending_receiver<SensorDevice> receiver);
 };
 
 // SensorDevice provides an interface to interact with a sensor device.
diff --git a/components/arc/test/fake_app_instance.cc b/components/arc/test/fake_app_instance.cc
index d91e241..b7ffc5f 100644
--- a/components/arc/test/fake_app_instance.cc
+++ b/components/arc/test/fake_app_instance.cc
@@ -158,7 +158,7 @@
                                       const mojom::AppInfo& app,
                                       const std::string& intent) {
   app_host_->OnTaskCreated(taskId, app.package_name, app.activity, app.name,
-                           intent);
+                           intent, 0 /* session_id */);
 }
 
 void FakeAppInstance::SendTaskDescription(
diff --git a/components/autofill/content/browser/content_autofill_driver.cc b/components/autofill/content/browser/content_autofill_driver.cc
index b505aec..0bf21286 100644
--- a/components/autofill/content/browser/content_autofill_driver.cc
+++ b/components/autofill/content/browser/content_autofill_driver.cc
@@ -505,16 +505,18 @@
 
   // Try to show offer notification when the last committed URL has the domain
   // that an offer is applicable for.
-  std::tuple<std::vector<GURL>, CreditCard*> result =
+  std::tuple<std::vector<GURL>, GURL, CreditCard*> result =
       offer_manager->GetEligibleDomainsAndCardForOfferForUrl(url);
   std::vector<GURL>& domains = std::get<0>(result);
-  CreditCard* card = std::get<1>(result);
+  GURL offer_details_url = std::get<1>(result);
+  CreditCard* card = std::get<2>(result);
   // TODO(crbug.com/1093057): Update return condition once we introduce the
   // promo offers.
   if (domains.empty() || !card)
     return;
 
-  autofill_manager_->client()->ShowOfferNotificationIfApplicable(domains, card);
+  autofill_manager_->client()->ShowOfferNotificationIfApplicable(
+      domains, offer_details_url, card);
 }
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/autofill_client.cc b/components/autofill/core/browser/autofill_client.cc
index 1d23d4b..05229af 100644
--- a/components/autofill/core/browser/autofill_client.cc
+++ b/components/autofill/core/browser/autofill_client.cc
@@ -60,6 +60,7 @@
 
 void AutofillClient::ShowOfferNotificationIfApplicable(
     const std::vector<GURL>& domains_to_display_bubble,
+    const GURL& offer_details_url,
     const CreditCard* card) {
   // This is overridden by platform subclasses. Currently only
   // ChromeAutofillClient (Chrome Desktop and Clank) implement this.
diff --git a/components/autofill/core/browser/autofill_client.h b/components/autofill/core/browser/autofill_client.h
index 7e296870..1a8c8b2 100644
--- a/components/autofill/core/browser/autofill_client.h
+++ b/components/autofill/core/browser/autofill_client.h
@@ -511,9 +511,12 @@
   // eligible offer or reward if no other notification bubble is currently
   // visible. See bubble controller for details. The bubble is sticky over a set
   // of domains given in |domains_to_display_bubble|. The bubble displays the
-  // information of the |card| if the offer is card-related.
+  // information of the |card| if the offer is card-related. On mobile, the
+  // bubble also shows the |offer_details_url| as a link which has more
+  // information about the offer.
   virtual void ShowOfferNotificationIfApplicable(
       const std::vector<GURL>& domains_to_display_bubble,
+      const GURL& offer_details_url,
       const CreditCard* card);
 
   // Whether the Autocomplete feature of Autofill should be enabled.
diff --git a/components/autofill/core/browser/payments/autofill_offer_manager.cc b/components/autofill/core/browser/payments/autofill_offer_manager.cc
index 81a398fa..7784a1e 100644
--- a/components/autofill/core/browser/payments/autofill_offer_manager.cc
+++ b/components/autofill/core/browser/payments/autofill_offer_manager.cc
@@ -88,13 +88,15 @@
                              last_committed_url_origin);
 }
 
-std::tuple<std::vector<GURL>, CreditCard*>
+std::tuple<std::vector<GURL>, GURL, CreditCard*>
 AutofillOfferManager::GetEligibleDomainsAndCardForOfferForUrl(
     const GURL& last_committed_url) {
   std::vector<GURL> linked_domains;
   std::vector<AutofillOfferData*> offers =
       personal_data_->GetCreditCardOffers();
   CreditCard* card = nullptr;
+  // Initialize to an empty url.
+  GURL offer_details_url = GURL();
 
   // Check which offer is eligible on current domain, then return the full set
   // of domains for that offer.
@@ -109,6 +111,7 @@
                  ? nullptr
                  : personal_data_->GetCreditCardByInstrumentId(
                        offer->eligible_instrument_id[0]);
+      offer_details_url = GURL(offer->offer_details_url);
       break;
     }
   }
@@ -118,7 +121,7 @@
   linked_domains.erase(base::ranges::unique(linked_domains),
                        linked_domains.end());
 
-  return std::make_tuple(linked_domains, card);
+  return std::make_tuple(linked_domains, offer_details_url, card);
 }
 
 void AutofillOfferManager::UpdateEligibleMerchantDomains() {
diff --git a/components/autofill/core/browser/payments/autofill_offer_manager.h b/components/autofill/core/browser/payments/autofill_offer_manager.h
index eb5b52ee..dab84da0 100644
--- a/components/autofill/core/browser/payments/autofill_offer_manager.h
+++ b/components/autofill/core/browser/payments/autofill_offer_manager.h
@@ -49,8 +49,10 @@
   bool IsUrlEligible(const GURL& last_committed_url);
 
   // Returns the set of domains and the card linked to a specific offer that
-  // contains the domain of |last_committed_url|.
-  std::tuple<std::vector<GURL>, CreditCard*>
+  // contains the domain of |last_committed_url|. Also return the
+  // offer_details_url which redirects to a GPay surface with more details about
+  // the offer.
+  std::tuple<std::vector<GURL>, GURL, CreditCard*>
   GetEligibleDomainsAndCardForOfferForUrl(const GURL& last_committed_url);
 
  private:
diff --git a/components/autofill/core/browser/payments/autofill_offer_manager_unittest.cc b/components/autofill/core/browser/payments/autofill_offer_manager_unittest.cc
index 7a553b6..24bac17c 100644
--- a/components/autofill/core/browser/payments/autofill_offer_manager_unittest.cc
+++ b/components/autofill/core/browser/payments/autofill_offer_manager_unittest.cc
@@ -32,6 +32,7 @@
 const char kTestUrl[] = "http://www.example.com/";
 const char kTestUrlWithParam[] =
     "http://www.example.com/en/payments?name=checkout";
+const char kOfferDetailsUrl[] = "http://pay.google.com";
 
 }  // namespace
 
@@ -85,6 +86,7 @@
     }
     offer_data.merchant_domain = std::move(domains);
     offer_data.eligible_instrument_id = {card.instrument_id()};
+    offer_data.offer_details_url = GURL(kOfferDetailsUrl);
     return offer_data;
   }
 
@@ -233,7 +235,8 @@
       autofill_offer_manager_->GetEligibleDomainsAndCardForOfferForUrl(
           GURL("http://www.example.com"));
   EXPECT_EQ(0U, std::get<0>(result).size());
-  EXPECT_EQ(nullptr, std::get<1>(result));
+  EXPECT_EQ(GURL(), std::get<1>(result));
+  EXPECT_EQ(nullptr, std::get<2>(result));
 }
 
 TEST_F(AutofillOfferManagerTest,
@@ -261,7 +264,8 @@
   EXPECT_NE(eligible_domain.end(),
             std::find(eligible_domain.begin(), eligible_domain.end(),
                       GURL("http://www.example2.com")));
-  EXPECT_EQ(101, std::get<1>(result)->instrument_id());
+  EXPECT_EQ(GURL(kOfferDetailsUrl), std::get<1>(result));
+  EXPECT_EQ(101, std::get<2>(result)->instrument_id());
 }
 
 TEST_F(
@@ -278,7 +282,8 @@
       autofill_offer_manager_->GetEligibleDomainsAndCardForOfferForUrl(
           GURL("http://www.google.com"));
   EXPECT_EQ(2U, std::get<0>(result).size());
-  EXPECT_EQ(nullptr, std::get<1>(result));
+  EXPECT_EQ(GURL(kOfferDetailsUrl), std::get<1>(result));
+  EXPECT_EQ(nullptr, std::get<2>(result));
 }
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/payments/autofill_offer_notification_infobar_delegate_mobile.cc b/components/autofill/core/browser/payments/autofill_offer_notification_infobar_delegate_mobile.cc
index 69b0801..ad4a039 100644
--- a/components/autofill/core/browser/payments/autofill_offer_notification_infobar_delegate_mobile.cc
+++ b/components/autofill/core/browser/payments/autofill_offer_notification_infobar_delegate_mobile.cc
@@ -30,10 +30,13 @@
 namespace autofill {
 
 AutofillOfferNotificationInfoBarDelegateMobile::
-    AutofillOfferNotificationInfoBarDelegateMobile(const CreditCard& card)
+    AutofillOfferNotificationInfoBarDelegateMobile(
+        const GURL& offer_details_url,
+        const CreditCard& card)
     : credit_card_identifier_string_(
           card.CardIdentifierStringForAutofillDisplay()),
-      network_icon_id_(CreditCard::IconResourceId(card.network())) {}
+      network_icon_id_(CreditCard::IconResourceId(card.network())),
+      deep_link_url_(offer_details_url) {}
 
 AutofillOfferNotificationInfoBarDelegateMobile::
     ~AutofillOfferNotificationInfoBarDelegateMobile() {}
diff --git a/components/autofill/core/browser/payments/autofill_offer_notification_infobar_delegate_mobile.h b/components/autofill/core/browser/payments/autofill_offer_notification_infobar_delegate_mobile.h
index dbd9a54..02afeb3 100644
--- a/components/autofill/core/browser/payments/autofill_offer_notification_infobar_delegate_mobile.h
+++ b/components/autofill/core/browser/payments/autofill_offer_notification_infobar_delegate_mobile.h
@@ -25,7 +25,8 @@
 class AutofillOfferNotificationInfoBarDelegateMobile
     : public ConfirmInfoBarDelegate {
  public:
-  AutofillOfferNotificationInfoBarDelegateMobile(const CreditCard& card);
+  AutofillOfferNotificationInfoBarDelegateMobile(const GURL& offer_details_url,
+                                                 const CreditCard& card);
 
   ~AutofillOfferNotificationInfoBarDelegateMobile() override;
 
@@ -38,7 +39,7 @@
     return credit_card_identifier_string_;
   }
   int network_icon_id() { return network_icon_id_; }
-  const base::string16& deep_link_url() const { return deep_link_url_; }
+  const GURL& deep_link_url() const { return deep_link_url_; }
 
   // Called when the offer details deep link was clicked.
   virtual void OnOfferDeepLinkClicked(GURL url);
@@ -56,7 +57,7 @@
   // Resource id for the icon representing the network of the credit card.
   int network_icon_id_;
   // URL that links to the offer details page in the Google Pay app.
-  base::string16 deep_link_url_;
+  GURL deep_link_url_;
 };
 
 }  // namespace autofill
diff --git a/components/background_task_scheduler/internal/android/java/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskBroadcastReceiver.java b/components/background_task_scheduler/internal/android/java/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskBroadcastReceiver.java
index 99385a4..5befc58 100644
--- a/components/background_task_scheduler/internal/android/java/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskBroadcastReceiver.java
+++ b/components/background_task_scheduler/internal/android/java/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskBroadcastReceiver.java
@@ -21,6 +21,7 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
 import org.chromium.base.ThreadUtils;
+import org.chromium.base.compat.ApiHelperForM;
 import org.chromium.base.task.PostTask;
 import org.chromium.components.background_task_scheduler.BackgroundTask;
 import org.chromium.components.background_task_scheduler.TaskInfo;
@@ -165,7 +166,7 @@
                 (ConnectivityManager) context.getApplicationContext().getSystemService(
                         Context.CONNECTIVITY_SERVICE);
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
-            Network network = connectivityManager.getActiveNetwork();
+            Network network = ApiHelperForM.getActiveNetwork(connectivityManager);
             if (requiredNetworkType == TaskInfo.NetworkType.ANY) return (network != null);
         } else {
             NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
@@ -181,7 +182,7 @@
                 (BatteryManager) context.getSystemService(Context.BATTERY_SERVICE);
 
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
-            return batteryManager.isCharging();
+            return ApiHelperForM.isCharging(batteryManager);
         }
 
         IntentFilter intentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
diff --git a/components/background_task_scheduler/internal/android/java/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerAlarmManager.java b/components/background_task_scheduler/internal/android/java/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerAlarmManager.java
index 06fad03..d7f24ba 100644
--- a/components/background_task_scheduler/internal/android/java/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerAlarmManager.java
+++ b/components/background_task_scheduler/internal/android/java/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerAlarmManager.java
@@ -16,6 +16,7 @@
 import org.chromium.base.IntentUtils;
 import org.chromium.base.Log;
 import org.chromium.base.ThreadUtils;
+import org.chromium.base.compat.ApiHelperForM;
 import org.chromium.components.background_task_scheduler.TaskInfo;
 import org.chromium.components.background_task_scheduler.TaskParameters;
 
@@ -108,7 +109,7 @@
         @Override
         public void visit(TaskInfo.ExactInfo exactInfo) {
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
-                mAlarmManager.setExactAndAllowWhileIdle(
+                ApiHelperForM.setAlarmManagerExactAndAllowWhileIdle(mAlarmManager,
                         /*type= */ AlarmManager.RTC_WAKEUP, exactInfo.getTriggerAtMs(),
                         mPendingIntent);
                 return;
diff --git a/components/browser_ui/notifications/android/java/src/org/chromium/components/browser_ui/notifications/ForegroundServiceUtils.java b/components/browser_ui/notifications/android/java/src/org/chromium/components/browser_ui/notifications/ForegroundServiceUtils.java
index ca6227ee..2d20548 100644
--- a/components/browser_ui/notifications/android/java/src/org/chromium/components/browser_ui/notifications/ForegroundServiceUtils.java
+++ b/components/browser_ui/notifications/android/java/src/org/chromium/components/browser_ui/notifications/ForegroundServiceUtils.java
@@ -15,6 +15,7 @@
 
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
+import org.chromium.base.compat.ApiHelperForQ;
 
 /**
  * Utility functions that call into Android foreground service related API, and provides
@@ -69,7 +70,7 @@
         if (notification == null) return;
 
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
-            service.startForeground(id, notification, foregroundServiceType);
+            ApiHelperForQ.startForeground(service, id, notification, foregroundServiceType);
         } else {
             service.startForeground(id, notification);
         }
diff --git a/components/browser_ui/notifications/android/java/src/org/chromium/components/browser_ui/notifications/NotificationManagerProxyImpl.java b/components/browser_ui/notifications/android/java/src/org/chromium/components/browser_ui/notifications/NotificationManagerProxyImpl.java
index 48d798c..503d4112 100644
--- a/components/browser_ui/notifications/android/java/src/org/chromium/components/browser_ui/notifications/NotificationManagerProxyImpl.java
+++ b/components/browser_ui/notifications/android/java/src/org/chromium/components/browser_ui/notifications/NotificationManagerProxyImpl.java
@@ -8,7 +8,6 @@
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationChannelGroup;
-import android.app.NotificationManager;
 import android.content.Context;
 import android.os.Build;
 
@@ -25,17 +24,16 @@
 public class NotificationManagerProxyImpl implements NotificationManagerProxy {
     private static final String TAG = "NotifManagerProxy";
     private final Context mContext;
-    private final NotificationManager mNotificationManager;
+    private final NotificationManagerCompat mNotificationManager;
 
     public NotificationManagerProxyImpl(Context context) {
         mContext = context;
-        mNotificationManager =
-                (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+        mNotificationManager = NotificationManagerCompat.from(mContext);
     }
 
     @Override
     public boolean areNotificationsEnabled() {
-        return NotificationManagerCompat.from(mContext).areNotificationsEnabled();
+        return mNotificationManager.areNotificationsEnabled();
     }
 
     @Override
diff --git a/components/browser_ui/notifications/android/java/src/org/chromium/components/browser_ui/notifications/NotificationWrapperStandardBuilder.java b/components/browser_ui/notifications/android/java/src/org/chromium/components/browser_ui/notifications/NotificationWrapperStandardBuilder.java
index d0c7a1d..eb76206 100644
--- a/components/browser_ui/notifications/android/java/src/org/chromium/components/browser_ui/notifications/NotificationWrapperStandardBuilder.java
+++ b/components/browser_ui/notifications/android/java/src/org/chromium/components/browser_ui/notifications/NotificationWrapperStandardBuilder.java
@@ -19,6 +19,9 @@
 import androidx.core.app.NotificationCompat;
 
 import org.chromium.base.Log;
+import org.chromium.base.compat.ApiHelperForM;
+import org.chromium.base.compat.ApiHelperForN;
+import org.chromium.base.compat.ApiHelperForO;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.components.browser_ui.notifications.channels.ChannelsInitializer;
 
@@ -37,7 +40,7 @@
         mBuilder = new Notification.Builder(mContext);
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
             channelsInitializer.safeInitialize(channelId);
-            mBuilder.setChannelId(channelId);
+            ApiHelperForO.setChannelId(mBuilder, channelId);
         }
         mMetadata = metadata;
     }
@@ -81,7 +84,7 @@
     @Override
     public NotificationWrapperBuilder setSmallIcon(Icon icon) {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
-            mBuilder.setSmallIcon(icon);
+            ApiHelperForM.setSmallIcon(mBuilder, icon);
         }
         return this;
     }
@@ -145,10 +148,11 @@
     public NotificationWrapperBuilder addAction(
             int icon, CharSequence title, PendingIntent intent) {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && icon != 0) {
-            mBuilder.addAction(
-                    new Notification.Action
-                            .Builder(Icon.createWithResource(mContext, icon), title, intent)
-                            .build());
+            mBuilder.addAction(ApiHelperForM
+                                       .newNotificationActionBuilder(
+                                               ApiHelperForM.createIconWithResource(mContext, icon),
+                                               title, intent)
+                                       .build());
         } else {
             mBuilder.addAction(icon, title, intent);
         }
@@ -287,7 +291,7 @@
     @SuppressWarnings("deprecation")
     public NotificationWrapperBuilder setContent(RemoteViews views) {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
-            mBuilder.setCustomContentView(views);
+            ApiHelperForN.setCustomContentView(mBuilder, views);
         } else {
             mBuilder.setContent(views);
         }
@@ -335,7 +339,7 @@
         assert mMetadata != null;
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
             return new NotificationWrapper(
-                    mBuilder.setCustomBigContentView(view).build(), mMetadata);
+                    ApiHelperForN.setCustomBigContentView(mBuilder, view).build(), mMetadata);
         } else {
             Notification notification = mBuilder.build();
             notification.bigContentView = view;
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_de.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_de.xtb
index c2955913..5f0c18c 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_de.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_de.xtb
@@ -23,6 +23,7 @@
 <translation id="1509960214886564027">Funktionen auf vielen Websites funktionieren möglicherweise nicht mehr</translation>
 <translation id="1620510694547887537">Kamera</translation>
 <translation id="1644574205037202324">Verlauf</translation>
+<translation id="1647582022260550163">Möchten Sie die Berechtigungen dieser Website wirklich zurücksetzen und ihre Cookies und Daten löschen?</translation>
 <translation id="1660204651932907780">Wiedergabe von Ton auf Websites zulassen (empfohlen)</translation>
 <translation id="1677097821151855053">Durch Cookies und andere Websitedaten erinnert sich die Website an Sie, z. B. bei der Anmeldung oder für personalisierte Werbung. Sie können Cookies für alle Websites <ph name="BEGIN_LINK" />in den Einstellungen verwalten<ph name="END_LINK" />.</translation>
 <translation id="1688867105868176567">Websitedaten löschen?</translation>
@@ -309,6 +310,7 @@
 <translation id="9074739597929991885">Bluetooth</translation>
 <translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> und <ph name="NUM_MORE" /> weitere}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> und <ph name="NUM_MORE" /> weitere}}</translation>
 <translation id="913657688200966289">Die Berechtigungen für <ph name="APP_NAME" /> können in den <ph name="BEGIN_LINK" />Android-Einstellungen<ph name="END_LINK" /> aktiviert werden.</translation>
+<translation id="930525582205581608">Informationen auf dieser Website löschen?</translation>
 <translation id="965817943346481315">Blockieren, wenn Website aufdringliche oder irreführende Werbung anzeigt (empfohlen)</translation>
 <translation id="967624055006145463">Gespeicherte Daten</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_kn.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_kn.xtb
index 6790a3c6..3b961e2 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_kn.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_kn.xtb
@@ -310,7 +310,7 @@
 <translation id="9074739597929991885">ಬ್ಲೂಟೂತ್‌</translation>
 <translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ಮತ್ತು ಇನ್ನೂ <ph name="NUM_MORE" />}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ಮತ್ತು ಇನ್ನೂ <ph name="NUM_MORE" />}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ಮತ್ತು ಇನ್ನೂ <ph name="NUM_MORE" />}}</translation>
 <translation id="913657688200966289"><ph name="BEGIN_LINK" />Android ಸೆಟ್ಟಿಂಗ್‌ಗಳಲ್ಲಿ<ph name="END_LINK" /> <ph name="APP_NAME" /> ಗಾಗಿ ಅನುಮತಿಗಳನ್ನು ಆನ್ ಮಾಡಿ.</translation>
-<translation id="930525582205581608">ಈ ಸೈಟ್ ಅನ್ನು ಮರೆಯುವುದೇ?</translation>
+<translation id="930525582205581608">ಈ ಸೈಟ್ ಅನ್ನು ಮರೆಯಬೇಕೇ?</translation>
 <translation id="965817943346481315">ಅತಿಕ್ರಮಣಕಾರಿಯಾಗಿರುವ ಅಥವಾ ತಪ್ಪುದಾರಿಗೆಳೆಯುವ ಜಾಹೀರಾತುಗಳನ್ನು ಸೈಟ್ ತೋರಿಸಿದರೆ ಅದನ್ನು ನಿರ್ಬಂಧಿಸಿ (ಶಿಫಾರಸು ಮಾಡಲಾಗಿದೆ)</translation>
 <translation id="967624055006145463">ಸಂಗ್ರಹಣೆ ಮಾಡಿರುವ ಡೇಟಾ</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_pa.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_pa.xtb
index 1fd5dc2..6f348d8 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_pa.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_pa.xtb
@@ -23,6 +23,7 @@
 <translation id="1509960214886564027">ਸ਼ਾਇਦ ਕਈ ਸਾਈਟਾਂ 'ਤੇ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਠੀਕ ਤਰੀਕੇ ਨਾਲ ਕੰਮ ਨਾ ਕਰਨ</translation>
 <translation id="1620510694547887537">ਕੈਮਰਾ</translation>
 <translation id="1644574205037202324">ਇਤਿਹਾਸ</translation>
+<translation id="1647582022260550163">ਕੀ ਤੁਸੀਂ ਪੱਕਾ ਇਜਾਜ਼ਤਾਂ ਨੂੰ ਰੀਸੈੱਟ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ, ਅਤੇ ਕੁਕੀਜ਼ ਅਤੇ ਹੋਰ ਸਾਈਟ ਡਾਟੇ ਨੂੰ ਕਲੀਅਰ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?</translation>
 <translation id="1660204651932907780">ਸਾਈਟਾਂ ਨੂੰ ਧੁਨੀ ਵਜਾਉਣ ਦਿਓ (ਸਿਫ਼ਾਰਸ਼ੀ)</translation>
 <translation id="1677097821151855053">ਕੁਕੀਜ਼ ਅਤੇ ਹੋਰ ਸਾਈਟ ਡਾਟੇ ਦੀ ਵਰਤੋਂ ਤੁਹਾਨੂੰ ਯਾਦ ਰੱਖਣ ਲਈ ਕੀਤੀ ਜਾਂਦੀ ਹੈ, ਉਦਾਹਰਨ ਦੇ ਤੌਰ 'ਤੇ ਤੁਹਾਨੂੰ ਸਾਈਨ-ਇਨ ਕਰਨ ਲਈ ਜਾਂ ਵਿਗਿਆਪਨਾਂ ਨੂੰ ਵਿਅਕਤੀਗਤ ਬਣਾਉਣ ਲਈ। ਸਾਰੀਆਂ ਸਾਈਟਾਂ ਲਈ ਕੁਕੀਜ਼ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਲਈ, <ph name="BEGIN_LINK" />ਸੈਟਿੰਗਾਂ<ph name="END_LINK" /> ਦੇਖੋ।</translation>
 <translation id="1688867105868176567">ਕੀ ਸਾਈਟ ਡਾਟਾ ਕਲੀਅਰ ਕਰਨਾ ਹੈ?</translation>
@@ -309,6 +310,7 @@
 <translation id="9074739597929991885">ਬਲੂਟੁੱਥ</translation>
 <translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ਅਤੇ <ph name="NUM_MORE" /> ਹੋਰ}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ਅਤੇ <ph name="NUM_MORE" /> ਹੋਰ}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ਅਤੇ <ph name="NUM_MORE" /> ਹੋਰ}}</translation>
 <translation id="913657688200966289"><ph name="BEGIN_LINK" />Android ਸੈਟਿੰਗਾਂ<ph name="END_LINK" /> ਵਿੱਚ <ph name="APP_NAME" /> ਲਈ ਇਜਾਜ਼ਤਾਂ ਚਾਲੂ ਕਰੋ।</translation>
+<translation id="930525582205581608">ਕੀ ਇਸ ਸਾਈਟ ਨੂੰ ਕਲੀਅਰ ਕਰਨਾ ਹੈ?</translation>
 <translation id="965817943346481315">ਜੇਕਰ ਸਾਈਟ ਦਖਲਅੰਦਾਜ਼ੀ ਅਤੇ ਗੁਮਰਾਹ ਕਰਨ ਵਾਲੇ ਵਿਗਿਆਪਨ ਦਿਖਾਉਂਦੀ ਹੈ, ਤਾਂ ਇਸਨੂੰ ਬਲਾਕ ਕਰੋ (ਸਿਫ਼ਾਰਸ਼ੀ)</translation>
 <translation id="967624055006145463">ਸਟੋਰ ਕੀਤਾ ਡਾਟਾ</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_sv.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_sv.xtb
index 5e19280b..bb40264 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_sv.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_sv.xtb
@@ -120,7 +120,7 @@
 <translation id="4336434711095810371">Rensa all data</translation>
 <translation id="4402755511846832236">Blockera webbplatser från att veta när du använder enheten aktivt</translation>
 <translation id="4433925000917964731">Lite-sida tillhandahållen av Google</translation>
-<translation id="4434045419905280838">Popup och omdirigeringar</translation>
+<translation id="4434045419905280838">Popup-fönster och omdirigeringar</translation>
 <translation id="445467742685312942">Tillåt att webbplatser spelar upp skyddat innehåll</translation>
 <translation id="4468959413250150279">Stäng av ljudet för en webbplats.</translation>
 <translation id="4479647676395637221">Fråga innan webbplatser tillåts att använda kameran (rekommenderas)</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_uk.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_uk.xtb
index 6acdc148..be8e1aab 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_uk.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_uk.xtb
@@ -23,7 +23,7 @@
 <translation id="1509960214886564027">Функції на багатьох сайтах можуть не працювати</translation>
 <translation id="1620510694547887537">Камера</translation>
 <translation id="1644574205037202324">Історія</translation>
-<translation id="1647582022260550163">Скинути дозволи й очистити файли cookie та дані сайтів?</translation>
+<translation id="1647582022260550163">Скинути дозволи й очистити файли cookie та дані сайту?</translation>
 <translation id="1660204651932907780">Дозволити сайтам відтворювати звук (рекомендується)</translation>
 <translation id="1677097821151855053">Файли cookie та інші дані із сайтів використовуються, щоб запам'ятати ваші дані, наприклад, щоб входити у ваш обліковий запис або персоналізувати рекламу. Щоб керувати файлами cookie для всіх сайтів, перегляньте <ph name="BEGIN_LINK" />Налаштування<ph name="END_LINK" />.</translation>
 <translation id="1688867105868176567">Очистити дані сайту?</translation>
diff --git a/components/browser_ui/strings/android/translations/browser_ui_strings_zh-CN.xtb b/components/browser_ui/strings/android/translations/browser_ui_strings_zh-CN.xtb
index c19ddb56..537ca9b 100644
--- a/components/browser_ui/strings/android/translations/browser_ui_strings_zh-CN.xtb
+++ b/components/browser_ui/strings/android/translations/browser_ui_strings_zh-CN.xtb
@@ -23,6 +23,7 @@
 <translation id="1509960214886564027">很多网站上的功能可能会无法正常运作</translation>
 <translation id="1620510694547887537">摄像头</translation>
 <translation id="1644574205037202324">历史记录</translation>
+<translation id="1647582022260550163">确定要重置权限并清除 Cookie 和网站数据吗?</translation>
 <translation id="1660204651932907780">允许网站播放声音(推荐)</translation>
 <translation id="1677097821151855053">系统会使用 Cookie 和其他网站数据来记住您,以便实现某些功能或目的(例如帮您登录或向您展示个性化广告)。如需管理所有网站的 Cookie,请参阅<ph name="BEGIN_LINK" />设置<ph name="END_LINK" />。</translation>
 <translation id="1688867105868176567">要清除网站数据吗?</translation>
@@ -309,6 +310,7 @@
 <translation id="9074739597929991885">蓝牙</translation>
 <translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{“<ph name="PERMISSION_1" />”权限、“<ph name="PERMISSION_2" />”权限和另外 <ph name="NUM_MORE" /> 项权限}other{“<ph name="PERMISSION_1" />”权限、“<ph name="PERMISSION_2" />”权限和另外 <ph name="NUM_MORE" /> 项权限}}</translation>
 <translation id="913657688200966289">在 <ph name="BEGIN_LINK" />Android 设置<ph name="END_LINK" />中为 <ph name="APP_NAME" /> 开启这些权限。</translation>
+<translation id="930525582205581608">移除此网站?</translation>
 <translation id="965817943346481315">屏蔽会展示侵扰性或误导性广告的网站(推荐)</translation>
 <translation id="967624055006145463">已存储的数据</translation>
 </translationbundle>
\ No newline at end of file
diff --git a/components/download/internal/common/android/java/src/org/chromium/components/download/DownloadCollectionBridge.java b/components/download/internal/common/android/java/src/org/chromium/components/download/DownloadCollectionBridge.java
index c5f96a97..645d002 100644
--- a/components/download/internal/common/android/java/src/org/chromium/components/download/DownloadCollectionBridge.java
+++ b/components/download/internal/common/android/java/src/org/chromium/components/download/DownloadCollectionBridge.java
@@ -11,10 +11,8 @@
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Build;
-import android.os.FileUtils;
 import android.os.ParcelFileDescriptor;
 import android.provider.BaseColumns;
-import android.provider.MediaStore;
 import android.provider.MediaStore.Downloads;
 import android.provider.MediaStore.MediaColumns;
 import android.text.TextUtils;
@@ -28,6 +26,7 @@
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.annotations.NativeMethods;
+import org.chromium.base.compat.ApiHelperForQ;
 import org.chromium.third_party.android.provider.MediaStoreUtils;
 import org.chromium.third_party.android.provider.MediaStoreUtils.PendingParams;
 import org.chromium.third_party.android.provider.MediaStoreUtils.PendingSession;
@@ -153,7 +152,7 @@
             PendingSession session = openPendingUri(destinationUri);
             OutputStream out = session.openOutputStream();
             InputStream in = new FileInputStream(sourcePath);
-            FileUtils.copy(in, out);
+            ApiHelperForQ.copy(in, out);
             in.close();
             out.close();
             return true;
@@ -272,7 +271,7 @@
         Cursor cursor = null;
         try {
             Uri uri = Downloads.EXTERNAL_CONTENT_URI;
-            cursor = resolver.query(MediaStore.setIncludePending(uri),
+            cursor = resolver.query(ApiHelperForQ.setIncludePending(uri),
                     new String[] {BaseColumns._ID, MediaColumns.DISPLAY_NAME}, null, null, null);
             if (cursor == null || cursor.getCount() == 0) return null;
             List<DisplayNameInfo> infos = new ArrayList<DisplayNameInfo>();
@@ -310,7 +309,7 @@
         try {
             Uri uri = Downloads.EXTERNAL_CONTENT_URI;
             cursor = ContextUtils.getApplicationContext().getContentResolver().query(
-                    MediaStore.setIncludePending(uri), new String[] {BaseColumns._ID},
+                    ApiHelperForQ.setIncludePending(uri), new String[] {BaseColumns._ID},
                     "_display_name LIKE ?1", new String[] {fileName}, null);
             if (cursor == null) return null;
             if (cursor.moveToNext()) {
diff --git a/components/feature_engagement/README.md b/components/feature_engagement/README.md
index ab2bce1..a22c25f 100644
--- a/components/feature_engagement/README.md
+++ b/components/feature_engagement/README.md
@@ -626,3 +626,7 @@
 `//components/feature_engagement/components_unittests.filter`.
 
 [field-trial-testing-configuration]: https://chromium.googlesource.com/chromium/src/+/master/testing/variations/README.md
+
+## IPH Analysis Guideline
+
+See [this doc](https://docs.google.com/document/d/1EhQe3G9juBiw-otuRnGf5gzTsfHZVZiSKrgF6r7Sz4E/edit#heading=h.la5fs7q2klme)
diff --git a/components/feature_engagement/public/event_constants.cc b/components/feature_engagement/public/event_constants.cc
index e20525f..1c67532 100644
--- a/components/feature_engagement/public/event_constants.cc
+++ b/components/feature_engagement/public/event_constants.cc
@@ -21,6 +21,9 @@
 const char kSixthTabOpened[] = "sixth_tab_opened";
 const char kTabGroupCreated[] = "tab_group_created";
 
+const char kReadingListItemAdded[] = "reading_list_item_added";
+const char kReadingListMenuOpened[] = "reading_list_menu_opened";
+
 const char kReopenTabConditionsMet[] = "reopen_tab_conditions_met";
 const char kTabReopened[] = "tab_reopened";
 
diff --git a/components/feature_engagement/public/event_constants.h b/components/feature_engagement/public/event_constants.h
index 9ed2ea4..f541f1e 100644
--- a/components/feature_engagement/public/event_constants.h
+++ b/components/feature_engagement/public/event_constants.h
@@ -28,6 +28,11 @@
 // The user made a new tab group.
 extern const char kTabGroupCreated[];
 
+// A tab was added to reading list.
+extern const char kReadingListItemAdded[];
+// Reading list was opened.
+extern const char kReadingListMenuOpened[];
+
 // All conditions for reopen closed tab IPH were met. Since this IPH needs to
 // track user events (opening/closing tabs, focusing the omnibox, etc) on the
 // second level, it must be done manually.
diff --git a/components/full_restore/app_restore_data.cc b/components/full_restore/app_restore_data.cc
index fb56511..12e83c4d 100644
--- a/components/full_restore/app_restore_data.cc
+++ b/components/full_restore/app_restore_data.cc
@@ -26,6 +26,8 @@
 constexpr char kActivationIndexKey[] = "index";
 constexpr char kDeskIdKey[] = "desk_id";
 constexpr char kVisibleOnAllWorkspacesKey[] = "all_desk";
+// TODO(sammiequon): This may not be needed as restore bounds are saved in
+// current_bounds if needed. See WindowInfo for more details.
 constexpr char kRestoreBoundsKey[] = "restore_bounds";
 constexpr char kCurrentBoundsKey[] = "current_bounds";
 constexpr char kWindowStateTypeKey[] = "window_state_type";
diff --git a/components/full_restore/full_restore_read_handler.cc b/components/full_restore/full_restore_read_handler.cc
index aa2bfc7dc..0dcfc40 100644
--- a/components/full_restore/full_restore_read_handler.cc
+++ b/components/full_restore/full_restore_read_handler.cc
@@ -15,7 +15,6 @@
 #include "components/full_restore/restore_data.h"
 #include "components/full_restore/window_info.h"
 #include "components/sessions/core/session_id.h"
-#include "ui/aura/client/aura_constants.h"
 #include "ui/aura/env.h"
 
 namespace full_restore {
@@ -154,10 +153,6 @@
       window_info->visible_on_all_workspaces.has_value();
   if (window_info->current_bounds)
     out_params->bounds = *window_info->current_bounds;
-  if (window_info->restore_bounds) {
-    out_params->init_properties_container.SetProperty(
-        aura::client::kRestoreBoundsKey, *window_info->restore_bounds);
-  }
   if (window_info->window_state_type) {
     // ToWindowShowState will make us lose some ash-specific types (left/right
     // snap). Ash is responsible for restoring these states by checking
diff --git a/components/full_restore/full_restore_save_handler.cc b/components/full_restore/full_restore_save_handler.cc
index adb649a..72970e5 100644
--- a/components/full_restore/full_restore_save_handler.cc
+++ b/components/full_restore/full_restore_save_handler.cc
@@ -200,7 +200,8 @@
 }
 
 void FullRestoreSaveHandler::OnTaskCreated(const std::string app_id,
-                                           int task_id) {
+                                           int32_t task_id,
+                                           int32_t session_id) {
   task_id_to_app_window_info_[task_id].app_id = app_id;
 
   auto it = app_id_to_app_launch_infos_.find(app_id);
@@ -227,7 +228,7 @@
   }
 }
 
-void FullRestoreSaveHandler::OnTaskDestroyed(int task_id) {
+void FullRestoreSaveHandler::OnTaskDestroyed(int32_t task_id) {
   RemoveAppRestoreData(task_id);
   task_id_to_app_window_info_.erase(task_id);
 }
diff --git a/components/full_restore/full_restore_save_handler.h b/components/full_restore/full_restore_save_handler.h
index f979e15..3c1213f 100644
--- a/components/full_restore/full_restore_save_handler.h
+++ b/components/full_restore/full_restore_save_handler.h
@@ -66,10 +66,12 @@
   void SaveWindowInfo(const WindowInfo& window_info);
 
   // Invoked when the task is created for an ARC app.
-  void OnTaskCreated(const std::string app_id, int task_id);
+  void OnTaskCreated(const std::string app_id,
+                     int32_t task_id,
+                     int32_t session_id);
 
   // Invoked when the task is destroyed for an ARC app.
-  void OnTaskDestroyed(int task_id);
+  void OnTaskDestroyed(int32_t task_id);
 
   // Flushes the full restore file in |profile_path| with the current restore
   // data.
diff --git a/components/full_restore/window_info.h b/components/full_restore/window_info.h
index f3fe175..eb877f2 100644
--- a/components/full_restore/window_info.h
+++ b/components/full_restore/window_info.h
@@ -35,9 +35,15 @@
 
   // The restored bounds in screen coordinates. Empty if the window is not
   // snapped/maximized/minimized.
+  // TODO(sammiequon): This may not be needed as we save the restore bounds in
+  // screen coordinates into |current_bounds|. On creating the widget,
+  // |current_bounds| will be stored as restore bounds and the maximized or
+  // snapped bounds will be determined by the system. Update the comment below
+  // if this is removed.
   base::Optional<gfx::Rect> restore_bounds;
 
-  // Current bounds in screen in coordinates.
+  // Current bounds in screen in coordinates. If the window has restore bounds,
+  // then this contains the restore bounds.
   base::Optional<gfx::Rect> current_bounds;
 
   // Window state, minimized, maximized, inactive, etc.
diff --git a/components/metrics/daily_event.cc b/components/metrics/daily_event.cc
index 6df1cdd4..786377e6 100644
--- a/components/metrics/daily_event.cc
+++ b/components/metrics/daily_event.cc
@@ -7,7 +7,7 @@
 #include <utility>
 
 #include "base/logging.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_functions.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 
@@ -17,10 +17,9 @@
 
 void RecordIntervalTypeHistogram(const std::string& histogram_name,
                                  DailyEvent::IntervalType type) {
-  const int num_types = static_cast<int>(DailyEvent::IntervalType::NUM_TYPES);
-  base::Histogram::FactoryGet(histogram_name, 1, num_types, num_types + 1,
-                              base::HistogramBase::kUmaTargetedHistogramFlag)
-      ->Add(static_cast<int>(type));
+  if (histogram_name.empty())
+    return;
+  base::UmaHistogramEnumeration(histogram_name, type);
 }
 
 }  // namespace
@@ -44,7 +43,7 @@
 
 // static
 void DailyEvent::RegisterPref(PrefRegistrySimple* registry,
-                              const char* pref_name) {
+                              const std::string& pref_name) {
   registry->RegisterInt64Pref(pref_name, 0);
 }
 
diff --git a/components/metrics/daily_event.h b/components/metrics/daily_event.h
index 326cad49..39f8308 100644
--- a/components/metrics/daily_event.h
+++ b/components/metrics/daily_event.h
@@ -31,7 +31,7 @@
     FIRST_RUN,
     DAY_ELAPSED,
     CLOCK_CHANGED,
-    NUM_TYPES,
+    kMaxValue = CLOCK_CHANGED,
   };
 
   // Observer receives notifications from a DailyEvent.
@@ -55,7 +55,8 @@
   // Caller is responsible for ensuring that |pref_service| and |pref_name|
   // outlive the DailyEvent.
   // |histogram_name| is the name of the UMA metric which record when this
-  // interval fires, and should be registered in histograms.xml
+  // interval fires, and should be registered in histograms.xml. If
+  // |histogram_name| is empty - interval fires are not recorded.
   DailyEvent(PrefService* pref_service,
              const char* pref_name,
              const std::string& histogram_name);
@@ -70,7 +71,8 @@
   void CheckInterval();
 
   // Registers the preference used by this interval.
-  static void RegisterPref(PrefRegistrySimple* registry, const char* pref_name);
+  static void RegisterPref(PrefRegistrySimple* registry,
+                           const std::string& pref_name);
 
  private:
   // Handles an interval elapsing because of |type|.
diff --git a/components/metrics/structured/structured_metrics_provider.cc b/components/metrics/structured/structured_metrics_provider.cc
index 7f16c39..672e5d7 100644
--- a/components/metrics/structured/structured_metrics_provider.cc
+++ b/components/metrics/structured/structured_metrics_provider.cc
@@ -27,7 +27,7 @@
 constexpr int kExternalMetricsIntervalMins = 10;
 
 // Directory containing serialized event protos to read.
-constexpr char kExternalMetricsDir[] = "/var/lib/metrics/structured/";
+constexpr char kExternalMetricsDir[] = "/var/lib/metrics/structured/events";
 
 }  // namespace
 
diff --git a/components/optimization_guide/content/browser/BUILD.gn b/components/optimization_guide/content/browser/BUILD.gn
index ec6a0d9..65aa5f4 100644
--- a/components/optimization_guide/content/browser/BUILD.gn
+++ b/components/optimization_guide/content/browser/BUILD.gn
@@ -74,6 +74,7 @@
     sources += [
       "bert_model_executor_unittest.cc",
       "optimization_target_model_executor_unittest.cc",
+      "page_content_annotations_model_manager_unittest.cc",
     ]
   }
   deps = [
diff --git a/components/optimization_guide/content/browser/page_content_annotations_model_manager.cc b/components/optimization_guide/content/browser/page_content_annotations_model_manager.cc
index d2ec6c2..27b962d 100644
--- a/components/optimization_guide/content/browser/page_content_annotations_model_manager.cc
+++ b/components/optimization_guide/content/browser/page_content_annotations_model_manager.cc
@@ -7,14 +7,32 @@
 #include "base/sequenced_task_runner.h"
 #include "base/task/task_traits.h"
 #include "components/optimization_guide/content/browser/optimization_guide_decider.h"
+#include "components/optimization_guide/proto/page_topics_model_metadata.pb.h"
 
 namespace optimization_guide {
 
+namespace {
+
+const char kPageTopicsModelMetadataTypeUrl[] =
+    "type.googleapis.com/"
+    "google.internal.chrome.optimizationguide.v1.PageTopicsModelMetadata";
+
+}  // namespace
+
 PageContentAnnotationsModelManager::PageContentAnnotationsModelManager(
     optimization_guide::OptimizationGuideDecider* optimization_guide_decider) {
+  proto::Any model_metadata;
+  model_metadata.set_type_url(kPageTopicsModelMetadataTypeUrl);
+  proto::PageTopicsModelMetadata page_topics_model_metadata;
+  page_topics_model_metadata.add_supported_output(
+      proto::PAGE_TOPICS_SUPPORTED_OUTPUT_SENSITIVITY);
+  page_topics_model_metadata.add_supported_output(
+      proto::PAGE_TOPICS_SUPPORTED_OUTPUT_CATEGORIES);
+  page_topics_model_metadata.SerializeToString(model_metadata.mutable_value());
+
   page_topics_model_executor_ = std::make_unique<BertModelExecutor>(
       optimization_guide_decider, proto::OPTIMIZATION_TARGET_PAGE_TOPICS,
-      /*model_metadata=*/base::nullopt,
+      model_metadata,
       base::ThreadPool::CreateSequencedTaskRunner(
           {base::MayBlock(), base::TaskPriority::BEST_EFFORT}));
 }
@@ -49,7 +67,11 @@
 
 base::Optional<int64_t>
 PageContentAnnotationsModelManager::GetPageTopicsModelVersion() const {
-  // TODO(crbug/1177102): Extract this from |page_topics_model_executor|.
+  base::Optional<proto::PageTopicsModelMetadata> model_metadata =
+      page_topics_model_executor_->ParsedSupportedFeaturesForLoadedModel<
+          proto::PageTopicsModelMetadata>();
+  if (model_metadata)
+    return model_metadata->version();
   return base::nullopt;
 }
 
diff --git a/components/optimization_guide/content/browser/page_content_annotations_model_manager.h b/components/optimization_guide/content/browser/page_content_annotations_model_manager.h
index 908ee194..f81c664 100644
--- a/components/optimization_guide/content/browser/page_content_annotations_model_manager.h
+++ b/components/optimization_guide/content/browser/page_content_annotations_model_manager.h
@@ -36,6 +36,8 @@
   base::Optional<int64_t> GetPageTopicsModelVersion() const;
 
  private:
+  friend class PageContentAnnotationsModelManagerTest;
+
   // Invoked when the page topics model has finished executing.
   void OnPageTopicsModelExecutionCompleted(
       PageContentAnnotatedCallback callback,
diff --git a/components/optimization_guide/content/browser/page_content_annotations_model_manager_unittest.cc b/components/optimization_guide/content/browser/page_content_annotations_model_manager_unittest.cc
new file mode 100644
index 0000000..7533433
--- /dev/null
+++ b/components/optimization_guide/content/browser/page_content_annotations_model_manager_unittest.cc
@@ -0,0 +1,142 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/optimization_guide/content/browser/page_content_annotations_model_manager.h"
+
+#include "base/path_service.h"
+#include "components/optimization_guide/content/browser/test_optimization_guide_decider.h"
+#include "components/optimization_guide/machine_learning_tflite_buildflags.h"
+#include "components/optimization_guide/proto/page_topics_model_metadata.pb.h"
+#include "content/public/test/browser_task_environment.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace optimization_guide {
+
+using testing::UnorderedElementsAre;
+
+class PageTopicsModelObserverTracker : public TestOptimizationGuideDecider {
+ public:
+  void AddObserverForOptimizationTargetModel(
+      proto::OptimizationTarget target,
+      const base::Optional<proto::Any>& model_metadata,
+      OptimizationTargetModelObserver* observer) override {
+    // Make sure we send what is expected.
+    if (target != proto::OptimizationTarget::OPTIMIZATION_TARGET_PAGE_TOPICS) {
+      return;
+    }
+    registered_model_metadata_ = model_metadata;
+  }
+
+  base::Optional<proto::Any> registered_model_metadata() const {
+    return registered_model_metadata_;
+  }
+
+ private:
+  base::Optional<proto::Any> registered_model_metadata_;
+};
+
+class PageContentAnnotationsModelManagerTest : public testing::Test {
+ public:
+  PageContentAnnotationsModelManagerTest() = default;
+  ~PageContentAnnotationsModelManagerTest() override = default;
+
+  void SetUp() override {
+    model_observer_tracker_ =
+        std::make_unique<PageTopicsModelObserverTracker>();
+    model_manager_ = std::make_unique<PageContentAnnotationsModelManager>(
+        model_observer_tracker_.get());
+  }
+
+  void TearDown() override {
+    model_manager_.reset();
+    model_observer_tracker_.reset();
+  }
+
+  void SendPageTopicsModelToExecutor(const proto::Any& model_metadata) {
+    base::FilePath source_root_dir;
+    base::PathService::Get(base::DIR_SOURCE_ROOT, &source_root_dir);
+    base::FilePath model_file_path =
+        source_root_dir.AppendASCII("components")
+            .AppendASCII("test")
+            .AppendASCII("data")
+            .AppendASCII("optimization_guide")
+            .AppendASCII("bert_page_topics_model.tflite");
+    model_manager()->page_topics_model_executor_->OnModelFileUpdated(
+        proto::OPTIMIZATION_TARGET_PAGE_TOPICS, model_metadata,
+        model_file_path);
+    RunUntilIdle();
+  }
+
+  PageTopicsModelObserverTracker* model_observer_tracker() {
+    return model_observer_tracker_.get();
+  }
+
+  PageContentAnnotationsModelManager* model_manager() {
+    return model_manager_.get();
+  }
+
+  void RunUntilIdle() { task_environment_.RunUntilIdle(); }
+
+ private:
+  content::BrowserTaskEnvironment task_environment_;
+
+  std::unique_ptr<PageTopicsModelObserverTracker> model_observer_tracker_;
+  std::unique_ptr<PageContentAnnotationsModelManager> model_manager_;
+};
+
+TEST_F(PageContentAnnotationsModelManagerTest, RegistersCorrectModelMetadata) {
+  base::Optional<proto::Any> registered_model_metadata =
+      model_observer_tracker()->registered_model_metadata();
+#if BUILDFLAG(BUILD_WITH_TFLITE_LIB)
+  EXPECT_TRUE(registered_model_metadata.has_value());
+  base::Optional<proto::PageTopicsModelMetadata> page_topics_model_metadata =
+      ParsedAnyMetadata<proto::PageTopicsModelMetadata>(
+          *registered_model_metadata);
+  EXPECT_TRUE(page_topics_model_metadata.has_value());
+  EXPECT_EQ(page_topics_model_metadata->supported_output_size(), 2);
+  EXPECT_THAT(
+      page_topics_model_metadata->supported_output(),
+      UnorderedElementsAre(proto::PAGE_TOPICS_SUPPORTED_OUTPUT_SENSITIVITY,
+                           proto::PAGE_TOPICS_SUPPORTED_OUTPUT_CATEGORIES));
+#else
+  EXPECT_FALSE(registered_model_metadata.has_value());
+#endif
+}
+
+TEST_F(PageContentAnnotationsModelManagerTest,
+       GetPageTopicsModelVersionNoPushedModel) {
+  EXPECT_FALSE(model_manager()->GetPageTopicsModelVersion().has_value());
+}
+
+TEST_F(PageContentAnnotationsModelManagerTest,
+       GetPageTopicsModelVersionFromExecutor) {
+  proto::Any any_metadata;
+  any_metadata.set_type_url(
+      "type.googleapis.com/com.foo.PageTopicsModelMetadata");
+  proto::PageTopicsModelMetadata page_topics_model_metadata;
+  page_topics_model_metadata.set_version(123);
+  page_topics_model_metadata.SerializeToString(any_metadata.mutable_value());
+  SendPageTopicsModelToExecutor(any_metadata);
+
+  base::Optional<int64_t> model_version =
+      model_manager()->GetPageTopicsModelVersion();
+  EXPECT_TRUE(model_version.has_value());
+  EXPECT_EQ(model_version.value(), 123);
+}
+
+TEST_F(PageContentAnnotationsModelManagerTest,
+       GetPageTopicsModelVersionFromExecutorBadMetadata) {
+  proto::Any any_metadata;
+  any_metadata.set_type_url(
+      "type.googleapis.com/com.foo.whatevernotpagetopics");
+  any_metadata.set_value("123");
+  SendPageTopicsModelToExecutor(any_metadata);
+
+  base::Optional<int64_t> model_version =
+      model_manager()->GetPageTopicsModelVersion();
+  EXPECT_FALSE(model_version.has_value());
+}
+
+}  // namespace optimization_guide
diff --git a/components/optimization_guide/proto/BUILD.gn b/components/optimization_guide/proto/BUILD.gn
index 813f3be..d85a4f8 100644
--- a/components/optimization_guide/proto/BUILD.gn
+++ b/components/optimization_guide/proto/BUILD.gn
@@ -18,6 +18,7 @@
     "lite_video_metadata.proto",
     "loading_predictor_metadata.proto",
     "models.proto",
+    "page_topics_model_metadata.proto",
     "performance_hints_metadata.proto",
     "public_image_metadata.proto",
   ]
diff --git a/components/optimization_guide/proto/page_topics_model_metadata.proto b/components/optimization_guide/proto/page_topics_model_metadata.proto
new file mode 100644
index 0000000..112aa0b
--- /dev/null
+++ b/components/optimization_guide/proto/page_topics_model_metadata.proto
@@ -0,0 +1,67 @@
+// Copyright 2021 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.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+option java_package = "org.chromium.components.optimization_guide.proto";
+option java_outer_classname = "PageTopicsModelMetadataProto";
+
+package optimization_guide.proto;
+
+enum PageTopicsSupportedOutput {
+  PAGE_TOPICS_SUPPORTED_OUTPUT_UNKNOWN = 0;
+  // Supports evaluating sensitivity of page content.
+  PAGE_TOPICS_SUPPORTED_OUTPUT_SENSITIVITY = 1;
+  // Supports evaluating categories of page content.
+  PAGE_TOPICS_SUPPORTED_OUTPUT_CATEGORIES = 2;
+}
+
+message PageTopicsSensitivityPostprocessingParams {
+  // The name of the category to evaluate for sensitivity.
+  optional string category_name = 1;
+}
+
+message PageTopicsCategoryPostprocessingParams {
+  // Output at most max_categories, and only those with min_category_weight.
+  optional int32 max_categories = 1;
+  // The minimum weight a category must have for it to be in the output.
+  optional float min_category_weight = 2;
+  // The minimum weight after category weights are normalized that the top N
+  // categories must have.
+  optional float min_normalized_weight_within_top_n = 3;
+  // The minimum weight for the NONE label has to be to remove all labels.
+  optional float min_none_weight = 4;
+}
+
+message PageTopicsOutputPostprocessingParams {
+  oneof params {
+    // The parameters to use to post-process sensitivity.
+    //
+    // Should only be used if |supported_output_type| is
+    // PAGE_TOPICS_SUPPORTED_OUTPUT_SENSITIVITY.
+    PageTopicsSensitivityPostprocessingParams sensitivity_params = 1;
+    // The parameters to use to post-process categories.
+    //
+    // Should only be used if |supported_output_type| is
+    // PAGE_TOPICS_SUPPORTED_OUTPUT_CATEGORIES.
+    PageTopicsCategoryPostprocessingParams category_params = 2;
+  }
+}
+
+message PageTopicsModelMetadata {
+  // The version of the model sent by the server, and thus, will only be
+  // populated by the server.
+  optional int64 version = 1;
+  // The supported output.
+  //
+  // If sent by the client, this represents the output that the client knows
+  // how to support. If sent by the server, this represents the outputs of the
+  // model.
+  repeated PageTopicsSupportedOutput supported_output = 2;
+  // A set of postprocessing parameters per supported output and will only be
+  // populated by the server.
+  repeated PageTopicsOutputPostprocessingParams output_postprocessing_params =
+      3;
+}
diff --git a/components/payments/content/secure_payment_confirmation_app_unittest.cc b/components/payments/content/secure_payment_confirmation_app_unittest.cc
index ed4b2e63..f77caf49 100644
--- a/components/payments/content/secure_payment_confirmation_app_unittest.cc
+++ b/components/payments/content/secure_payment_confirmation_app_unittest.cc
@@ -128,8 +128,7 @@
   }
 
   void OnInstrumentDetailsError(const std::string& error_message) override {
-    EXPECT_EQ(error_message,
-              "Authenticator returned AuthenticatorStatus::NOT_ALLOWED_ERROR.");
+    EXPECT_EQ(error_message, "Authenticator returned NOT_ALLOWED_ERROR.");
     on_instrument_details_error_called_ = true;
   }
 
diff --git a/components/policy/core/common/cloud/cloud_policy_client_unittest.cc b/components/policy/core/common/cloud/cloud_policy_client_unittest.cc
index 15c4868..21611bfd 100644
--- a/components/policy/core/common/cloud/cloud_policy_client_unittest.cc
+++ b/components/policy/core/common/cloud/cloud_policy_client_unittest.cc
@@ -336,6 +336,53 @@
 }
 #endif
 
+em::DeviceManagementRequest GetUnregistrationRequest() {
+  em::DeviceManagementRequest unregistration_request;
+  // Accessing the field sets the type of the request.
+  unregistration_request.mutable_unregister_request();
+  return unregistration_request;
+}
+
+em::DeviceManagementResponse GetUnregistrationResponse() {
+  em::DeviceManagementResponse unregistration_response;
+  // Accessing the field sets the type of the response.
+  unregistration_response.mutable_unregister_response();
+  return unregistration_response;
+}
+
+em::DeviceManagementRequest GetUploadMachineCertificateRequest() {
+  em::DeviceManagementRequest upload_machine_certificate_request;
+  upload_machine_certificate_request.mutable_cert_upload_request()
+      ->set_device_certificate(kMachineCertificate);
+  upload_machine_certificate_request.mutable_cert_upload_request()
+      ->set_certificate_type(
+          em::DeviceCertUploadRequest::ENTERPRISE_MACHINE_CERTIFICATE);
+  return upload_machine_certificate_request;
+}
+
+em::DeviceManagementRequest GetUploadEnrollmentCertificateRequest() {
+  em::DeviceManagementRequest upload_enrollment_certificate_request;
+  upload_enrollment_certificate_request.mutable_cert_upload_request()
+      ->set_device_certificate(kEnrollmentCertificate);
+  upload_enrollment_certificate_request.mutable_cert_upload_request()
+      ->set_certificate_type(
+          em::DeviceCertUploadRequest::ENTERPRISE_ENROLLMENT_CERTIFICATE);
+  return upload_enrollment_certificate_request;
+}
+
+em::DeviceManagementRequest GetUploadEnrollmentIdRequest() {
+  em::DeviceManagementRequest upload_enrollment_id_request;
+  upload_enrollment_id_request.mutable_cert_upload_request()->set_enrollment_id(
+      kEnrollmentId);
+  return upload_enrollment_id_request;
+}
+
+em::DeviceManagementResponse GetUploadCertificateResponse() {
+  em::DeviceManagementResponse upload_certificate_response;
+  upload_certificate_response.mutable_cert_upload_response();
+  return upload_certificate_response;
+}
+
 }  // namespace
 
 class CloudPolicyClientTest : public testing::Test {
@@ -344,22 +391,6 @@
       : job_type_(DeviceManagementService::JobConfiguration::TYPE_INVALID),
         client_id_(kClientID),
         policy_type_(dm_protocol::kChromeUserPolicyType) {
-    unregistration_request_.mutable_unregister_request();
-    unregistration_response_.mutable_unregister_response();
-    upload_machine_certificate_request_.mutable_cert_upload_request()
-        ->set_device_certificate(kMachineCertificate);
-    upload_machine_certificate_request_.mutable_cert_upload_request()
-        ->set_certificate_type(
-            em::DeviceCertUploadRequest::ENTERPRISE_MACHINE_CERTIFICATE);
-    upload_enrollment_certificate_request_.mutable_cert_upload_request()
-        ->set_device_certificate(kEnrollmentCertificate);
-    upload_enrollment_certificate_request_.mutable_cert_upload_request()
-        ->set_certificate_type(
-            em::DeviceCertUploadRequest::ENTERPRISE_ENROLLMENT_CERTIFICATE);
-    upload_enrollment_id_request_.mutable_cert_upload_request()
-        ->set_enrollment_id(kEnrollmentId);
-    upload_certificate_response_.mutable_cert_upload_response();
-
     upload_status_request_.mutable_device_status_report_request();
     upload_status_request_.mutable_session_status_report_request();
     upload_status_request_.mutable_child_status_report_request();
@@ -533,10 +564,6 @@
   }
 
   // Request protobufs used as expectations for the client requests.
-  em::DeviceManagementRequest unregistration_request_;
-  em::DeviceManagementRequest upload_machine_certificate_request_;
-  em::DeviceManagementRequest upload_enrollment_certificate_request_;
-  em::DeviceManagementRequest upload_enrollment_id_request_;
   em::DeviceManagementRequest upload_status_request_;
   em::DeviceManagementRequest chrome_desktop_report_request_;
   em::DeviceManagementRequest chrome_os_user_report_request_;
@@ -548,8 +575,6 @@
   em::DeviceManagementRequest robot_auth_code_fetch_request_;
 
   // Protobufs used in successful responses.
-  em::DeviceManagementResponse unregistration_response_;
-  em::DeviceManagementResponse upload_certificate_response_;
   em::DeviceManagementResponse upload_status_response_;
   em::DeviceManagementResponse chrome_desktop_report_response_;
   em::DeviceManagementResponse chrome_os_user_report_response_;
@@ -1209,7 +1234,7 @@
 TEST_F(CloudPolicyClientTest, Unregister) {
   RegisterClient();
 
-  ExpectAndCaptureJob(/*response=*/unregistration_response_);
+  ExpectAndCaptureJob(GetUnregistrationResponse());
   EXPECT_CALL(observer_, OnRegistrationStateChanged);
   client_->Unregister();
   base::RunLoop().RunUntilIdle();
@@ -1217,7 +1242,7 @@
             job_type_);
   EXPECT_EQ(auth_data_, DMAuth::FromDMToken(kDMToken));
   EXPECT_EQ(job_request_.SerializePartialAsString(),
-            unregistration_request_.SerializePartialAsString());
+            GetUnregistrationRequest().SerializePartialAsString());
   EXPECT_FALSE(client_->is_registered());
   EXPECT_EQ(DM_STATUS_SUCCESS, client_->status());
 }
@@ -1226,10 +1251,12 @@
   RegisterClient();
 
   DeviceManagementService::JobConfiguration::JobType job_type;
-  unregistration_response_.clear_unregister_response();
+  em::DeviceManagementResponse unregistration_response =
+      GetUnregistrationResponse();
+  unregistration_response.clear_unregister_response();
   EXPECT_CALL(service_, StartJob)
       .WillOnce(DoAll(service_.CaptureJobType(&job_type),
-                      service_.StartJobOKAsync(unregistration_response_)));
+                      service_.StartJobOKAsync(unregistration_response)));
   EXPECT_CALL(observer_, OnRegistrationStateChanged);
   client_->Unregister();
   base::RunLoop().RunUntilIdle();
@@ -1333,7 +1360,7 @@
 TEST_F(CloudPolicyClientTest, UploadEnterpriseMachineCertificate) {
   RegisterClient();
 
-  ExpectAndCaptureJob(/*response=*/upload_certificate_response_);
+  ExpectAndCaptureJob(GetUploadCertificateResponse());
   EXPECT_CALL(callback_observer_, OnCallbackComplete(true)).Times(1);
   CloudPolicyClient::StatusCallback callback =
       base::BindOnce(&MockStatusCallbackObserver::OnCallbackComplete,
@@ -1344,14 +1371,14 @@
   EXPECT_EQ(DeviceManagementService::JobConfiguration::TYPE_UPLOAD_CERTIFICATE,
             job_type_);
   EXPECT_EQ(job_request_.SerializePartialAsString(),
-            upload_machine_certificate_request_.SerializePartialAsString());
+            GetUploadMachineCertificateRequest().SerializePartialAsString());
   EXPECT_EQ(DM_STATUS_SUCCESS, client_->status());
 }
 
 TEST_F(CloudPolicyClientTest, UploadEnterpriseEnrollmentCertificate) {
   RegisterClient();
 
-  ExpectAndCaptureJob(/*response=*/upload_certificate_response_);
+  ExpectAndCaptureJob(GetUploadCertificateResponse());
   EXPECT_CALL(callback_observer_, OnCallbackComplete(true)).Times(1);
   CloudPolicyClient::StatusCallback callback =
       base::BindOnce(&MockStatusCallbackObserver::OnCallbackComplete,
@@ -1362,15 +1389,17 @@
   EXPECT_EQ(DeviceManagementService::JobConfiguration::TYPE_UPLOAD_CERTIFICATE,
             job_type_);
   EXPECT_EQ(job_request_.SerializePartialAsString(),
-            upload_enrollment_certificate_request_.SerializePartialAsString());
+            GetUploadEnrollmentCertificateRequest().SerializePartialAsString());
   EXPECT_EQ(DM_STATUS_SUCCESS, client_->status());
 }
 
 TEST_F(CloudPolicyClientTest, UploadEnterpriseMachineCertificateEmpty) {
   RegisterClient();
 
-  upload_certificate_response_.clear_cert_upload_response();
-  ExpectAndCaptureJob(/*response=*/upload_certificate_response_);
+  em::DeviceManagementResponse upload_certificate_response =
+      GetUploadCertificateResponse();
+  upload_certificate_response.clear_cert_upload_response();
+  ExpectAndCaptureJob(upload_certificate_response);
   EXPECT_CALL(callback_observer_, OnCallbackComplete(false)).Times(1);
   CloudPolicyClient::StatusCallback callback =
       base::BindOnce(&MockStatusCallbackObserver::OnCallbackComplete,
@@ -1381,15 +1410,17 @@
   EXPECT_EQ(DeviceManagementService::JobConfiguration::TYPE_UPLOAD_CERTIFICATE,
             job_type_);
   EXPECT_EQ(job_request_.SerializePartialAsString(),
-            upload_machine_certificate_request_.SerializePartialAsString());
+            GetUploadMachineCertificateRequest().SerializePartialAsString());
   EXPECT_EQ(DM_STATUS_SUCCESS, client_->status());
 }
 
 TEST_F(CloudPolicyClientTest, UploadEnterpriseEnrollmentCertificateEmpty) {
   RegisterClient();
 
-  upload_certificate_response_.clear_cert_upload_response();
-  ExpectAndCaptureJob(/*response=*/upload_certificate_response_);
+  em::DeviceManagementResponse upload_certificate_response =
+      GetUploadCertificateResponse();
+  upload_certificate_response.clear_cert_upload_response();
+  ExpectAndCaptureJob(upload_certificate_response);
   EXPECT_CALL(callback_observer_, OnCallbackComplete(false)).Times(1);
   CloudPolicyClient::StatusCallback callback =
       base::BindOnce(&MockStatusCallbackObserver::OnCallbackComplete,
@@ -1400,7 +1431,7 @@
   EXPECT_EQ(DeviceManagementService::JobConfiguration::TYPE_UPLOAD_CERTIFICATE,
             job_type_);
   EXPECT_EQ(job_request_.SerializePartialAsString(),
-            upload_enrollment_certificate_request_.SerializePartialAsString());
+            GetUploadEnrollmentCertificateRequest().SerializePartialAsString());
   EXPECT_EQ(DM_STATUS_SUCCESS, client_->status());
 }
 
@@ -1431,7 +1462,7 @@
 TEST_F(CloudPolicyClientTest, UploadEnterpriseEnrollmentId) {
   RegisterClient();
 
-  ExpectAndCaptureJob(/*response=*/upload_certificate_response_);
+  ExpectAndCaptureJob(GetUploadCertificateResponse());
   EXPECT_CALL(callback_observer_, OnCallbackComplete(true)).Times(1);
   CloudPolicyClient::StatusCallback callback =
       base::BindOnce(&MockStatusCallbackObserver::OnCallbackComplete,
@@ -1441,7 +1472,7 @@
   EXPECT_EQ(DeviceManagementService::JobConfiguration::TYPE_UPLOAD_CERTIFICATE,
             job_type_);
   EXPECT_EQ(job_request_.SerializePartialAsString(),
-            upload_enrollment_id_request_.SerializePartialAsString());
+            GetUploadEnrollmentIdRequest().SerializePartialAsString());
   EXPECT_EQ(DM_STATUS_SUCCESS, client_->status());
 }
 
@@ -2000,7 +2031,7 @@
       .WillOnce(DoAll(
           service_.CaptureJobType(&cert_type),
           service_.StartJobAsync(net::OK, DeviceManagementService::kSuccess,
-                                 upload_certificate_response_)));
+                                 GetUploadCertificateResponse())));
 
   // Expect two calls on our upload observer, one for the status upload and
   // one for the certificate upload.
@@ -2071,7 +2102,7 @@
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1, client_->GetActiveRequestCountForTest());
   EXPECT_CALL(observer_, OnRegistrationStateChanged);
-  ExpectAndCaptureJob(/*response=*/unregistration_response_);
+  ExpectAndCaptureJob(GetUnregistrationResponse());
   client_->Unregister();
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(DeviceManagementService::JobConfiguration::TYPE_UPLOAD_STATUS,
@@ -2080,7 +2111,7 @@
             job_type_);
   EXPECT_EQ(auth_data_, DMAuth::FromDMToken(kDMToken));
   EXPECT_EQ(job_request_.SerializePartialAsString(),
-            unregistration_request_.SerializePartialAsString());
+            GetUnregistrationRequest().SerializePartialAsString());
   EXPECT_EQ(0, client_->GetActiveRequestCountForTest());
 }
 
diff --git a/components/policy/core/common/cloud/cloud_policy_validator.cc b/components/policy/core/common/cloud/cloud_policy_validator.cc
index ffa97e11..2e5be327 100644
--- a/components/policy/core/common/cloud/cloud_policy_validator.cc
+++ b/components/policy/core/common/cloud/cloud_policy_validator.cc
@@ -27,24 +27,6 @@
 
 namespace {
 
-const char kMetricPolicyKeyVerification[] = "Enterprise.PolicyKeyVerification";
-
-enum MetricPolicyKeyVerification {
-  // Obsolete. Kept to avoid reuse, as this is used in histograms.
-  // UMA metric recorded when the client has no verification key.
-  METRIC_POLICY_KEY_VERIFICATION_KEY_MISSING_DEPRECATED,
-  // Recorded when the policy being verified has no key signature (e.g. policy
-  // fetched before the server supported the verification key).
-  METRIC_POLICY_KEY_VERIFICATION_SIGNATURE_MISSING,
-  // Recorded when the key signature did not match the expected value (in
-  // theory, this should only happen after key rotation or if the policy cached
-  // on disk has been modified).
-  METRIC_POLICY_KEY_VERIFICATION_FAILED,
-  // Recorded when key verification succeeded.
-  METRIC_POLICY_KEY_VERIFICATION_SUCCEEDED,
-  METRIC_POLICY_KEY_VERIFICATION_SIZE  // Must be the last.
-};
-
 const char kMetricPolicyUserVerification[] =
     "Enterprise.PolicyUserVerification";
 
@@ -392,9 +374,6 @@
   if (!policy_->has_new_public_key_verification_signature_deprecated()) {
     // Policy does not contain a verification signature, so log an error.
     LOG(ERROR) << "Policy is missing public_key_verification_signature";
-    UMA_HISTOGRAM_ENUMERATION(kMetricPolicyKeyVerification,
-                              METRIC_POLICY_KEY_VERIFICATION_SIGNATURE_MISSING,
-                              METRIC_POLICY_KEY_VERIFICATION_SIZE);
     return false;
   }
 
@@ -402,16 +381,10 @@
           policy_->new_public_key(), verification_key_,
           policy_->new_public_key_verification_signature_deprecated())) {
     LOG(ERROR) << "Signature verification failed";
-    UMA_HISTOGRAM_ENUMERATION(kMetricPolicyKeyVerification,
-                              METRIC_POLICY_KEY_VERIFICATION_FAILED,
-                              METRIC_POLICY_KEY_VERIFICATION_SIZE);
     return false;
   }
   // Signature verification succeeded - return success to the caller.
   DVLOG(1) << "Signature verification succeeded";
-  UMA_HISTOGRAM_ENUMERATION(kMetricPolicyKeyVerification,
-                            METRIC_POLICY_KEY_VERIFICATION_SUCCEEDED,
-                            METRIC_POLICY_KEY_VERIFICATION_SIZE);
   return true;
 }
 
diff --git a/components/policy/core/common/cloud/user_cloud_policy_store.cc b/components/policy/core/common/cloud/user_cloud_policy_store.cc
index d21434e..7d37f7f 100644
--- a/components/policy/core/common/cloud/user_cloud_policy_store.cc
+++ b/components/policy/core/common/cloud/user_cloud_policy_store.cc
@@ -39,9 +39,6 @@
 const base::FilePath::CharType kKeyCacheFile[] =
     FILE_PATH_LITERAL("Signing Key");
 
-const char kMetricPolicyHasVerifiedCachedKey[] =
-    "Enterprise.PolicyHasVerifiedCachedKey";
-
 // Maximum policy and key size that will be loaded, in bytes.
 const size_t kPolicySizeLimit = 1024 * 1024;
 const size_t kKeySizeLimit = 16 * 1024;
@@ -201,12 +198,6 @@
     result.key.clear_signing_key();
   }
 
-  // Track the occurrence of valid cached keys - when this ratio gets high
-  // enough, we can update the code to reject unsigned policy or unverified
-  // keys.
-  UMA_HISTOGRAM_BOOLEAN(kMetricPolicyHasVerifiedCachedKey,
-                        result.key.has_signing_key());
-
   return result;
 }
 
diff --git a/components/policy/resources/policy_templates_de.xtb b/components/policy/resources/policy_templates_de.xtb
index d49ce41..8e18e0b 100644
--- a/components/policy/resources/policy_templates_de.xtb
+++ b/components/policy/resources/policy_templates_de.xtb
@@ -893,6 +893,9 @@
       Diese Vorschläge werden per Remotezugriff von Google-Servern abgerufen.
 
       Wird die Richtlinie auf "false" gesetzt, werden keine Vorschläge abgerufen oder angezeigt.</translation>
+<translation id="2246011554082893079">Steuert die Verfügbarkeit von <ph name="BOREALIS_NAME" /> für dieses Gerät.
+
+      Wenn die Richtlinie auf „false“ gesetzt ist, steht <ph name="BOREALIS_NAME" /> Nutzern dieses Geräts nicht zur Verfügung. Wenn die Richtlinie nicht konfiguriert oder auf „true“ gesetzt ist, ist <ph name="BOREALIS_NAME" /> verfügbar, sofern die Richtlinie nicht durch eine andere Richtlinie oder Einstellung außer Kraft gesetzt wird.</translation>
 <translation id="225340736558643885">Warnmeldungen für nicht sichere Formulare aktivieren</translation>
 <translation id="2258126710006312594">Nutzern mit Remotezugriff die Übertragung von Dateien vom/zum Host gestatten</translation>
 <translation id="2261329877420573811">Wenn <ph name="PRINTERS_WHITELIST" /> für <ph name="DEVICE_PRINTERS_ACCESS_MODE_POLICY_NAME" /> ausgewählt ist, wird durch Festlegen von <ph name="DEVICE_NATIVE_PRINTERS_WHITELIST_POLICY_NAME" /> angegeben, welche Drucker die Nutzer verwenden können. Den Nutzern stehen nur die Drucker zur Verfügung, deren IDs mit den Werten in dieser Richtlinie übereinstimmen. Die IDs müssen dem Feld <ph name="ID_FIELD" /> oder dem Feld <ph name="GUID_FIELD" /> in der Datei entsprechen, die in <ph name="DEVICE_PRINTERS_POLICY_NAME" /> angegeben ist.
@@ -1113,6 +1116,13 @@
           Ist die Richtlinie nicht konfiguriert, ist "Textcursor hervorheben" anfangs deaktiviert, kann jedoch vom Nutzer jederzeit aktiviert werden.</translation>
 <translation id="2509919237512982967">Verwenden Sie alte Formularsteuerelemente bis M84.</translation>
 <translation id="2515699738406900920">Verfügbarkeit von Profil-Picker beim Start</translation>
+<translation id="2515914624025258624">Diese Einstellung erlaubt Nutzern, sekundäre Profile zu erstellen und den Gastmodus im <ph name="LACROS_NAME" />-Browser zu verwenden.
+
+      Wenn diese Richtlinie auf „false“ gesetzt oder nicht konfiguriert ist, kann der Nutzer ähnlich wie bei BrowserAddPersonEnabled und BrowserGuestModeEnabled keine sekundären Profile erstellen und den Gastmodus nicht verwenden.
+
+      Ist diese Richtlinie auf „true“ festgelegt, kann der Nutzer sekundäre Profile erstellen und den Gastmodus verwenden.
+
+      Beachten Sie, dass der Nutzer keine sekundären Profile erstellen kann, wenn diese Richtlinie auf „true“ gesetzt ist, BrowserAddPersonEnabled jedoch auf „false“. Dasselbe gilt für BrowserGuestModeEnabled und den Gastmodus.</translation>
 <translation id="2517466659416174529">Deaktivieren von Tabs im Hintergrund zulassen</translation>
 <translation id="2518231489509538392">Wiedergabe von Audioinhalten zulassen</translation>
 <translation id="2521581787935130926">App-Verknüpfung in der Lesezeichenleiste anzeigen</translation>
@@ -1438,6 +1448,9 @@
 <translation id="2960013482187484833">Zuletzt genutzten Drucker als Standarddrucker in der Druckvorschau verwenden</translation>
 <translation id="2960128438010718932">Staging-Zeitplan zum Anwenden eines neuen Updates</translation>
 <translation id="2960691910306063964">Authentifizierung ohne PIN für Hosts für den Remotezugriff aktivieren oder deaktivieren</translation>
+<translation id="2964056138564883247">Steuert die Verfügbarkeit von <ph name="BOREALIS_NAME" /> für diesen Nutzer.
+
+      Wenn die Richtlinie auf „false“ gesetzt ist, steht <ph name="BOREALIS_NAME" /> nicht zur Verfügung. Wenn die Richtlinie nicht konfiguriert oder auf „true“ gesetzt ist, ist <ph name="BOREALIS_NAME" /> verfügbar, sofern die Richtlinie nicht durch eine andere Richtlinie oder Einstellung außer Kraft gesetzt wird.</translation>
 <translation id="2964373560810620158">Verhindern, dass Nutzer den <ph name="LACROS_NAME" />-Browser verwenden</translation>
 <translation id="2969797921412053304">Mit dieser Richtlinie wird festgelegt, welche URLs während des SAML-Flows auf dem Anmeldebildschirm die Remote-Attestierung der Geräteidentität verwenden dürfen.
 
@@ -2710,6 +2723,7 @@
       Wenn Sie diese Richtlinie konfigurieren, kann sie von Nutzern nicht geändert werden. Falls die Richtlinie nicht konfiguriert ist, können Nutzer selbst entscheiden, ob die Ablage automatisch ausgeblendet werden soll.</translation>
 <translation id="4812714598405913256">Meldung zum Ablaufdatum für die automatische Aktualisierung für die Richtlinie DeviceMinimumVersion konfigurieren</translation>
 <translation id="4816674326202173458">Unternehmensnutzer sowohl als primären als auch als sekundären Nutzer zulassen (Standardverhalten für nicht verwaltete Nutzer)</translation>
+<translation id="4820432864264617413">Ausführung von <ph name="BOREALIS_NAME" /> für einen Nutzer verhindern</translation>
 <translation id="4826326557828204741">Auszuführende Aktion beim Erreichen der Leerlaufverzögerung während des Akkubetriebs</translation>
 <translation id="482803100714220060">Vollständige URLs anzeigen</translation>
 <translation id="4832852360828533362">Berichte zu Nutzern und Geräten</translation>
@@ -2723,6 +2737,7 @@
       Wenn sie nicht konfiguriert ist oder einen ungültigen Wert enthält, ist der Deaktivierungsmodus in den Systemfunktionen auf „blockiert“ gesetzt.</translation>
 <translation id="4835470005923546373">Standardmäßig Druckmodus mit Hintergrundgrafiken deaktivieren</translation>
 <translation id="4835622243021053389">NTLMv2-Authentifizierung aktivieren.</translation>
+<translation id="485419696366295465">Steuert zum <ph name="BOREALIS_NAME" />-Subsystem gehörige Richtlinien.</translation>
 <translation id="4855636880814771207">Wenn die Richtlinie aktiviert oder nicht konfiguriert ist, können Nutzer Bluetooth aktivieren oder deaktivieren.
 
       Wenn die Richtlinie deaktiviert ist, wird Bluetooth von <ph name="PRODUCT_OS_NAME" /> deaktiviert und Nutzer können es nicht aktivieren.
@@ -3194,6 +3209,7 @@
 
           Wenn die Richtlinie deaktiviert wird, ist die Funktion standardmäßig deaktiviert.
           </translation>
+<translation id="5432043531153963184">Nutzer daran hindern, sekundäre Profile zu erstellen und den Gastmodus im <ph name="LACROS_NAME" />-Browser zu verwenden</translation>
 <translation id="5442026853063570579">Mit dieser Richtlinie wird außerdem der Zugriff auf Android-Entwickleroptionen festgelegt. Wenn Sie diese Richtlinie auf "DeveloperToolsDisallowed" (Wert 2) setzen, können Nutzer nicht auf die Entwickleroptionen zugreifen. Wenn Sie diese Richtlinie auf einen anderen Wert setzen oder sie nicht festlegen, können Nutzer auf die Entwickleroptionen zugreifen, indem sie in der Android-App "Einstellungen" siebenmal auf die Build-Nummer tippen.</translation>
 <translation id="5445596354079213552">Diese Richtlinie wird nur angewendet, wenn das Gerät das Ablaufdatum für die automatische Aktualisierung erreicht hat und die durch die Richtlinie <ph name="DEVICE_MINIMUM_VERSION_POLICY_NAME" /> festgelegte Mindestanforderung im Hinblick auf die <ph name="PRODUCT_OS_NAME" />-Version nicht mehr erfüllt.
 
@@ -3277,6 +3293,7 @@
 <translation id="554903022911579950">Kerberos</translation>
 <translation id="555022085242359084">Hohen Kontrast auf dem Anmeldebildschirm aktivieren</translation>
 <translation id="555077880566103058">Automatische Ausführung des Plug-ins "<ph name="FLASH_PLUGIN_NAME" />" für alle Websites zulassen</translation>
+<translation id="5556607617517096419">Borealis</translation>
 <translation id="5559079916187891399">Diese Richtlinie hat keine Auswirkung auf Android-Apps.</translation>
 <translation id="5560039246134246593">Hiermit fügen Sie beim Abrufen des Varianten-Seeds in <ph name="PRODUCT_NAME" /> einen Parameter hinzu.
 
@@ -3481,6 +3498,7 @@
 <translation id="5814301096961727113">Standardstatus für das gesprochene Feedback auf der Anmeldeseite festlegen</translation>
 <translation id="5815129011704381141">Nach Update automatisch neu starten</translation>
 <translation id="582857022372205358">Duplexdruck (kurze Kante) aktivieren</translation>
+<translation id="5830196507442186669">Geräten die Verwendung von <ph name="BOREALIS_NAME" /> unter <ph name="PRODUCT_OS_NAME" /> erlauben</translation>
 <translation id="5832274826894536455">Veraltete Richtlinien</translation>
 <translation id="5835253272509953988">Wenn die Richtlinie aktiviert ist, können Nutzer von <ph name="PRODUCT_NAME" /> prüfen lassen, ob die eingegebenen Nutzernamen und Passwörter Teil eines Datenlecks sind.
 
@@ -3693,12 +3711,14 @@
 <translation id="6097601282776163274">Anonymisierte URL-Datenerfassung aktivieren</translation>
 <translation id="6099853574908182288">Standardmäßiger Farbdruckmodus</translation>
 <translation id="6102342563050263313">Scrollen zu in URL-Fragmenten angegebenem Text aktivieren</translation>
+<translation id="6102449843040973938">Ausführung von <ph name="BOREALIS_NAME" /> auf einem Gerät nicht verhindern</translation>
 <translation id="6107642964266628393">Legt fest, wie und wann Chrome OS-Updates angewendet werden.</translation>
 <translation id="6111936128861357925">Easter Egg-Dinosaurierspiel zulassen</translation>
 <translation id="6123052603197028610">Anfragen an Google-Server dürfen keine Zeitstempel abrufen</translation>
 <translation id="6132506775968708399">Drittanbieter-Cookies blockieren</translation>
 <translation id="6133088669883929098">Schlüsselgenerierung für alle Websites zulassen</translation>
 <translation id="6135398260575578389">Safe Browsing ist im erweiterten Modus aktiv. Dieser bietet einen besseren Schutz. Es müssen jedoch mehr Browserdaten mit Google geteilt werden.</translation>
+<translation id="6135895880862759946">Nutzern erlauben, sekundäre Profile zu erstellen und den Gastmodus im <ph name="LACROS_NAME" />-Browser zu verwenden</translation>
 <translation id="6138636318340561140">Safe Browsing-Status von URLs in Echtzeit prüfen</translation>
 <translation id="6141402445226505817">Immer die ungefähre Erkennung der Zeitzone verwenden</translation>
 <translation id="6144046700495610112">Wenn die Richtlinie aktiviert ist, werden Formulardaten zum automatischen Ausfüllen bei der ersten Ausführung aus dem Standardbrowser importiert. Ist die Richtlinie deaktiviert oder nicht konfiguriert, werden bei der ersten Ausführung keine Formulardaten zum automatischen Ausfüllen importiert.
@@ -3759,6 +3779,7 @@
       Dadurch entstehen Sicherheitsrisiken für den Nutzer, die auf die Ausführung des Audiosubsystems ohne Sandbox zurückzuführen sind.
       Wenn die Richtlinie nicht konfiguriert wird, kommt die Standardkonfiguration für die Audio-Sandbox zum Einsatz, die je nach Plattform variiert.
       Mit dieser Richtlinie sollen Unternehmen die Möglichkeit erhalten, die Audio-Sandbox zu deaktivieren, falls sie Softwarekonfigurationen für die Sicherheit einsetzen, die mit der Sandbox in Konflikt stehen könnten.</translation>
+<translation id="6252773211180267325">Ausführung von <ph name="BOREALIS_NAME" /> für einen Nutzer nicht verhindern</translation>
 <translation id="6261643884958898336">Gerätebezogene Daten erfassen</translation>
 <translation id="6265892395051519509">Diesen Websites den Zugriff auf Sensoren erlauben</translation>
 <translation id="6273015149273504999">
@@ -4229,6 +4250,7 @@
 
 
       Hiermit werden die Parameter angegeben, die beim Starten von <ph name="PRODUCT_NAME" /> angewendet werden sollen. Sie gelten nur auf dem Anmeldebildschirm. Über diese Richtlinie festgelegte Parameter haben keine Auswirkungen auf Nutzersitzungen.</translation>
+<translation id="6857240169209507953">Ausführung von <ph name="BOREALIS_NAME" /> auf einem Gerät verhindern</translation>
 <translation id="685769593149966548">Strikt eingeschränkten Modus auf YouTube erzwingen</translation>
 <translation id="686079137349561371">Microsoft Windows 7 oder höher</translation>
 <translation id="68818134518270542">Mit der Konfiguration der Richtlinie werden die Apps festgelegt, die Nutzer als Notizen-App auf dem Sperrbildschirm von <ph name="PRODUCT_OS_NAME" /> aktivieren können.
@@ -4651,6 +4673,7 @@
       Wenn für diese Richtlinie "RemoveLRUIfDormant" festgelegt ist, entfernt die automatische Bereinigungsfunktion nur diejenigen Nutzer vom Gerät, die seit mindestens drei Monaten nicht mehr angemeldet waren. Diese Nutzer werden in der chronologischen Reihenfolge ihrer letzten Anmeldung vom Gerät gelöscht, bis wieder genügend freier Speicher vorhanden ist.
 
       Ist die Richtlinie nicht konfiguriert, erfolgt die automatische Bereinigung auf Grundlage der integrierten Standardstrategie. Zurzeit handelt es sich dabei um die "RemoveLRUIfDormant"-Strategie.</translation>
+<translation id="7334517274921831425">Nutzern die Verwendung von <ph name="BOREALIS_NAME" /> unter <ph name="PRODUCT_OS_NAME" /> erlauben</translation>
 <translation id="7336785017449297672">Legt die Einstellungen für die Uhrzeit und Zeitzone fest.</translation>
 <translation id="7336878834592315572">Cookies für die Dauer der Sitzung beibehalten</translation>
 <translation id="7338217396351647423">Über eine Konfiguration dieser Richtlinie wird eine Reihe von Richtlinien angegeben, die für die ARC-Laufzeit übergeben werden. Damit können Administratoren Android-Apps für die automatische Installation festlegen. Geben Sie einen gültigen JSON-Wert an.
@@ -5071,6 +5094,12 @@
 <translation id="7933141401888114454">Erstellung von betreuten Nutzern aktivieren</translation>
 <translation id="793473937901685727">Verfügbarkeit von Zertifikaten für ARC-Apps festlegen</translation>
 <translation id="7937766917976512374">Videoaufzeichnung gestatten oder ablehnen</translation>
+<translation id="7940359358774136765">Aktiviert eine Seite auf chrome://password-change, auf der SAML-Nutzer ihre SAML-Passwörter bei laufender Sitzung ändern können. Hierdurch wird dafür gesorgt, dass das SAML-Passwort und das Passwort für den Sperrbildschirm des Geräts synchronisiert bleiben.
+
+      Außerdem ermöglicht diese Richtlinie Benachrichtigungen, mit denen SAML-Nutzer gewarnt werden, wenn ihre SAML-Passwörter bald ablaufen. Sie können dann direkt bei laufender Sitzung ihr Passwort ändern.
+      Allerdings werden diese Benachrichtigungen nur angezeigt, wenn vom SAML-Identitätsanbieter während des SAML-Anmeldeablaufs Informationen zum Ablauf des Passworts an das Gerät gesendet werden.
+
+      Ist die Richtlinie deaktiviert oder nicht konfiguriert, kann das SAML-Passwort auf chrome://password-change nicht geändert werden und Sie erhalten keine Benachrichtigung, wenn SAML-Passwörter bald ablaufen.</translation>
 <translation id="7941975817681987555">Netzwerkaktionen nicht über Netzwerkverbindungen vervollständigen</translation>
 <translation id="7951605113561734721">Diese Richtlinie gibt geräteübergreifende Clientzertifikate an, die über das Geräteverwaltungsprotokoll registriert werden sollen.</translation>
 <translation id="7952007677054834789">Hiermit werden die Seiten konfiguriert, die beim Start geladen werden: die standardmäßige Startseite und die Standardseite "Neuer Tab" in <ph name="PRODUCT_NAME" />. Außerdem wird verhindert, dass Nutzer diese Einstellungen ändern.
diff --git a/components/policy/resources/policy_templates_uk.xtb b/components/policy/resources/policy_templates_uk.xtb
index 8a29989d..cab6e8c 100644
--- a/components/policy/resources/policy_templates_uk.xtb
+++ b/components/policy/resources/policy_templates_uk.xtb
@@ -915,9 +915,9 @@
       Ці пропозиції завантажуються віддалено із серверів Google.
 
       Якщо вибрано значення false, пропозиції не будуть завантажуватись або відображатися.</translation>
-<translation id="2246011554082893079">Керує доступністю правила "<ph name="BOREALIS_NAME" />" для цього пристрою.
+<translation id="2246011554082893079">Керує доступністю правила <ph name="BOREALIS_NAME" /> для цього пристрою.
 
-      Правило "<ph name="BOREALIS_NAME" />" буде недоступне для всіх користувачів пристрою, якщо для нього вибрано значення false. Інакше (якщо правило не налаштовано або для нього встановлено значення true) правило "<ph name="BOREALIS_NAME" />" буде доступне, лише якщо інше правило чи налаштування не вимикатиме його.</translation>
+      Якщо вибрати значення false, правило <ph name="BOREALIS_NAME" /> буде недоступне для всіх користувачів пристрою. Якщо ж не налаштовувати правило або вибрати для нього значення true, правило <ph name="BOREALIS_NAME" /> буде доступне, лише якщо інше правило чи налаштування не вимикатиме його.</translation>
 <translation id="225340736558643885">Увімкнути попередження про ненадійні форми</translation>
 <translation id="2258126710006312594">Дозволити користувачам із віддаленим доступом переносити файли на хост і з нього</translation>
 <translation id="2261329877420573811">Якщо для правила <ph name="DEVICE_PRINTERS_ACCESS_MODE_POLICY_NAME" /> вибрано параметр <ph name="PRINTERS_WHITELIST" />, тоді налаштування <ph name="DEVICE_NATIVE_PRINTERS_WHITELIST_POLICY_NAME" /> визначає, які принтери можна використовувати. Користувачам доступні лише принтери з переліченими в правилі ідентифікаторами. Ідентифікатори мають відповідати полю <ph name="ID_FIELD" /> або <ph name="GUID_FIELD" /> у файлі, указаному в правилі <ph name="DEVICE_PRINTERS_POLICY_NAME" />.
@@ -1474,9 +1474,9 @@
 <translation id="2960013482187484833">За умовчанням використовувати в режимі попереднього перегляду останній вибраний принтер</translation>
 <translation id="2960128438010718932">Поетапний графік застосування нового оновлення</translation>
 <translation id="2960691910306063964">Увімкнути або вимкнути автентифікацію без PIN-коду для хостів віддаленого доступу</translation>
-<translation id="2964056138564883247">Керує доступністю правила "<ph name="BOREALIS_NAME" />" для цього користувача.
+<translation id="2964056138564883247">Керує доступністю правила <ph name="BOREALIS_NAME" /> для цього користувача.
 
-      Правило "<ph name="BOREALIS_NAME" />" буде недоступне, якщо для нього вибрано значення false. Інакше (якщо правило не налаштовано або для нього встановлено значення true) правило "<ph name="BOREALIS_NAME" />" буде доступне, лише якщо інше правило чи налаштування не вимикатиме його.</translation>
+      Якщо вибрати значення false, правило <ph name="BOREALIS_NAME" /> буде недоступне. Якщо ж не налаштовувати правило або вибрати для нього значення true, правило <ph name="BOREALIS_NAME" /> буде доступне, лише якщо інше правило чи налаштування не вимикатиме його.</translation>
 <translation id="2964373560810620158">Заборонити використовувати веб-переглядач <ph name="LACROS_NAME" /></translation>
 <translation id="2969797921412053304">Це правило визначає, які URL-адреси зможуть віддалено засвідчувати облікові дані пристрою під час процедури SAML на екрані входу.
 
@@ -2750,7 +2750,7 @@
       Якщо це правило налаштовано, користувачі не зможуть змінювати його. Якщо це правило не налаштовано, користувачі вибирають, чи потрібно автоматично ховати панель.</translation>
 <translation id="4812714598405913256">Налаштувати повідомлення про припинення дії автоматичних оновлень для правила DeviceMinimumVersion</translation>
 <translation id="4816674326202173458">Дозволити корпоративному користувачеві бути основним і додатковим користувачем (налаштування за умовчанням для користувачів, якими не керує адміністратор підприємства)</translation>
-<translation id="4820432864264617413">Запобігати виконанню правила "<ph name="BOREALIS_NAME" />" для користувача</translation>
+<translation id="4820432864264617413">Запобігати виконанню правила <ph name="BOREALIS_NAME" /> для користувача</translation>
 <translation id="4826326557828204741">Дія, яка має виконуватися під час живлення від акумулятора, коли виникає затримка через неактивність</translation>
 <translation id="482803100714220060">Показувати повні URL-адреси</translation>
 <translation id="4832852360828533362">Звіти про користувачів і пристрої</translation>
@@ -2764,7 +2764,7 @@
       Якщо це правило не налаштовано або має недійсне значення, режим блокування системних функцій буде "заблоковано".</translation>
 <translation id="4835470005923546373">Вимкнути режим друку з фоновими зображеннями за умовчанням</translation>
 <translation id="4835622243021053389">Увімкнути автентифікацію NTLMv2.</translation>
-<translation id="485419696366295465">Керує правилом, пов'язаним із підсистемою "<ph name="BOREALIS_NAME" />"</translation>
+<translation id="485419696366295465">Керує правилами для підсистеми <ph name="BOREALIS_NAME" />.</translation>
 <translation id="4855636880814771207">Якщо для цього правила вибрано значення Enabled або його не налаштовано, користувачі зможуть вмикати й вимикати Bluetooth.
 
       Якщо для цього правила вибрано значення Disabled, <ph name="PRODUCT_OS_NAME" /> вимикає Bluetooth і користувачі не зможуть увімкнути цю технологію.
@@ -3536,7 +3536,7 @@
 <translation id="5814301096961727113">Налаштувати стан за умовчанням для голосових підказок на екрані входу</translation>
 <translation id="5815129011704381141">Автоматично перезавантажувати після оновлення</translation>
 <translation id="582857022372205358">Увімкнути двосторонній друк за коротким краєм</translation>
-<translation id="5830196507442186669">Дозволити пристроям застосовувати правило "<ph name="BOREALIS_NAME" />" на <ph name="PRODUCT_OS_NAME" /></translation>
+<translation id="5830196507442186669">Дозволити пристроям застосовувати правило <ph name="BOREALIS_NAME" /> в <ph name="PRODUCT_OS_NAME" /></translation>
 <translation id="5832274826894536455">Правила, які не підтримуються</translation>
 <translation id="5835253272509953988">Якщо це правило ввімкнено, <ph name="PRODUCT_NAME" /> може перевіряти, чи був витік введених імен користувачів і паролів.
 
@@ -3750,7 +3750,7 @@
 <translation id="6097601282776163274">Увімкнути збір анонімних даних, захищених паролем URL-адрес</translation>
 <translation id="6099853574908182288">Стандартні параметри кольорового друку</translation>
 <translation id="6102342563050263313">Увімкнути прокручування до тексту з фрагментів у URL-адресі</translation>
-<translation id="6102449843040973938">Не запобігати виконанню правила "<ph name="BOREALIS_NAME" />" на пристрої</translation>
+<translation id="6102449843040973938">Не запобігати виконанню правила <ph name="BOREALIS_NAME" /> на пристрої</translation>
 <translation id="6107642964266628393">Контролює, як і коли застосовуються оновлення ОС Chrome.</translation>
 <translation id="6111936128861357925">Дозволити грати в гру Dinosaur Easter Egg</translation>
 <translation id="6123052603197028610">Заборонити запити до серверів Google для отримання позначок часу</translation>
@@ -3815,7 +3815,7 @@
       Через це користувачі можуть зіштовхнутися із загрозами безпеці, пов'язаними з підсистемою аудіо, що обробляється поза режимом ізольованого програмного середовища.
       Якщо це правило не налаштовано, для ізольованого програмного середовища для аудіо застосовуватимуться параметри за умовчанням, які можуть відрізнятися залежно від платформи.
       Це правило дає можливість підприємствам вимикати ізольоване програмне середовище для аудіо, якщо вони користуються програмним забезпеченням для захисту, яке конфліктує з ним.</translation>
-<translation id="6252773211180267325">Не запобігати виконанню правила "<ph name="BOREALIS_NAME" />" для користувача</translation>
+<translation id="6252773211180267325">Не запобігати виконанню правила <ph name="BOREALIS_NAME" /> для користувача</translation>
 <translation id="6261643884958898336">Повідомляти ідентифікаційну інформацію комп’ютера</translation>
 <translation id="6265892395051519509">Надати доступ до датчиків на цих сайтах</translation>
 <translation id="6273015149273504999">
@@ -4285,7 +4285,7 @@
 <translation id="6856743875250214792">Це правило не підтримується та видалене у версії M66, оскільки воно використовувалося в цілях безпеки та лише для внутрішнього тестування.
 
       Указує позначки, які мають застосовуватися під час запуску <ph name="PRODUCT_NAME" />. Вони застосовуються лише на екрані входу. Позначки, додані за допомогою цього правила, не поширюються на сеанси користувача.</translation>
-<translation id="6857240169209507953">Запобігати виконанню правила "<ph name="BOREALIS_NAME" />" на пристрої</translation>
+<translation id="6857240169209507953">Запобігати виконанню правила <ph name="BOREALIS_NAME" /> на пристрої</translation>
 <translation id="685769593149966548">Застосувати строгий безпечний режим на YouTube</translation>
 <translation id="686079137349561371">Microsoft Windows 7 і новіших версій</translation>
 <translation id="68818134518270542">За допомогою цього правила можна створити список додатків, які користувачі можуть використовувати для нотаток на заблокованому екрані пристрою <ph name="PRODUCT_OS_NAME" />.
@@ -4709,7 +4709,7 @@
       Якщо для цього правила встановлено значення "RemoveLRUIfDormant", під час автоматичного очищення з пристрою видалятимуться дані користувачів, які не входили в обліковий запис протягом останніх 3 місяців, починаючи з тих, які входили в обліковий запис найдавніше, доки не буде звільнено достатньо місця.
 
       Якщо це правило не встановлено, під час автоматичного очищення використовується правило за умовчанням. Зараз це правило "RemoveLRUIfDormant".</translation>
-<translation id="7334517274921831425">Дозволити користувачам застосовувати правило "<ph name="BOREALIS_NAME" />" на <ph name="PRODUCT_OS_NAME" /></translation>
+<translation id="7334517274921831425">Дозволити користувачам застосовувати правило <ph name="BOREALIS_NAME" /> в <ph name="PRODUCT_OS_NAME" /></translation>
 <translation id="7336785017449297672">Керує налаштуваннями годинника й часового поясу.</translation>
 <translation id="7336878834592315572">Зберігати файли cookie впродовж сеансу</translation>
 <translation id="7338217396351647423">Налаштування цього правила визначають набір умов, які буде передано середовищу виконання ARC. Адміністратори можуть використовувати його, щоб вибирати, які додатки для Android можуть встановлюватися автоматично. Введіть значення в дійсному форматі JSON.
diff --git a/components/policy/resources/policy_templates_zh-CN.xtb b/components/policy/resources/policy_templates_zh-CN.xtb
index 70e138e2..4c80d50 100644
--- a/components/policy/resources/policy_templates_zh-CN.xtb
+++ b/components/policy/resources/policy_templates_zh-CN.xtb
@@ -894,6 +894,9 @@
       这些建议是系统从 Google 服务器远程获取的。
 
       如果此政策设为 false,系统将不会获取或显示这类建议。</translation>
+<translation id="2246011554082893079">控制该设备能否使用 <ph name="BOREALIS_NAME" />。
+
+      如果此政策设为 false,该设备的所有用户都将无法使用 <ph name="BOREALIS_NAME" />。否则(如果此政策未设置或设为 true),仅当未被任何其他政策或设置停用时,<ph name="BOREALIS_NAME" /> 才可用。</translation>
 <translation id="225340736558643885">启用针对不安全表单的警告</translation>
 <translation id="2258126710006312594">允许远程访问用户将文件传到主机或接收从主机传出的文件</translation>
 <translation id="2261329877420573811">如果为 <ph name="DEVICE_PRINTERS_ACCESS_MODE_POLICY_NAME" /> 选择了 <ph name="PRINTERS_WHITELIST" />,您便可通过设置 <ph name="DEVICE_NATIVE_PRINTERS_WHITELIST_POLICY_NAME" /> 来指定用户可以使用哪些打印机。用户将只能使用那些符合条件(ID 与此政策中所列的值匹配)的打印机。ID 必须与 <ph name="DEVICE_PRINTERS_POLICY_NAME" /> 所指定文件内的<ph name="ID_FIELD" />或<ph name="GUID_FIELD" />字段相符。
@@ -1114,13 +1117,13 @@
           如果未设置此政策,则“插入符号突出显示”最初会处于停用状态,但用户可以随时启用该功能。</translation>
 <translation id="2509919237512982967">在 M84 之前的版本中使用旧版表单控件。</translation>
 <translation id="2515699738406900920">在 Chrome 启动时是否显示个人资料选择器</translation>
-<translation id="2515914624025258624">此设置允许用户在 <ph name="LACROS_NAME" /> 浏览器中创建辅助个人资料以及使用访客模式。
+<translation id="2515914624025258624">此设置允许用户在 <ph name="LACROS_NAME" /> 浏览器中创建次级个人资料以及使用访客模式。
 
-      与 BrowserAddPersonEnabled 和 BrowserGuestModeEnabled 这两项政策类似,如果此政策设为 false 或未设置,用户将无法创建辅助个人资料,也无法使用访客模式。
+      与 BrowserAddPersonEnabled 和 BrowserGuestModeEnabled 这两项政策类似,如果此政策设为 false 或未设置,用户将无法创建次级个人资料,也无法使用访客模式。
 
-      如果此政策设为 true,用户将能够创建辅助个人资料以及使用访客模式。
+      如果此政策设为 true,用户将能够创建次级个人资料以及使用访客模式。
 
-      请注意,如果此政策设为 true 但 BrowserAddPersonEnabled 设为 false,用户将无法创建辅助个人资料。同理,如果此政策设为 true 但 BrowserGuestModeEnabled 设为 false,用户将无法使用访客模式。</translation>
+      请注意,如果此政策设为 true 但 BrowserAddPersonEnabled 设为 false,用户将无法创建次级个人资料。同理,如果此政策设为 true 但 BrowserGuestModeEnabled 设为 false,用户将无法使用访客模式。</translation>
 <translation id="2517466659416174529">允许系统冻结后台标签页</translation>
 <translation id="2518231489509538392">允许播放视频</translation>
 <translation id="2521581787935130926">在书签栏中显示应用快捷方式</translation>
@@ -1446,6 +1449,9 @@
 <translation id="2960013482187484833">在打印预览中将上次使用的打印机设为默认选项</translation>
 <translation id="2960128438010718932">分阶段应用新更新的时间表</translation>
 <translation id="2960691910306063964">针对远程访问主机启用或停用无 PIN 码身份验证</translation>
+<translation id="2964056138564883247">控制该用户能否使用 <ph name="BOREALIS_NAME" />。
+
+      如果此政策设为 false,<ph name="BOREALIS_NAME" /> 会处于不可用状态。否则(如果此政策未设置或设为 true),仅当未被任何其他政策或设置停用时,<ph name="BOREALIS_NAME" /> 才可用。</translation>
 <translation id="2964373560810620158">阻止用户使用 <ph name="LACROS_NAME" /> 浏览器</translation>
 <translation id="2969797921412053304">此政策用于配置哪些网址有权在登录屏幕上的 SAML 流程中对设备身份执行远程认证。
 
@@ -2705,6 +2711,7 @@
       如果您设置了此政策,用户便无法更改它。如果您不设置此政策,用户可以决定是否让工具栏自动隐藏。</translation>
 <translation id="4812714598405913256">为 DeviceMinimumVersion 政策配置自动更新期限已过消息</translation>
 <translation id="4816674326202173458">允许企业用户以主用户或次要用户的身份登录多个人资料会话(非托管用户的默认行为)</translation>
+<translation id="4820432864264617413">禁止用户运行 <ph name="BOREALIS_NAME" /></translation>
 <translation id="4826326557828204741">当闲置延迟时间已过且使用电池供电时应执行的操作</translation>
 <translation id="482803100714220060">显示完整网址</translation>
 <translation id="4832852360828533362">用户和设备报告</translation>
@@ -2718,6 +2725,7 @@
       如果此政策未设置或包含无效值,系统功能的停用模式将会是“已禁用”。</translation>
 <translation id="4835470005923546373">默认停用背景图片打印模式</translation>
 <translation id="4835622243021053389">启用 NTLMv2 身份验证。</translation>
+<translation id="485419696366295465">控制与 <ph name="BOREALIS_NAME" /> 子系统相关的政策。</translation>
 <translation id="4855636880814771207">如果此政策已启用或未设置,用户将可以开启或关闭蓝牙。
 
       如果此政策已停用,<ph name="PRODUCT_OS_NAME" />会关闭蓝牙,而且用户无法开启它。
@@ -3185,7 +3193,7 @@
 
           如果此政策已停用,系统会强制停用该功能。
           </translation>
-<translation id="5432043531153963184">禁止用户在 <ph name="LACROS_NAME" /> 浏览器中创建辅助个人资料以及使用访客模式</translation>
+<translation id="5432043531153963184">禁止用户在 <ph name="LACROS_NAME" /> 浏览器中创建次级个人资料以及使用访客模式</translation>
 <translation id="5442026853063570579">此政策亦用于控制对 Android 开发者选项的访问权限。如果此政策设为“DeveloperToolsDisallowed”(值为 2),用户将无法访问开发者选项。如果此政策设为其他值或未设置,用户只需在 Android 的“设置”应用中连续点按 7 次版本号即可访问开发者选项。</translation>
 <translation id="5445596354079213552">仅当设备的自动更新期限已过且不符合允许使用的最低 <ph name="PRODUCT_OS_NAME" />版本(通过 <ph name="DEVICE_MINIMUM_VERSION_POLICY_NAME" /> 政策设置)的要求时,此政策才有效。
 
@@ -3269,6 +3277,7 @@
 <translation id="554903022911579950">Kerberos</translation>
 <translation id="555022085242359084">在登录屏幕上启用高对比度模式</translation>
 <translation id="555077880566103058">允许所有网站自动运行 <ph name="FLASH_PLUGIN_NAME" /> 插件</translation>
+<translation id="5556607617517096419">Borealis</translation>
 <translation id="5559079916187891399">此政策对 Android 应用没有任何影响。</translation>
 <translation id="5560039246134246593">在提取 <ph name="PRODUCT_NAME" /> 中的变体种子的方法中添加参数。
 
@@ -3472,6 +3481,7 @@
 <translation id="5814301096961727113">设置登录屏幕上语音反馈的默认状态</translation>
 <translation id="5815129011704381141">更新后自动重启</translation>
 <translation id="582857022372205358">启用短边双面打印</translation>
+<translation id="5830196507442186669">允许搭载 <ph name="PRODUCT_OS_NAME" />的设备使用 <ph name="BOREALIS_NAME" /></translation>
 <translation id="5832274826894536455">已弃用的政策</translation>
 <translation id="5835253272509953988">如果此政策已启用,用户便可让 <ph name="PRODUCT_NAME" /> 检查所输入的用户名和密码是否已泄露。
 
@@ -3669,13 +3679,14 @@
 <translation id="6097601282776163274">启用以网址为键的匿名化数据收集功能</translation>
 <translation id="6099853574908182288">默认打印颜色模式</translation>
 <translation id="6102342563050263313">允许滚动至网址片段指定的文本所在的位置</translation>
+<translation id="6102449843040973938">允许 <ph name="BOREALIS_NAME" /> 在设备上运行</translation>
 <translation id="6107642964266628393">控制何时以何种方式应用 Chrome 操作系统更新。</translation>
 <translation id="6111936128861357925">允许用户玩恐龙复活节彩蛋游戏</translation>
 <translation id="6123052603197028610">不允许向 Google 服务器发送检索时间戳的查询</translation>
 <translation id="6132506775968708399">禁用第三方 Cookie</translation>
 <translation id="6133088669883929098">允许所有网站使用密钥生成功能</translation>
 <translation id="6135398260575578389">“安全浏览”功能会处于开启状态且会在增强模式下运行。此模式可提高安全性,但需与 Google 分享更多浏览信息。</translation>
-<translation id="6135895880862759946">允许用户在 <ph name="LACROS_NAME" /> 浏览器中创建辅助个人资料以及使用访客模式</translation>
+<translation id="6135895880862759946">允许用户在 <ph name="LACROS_NAME" /> 浏览器中创建次级个人资料以及使用访客模式</translation>
 <translation id="6138636318340561140">实时查看网址的安全浏览状态</translation>
 <translation id="6141402445226505817">一律使用粗略式时区检测方式</translation>
 <translation id="6144046700495610112">如果此政策已启用,当首次运行浏览器时,系统将会从先前的默认浏览器导入自动填充表单数据。如果此政策已停用或未设置,当首次运行浏览器时,系统不会导入任何自动填充表单数据。
@@ -3733,6 +3744,7 @@
       运行未采用沙盒机制的音频子系统会致使用户面临安全风险。
       如果此政策未设置,系统将使用音频沙盒的默认配置(此配置可能会因平台而异)。
       借助此政策,当企业使用的安全软件设置会干扰音频沙盒时,他们就能够灵活地停用沙盒。</translation>
+<translation id="6252773211180267325">允许用户运行 <ph name="BOREALIS_NAME" /></translation>
 <translation id="6261643884958898336">报告机器标识信息</translation>
 <translation id="6265892395051519509">允许在这些网站上使用传感器</translation>
 <translation id="6273015149273504999">
@@ -4202,6 +4214,7 @@
 <translation id="6856743875250214792">我们已在 M66 中弃用并移除了此政策,因为它仅用于内部测试且存在安全隐患。
 
       指定要在 <ph name="PRODUCT_NAME" /> 启动时向其应用的实验性设置。指定的实验性设置仅会应用于登录屏幕。通过此政策设定的实验性设置不会反映在用户会话中。</translation>
+<translation id="6857240169209507953">禁止 <ph name="BOREALIS_NAME" /> 在设备上运行</translation>
 <translation id="685769593149966548">强制启用 YouTube“严格”受限模式</translation>
 <translation id="686079137349561371">Microsoft Windows 7 或更高版本</translation>
 <translation id="68818134518270542">通过设置此政策,您可以指定用户能在 <ph name="PRODUCT_OS_NAME" />锁定屏幕中将哪些应用作为笔记应用开启。
@@ -4624,6 +4637,7 @@
       如果此政策设为“RemoveLRUIfDormant”,自动清理将按最近最少登录顺序移除至少已有3个月未登录的用户,直至系统有足够的可用空间。
 
       如果此政策未设置,自动清理将使用默认的内置策略(目前为“RemoveLRUIfDormant”策略)。</translation>
+<translation id="7334517274921831425">允许用户在搭载 <ph name="PRODUCT_OS_NAME" />的设备上使用 <ph name="BOREALIS_NAME" /></translation>
 <translation id="7336785017449297672">控制时钟和时区设置。</translation>
 <translation id="7336878834592315572">在会话期间保留 Cookie</translation>
 <translation id="7338217396351647423">设置此政策可指定要传递给 ARC 运行时的一组政策。管理员可以使用此政策选择要自动安装的 Android 应用。请以有效的 JSON 格式输入所需值。
diff --git a/components/services/app_service/public/cpp/intent_util.cc b/components/services/app_service/public/cpp/intent_util.cc
index 185c20c6..5da9023d 100644
--- a/components/services/app_service/public/cpp/intent_util.cc
+++ b/components/services/app_service/public/cpp/intent_util.cc
@@ -4,7 +4,12 @@
 
 #include "components/services/app_service/public/cpp/intent_util.h"
 
+#include <string>
+#include <utility>
+#include <vector>
+
 #include "base/compiler_specific.h"
+#include "base/containers/flat_map.h"
 #include "base/optional.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
@@ -23,6 +28,11 @@
 const char kDriveShareUrlKey[] = "drive_share_url";
 const char kShareTextKey[] = "share_text";
 const char kShareTitleKey[] = "share_title";
+const char kStartTypeKey[] = "start_type";
+const char kCategoriesKey[] = "categories";
+const char kDataKey[] = "data";
+const char kUiBypassedKey[] = "ui_bypassed";
+const char kExtrasKey[] = "extras";
 
 // Get the intent condition value based on the condition type.
 base::Optional<std::string> GetIntentConditionValueByType(
@@ -406,6 +416,34 @@
   if (intent->share_title.has_value() && !intent->share_title.value().empty())
     intent_value.SetStringKey(kShareTitleKey, intent->share_title.value());
 
+  if (intent->start_type.has_value() && !intent->start_type.value().empty())
+    intent_value.SetStringKey(kStartTypeKey, intent->start_type.value());
+
+  if (intent->categories.has_value() && !intent->categories.value().empty()) {
+    base::Value categories(base::Value::Type::LIST);
+    for (const auto& category : intent->categories.value()) {
+      categories.Append(base::Value(category));
+    }
+    intent_value.SetKey(kCategoriesKey, std::move(categories));
+  }
+
+  if (intent->data.has_value() && !intent->data.value().empty())
+    intent_value.SetStringKey(kDataKey, intent->data.value());
+
+  if (intent->ui_bypassed != apps::mojom::OptionalBool::kUnknown) {
+    intent_value.SetBoolKey(
+        kUiBypassedKey,
+        intent->ui_bypassed == apps::mojom::OptionalBool::kTrue ? true : false);
+  }
+
+  if (intent->extras.has_value() && !intent->extras.value().empty()) {
+    base::Value extras(base::Value::Type::DICTIONARY);
+    for (const auto& extra : intent->extras.value()) {
+      extras.SetStringKey(extra.first, extra.second);
+    }
+    intent_value.SetKey(kExtrasKey, std::move(extras));
+  }
+
   return intent_value;
 }
 
@@ -422,6 +460,20 @@
   return *value;
 }
 
+apps::mojom::OptionalBool GetBoolValueFromDict(
+    const base::DictionaryValue& dict,
+    const std::string& key_name) {
+  if (!dict.HasKey(key_name))
+    return apps::mojom::OptionalBool::kUnknown;
+
+  base::Optional<bool> value = dict.FindBoolKey(key_name);
+  if (!value.has_value())
+    return apps::mojom::OptionalBool::kUnknown;
+
+  return value.value() ? apps::mojom::OptionalBool::kTrue
+                       : apps::mojom::OptionalBool::kFalse;
+}
+
 base::Optional<GURL> GetGurlValueFromDict(const base::DictionaryValue& dict,
                                           const std::string& key_name) {
   if (!dict.HasKey(key_name))
@@ -457,6 +509,43 @@
   return file_urls;
 }
 
+base::Optional<std::vector<std::string>> GetCategoriesFromDict(
+    const base::DictionaryValue& dict,
+    const std::string& key_name) {
+  if (!dict.HasKey(key_name))
+    return base::nullopt;
+
+  const base::Value* value = dict.FindListKey(key_name);
+  if (!value || !value->is_list() || value->GetList().empty())
+    return base::nullopt;
+
+  std::vector<std::string> categories;
+  for (const auto& item : value->GetList())
+    categories.push_back(item.GetString());
+
+  return categories;
+}
+
+base::Optional<base::flat_map<std::string, std::string>> GetExtrasFromDict(
+    const base::DictionaryValue& dict,
+    const std::string& key_name) {
+  if (!dict.HasKey(key_name))
+    return base::nullopt;
+
+  const base::Value* value = dict.FindDictKey(key_name);
+  if (!value || !value->is_dict())
+    return base::nullopt;
+
+  base::flat_map<std::string, std::string> extras;
+  for (const auto& pair : value->DictItems()) {
+    std::string value;
+    if (pair.second.GetAsString(&value))
+      extras[pair.first] = value;
+  }
+
+  return extras;
+}
+
 apps::mojom::IntentPtr ConvertValueToIntent(base::Value&& value) {
   auto intent = apps::mojom::Intent::New();
 
@@ -472,6 +561,11 @@
   intent->drive_share_url = GetGurlValueFromDict(*dict, kDriveShareUrlKey);
   intent->share_text = GetStringValueFromDict(*dict, kShareTextKey);
   intent->share_title = GetStringValueFromDict(*dict, kShareTitleKey);
+  intent->start_type = GetStringValueFromDict(*dict, kStartTypeKey);
+  intent->categories = GetCategoriesFromDict(*dict, kCategoriesKey);
+  intent->data = GetStringValueFromDict(*dict, kDataKey);
+  intent->ui_bypassed = GetBoolValueFromDict(*dict, kUiBypassedKey);
+  intent->extras = GetExtrasFromDict(*dict, kExtrasKey);
 
   return intent;
 }
diff --git a/components/services/app_service/public/cpp/intent_util.h b/components/services/app_service/public/cpp/intent_util.h
index d2c6d31..f33b47e 100644
--- a/components/services/app_service/public/cpp/intent_util.h
+++ b/components/services/app_service/public/cpp/intent_util.h
@@ -105,6 +105,12 @@
     const base::DictionaryValue& dict,
     const std::string& key_name);
 
+// Gets the apps::mojom::OptionalBool value from base::DictionaryValue, e.g. {
+// "key": "value" } returns "value".
+apps::mojom::OptionalBool GetBoolValueFromDict(
+    const base::DictionaryValue& dict,
+    const std::string& key_name);
+
 // Gets GURL from base::DictionaryValue, e.g. { "url": "abc.com" } returns
 // "abc.com".
 base::Optional<GURL> GetGurlValueFromDict(const base::DictionaryValue& dict,
diff --git a/components/services/app_service/public/cpp/intent_util_unittest.cc b/components/services/app_service/public/cpp/intent_util_unittest.cc
index 2cccc97..2c7dbf89 100644
--- a/components/services/app_service/public/cpp/intent_util_unittest.cc
+++ b/components/services/app_service/public/cpp/intent_util_unittest.cc
@@ -33,14 +33,20 @@
     return intent;
   }
 
-  apps::mojom::IntentPtr CreateIntent(const std::string& action,
-                                      const GURL& url,
-                                      const std::string& mime_type,
-                                      const std::vector<::GURL>& file_urls,
-                                      const std::string& activity_name,
-                                      const GURL& drive_share_url,
-                                      const std::string& share_text,
-                                      const std::string& share_title) {
+  apps::mojom::IntentPtr CreateIntent(
+      const std::string& action,
+      const GURL& url,
+      const std::string& mime_type,
+      const std::vector<::GURL>& file_urls,
+      const std::string& activity_name,
+      const GURL& drive_share_url,
+      const std::string& share_text,
+      const std::string& share_title,
+      const std::string& start_type,
+      const std::vector<std::string>& categories,
+      const std::string& data,
+      apps::mojom::OptionalBool ui_bypassed,
+      const base::flat_map<std::string, std::string>& extras) {
     auto intent = apps::mojom::Intent::New();
     intent->action = action;
     intent->url = url;
@@ -50,6 +56,11 @@
     intent->drive_share_url = drive_share_url;
     intent->share_text = share_text;
     intent->share_title = share_title;
+    intent->start_type = start_type;
+    intent->categories = categories;
+    intent->data = data;
+    intent->ui_bypassed = ui_bypassed;
+    intent->extras = extras;
     return intent;
   }
 };
@@ -441,10 +452,18 @@
   const std::string activity_name = "test";
   const std::string share_text = "share text";
   const std::string share_title = "share title";
+  const std::string start_type = "start type";
+  const std::string category1 = "category1";
+  const std::string data = "data";
+  const apps::mojom::OptionalBool ui_bypassed =
+      apps::mojom::OptionalBool::kTrue;
+  base::flat_map<std::string, std::string> extras = {
+      {"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}};
 
   auto src_intent =
       CreateIntent(action, test_url1, mime_type, {test_url1, test_url2},
-                   activity_name, test_url3, share_text, share_title);
+                   activity_name, test_url3, share_text, share_title,
+                   start_type, {category1}, data, ui_bypassed, extras);
   base::Value value = apps_util::ConvertIntentToValue(src_intent);
   auto dst_intent = apps_util::ConvertValueToIntent(std::move(value));
 
@@ -458,6 +477,14 @@
   EXPECT_EQ(test_url3, dst_intent->drive_share_url.value());
   EXPECT_EQ(share_text, dst_intent->share_text.value());
   EXPECT_EQ(share_title, dst_intent->share_title.value());
+  EXPECT_EQ(start_type, dst_intent->start_type.value());
+  EXPECT_EQ(1u, dst_intent->categories->size());
+  EXPECT_EQ(category1, dst_intent->categories.value()[0]);
+  EXPECT_EQ(data, dst_intent->data.value());
+  EXPECT_EQ(ui_bypassed, dst_intent->ui_bypassed);
+  EXPECT_TRUE(dst_intent->extras.has_value());
+  EXPECT_EQ(3u, dst_intent->extras->size());
+  EXPECT_EQ(extras, dst_intent->extras.value());
 }
 
 TEST_F(IntentUtilTest, ConvertEmptyIntent) {
@@ -473,4 +500,9 @@
   EXPECT_FALSE(dst_intent->drive_share_url.has_value());
   EXPECT_FALSE(dst_intent->share_text.has_value());
   EXPECT_FALSE(dst_intent->share_title.has_value());
+  EXPECT_FALSE(dst_intent->start_type.has_value());
+  EXPECT_FALSE(dst_intent->categories.has_value());
+  EXPECT_FALSE(dst_intent->data.has_value());
+  EXPECT_EQ(apps::mojom::OptionalBool::kUnknown, dst_intent->ui_bypassed);
+  EXPECT_FALSE(dst_intent->extras.has_value());
 }
diff --git a/components/services/app_service/public/mojom/types.mojom b/components/services/app_service/public/mojom/types.mojom
index ec75f8e..d57dcdd1 100644
--- a/components/services/app_service/public/mojom/types.mojom
+++ b/components/services/app_service/public/mojom/types.mojom
@@ -194,8 +194,7 @@
 };
 
 // Enumeration of possible app launch sources.
-// Note the enumeration is used in UMA histogram so entries
-// should not be re-ordered or removed.
+// This should be kept in sync with histogram_suffixes_list.xml.
 enum LaunchSource {
   kUnknown = 0,
   kFromAppListGrid = 1,               // Grid of apps, not the search box.
@@ -221,6 +220,7 @@
   kFromSharesheet = 18,               // Sharesheet.
   kFromReleaseNotesNotification = 19, // Release Notes Notification.
   kFromFullRestore = 20,              // Full restore.
+  kFromSmartTextContextMenu = 21,     // Smart text selection context menu.
 };
 
 enum TriState {
@@ -340,6 +340,10 @@
   string? share_text; // Text to share. e.g. Share link to other app.
   string? share_title; // Title for the share.
   string? start_type; // Start type.
+  array<string>? categories;
+  string? data;  // URI
+  OptionalBool ui_bypassed; // Whether or not the user saw the UI.
+  map<string, string>? extras; // Optional string extras.
 };
 
 // Represents a group of |app_ids| that is no longer preferred app of their
diff --git a/components/shared_highlighting/core/common/shared_highlighting_features.cc b/components/shared_highlighting/core/common/shared_highlighting_features.cc
index 966cca95..0046790b 100644
--- a/components/shared_highlighting/core/common/shared_highlighting_features.cc
+++ b/components/shared_highlighting/core/common/shared_highlighting_features.cc
@@ -10,7 +10,6 @@
 
 const base::Feature kSharedHighlightingUseBlocklist{
     "SharedHighlightingUseBlocklist", base::FEATURE_ENABLED_BY_DEFAULT};
-
 const base::Feature kSharedHighlightingV2{"SharedHighlightingV2",
                                           base::FEATURE_DISABLED_BY_DEFAULT};
 
diff --git a/components/shared_highlighting/core/common/shared_highlighting_features.h b/components/shared_highlighting/core/common/shared_highlighting_features.h
index 5ff75c41..fee4c1f 100644
--- a/components/shared_highlighting/core/common/shared_highlighting_features.h
+++ b/components/shared_highlighting/core/common/shared_highlighting_features.h
@@ -14,7 +14,6 @@
 // If enabled, a blocklist will disable link generation on certain pages where
 // the feature is unlikely to work correctly.
 extern const base::Feature kSharedHighlightingUseBlocklist;
-
 extern const base::Feature kSharedHighlightingV2;
 
 }  // namespace shared_highlighting
diff --git a/components/strings/components_strings_ar.xtb b/components/strings/components_strings_ar.xtb
index 861349276..2fe88c9 100644
--- a/components/strings/components_strings_ar.xtb
+++ b/components/strings/components_strings_ar.xtb
@@ -540,7 +540,7 @@
 <translation id="3037605927509011580">عذرًا!</translation>
 <translation id="3041612393474885105">معلومات الشهادة</translation>
 <translation id="3060227939791841287">‏C9 (مغلف)</translation>
-<translation id="3060557858482803256">‏<ph name="RUN_CHROME_SAFETY_CHECK_FOCUSED_FRIENDLY_MATCH_TEXT" />، اضغط على مفتاح التبويب (Tab) ثم Enter لتفعيل ميزة "تأكيد السلامة" في إعدادات Chrome.</translation>
+<translation id="3060557858482803256">‏<ph name="RUN_CHROME_SAFETY_CHECK_FOCUSED_FRIENDLY_MATCH_TEXT" />، اضغط على مفتاح التبويب (Tab) ثم Enter لتشغيل ميزة "تأكيد السلامة" في إعدادات Chrome.</translation>
 <translation id="3061707000357573562">خدمة رمز التصحيح</translation>
 <translation id="3064966200440839136">ستتم مغادرة وضع التصفح المتخفي للدفع عبر تطبيق خارجي. هل تريد المتابعة؟</translation>
 <translation id="3080254622891793721">الرسم البياني</translation>
@@ -778,7 +778,7 @@
 <translation id="3964661563329879394">{COUNT,plural, =0{بدون}=1{من موقع واحد }two{من موقعين (#) }few{من # مواقع }many{من # موقعًا }other{من # موقع }}</translation>
 <translation id="397105322502079400">جارٍ الحساب...</translation>
 <translation id="3973234410852337861">تم حظر <ph name="HOST_NAME" /></translation>
-<translation id="3973357910713125165">‏زر تفعيل ميزة "تأكيد السلامة" في Chrome، اضغط على مفتاح Enter لتفعيل هذه الميزة في إعدادات Chrome.</translation>
+<translation id="3973357910713125165">‏زر تشغيل ميزة "تأكيد السلامة" في Chrome، اضغط على مفتاح Enter لتشغيل هذه الميزة في إعدادات Chrome.</translation>
 <translation id="3987405730340719549">‏تبيّن لمتصفح Chrome أن هذا الموقع الإلكتروني قد يكون مزيفًا أو احتياليًا.
 
     إذا كنت تعتقد أنّه تم عرض هذه الرسالة عن طريق الخطأ، يُرجى الانتقال إلى https://bugs.chromium.org/p/chromium/issues/entry?template=Safety+Tips+Appeals.</translation>
@@ -860,7 +860,7 @@
     &lt;h4&gt;الخطوة 5: الحصول على مساعدة إضافية&lt;/h4&gt;
     &lt;p&gt;في حال استمرار ظهور هذا الخطأ، اتصِل بمالك الموقع الإلكتروني.&lt;/p&gt;</translation>
 <translation id="4226937834893929579"><ph name="BEGIN_LINK" />تجربة تشغيل بيانات تشخيص الشبكة<ph name="END_LINK" />.</translation>
-<translation id="4229544452621580519">‏تفعيل ميزة "تأكيد السلامة" في إعدادات Chrome</translation>
+<translation id="4229544452621580519">‏تشغيل ميزة "تأكيد السلامة" في إعدادات Chrome</translation>
 <translation id="4234495348042597185"><ph name="BEGIN_LINK" />المتابعة إلى <ph name="SITE" /><ph name="END_LINK" /></translation>
 <translation id="4235360514405112390">صالح</translation>
 <translation id="4250431568374086873">إن اتصالك بهذا الموقع غير آمن تمامًا</translation>
@@ -988,7 +988,7 @@
 <translation id="4756388243121344051">ال&amp;سجل</translation>
 <translation id="4758311279753947758">إضافة معلومات الاتصال</translation>
 <translation id="4761104368405085019">استخدام الميكروفون</translation>
-<translation id="4761869838909035636">‏تفعيل ميزة "تأكيد السلامة" في Chrome</translation>
+<translation id="4761869838909035636">‏تشغيل ميزة "تأكيد السلامة" في Chrome</translation>
 <translation id="4764776831041365478">قد تكون صفحة الويب على العنوان <ph name="URL" /> غير متاحة مؤقتًا أو قد يكون تم نقلها نهائيًا إلى عنوان ويب جديد.</translation>
 <translation id="4766713847338118463">وضع دبوسَين بالأسفل</translation>
 <translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
diff --git a/components/strings/components_strings_de.xtb b/components/strings/components_strings_de.xtb
index 59ee21b..8c61353 100644
--- a/components/strings/components_strings_de.xtb
+++ b/components/strings/components_strings_de.xtb
@@ -534,6 +534,7 @@
 <translation id="3037605927509011580">Oh nein!</translation>
 <translation id="3041612393474885105">Zertifikatinformationen</translation>
 <translation id="3060227939791841287">C9 (Umschlag)</translation>
+<translation id="3060557858482803256"><ph name="RUN_CHROME_SAFETY_CHECK_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um den Sicherheitscheck in den Chrome-Einstellungen auszuführen</translation>
 <translation id="3061707000357573562">Patchdienst</translation>
 <translation id="3064966200440839136">Der Inkognitomodus wird beendet, um über eine externe Anwendung zu zahlen. Fortfahren?</translation>
 <translation id="3080254622891793721">Grafik</translation>
@@ -769,6 +770,7 @@
 <translation id="3964661563329879394">{COUNT,plural, =0{Keine}=1{Von 1 Website }other{Von # Websites }}</translation>
 <translation id="397105322502079400">Wird berechnet...</translation>
 <translation id="3973234410852337861"><ph name="HOST_NAME" /> ist gesperrt</translation>
+<translation id="3973357910713125165">Schaltfläche zum Ausführen des Chrome-Sicherheitschecks – drücken Sie die Eingabetaste, um den Sicherheitscheck in den Chrome-Einstellungen auszuführen</translation>
 <translation id="3987405730340719549">Chrome hat festgestellt, dass diese Website eventuell gefälscht oder betrügerisch ist.
 
     Wenn dies Ihrer Meinung nach fälschlicherweise angezeigt wird, gehen Sie bitte auf: https://bugs.chromium.org/p/chromium/issues/entry?template=Safety+Tips+Appeals.</translation>
@@ -845,6 +847,7 @@
     &lt;h4&gt;Schritt 5: Weitere Hilfe erhalten&lt;/h4&gt;
     &lt;p&gt;Wenden Sie sich an den Websiteinhaber, wenn der Fehler noch immer angezeigt wird.&lt;/p&gt;</translation>
 <translation id="4226937834893929579"><ph name="BEGIN_LINK" />Versuchen Sie, die Netzwerkdiagnose auszuführen.<ph name="END_LINK" /></translation>
+<translation id="4229544452621580519">Sicherheitscheck in den Chrome-Einstellungen ausführen</translation>
 <translation id="4234495348042597185"><ph name="BEGIN_LINK" />Weiter zu <ph name="SITE" /><ph name="END_LINK" /></translation>
 <translation id="4235360514405112390">Gültig</translation>
 <translation id="4250431568374086873">Die Verbindung zu dieser Website ist nicht uneingeschränkt sicher</translation>
@@ -972,6 +975,7 @@
 <translation id="4756388243121344051">&amp;Verlauf</translation>
 <translation id="4758311279753947758">Kontaktdaten hinzufügen</translation>
 <translation id="4761104368405085019">Mikrofon verwenden</translation>
+<translation id="4761869838909035636">Chrome-Sicherheitscheck ausführen</translation>
 <translation id="4764776831041365478">Die Webseite unter <ph name="URL" /> ist eventuell vorübergehend nicht verfügbar oder wurde dauerhaft an eine neue Webadresse verschoben.</translation>
 <translation id="4766713847338118463">Zwei Heftklammern unten</translation>
 <translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
diff --git a/components/strings/components_strings_gu.xtb b/components/strings/components_strings_gu.xtb
index 96f9ae86..121478c 100644
--- a/components/strings/components_strings_gu.xtb
+++ b/components/strings/components_strings_gu.xtb
@@ -1919,7 +1919,7 @@
 વધારાની વિગતો:
 <ph name="DEBUG_INFO" /></translation>
 <translation id="8424582179843326029"><ph name="FIRST_LABEL" /> <ph name="SECOND_LABEL" /> <ph name="THIRD_LABEL" /></translation>
-<translation id="8428213095426709021">સેટિંગ્સ</translation>
+<translation id="8428213095426709021">સેટિંગ</translation>
 <translation id="8433057134996913067">આ તમને મોટાભાગની વેબસાઇટ્સમાંથી સાઇન આઉટ કરશે.</translation>
 <translation id="8437238597147034694">&amp;ખસેડવું પૂર્વવત્‌ કરો</translation>
 <translation id="8438786541497918448">કૅમેરા અને માઇક્રોફોનનો ઉપયોગ કરીએ?</translation>
diff --git a/components/strings/components_strings_pa.xtb b/components/strings/components_strings_pa.xtb
index 69cb55f..b899ac9 100644
--- a/components/strings/components_strings_pa.xtb
+++ b/components/strings/components_strings_pa.xtb
@@ -535,6 +535,7 @@
 <translation id="3037605927509011580">ਆਹ, ਸਨੈਪ!</translation>
 <translation id="3041612393474885105">ਪ੍ਰਮਾਣ-ਪੱਤਰ ਬਾਰੇ ਜਾਣਕਾਰੀ</translation>
 <translation id="3060227939791841287">C9 (ਲਿਫ਼ਾਫ਼ਾ)</translation>
+<translation id="3060557858482803256"><ph name="RUN_CHROME_SAFETY_CHECK_FOCUSED_FRIENDLY_MATCH_TEXT" />, ਟੈਬ ਨੂੰ ਦਬਾਓ ਫਿਰ Chrome ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਸੁਰੱਖਿਆ ਜਾਂਚ ਚਲਾਉਣ ਲਈ Enter ਦਬਾਓ</translation>
 <translation id="3061707000357573562">ਪੈਚ ਸੇਵਾ</translation>
 <translation id="3064966200440839136">ਕਿਸੇ ਬਾਹਰੀ ਐਪਲੀਕੇਸ਼ਨ ਰਾਹੀਂ ਭੁਗਤਾਨ ਕਰਨ ਲਈ ਇਨਕੋਗਨਿਟੋ ਮੋਡ ਤੋਂ ਬਾਹਰ ਜਾਇਆ ਜਾ ਰਿਹਾ ਹੈ। ਜਾਰੀ ਰੱਖੀਏ?</translation>
 <translation id="3080254622891793721">ਗ੍ਰਾਫ਼ਿਕ</translation>
@@ -769,6 +770,7 @@
 <translation id="3964661563329879394">{COUNT,plural, =0{ਕੋਈ ਨਹੀਂ}=1{1 ਸਾਈਟ ਤੋਂ }other{# ਸਾਈਟਾਂ ਤੋਂ }}</translation>
 <translation id="397105322502079400">ਅਨੁਮਾਨ ਲਗਾ ਰਿਹਾ ਹੈ...</translation>
 <translation id="3973234410852337861"><ph name="HOST_NAME" /> ਨੂੰ ਬਲੌਕ ਕੀਤਾ ਗਿਆ ਹੈ</translation>
+<translation id="3973357910713125165">'Chrome ਸੁਰੱਖਿਆ ਜਾਂਚ' ਬਟਨ ਚਲਾਓ, Chrome ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਸੁਰੱਖਿਆ ਜਾਂਚ ਚਲਾਉਣ ਲਈ Enter ਦਬਾਓ</translation>
 <translation id="3987405730340719549">Chrome ਨੇ ਨਿਰਧਾਰਤ ਕੀਤਾ ਹੈ ਕਿ ਇਹ ਸਾਈਟ ਨਕਲੀ ਜਾਂ ਧੋਖਾਧੜੀ ਵਾਲੀ ਹੋ ਸਕਦੀ ਹੈ।
 
     ਜੇ ਤੁਹਾਨੂੰ ਲੱਗਦਾ ਹੈ ਕਿ ਇਹ ਗਲਤੀ ਨਾਲ ਦਿਖਾਇਆ ਗਿਆ ਹੈ ਤਾਂ ਕਿਰਪਾ ਕਰਕੇ https://bugs.chromium.org/p/chromium/issues/entry?template=Safety+Tips+Appeals 'ਤੇ ਜਾਓ।</translation>
@@ -845,6 +847,7 @@
     &lt;h4&gt;ਪੜਾਅ 5: ਵਾਧੂ ਮਦਦ ਲਓ&lt;/h4&gt;
     &lt;p&gt;ਜੇਕਰ ਤੁਹਾਨੂੰ ਹਾਲੇ ਵੀ ਗੜਬੜ ਦਿਖਾਈ ਦਿੰਦੀ ਹੈ, ਤਾਂ ਵੈੱਬਸਾਈਟ ਮਾਲਕ ਨਾਲ ਸੰਪਰਕ ਕਰੋ।&lt;/p&gt;</translation>
 <translation id="4226937834893929579"><ph name="BEGIN_LINK" />ਨੈੱਟਵਰਕ ਤਸ਼ਖੀਸਾਂ ਨੂੰ ਚਲਾ ਕੇ ਦੇਖੋ<ph name="END_LINK" />।</translation>
+<translation id="4229544452621580519">Chrome ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਸੁਰੱਖਿਆ ਜਾਂਚ ਚਲਾਓ</translation>
 <translation id="4234495348042597185"><ph name="BEGIN_LINK" /><ph name="SITE" /> 'ਤੇ ਜਾਰੀ ਰੱਖੋ<ph name="END_LINK" /></translation>
 <translation id="4235360514405112390">ਵੈਧ</translation>
 <translation id="4250431568374086873">ਇਸ ਸਾਈਟ ਨਾਲ ਤੁਹਾਡਾ ਕਨੈਕਸ਼ਨ ਪੂਰੀ ਤਰ੍ਹਾਂ ਸੁਰੱਖਿਅਤ ਨਹੀਂ ਹੈ</translation>
@@ -972,6 +975,7 @@
 <translation id="4756388243121344051">&amp;ਇਤਿਹਾਸ</translation>
 <translation id="4758311279753947758">ਸੰਪਰਕ ਜਾਣਕਾਰੀ ਸ਼ਾਮਲ ਕਰੋ</translation>
 <translation id="4761104368405085019">ਆਪਣਾ ਮਾਈਕ੍ਰੋਫੋਨ ਵਰਤੋ</translation>
+<translation id="4761869838909035636">Chrome ਸੁਰੱਖਿਆ ਜਾਂਚ ਚਲਾਓ</translation>
 <translation id="4764776831041365478"><ph name="URL" /> ਤੇ ਵੈਬਪੇਜ ਅਸਥਾਈ ਤੌਰ ਤੇ ਹੌਲੀ ਹੋ ਸਕਦਾ ਹੈ ਜਾਂ ਇਹ ਸਥਾਈ ਤੌਰ ਤੇ ਕਿਸੇ ਨਵੇਂ ਵੈਬ ਪਤੇ ਤੇ ਮੂਵ ਹੋ ਗਿਆ ਹੋ ਸਕਦਾ ਹੈ।</translation>
 <translation id="4766713847338118463">ਹੇਠਾਂ ਦੋ ਪਿੰਨਾਂ</translation>
 <translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
diff --git a/components/strings/components_strings_pl.xtb b/components/strings/components_strings_pl.xtb
index a86c99f..5879c700 100644
--- a/components/strings/components_strings_pl.xtb
+++ b/components/strings/components_strings_pl.xtb
@@ -536,7 +536,7 @@
 <translation id="3037605927509011580">Kurza twarz!</translation>
 <translation id="3041612393474885105">Informacje o certyfikacie</translation>
 <translation id="3060227939791841287">C9 (koperta)</translation>
-<translation id="3060557858482803256"><ph name="RUN_CHROME_SAFETY_CHECK_FOCUSED_FRIENDLY_MATCH_TEXT" />, naciśnij Tab, a potem Enter, aby uruchomić potwierdzenie bezpieczeństwa w ustawieniach Chrome</translation>
+<translation id="3060557858482803256"><ph name="RUN_CHROME_SAFETY_CHECK_FOCUSED_FRIENDLY_MATCH_TEXT" />; aby uruchomić potwierdzenie bezpieczeństwa w ustawieniach Chrome, naciśnij Tab, a potem Enter</translation>
 <translation id="3061707000357573562">Zastosowanie poprawki do usługi</translation>
 <translation id="3064966200440839136">Opuszczasz tryb incognito, by zapłacić w aplikacji zewnętrznej. Kontynuować?</translation>
 <translation id="3080254622891793721">Grafika</translation>
@@ -774,7 +774,7 @@
 <translation id="3964661563329879394">{COUNT,plural, =0{Brak}=1{Z 1 witryny }few{Z # witryn }many{Z # witryn }other{Z # witryny }}</translation>
 <translation id="397105322502079400">Obliczanie...</translation>
 <translation id="3973234410852337861">Strona <ph name="HOST_NAME" /> jest zablokowana</translation>
-<translation id="3973357910713125165">Przycisk Uruchom potwierdzenie bezpieczeństwa Chrome; naciśnij Enter, aby uruchomić potwierdzenie bezpieczeństwa w ustawieniach Chrome</translation>
+<translation id="3973357910713125165">Przycisk Uruchom potwierdzenie bezpieczeństwa Chrome; aby uruchomić potwierdzenie bezpieczeństwa w ustawieniach Chrome, naciśnij Enter</translation>
 <translation id="3987405730340719549">Według Chrome ta strona może być fałszywa.
 
     Jeśli uważasz, że ten komunikat pojawił się w wyniku pomyłki, wejdź na https://bugs.chromium.org/p/chromium/issues/entry?template=Safety+Tips+Appeals</translation>
diff --git a/components/strings/components_strings_sv.xtb b/components/strings/components_strings_sv.xtb
index d709ef500c..df28197 100644
--- a/components/strings/components_strings_sv.xtb
+++ b/components/strings/components_strings_sv.xtb
@@ -916,7 +916,7 @@
 <translation id="443121186588148776">Serieport</translation>
 <translation id="4432688616882109544"><ph name="HOST_NAME" /> godkände inte inloggningscertifikatet eller så har inget inloggningscertifikat angetts.</translation>
 <translation id="4432792777822557199">Sidor på <ph name="SOURCE_LANGUAGE" /> översätts till <ph name="TARGET_LANGUAGE" /> från och med nu</translation>
-<translation id="4434045419905280838">Popup och omdirigeringar</translation>
+<translation id="4434045419905280838">Popup-fönster och omdirigeringar</translation>
 <translation id="4435702339979719576">vykort)</translation>
 <translation id="443673843213245140">Användning av proxy är inaktiverad men en explicit proxykonfiguration har angetts.</translation>
 <translation id="4466881336512663640">Ändringar i formuläret ändras inte. Vill du fortsätta?</translation>
diff --git a/components/strings/components_strings_te.xtb b/components/strings/components_strings_te.xtb
index 2f29043a..310915a 100644
--- a/components/strings/components_strings_te.xtb
+++ b/components/strings/components_strings_te.xtb
@@ -149,7 +149,7 @@
 <translation id="1462951478840426066">మీ కంప్యూటర్‌లోని ఫాంట్‌లను ఉపయోగించండి, తద్వారా మీరు అధిక నాణ్యత గల కంటెంట్‌ను క్రియేట్ చేయవచ్చు</translation>
 <translation id="1463543813647160932">5x7</translation>
 <translation id="1467432559032391204">ఎడమ</translation>
-<translation id="1468653229182955856"><ph name="TOP_ORIGIN" />కు కొనసాగడానికి <ph name="ONE_TIME_CODE" /> అనేది మీ <ph name="EMBEDDED_ORIGIN" /> కోడ్</translation>
+<translation id="1468653229182955856"><ph name="EMBEDDED_ORIGIN" /> ను <ph name="TOP_ORIGIN" />కు కొనసాగేలా చేయడానికి మీకు కావాల్సిన కోడ్ <ph name="ONE_TIME_CODE" /></translation>
 <translation id="1472675084647422956">మరిన్ని చూపించు</translation>
 <translation id="1473183651233018052">JIS B10</translation>
 <translation id="147358896496811705">2A0</translation>
diff --git a/components/strings/components_strings_zh-CN.xtb b/components/strings/components_strings_zh-CN.xtb
index 817f5906..1adef5a 100644
--- a/components/strings/components_strings_zh-CN.xtb
+++ b/components/strings/components_strings_zh-CN.xtb
@@ -534,6 +534,7 @@
 <translation id="3037605927509011580">喔唷,崩溃啦!</translation>
 <translation id="3041612393474885105">证书信息</translation>
 <translation id="3060227939791841287">C9 (Envelope)</translation>
+<translation id="3060557858482803256"><ph name="RUN_CHROME_SAFETY_CHECK_FOCUSED_FRIENDLY_MATCH_TEXT" />,依次按 Tab 键和 Enter 键即可从 Chrome 设置中运行安全检查</translation>
 <translation id="3061707000357573562">修补服务</translation>
 <translation id="3064966200440839136">将要退出隐身模式,以便通过外部应用付款。是否继续?</translation>
 <translation id="3080254622891793721">图形</translation>
@@ -767,6 +768,7 @@
 <translation id="3964661563329879394">{COUNT,plural, =0{无}=1{来自 1 个网站}other{来自 # 个网站}}</translation>
 <translation id="397105322502079400">正在计算...</translation>
 <translation id="3973234410852337861"><ph name="HOST_NAME" /> 已被屏蔽</translation>
+<translation id="3973357910713125165">“运行 Chrome 安全检查”按钮,按 Enter 键即可从 Chrome 设置中运行安全检查</translation>
 <translation id="3987405730340719549">Chrome 已确定此网站可能是虚假网站或欺诈性网站。
 
     如果您认为系统不该向您显示这条提示,请访问 https://bugs.chromium.org/p/chromium/issues/entry?template=Safety+Tips+Appeals。</translation>
@@ -843,6 +845,7 @@
     &lt;h4&gt;第 5 步:获取额外帮助&lt;/h4&gt;
     &lt;p&gt;如果您仍会看到这条错误消息,请与网站所有者联系。&lt;/p&gt;</translation>
 <translation id="4226937834893929579"><ph name="BEGIN_LINK" />尝试运行网络诊断<ph name="END_LINK" />。</translation>
+<translation id="4229544452621580519">从 Chrome 设置中运行安全检查</translation>
 <translation id="4234495348042597185"><ph name="BEGIN_LINK" />继续前往 <ph name="SITE" /><ph name="END_LINK" /></translation>
 <translation id="4235360514405112390">有效</translation>
 <translation id="4250431568374086873">您与此网站之间建立的连接并非完全安全</translation>
@@ -970,6 +973,7 @@
 <translation id="4756388243121344051">历史记录(&amp;H)</translation>
 <translation id="4758311279753947758">添加联系信息</translation>
 <translation id="4761104368405085019">使用您的麦克风</translation>
+<translation id="4761869838909035636">运行 Chrome 安全检查</translation>
 <translation id="4764776831041365478">网址为 <ph name="URL" /> 的网页可能暂时无法连接,或者它已永久性地移动到了新网址。</translation>
 <translation id="4766713847338118463">双钉(底部)</translation>
 <translation id="4768815695067202997"><ph name="BEGIN_BOLD" />
diff --git a/components/test/data/ads_observer/ad_iframe_writer.js b/components/test/data/ads_observer/ad_iframe_writer.js
new file mode 100644
index 0000000..b5929a1
--- /dev/null
+++ b/components/test/data/ads_observer/ad_iframe_writer.js
@@ -0,0 +1,47 @@
+// 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.
+
+// Creates and iframe and appends it to the body element. Make sure the caller
+// has a body element!
+function createAdIframe() {
+  const frame = document.createElement('iframe');
+  document.body.appendChild(frame);
+  return frame;
+}
+
+function createAdIframeWithSrc(src) {
+  const frame = document.createElement('iframe');
+  frame.src = src;
+  document.body.appendChild(frame);
+  return frame;
+}
+
+function createAdIframeAtRect(x, y, width, height) {
+  const frame = document.createElement('iframe');
+  frame.style.border = '0px none transparent';
+  frame.style.overflow = 'hidden';
+  frame.style.position = 'fixed';
+  frame.style.left = x;
+  frame.style.top = y;
+  frame.scrolling = 'no';
+  frame.frameborder = '0';
+  frame.allowTransparency = 'true';
+  frame.width = width;
+  frame.height = height;
+  document.body.appendChild(frame);
+  return frame;
+}
+
+function createStickyAdIframeAtBottomOfViewport(width, height) {
+  const frame = document.createElement('iframe');
+  frame.style.position = 'fixed';
+  frame.style.bottom = '0px';
+  frame.scrolling = 'no';
+  frame.width = width;
+  frame.height = height;
+  document.body.appendChild(frame);
+  return frame;
+}
+
+document.scriptExecuted = true;
diff --git a/chrome/test/data/ads_observer/ad_with_incomplete_resource.html b/components/test/data/ads_observer/ad_with_incomplete_resource.html
similarity index 100%
rename from chrome/test/data/ads_observer/ad_with_incomplete_resource.html
rename to components/test/data/ads_observer/ad_with_incomplete_resource.html
diff --git a/chrome/test/data/ads_observer/blank_with_adiframe_writer.html b/components/test/data/ads_observer/blank_with_adiframe_writer.html
similarity index 100%
rename from chrome/test/data/ads_observer/blank_with_adiframe_writer.html
rename to components/test/data/ads_observer/blank_with_adiframe_writer.html
diff --git a/chrome/test/data/ads_observer/display_block_adframe.html b/components/test/data/ads_observer/display_block_adframe.html
similarity index 100%
rename from chrome/test/data/ads_observer/display_block_adframe.html
rename to components/test/data/ads_observer/display_block_adframe.html
diff --git a/chrome/test/data/ads_observer/display_none_adframe.html b/components/test/data/ads_observer/display_none_adframe.html
similarity index 100%
rename from chrome/test/data/ads_observer/display_none_adframe.html
rename to components/test/data/ads_observer/display_none_adframe.html
diff --git a/chrome/test/data/ads_observer/docwrite_blank_frame.html b/components/test/data/ads_observer/docwrite_blank_frame.html
similarity index 100%
rename from chrome/test/data/ads_observer/docwrite_blank_frame.html
rename to components/test/data/ads_observer/docwrite_blank_frame.html
diff --git a/chrome/test/data/ads_observer/docwrite_provisional_frame.html b/components/test/data/ads_observer/docwrite_provisional_frame.html
similarity index 100%
rename from chrome/test/data/ads_observer/docwrite_provisional_frame.html
rename to components/test/data/ads_observer/docwrite_provisional_frame.html
diff --git a/chrome/test/data/ads_observer/expensive_animation_frame.html b/components/test/data/ads_observer/expensive_animation_frame.html
similarity index 100%
rename from chrome/test/data/ads_observer/expensive_animation_frame.html
rename to components/test/data/ads_observer/expensive_animation_frame.html
diff --git a/chrome/test/data/ads_observer/large_scrollable_page_with_adiframe_writer.html b/components/test/data/ads_observer/large_scrollable_page_with_adiframe_writer.html
similarity index 100%
rename from chrome/test/data/ads_observer/large_scrollable_page_with_adiframe_writer.html
rename to components/test/data/ads_observer/large_scrollable_page_with_adiframe_writer.html
diff --git a/chrome/test/data/ads_observer/pixel.png b/components/test/data/ads_observer/pixel.png
similarity index 100%
rename from chrome/test/data/ads_observer/pixel.png
rename to components/test/data/ads_observer/pixel.png
Binary files differ
diff --git a/chrome/test/data/ads_observer/pixel2.png b/components/test/data/ads_observer/pixel2.png
similarity index 100%
rename from chrome/test/data/ads_observer/pixel2.png
rename to components/test/data/ads_observer/pixel2.png
Binary files differ
diff --git a/chrome/test/data/ads_observer/pixel3.png b/components/test/data/ads_observer/pixel3.png
similarity index 100%
rename from chrome/test/data/ads_observer/pixel3.png
rename to components/test/data/ads_observer/pixel3.png
Binary files differ
diff --git a/chrome/test/data/ads_observer/same_origin_ad.html b/components/test/data/ads_observer/same_origin_ad.html
similarity index 100%
rename from chrome/test/data/ads_observer/same_origin_ad.html
rename to components/test/data/ads_observer/same_origin_ad.html
diff --git a/chrome/test/data/ads_observer/srcdoc_embedded_ad.html b/components/test/data/ads_observer/srcdoc_embedded_ad.html
similarity index 100%
rename from chrome/test/data/ads_observer/srcdoc_embedded_ad.html
rename to components/test/data/ads_observer/srcdoc_embedded_ad.html
diff --git a/chrome/test/data/ads_observer/srcdoc_embedded_ad_empty.html b/components/test/data/ads_observer/srcdoc_embedded_ad_empty.html
similarity index 100%
rename from chrome/test/data/ads_observer/srcdoc_embedded_ad_empty.html
rename to components/test/data/ads_observer/srcdoc_embedded_ad_empty.html
diff --git a/chrome/test/data/ads_observer/two_raf_frames.html b/components/test/data/ads_observer/two_raf_frames.html
similarity index 100%
rename from chrome/test/data/ads_observer/two_raf_frames.html
rename to components/test/data/ads_observer/two_raf_frames.html
diff --git a/components/webapps/services/web_app_origin_association/BUILD.gn b/components/webapps/services/web_app_origin_association/BUILD.gn
index 6a9abd5..58922f5 100644
--- a/components/webapps/services/web_app_origin_association/BUILD.gn
+++ b/components/webapps/services/web_app_origin_association/BUILD.gn
@@ -10,6 +10,8 @@
     "web_app_origin_association_parser.h",
     "web_app_origin_association_parser_impl.cc",
     "web_app_origin_association_parser_impl.h",
+    "web_app_origin_association_uma_util.cc",
+    "web_app_origin_association_uma_util.h",
   ]
 
   deps = [
diff --git a/components/webapps/services/web_app_origin_association/web_app_origin_association_fetcher.cc b/components/webapps/services/web_app_origin_association/web_app_origin_association_fetcher.cc
index 9d8ca43..ad0ef969 100644
--- a/components/webapps/services/web_app_origin_association/web_app_origin_association_fetcher.cc
+++ b/components/webapps/services/web_app_origin_association/web_app_origin_association_fetcher.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "components/webapps/services/web_app_origin_association/web_app_origin_association_uma_util.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "services/network/public/cpp/resource_request.h"
@@ -116,7 +117,10 @@
       url_handler.origin.GetURL().Resolve(association_file_name);
   if (!ShouldFetchAssociationFile(resource_url)) {
     // Do not proceed if |resource_url| is not valid.
-    OnResponse(std::move(callback), nullptr);
+    webapps::WebAppOriginAssociationMetrics::RecordFetchResult(
+        webapps::WebAppOriginAssociationMetrics::FetchResult::
+            kFetchFailedInvalidUrl);
+    std::move(callback).Run(nullptr);
     return;
   }
 
@@ -139,6 +143,14 @@
 void WebAppOriginAssociationFetcher::OnResponse(
     FetchFileCallback callback,
     std::unique_ptr<std::string> response_body) {
+  if (!response_body) {
+    webapps::WebAppOriginAssociationMetrics::RecordFetchResult(
+        webapps::WebAppOriginAssociationMetrics::FetchResult::
+            kFetchFailedNoResponseBody);
+  } else {
+    webapps::WebAppOriginAssociationMetrics::RecordFetchResult(
+        webapps::WebAppOriginAssociationMetrics::FetchResult::kFetchSucceed);
+  }
   std::move(callback).Run(std::move(response_body));
 }
 
diff --git a/components/webapps/services/web_app_origin_association/web_app_origin_association_fetcher_unittest.cc b/components/webapps/services/web_app_origin_association/web_app_origin_association_fetcher_unittest.cc
index a91465e..5471a0a 100644
--- a/components/webapps/services/web_app_origin_association/web_app_origin_association_fetcher_unittest.cc
+++ b/components/webapps/services/web_app_origin_association/web_app_origin_association_fetcher_unittest.cc
@@ -9,7 +9,9 @@
 
 #include "base/run_loop.h"
 #include "base/test/bind.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "base/test/task_environment.h"
+#include "components/webapps/services/web_app_origin_association/web_app_origin_association_uma_util.h"
 #include "content/public/browser/network_service_instance.h"
 #include "content/public/test/browser_task_environment.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
@@ -31,6 +33,8 @@
     "    }"
     "}]})";
 
+constexpr char kFetchResultHistogram[] =
+    "Webapp.WebAppOriginAssociationFetchResult";
 }  // namespace
 
 namespace webapps {
@@ -81,6 +85,7 @@
   net::test_server::EmbeddedTestServerHandle test_server_handle_;
   scoped_refptr<network::TestSharedURLLoaderFactory> shared_url_loader_factory_;
   std::unique_ptr<WebAppOriginAssociationFetcher> fetcher_;
+  base::HistogramTester histogram_tester_;
 };
 
 TEST_F(WebAppOriginAssociationFetcherTest, FileExists) {
@@ -93,6 +98,9 @@
           [&](std::unique_ptr<std::string> file_content) {
             ASSERT_FALSE(!file_content);
             EXPECT_EQ(*file_content, kWebAppOriginAssociationFileContent);
+            histogram_tester_.ExpectBucketCount(
+                kFetchResultHistogram,
+                WebAppOriginAssociationMetrics::FetchResult::kFetchSucceed, 1);
             run_loop.Quit();
           }));
   run_loop.Run();
@@ -101,12 +109,18 @@
 TEST_F(WebAppOriginAssociationFetcherTest, FileDoesNotExist) {
   base::RunLoop run_loop;
   auto handler = apps::UrlHandlerInfo();
-  handler.origin = url::Origin::Create(server_.GetURL("https://foo.com", "/"));
+  GURL url = server_.GetURL("foo.com", "/");
+  handler.origin = url::Origin::Create(url);
   fetcher_->FetchWebAppOriginAssociationFile(
       std::move(handler), shared_url_loader_factory_.get(),
       base::BindLambdaForTesting(
           [&](std::unique_ptr<std::string> file_content) {
             ASSERT_TRUE(!file_content);
+            histogram_tester_.ExpectBucketCount(
+                kFetchResultHistogram,
+                WebAppOriginAssociationMetrics::FetchResult::
+                    kFetchFailedNoResponseBody,
+                1);
             run_loop.Quit();
           }));
   run_loop.Run();
@@ -121,6 +135,11 @@
       base::BindLambdaForTesting(
           [&](std::unique_ptr<std::string> file_content) {
             ASSERT_TRUE(!file_content);
+            histogram_tester_.ExpectBucketCount(
+                kFetchResultHistogram,
+                WebAppOriginAssociationMetrics::FetchResult::
+                    kFetchFailedInvalidUrl,
+                1);
             run_loop.Quit();
           }));
   run_loop.Run();
diff --git a/components/webapps/services/web_app_origin_association/web_app_origin_association_uma_util.cc b/components/webapps/services/web_app_origin_association/web_app_origin_association_uma_util.cc
new file mode 100644
index 0000000..b8c118df
--- /dev/null
+++ b/components/webapps/services/web_app_origin_association/web_app_origin_association_uma_util.cc
@@ -0,0 +1,16 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/webapps/services/web_app_origin_association/web_app_origin_association_uma_util.h"
+
+#include "base/metrics/histogram_functions.h"
+
+namespace webapps {
+
+void WebAppOriginAssociationMetrics::RecordFetchResult(FetchResult result) {
+  base::UmaHistogramEnumeration("Webapp.WebAppOriginAssociationFetchResult",
+                                result);
+}
+
+}  // namespace webapps
diff --git a/components/webapps/services/web_app_origin_association/web_app_origin_association_uma_util.h b/components/webapps/services/web_app_origin_association/web_app_origin_association_uma_util.h
new file mode 100644
index 0000000..93744c4
--- /dev/null
+++ b/components/webapps/services/web_app_origin_association/web_app_origin_association_uma_util.h
@@ -0,0 +1,26 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_WEBAPPS_SERVICES_WEB_APP_ORIGIN_ASSOCIATION_WEB_APP_ORIGIN_ASSOCIATION_UMA_UTIL_H_
+#define COMPONENTS_WEBAPPS_SERVICES_WEB_APP_ORIGIN_ASSOCIATION_WEB_APP_ORIGIN_ASSOCIATION_UMA_UTIL_H_
+
+namespace webapps {
+
+class WebAppOriginAssociationMetrics {
+ public:
+  // These values are persisted to logs. Entries should not be renumbered and
+  // numeric values should never be reused.
+  enum class FetchResult {
+    kFetchSucceed = 0,
+    kFetchFailedNoResponseBody = 1,
+    kFetchFailedInvalidUrl = 2,
+    kMaxValue = kFetchFailedInvalidUrl,
+  };
+
+  static void RecordFetchResult(FetchResult result);
+};
+
+}  // namespace webapps
+
+#endif  // COMPONENTS_WEBAPPS_SERVICES_WEB_APP_ORIGIN_ASSOCIATION_WEB_APP_ORIGIN_ASSOCIATION_UMA_UTIL_H_
diff --git a/content/browser/accessibility/dump_accessibility_events_browsertest.cc b/content/browser/accessibility/dump_accessibility_events_browsertest.cc
index 60ad40a..1857bf4 100644
--- a/content/browser/accessibility/dump_accessibility_events_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_events_browsertest.cc
@@ -532,8 +532,16 @@
   RunEventTest(FILE_PATH_LITERAL("caret-move.html"));
 }
 
+// Flaky on Windows: https://crbug.com/1186887
+#if defined(OS_WIN)
+#define MAYBE_AccessibilityEventsCaretMoveHiddenInput \
+  DISABLED_AccessibilityEventsCaretMoveHiddenInput
+#else
+#define MAYBE_AccessibilityEventsCaretMoveHiddenInput \
+  AccessibilityEventsCaretMoveHiddenInput
+#endif
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest,
-                       AccessibilityEventsCaretMoveHiddenInput) {
+                       MAYBE_AccessibilityEventsCaretMoveHiddenInput) {
   RunEventTest(FILE_PATH_LITERAL("caret-move-hidden-input.html"));
 }
 
@@ -586,9 +594,10 @@
   RunEventTest(FILE_PATH_LITERAL("aria-hidden-single-descendant.html"));
 }
 
+// crbug.com/1181414.
 IN_PROC_BROWSER_TEST_P(
     DumpAccessibilityEventsTest,
-    AccessibilityEventsAriaHiddenSingleDescendantDisplayNone) {
+    DISABLED_AccessibilityEventsAriaHiddenSingleDescendantDisplayNone) {
   RunEventTest(
       FILE_PATH_LITERAL("aria-hidden-single-descendant-display-none.html"));
 }
diff --git a/content/browser/mojo_binder_policy_map_impl.cc b/content/browser/mojo_binder_policy_map_impl.cc
index 667726bc..e02819f 100644
--- a/content/browser/mojo_binder_policy_map_impl.cc
+++ b/content/browser/mojo_binder_policy_map_impl.cc
@@ -10,6 +10,7 @@
 #include "content/public/common/content_client.h"
 #include "device/gamepad/public/mojom/gamepad.mojom.h"
 #include "services/network/public/mojom/restricted_cookie_manager.mojom.h"
+#include "third_party/blink/public/mojom/clipboard/clipboard.mojom.h"
 #include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom.h"
 
 namespace content {
@@ -24,6 +25,12 @@
       MojoBinderPolicy::kCancel);
   map.SetPolicy<device::mojom::GamepadMonitor>(MojoBinderPolicy::kCancel);
 
+  // ClipboardHost has sync messages, so it cannot be kDefer. However, the
+  // renderer is not expected to request the interface because it only does so
+  // after blink::mojom::PermissionService is bound, which is a deferred
+  // interface.
+  map.SetPolicy<blink::mojom::ClipboardHost>(MojoBinderPolicy::kUnexpected);
+
   map.SetPolicy<blink::mojom::IDBFactory>(MojoBinderPolicy::kGrant);
   map.SetPolicy<network::mojom::RestrictedCookieManager>(
       MojoBinderPolicy::kGrant);
diff --git a/content/browser/prerender/prerender_browsertest.cc b/content/browser/prerender/prerender_browsertest.cc
index 39c7c69..b2c230b 100644
--- a/content/browser/prerender/prerender_browsertest.cc
+++ b/content/browser/prerender/prerender_browsertest.cc
@@ -42,6 +42,7 @@
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/embedded_test_server/http_request.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/mojom/browser_interface_broker.mojom.h"
 #include "ui/shell_dialogs/select_file_dialog.h"
@@ -986,10 +987,11 @@
             EvalJs(shell()->web_contents(), "document.cookie"));
 }
 
+// TODO(crbug.com/1186584) Test is flaky.
 // Test that a cross-site navigation from prerendering browser context will
 // cancel prerendering.
 IN_PROC_BROWSER_TEST_P(PrerenderBrowserTest,
-                       PrerenderedPageCrossSiteNavigation) {
+                       DISABLED_PrerenderedPageCrossSiteNavigation) {
   base::HistogramTester histogram_tester;
   const GURL kInitialUrl = GetUrl("/prerender/add_prerender.html");
   const GURL kPrerenderingUrl = GetUrl("/empty.html");
@@ -1427,6 +1429,35 @@
 
 // - End: Tests for Mojo capability control methodology restrictions ===========
 
+// Tests that prerendering pages cannot access Clipboard.
+// This cannot be upstreamed as a WPT test because the spec (probably) will
+// require that no error is thrown until activation.
+IN_PROC_BROWSER_TEST_P(PrerenderBrowserTest, ClipboardAccessError) {
+  const GURL kInitialUrl = GetUrl("/prerender/add_prerender.html");
+  const GURL kPrerenderingUrl = GetUrl("/empty.html");
+
+  // Navigate to an initial page.
+  ASSERT_TRUE(NavigateToURL(shell(), kInitialUrl));
+
+  // Make a prerendered page.
+  AddPrerender(kPrerenderingUrl);
+
+  PrerenderHostRegistry& registry = GetPrerenderHostRegistry();
+  PrerenderHost* prerender_host =
+      registry.FindHostByUrlForTesting(kPrerenderingUrl);
+  ASSERT_TRUE(prerender_host);
+  RenderFrameHostImpl* prerendered_render_frame_host =
+      prerender_host->GetPrerenderedMainFrameHostForTesting();
+
+  // Accessing Clipboard on prerendering pages should fail because the
+  // prerendering documents are not focused.
+  // (https://w3c.github.io/clipboard-apis/#privacy-async)
+  auto result = EvalJs(prerendered_render_frame_host,
+                       "navigator.clipboard.writeText(location.href);");
+  EXPECT_THAT(result.error, ::testing::HasSubstr(
+                                "NotAllowedError: Document is not focused."));
+}
+
 // End: Tests for feature restrictions in prerendered pages ====================
 
 // Tests that prerendering doesn't run for low-end devices.
diff --git a/content/browser/prerender/prerender_host.cc b/content/browser/prerender/prerender_host.cc
index 6ca0781..18292e2 100644
--- a/content/browser/prerender/prerender_host.cc
+++ b/content/browser/prerender/prerender_host.cc
@@ -203,10 +203,13 @@
     // Activate the prerendered contents.
     WebContentsDelegate* delegate = current_web_contents->GetDelegate();
     DCHECK(delegate);
-    DCHECK(web_contents_);
     DCHECK(GetMainFrame()->frame_tree()->is_prerendering());
     GetMainFrame()->frame_tree()->ActivatePrerenderedFrameTree();
 
+    DCHECK(web_contents_);
+    auto* successor_web_contents =
+        static_cast<WebContentsImpl*>(web_contents_.get());
+
     // Tentatively use Portal's activation function.
     // TODO(https://crbug.com/1132746): Replace this with the MPArch.
     std::unique_ptr<WebContents> predecessor_web_contents =
@@ -215,6 +218,11 @@
 
     // Stop loading on the predecessor WebContents.
     predecessor_web_contents->Stop();
+
+    // Notify the renderer of activation to update the prerendering state and
+    // dispatch the prerenderingchange event.
+    successor_web_contents->NotifyPrerenderingPageActivated();
+
     return true;
   }
 
diff --git a/content/browser/renderer_host/navigation_controller_impl.cc b/content/browser/renderer_host/navigation_controller_impl.cc
index 3921efd..be8ba06 100644
--- a/content/browser/renderer_host/navigation_controller_impl.cc
+++ b/content/browser/renderer_host/navigation_controller_impl.cc
@@ -1477,9 +1477,9 @@
         rfh->frame_tree_node()->unique_name(), params.item_sequence_number,
         params.document_sequence_number, rfh->GetSiteInstance(), nullptr,
         params.url, (params.url_is_unreachable) ? nullptr : &params.origin,
-        Referrer(*params.referrer), initiator_origin, params.redirects,
-        params.page_state, params.method, params.post_id,
-        nullptr /* blob_url_loader_factory */,
+        Referrer(*params.referrer), initiator_origin,
+        request->GetRedirectChain(), params.page_state, params.method,
+        params.post_id, nullptr /* blob_url_loader_factory */,
         nullptr /* web_bundle_navigation_info */,
         request->GetSubresourceWebBundleNavigationInfo(),
         // We will set the document policies later in this function.
@@ -1606,7 +1606,7 @@
   frame_entry->set_frame_unique_name(rfh->frame_tree_node()->unique_name());
   frame_entry->set_item_sequence_number(params.item_sequence_number);
   frame_entry->set_document_sequence_number(params.document_sequence_number);
-  frame_entry->set_redirect_chain(params.redirects);
+  frame_entry->set_redirect_chain(request->GetRedirectChain());
   frame_entry->SetPageState(params.page_state);
   frame_entry->set_method(params.method);
   frame_entry->set_post_id(params.post_id);
@@ -1839,7 +1839,7 @@
       rfh->frame_tree_node(), params.item_sequence_number,
       params.document_sequence_number, rfh->GetSiteInstance(), nullptr,
       params.url, GetCommittedOriginForFrameEntry(params),
-      Referrer(*params.referrer), initiator_origin, params.redirects,
+      Referrer(*params.referrer), initiator_origin, request->GetRedirectChain(),
       params.page_state, params.method, params.post_id,
       nullptr /* blob_url_loader_factory */,
       request->web_bundle_navigation_info()
@@ -1900,7 +1900,7 @@
       rfh->frame_tree_node()->unique_name(), params.item_sequence_number,
       params.document_sequence_number, rfh->GetSiteInstance(), nullptr,
       params.url, (params.url_is_unreachable) ? nullptr : &params.origin,
-      Referrer(*params.referrer), initiator_origin, params.redirects,
+      Referrer(*params.referrer), initiator_origin, request->GetRedirectChain(),
       params.page_state, params.method, params.post_id,
       nullptr /* blob_url_loader_factory */,
       request->web_bundle_navigation_info()
@@ -1986,7 +1986,7 @@
       rfh->frame_tree_node(), params.item_sequence_number,
       params.document_sequence_number, rfh->GetSiteInstance(), nullptr,
       params.url, GetCommittedOriginForFrameEntry(params),
-      Referrer(*params.referrer), initiator_origin, params.redirects,
+      Referrer(*params.referrer), initiator_origin, request->GetRedirectChain(),
       params.page_state, params.method, params.post_id,
       nullptr /* blob_url_loader_factory */,
       request->web_bundle_navigation_info()
diff --git a/content/browser/renderer_host/navigation_controller_impl_browsertest.cc b/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
index 1ca2ebc5..e645c97 100644
--- a/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
@@ -5946,16 +5946,7 @@
     // navigations are always classified as client redirects. So, they start
     // with the previous page's URL in the redirect chain.
     EXPECT_EQ(entry->GetRedirectChain().size(), 2u);
-    if (CanSameSiteMainFrameNavigationsChangeRenderFrameHosts()) {
-      // If we change RenderFrameHosts, the previous page's URL can't be
-      // obtained from the new renderer's DocumentLoader - we will incorrectly
-      // get an empty URL in its place, which will be rewritten by the URL
-      // filters to "about:blank#blocked".
-      // TODO(https://crbug.com/1171210): Fix this.
-      EXPECT_EQ(entry->GetRedirectChain()[0], GURL(kBlockedURL));
-    } else {
-      EXPECT_EQ(entry->GetRedirectChain()[0], start_url);
-    }
+    EXPECT_EQ(entry->GetRedirectChain()[0], start_url);
     EXPECT_EQ(entry->GetRedirectChain()[1], url_2);
 
     // No replaced entry because it's not a "real" client-side redirect.
@@ -6021,7 +6012,6 @@
 
   GURL url_2(embedded_test_server()->GetURL("b.com", "/title2.html"));
   {
-    auto* old_rfh = shell()->web_contents()->GetMainFrame();
     // Renderer-initiated cross-site navigation.
     EXPECT_TRUE(NavigateToURLFromRenderer(shell(), url_2));
 
@@ -6034,17 +6024,7 @@
     // navigations are always classified as client redirects. So, they start
     // with the previous page's URL in the redirect chain.
     EXPECT_EQ(entry->GetRedirectChain().size(), 2u);
-    auto* new_rfh = shell()->web_contents()->GetMainFrame();
-    if (old_rfh != new_rfh) {
-      // If we change RenderFrameHosts, the previous page's URL can't be
-      // obtained from the new renderer's DocumentLoader - we will incorrectly
-      // get an empty URL in its place, which will be rewritten by the URL
-      // filters to "about:blank#blocked".
-      // TODO(https://crbug.com/1171210): Fix this.
-      EXPECT_EQ(entry->GetRedirectChain()[0], GURL(kBlockedURL));
-    } else {
-      EXPECT_EQ(entry->GetRedirectChain()[0], start_url);
-    }
+    EXPECT_EQ(entry->GetRedirectChain()[0], start_url);
     EXPECT_EQ(entry->GetRedirectChain()[1], url_2);
 
     // No replaced entry because it's not a "real" client-side redirect.
@@ -6250,15 +6230,7 @@
     // On renderer-initiated reloads with no redirects, the redirect chain
     // contains the reloaded page's URL twice.
     EXPECT_EQ(frame_entry->redirect_chain().size(), 2u);
-    if (ShouldCreateNewHostForSameSiteSubframe()) {
-      // If we change RenderFrameHosts, the previous page's URL can't be
-      // obtained from the new renderer's DocumentLoader - we will incorrectly
-      // get an about:blank URL in its place.
-      // TODO(https://crbug.com/1171210): Fix this.
-      EXPECT_EQ(frame_entry->redirect_chain()[0], GURL(url::kAboutBlankURL));
-    } else {
-      EXPECT_EQ(frame_entry->redirect_chain()[0], iframe_url);
-    }
+    EXPECT_EQ(frame_entry->redirect_chain()[0], iframe_url);
     EXPECT_EQ(frame_entry->redirect_chain()[1], iframe_url);
   }
 
@@ -6274,18 +6246,14 @@
         controller.GetLastCommittedEntry()->GetFrameEntry(iframe);
     EXPECT_EQ(iframe_url, frame_entry->url());
 
-    // On subframe browser-initiated reloads, the redirect chain only contains
-    // the original URL once.
-    // This should've contained three copies of `iframe_url`,because the browser
-    // actually sent the previous FNE's redirect chain at commit, containing the
-    // two entries seen above. The renderer should've added one more entry of
-    // `iframe_url` (as the current document URL) and sent that back to the
-    // browser, but the renderer actually thought that the redirect chain is
-    // empty (because it checked for the redirect_response array, instead of the
-    // redirects array). So we end up with a redirect chain of size 1.
-    // TODO(https://crbug.com/1171225): Fix this.
-    EXPECT_EQ(frame_entry->redirect_chain().size(), 1u);
+    // On subframe browser-initiated reloads, the redirect chain contains three
+    // copies of `iframe_url`, because we reused the previous FNE's redirect
+    // chain at commit, containing the two entries seen above, and we added one
+    // more entry of `iframe_url` (as the current document URL).
+    EXPECT_EQ(frame_entry->redirect_chain().size(), 3u);
     EXPECT_EQ(frame_entry->redirect_chain()[0], iframe_url);
+    EXPECT_EQ(frame_entry->redirect_chain()[1], iframe_url);
+    EXPECT_EQ(frame_entry->redirect_chain()[2], iframe_url);
   }
 }
 
@@ -6327,11 +6295,9 @@
     EXPECT_EQ(url_2, entry->GetURL());
 
     // On renderer-initiated cross-site navigations with no redirects that end
-    // up in error pages, the redirect chain contains the error page URL.
-    // TODO(https://crbug.com/1171237): This should be the commit URL (url_2)
-    // instead.
+    // up in error pages, the redirect chain contains the final URL.
     EXPECT_EQ(entry->GetRedirectChain().size(), 1u);
-    EXPECT_EQ(entry->GetRedirectChain()[0], GURL(kUnreachableWebDataURL));
+    EXPECT_EQ(entry->GetRedirectChain()[0], url_2);
 
     // No replaced entry because it's not a client-side redirect.
     EXPECT_FALSE(entry->GetReplacedEntryData().has_value());
@@ -6351,9 +6317,9 @@
     EXPECT_EQ(url_3, entry->GetURL());
 
     // On browser-initiated cross-site navigations with no redirects that end
-    // up in error pages, the redirect chain contains the error page URL.
+    // up in error pages, the redirect chain contains the final URL.
     EXPECT_EQ(entry->GetRedirectChain().size(), 1u);
-    EXPECT_EQ(entry->GetRedirectChain()[0], GURL(kUnreachableWebDataURL));
+    EXPECT_EQ(entry->GetRedirectChain()[0], url_3);
 
     // No replaced entry because it's not a client-side redirect.
     EXPECT_FALSE(entry->GetReplacedEntryData().has_value());
@@ -6385,12 +6351,10 @@
   EXPECT_EQ(fail_url, entry->GetURL());
 
   // On navigations that end up in error pages, the redirect chain only
-  // contains the error page URL, even if the navigation went through server
+  // contains the final URL, even if the navigation went through server
   // redirects.
-  // TODO(https://crbug.com/1171237): This should be the commit URL (fail_url)
-  // instead.
   EXPECT_EQ(entry->GetRedirectChain().size(), 1u);
-  EXPECT_EQ(entry->GetRedirectChain()[0], GURL(kUnreachableWebDataURL));
+  EXPECT_EQ(entry->GetRedirectChain()[0], fail_url);
 
   // No replaced entry because it's not a client-side redirect.
   EXPECT_FALSE(entry->GetReplacedEntryData().has_value());
@@ -6446,12 +6410,10 @@
     EXPECT_EQ(fail_url, entry->GetURL());
 
     // On navigations that end up in error pages, the redirect chain only
-    // contains the error page URL, even if the navigation went through client
+    // contains the final URL, even if the navigation went through client
     // and server redirects.
-    // TODO(https://crbug.com/1171237): This should be the commit URL (fail_url)
-    // instead.
     EXPECT_EQ(entry->GetRedirectChain().size(), 1u);
-    EXPECT_EQ(entry->GetRedirectChain()[0], GURL(kUnreachableWebDataURL));
+    EXPECT_EQ(entry->GetRedirectChain()[0], fail_url);
 
     // No replaced entry because it's not a client-side redirect.
     EXPECT_FALSE(entry->GetReplacedEntryData().has_value());
diff --git a/content/browser/renderer_host/navigation_controller_impl_unittest.cc b/content/browser/renderer_host/navigation_controller_impl_unittest.cc
index de692328..62d2732 100644
--- a/content/browser/renderer_host/navigation_controller_impl_unittest.cc
+++ b/content/browser/renderer_host/navigation_controller_impl_unittest.cc
@@ -107,6 +107,7 @@
               (override));
   MOCK_METHOD(void, AudioStateChanged, (bool is_audio_playing), (override));
   MOCK_METHOD(void, SetInsidePortal, (bool is_inside_portal), (override));
+  MOCK_METHOD(void, ActivatePrerender, (), (override));
   MOCK_METHOD(void,
               UpdateWebPreferences,
               (const ::blink::web_pref::WebPreferences& preferences),
@@ -1402,8 +1403,12 @@
   navigation->Redirect(url2);
   navigation->Commit();
   NavigationEntryImpl* committed_entry = controller.GetLastCommittedEntry();
-  ASSERT_EQ(1U, committed_entry->GetRedirectChain().size());
-  EXPECT_EQ(url2, committed_entry->GetRedirectChain()[0]);
+
+  // The navigation started out trying to get to |url1|, but got redirected to
+  // |url2|, so they're both in the redirect chain.
+  ASSERT_EQ(2U, committed_entry->GetRedirectChain().size());
+  EXPECT_EQ(url1, committed_entry->GetRedirectChain()[0]);
+  EXPECT_EQ(url2, committed_entry->GetRedirectChain()[1]);
 }
 
 // Tests that webkit preferences are updated when user agent override changes.
@@ -2297,7 +2302,6 @@
   params->method = "GET";
   params->page_state = blink::PageState::CreateFromURL(url2);
   params->post_id = -1;
-  params->redirects.push_back(url2);
 
   // This should NOT generate a new entry, nor prune the list.
   LoadCommittedDetailsObserver observer(contents());
@@ -2322,7 +2326,6 @@
   params->should_update_history = true;
   params->post_id = -1;
   params->gesture = NavigationGesture::NavigationGestureAuto;
-  params->redirects.push_back(url);
   main_test_rfh()->SendRendererInitiatedNavigationRequest(
       url, false /* has_user_gesture */);
   main_test_rfh()->PrepareForCommit();
@@ -3006,7 +3009,6 @@
   params->method = "GET";
   params->post_id = -1;
   params->should_update_history = true;
-  params->redirects.push_back(different_origin_url);
   main_test_rfh()->SendRendererInitiatedNavigationRequest(different_origin_url,
                                                           false);
   main_test_rfh()->PrepareForCommit();
@@ -4113,7 +4115,6 @@
   params->method = "GET";
   params->should_update_history = true;
   params->post_id = -1;
-  params->redirects.push_back(kUrl2);
   main_test_rfh()->SendNavigateWithParams(std::move(params), true);
 
   // The title should immediately be visible on the new NavigationEntry.
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index 5f17c1a..c00d3ca 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -1561,7 +1561,7 @@
       base::debug::DumpWithoutCrashing();
     }
 
-    ComputeSandboxFlagsToCommit(/*response_head=*/nullptr, required_csp_.get());
+    ComputePoliciesToCommit();
 
     // Same-document navigations occur in the currently loaded document. See
     // also RenderFrameHostManager::DidCreateNavigationRequest() which will
@@ -1685,8 +1685,15 @@
   // Finally, add the current URL to the vector of redirects.
   // Note: for NavigationRequests created at commit time, the current URL has
   // been added to |commit_params_->redirects|, so don't add it a second time.
-  if (!is_for_commit)
-    redirect_chain_.push_back(common_params_->url);
+  if (!is_for_commit) {
+    if (!common_params_->base_url_for_data_url.is_empty()) {
+      // If this is a loadDataWithBaseURL/loadDataAsStringWithBaseUrl
+      // navigation, use the base URL instead of the data: URL used for commit.
+      redirect_chain_.push_back(common_params_->base_url_for_data_url);
+    } else {
+      redirect_chain_.push_back(common_params_->url);
+    }
+  }
 
   // Mirrors the logic in RenderFrameImpl::SendDidCommitProvisionalLoad.
   if (common_params_->transition & ui::PAGE_TRANSITION_CLIENT_REDIRECT) {
@@ -2307,13 +2314,17 @@
 }
 
 const GURL& NavigationRequest::GetOriginalRequestURL() {
-  // If the navigation resulted in an error we should return the URL used to
-  // commit, even if the navigation went through redirects. This is to preserve
-  // the previous behavior where we use the redirect chain from the renderer to
-  // get the original request URL. When we commit an error page, the redirect
-  // chain in the renderer only contains the commit URL.
-  if (net_error_ != net::OK)
+  // If the navigation resulted in an error or this is a loadData navigation we
+  // should return the URL used to commit, even if the navigation went through
+  // redirects. This is to preserve the previous behavior where we use the
+  // edirect chain from the renderer to get the original request URL. When we
+  // commit an error page or a loadDataWithBaseURL/loadDataAsStringWithBaseUrl
+  // navigation, the redirect chain in the renderer only contains the commit
+  // URL.
+  if (net_error_ != net::OK ||
+      NavigationRequest::IsLoadDataWithBaseURL(*common_params_)) {
     return GetURL();
+  }
 
   // Otherwise, return the first URL in the redirect chain. If the navigation
   // is started by a client redirect, this will be the URL of the document that
@@ -2396,7 +2407,7 @@
     return;
   }
 
-  ComputeSandboxFlagsToCommit(response_head_.get(), required_csp_.get());
+  ComputePoliciesToCommit();
 
   // The navigation may have encountered a header that requests isolation for
   // the url's origin. Before we pick the renderer, make sure we update the
@@ -3422,8 +3433,11 @@
   // flags from their parent/opener. Document loaded from the network
   // shouldn't have any influence over Chrome's internal error page. We should
   // define our own flags, preferably the strictest ones instead.
-  ComputeSandboxFlagsToCommit(/*response_head=*/nullptr,
-                              /*required_csp=*/nullptr);
+  ComputePoliciesToCommitForError();
+
+  // On failed navigations, the redirect chain should only contain the last URL.
+  redirect_chain_.clear();
+  redirect_chain_.push_back(GetURL());
 
   ReadyToCommitNavigation(true);
   // Use a separate cache shard, and no cookies, for error pages.
@@ -4822,22 +4836,6 @@
     UpdatePrivateNetworkRequestPolicy();
   }
 
-  policy_container_navigation_bundle_->SetIPAddressSpace(
-      CalculateIPAddressSpace(common_params_->url, response_head_.get()));
-
-  // Use the unchecked / non-sandboxed origin to calculate potential
-  // trustworthiness. Indeed, the potential trustworthiness check should apply
-  // to the origin of the creation URL, prior to opaquification.
-  policy_container_navigation_bundle_->SetIsOriginPotentiallyTrustworthy(
-      network::IsOriginPotentiallyTrustworthy(
-          GetOriginForURLLoaderFactoryUnchecked(this)));
-
-  if (is_error) {
-    policy_container_navigation_bundle_->FinalizePoliciesForError();
-  } else {
-    policy_container_navigation_bundle_->FinalizePolicies(common_params_->url);
-  }
-
   if (appcache_handle_) {
     DCHECK(appcache_handle_->host());
     appcache_handle_->host()->SetProcessId(
@@ -5667,17 +5665,46 @@
   return cookie_observers_.TakeReceivers();
 }
 
+void NavigationRequest::ComputePoliciesToCommit() {
+  policy_container_navigation_bundle_->SetIPAddressSpace(
+      CalculateIPAddressSpace(common_params_->url, response_head_.get()));
+
+  // Use the unchecked / non-sandboxed origin to calculate potential
+  // trustworthiness. Indeed, the potential trustworthiness check should apply
+  // to the origin of the creation URL, prior to opaquification.
+  policy_container_navigation_bundle_->SetIsOriginPotentiallyTrustworthy(
+      network::IsOriginPotentiallyTrustworthy(
+          GetOriginForURLLoaderFactoryUnchecked(this)));
+  policy_container_navigation_bundle_->ComputePolicies(common_params_->url);
+
+  ComputeSandboxFlagsToCommit(response_head_.get(), required_csp_.get());
+}
+
+void NavigationRequest::ComputePoliciesToCommitForError() {
+  policy_container_navigation_bundle_->ComputePoliciesForError();
+  ComputeSandboxFlagsToCommit(/*response_head=*/nullptr,
+                              /*required_csp=*/nullptr);
+}
+
 void NavigationRequest::ComputeSandboxFlagsToCommit(
     const network::mojom::URLResponseHead* response_head,
-    network::mojom::ContentSecurityPolicy* required_csp) {
+    const network::mojom::ContentSecurityPolicy* required_csp) {
   DCHECK(commit_params_);
   DCHECK(!HasCommitted());
   DCHECK(!IsErrorPage());
   DCHECK(!sandbox_flags_to_commit_);
 
+  // Inherit sandbox from the frame.
   sandbox_flags_to_commit_ = commit_params_->frame_policy.sandbox_flags;
 
-  // The response can also restrict the policy further.
+  // The document can also restrict sandbox further, via its CSP.
+  const PolicyContainerPolicies& policies_to_commit =
+      policy_container_navigation_bundle_->FinalPolicies();
+  for (const auto& csp : policies_to_commit.content_security_policies)
+    *sandbox_flags_to_commit_ |= csp->sandbox;
+
+  // TODO(antoniosartori): Remove this block. The response_head CSP should
+  // already be part of the policy container.
   if (response_head) {
     for (const auto& csp :
          response_head->parsed_headers->content_security_policy) {
@@ -5687,6 +5714,8 @@
 
   // If the embedee opts in, the embedder can force its HTMLIframeElement.csp
   // attribute to be used by the embedee.
+  // TODO(antoniosartori): Remove this block. Include required_csp into
+  // policy container directly.
   if (required_csp)
     *sandbox_flags_to_commit_ |= required_csp->sandbox;
 
diff --git a/content/browser/renderer_host/navigation_request.h b/content/browser/renderer_host/navigation_request.h
index 267d1cf2..74c3bfb4 100644
--- a/content/browser/renderer_host/navigation_request.h
+++ b/content/browser/renderer_host/navigation_request.h
@@ -1190,12 +1190,27 @@
   // NavigationRequest is in.
   NavigationControllerImpl* GetNavigationController();
 
+  // Computes the PolicyContainerPolicies and the sandbox flags to use for
+  // committing a regular document.
+  // Called when the response to commit is known.
+  void ComputePoliciesToCommit();
+
+  // Computes the PolicyContainerPolicies and the sandbox flags to use for
+  // committing an error document.
+  //
+  // Note:
+  // |ComputePoliciesToCommit()| can be followed by
+  // |ComputePoliciesToCommitForErrorPage()|. This happens when the decision to
+  // commit an error document happens after receiving the regular document's
+  // response.
+  void ComputePoliciesToCommitForError();
+
   // Compute the sandbox policy of the document to be loaded. This is called
   // once the final response is known. It is based on the current FramePolicy,
   // the response's CSP and the embedder's HTMLIframeElement.csp.
   void ComputeSandboxFlagsToCommit(
       const network::mojom::URLResponseHead* response_head,
-      network::mojom::ContentSecurityPolicy* required_csp);
+      const network::mojom::ContentSecurityPolicy* required_csp);
 
   // DCHECK that tranistioning from the current state to |state| valid. This
   // does nothing in non-debug builds.
diff --git a/content/browser/renderer_host/policy_container_host.cc b/content/browser/renderer_host/policy_container_host.cc
index 73cbeb07..493b160c 100644
--- a/content/browser/renderer_host/policy_container_host.cc
+++ b/content/browser/renderer_host/policy_container_host.cc
@@ -91,6 +91,13 @@
       mojo::Clone(content_security_policies));
 }
 
+void PolicyContainerPolicies::AddContentSecurityPolicies(
+    std::vector<network::mojom::ContentSecurityPolicyPtr> policies) {
+  content_security_policies.insert(content_security_policies.end(),
+                                   std::make_move_iterator(policies.begin()),
+                                   std::make_move_iterator(policies.end()));
+}
+
 PolicyContainerHost::PolicyContainerHost()
     : PolicyContainerHost(std::make_unique<PolicyContainerPolicies>()) {}
 
@@ -133,10 +140,7 @@
 void PolicyContainerHost::AddContentSecurityPolicies(
     std::vector<network::mojom::ContentSecurityPolicyPtr>
         content_security_policies) {
-  policies_->content_security_policies.insert(
-      policies_->content_security_policies.end(),
-      std::make_move_iterator(content_security_policies.begin()),
-      std::make_move_iterator(content_security_policies.end()));
+  policies_->AddContentSecurityPolicies(std::move(content_security_policies));
 }
 
 blink::mojom::PolicyContainerPtr
diff --git a/content/browser/renderer_host/policy_container_host.h b/content/browser/renderer_host/policy_container_host.h
index 22eac15c..8099fca 100644
--- a/content/browser/renderer_host/policy_container_host.h
+++ b/content/browser/renderer_host/policy_container_host.h
@@ -35,6 +35,10 @@
   // pointer.
   std::unique_ptr<PolicyContainerPolicies> Clone() const;
 
+  // Helper function to append items to `content_security_policies`.
+  void AddContentSecurityPolicies(
+      std::vector<network::mojom::ContentSecurityPolicyPtr> policies);
+
   // The referrer policy for the associated document. If not overwritten via a
   // call to SetReferrerPolicy (for example after parsing the Referrer-Policy
   // header or a meta tag), the default referrer policy will be applied to the
diff --git a/content/browser/renderer_host/policy_container_navigation_bundle.cc b/content/browser/renderer_host/policy_container_navigation_bundle.cc
index 92fc443d..3f080a0 100644
--- a/content/browser/renderer_host/policy_container_navigation_bundle.cc
+++ b/content/browser/renderer_host/policy_container_navigation_bundle.cc
@@ -85,48 +85,53 @@
 
 const PolicyContainerPolicies*
 PolicyContainerNavigationBundle::InitiatorPolicies() const {
-  DCHECK(!IsFinalized());
-
   return initiator_policies_.get();
 }
 
 const PolicyContainerPolicies* PolicyContainerNavigationBundle::ParentPolicies()
     const {
-  DCHECK(!IsFinalized());
-
   return parent_policies_.get();
 }
 
 const PolicyContainerPolicies*
 PolicyContainerNavigationBundle::HistoryPolicies() const {
-  DCHECK(!IsFinalized());
-
   return history_policies_.get();
 }
 
 void PolicyContainerNavigationBundle::SetIPAddressSpace(
     network::mojom::IPAddressSpace address_space) {
-  DCHECK(!IsFinalized());
-
+  DCHECK(!HasComputedPolicies());
   delivered_policies_->ip_address_space = address_space;
 }
 
 void PolicyContainerNavigationBundle::SetIsOriginPotentiallyTrustworthy(
     bool value) {
-  DCHECK(!IsFinalized());
-
+  DCHECK(!HasComputedPolicies());
   delivered_policies_->is_web_secure_context = value;
 }
 
+void PolicyContainerNavigationBundle::AddContentSecurityPolicy(
+    network::mojom::ContentSecurityPolicyPtr policy) {
+  DCHECK(!HasComputedPolicies());
+  DCHECK(policy);
+
+  delivered_policies_->content_security_policies.push_back(std::move(policy));
+}
+
 const PolicyContainerPolicies&
 PolicyContainerNavigationBundle::DeliveredPolicies() const {
-  DCHECK(!IsFinalized());
+  DCHECK(!HasComputedPolicies());
 
   return *delivered_policies_;
 }
 
-void PolicyContainerNavigationBundle::FinalizePoliciesForError() {
-  DCHECK(!IsFinalized());
+void PolicyContainerNavigationBundle::ComputePoliciesForError() {
+  // The decision to commit an error page can happen after receiving the
+  // response for a regular document. It overrides any previous attempt to
+  // |ComputePolicies()|.
+  host_ = nullptr;
+
+  DCHECK(!HasComputedPolicies());
 
   // TODO(https://crbug.com/1175787): We should enforce strict policies on error
   // pages.
@@ -139,10 +144,12 @@
   policies->ip_address_space = delivered_policies_->ip_address_space;
 
   SetFinalPolicies(std::move(policies));
+
+  DCHECK(HasComputedPolicies());
 }
 
-void PolicyContainerNavigationBundle::FinalizeIsWebSecureContext() {
-  DCHECK(!IsFinalized());
+void PolicyContainerNavigationBundle::ComputeIsWebSecureContext() {
+  DCHECK(!HasComputedPolicies());
 
   if (!parent_policies_) {
     // No parent. Only the trustworthiness of the origin matters.
@@ -154,57 +161,64 @@
       parent_policies_->is_web_secure_context;
 }
 
-void PolicyContainerNavigationBundle::FinalizePolicies(const GURL& url) {
-  DCHECK(!IsFinalized());
+void PolicyContainerNavigationBundle::ComputePolicies(const GURL& url) {
+  DCHECK(!HasComputedPolicies());
 
-  FinalizeIsWebSecureContext();
+  ComputeIsWebSecureContext();
 
   if (history_policies_) {
     DCHECK(HasLocalScheme(url))
         << "Document is restoring policies from history for non-local scheme: "
         << url;
-    SetFinalPolicies(std::move(history_policies_));
-  } else if (url.IsAboutSrcdoc()) {
+    SetFinalPolicies(history_policies_->Clone());
+    return;
+  }
+
+  if (url.IsAboutSrcdoc()) {
     DCHECK(parent_policies_)
         << "About:srcdoc documents should always have a parent frame.";
-    SetFinalPolicies(std::move(parent_policies_));
-  } else if (HasLocalScheme(url)) {
-    SetFinalPolicies(initiator_policies_
-                         ? std::move(initiator_policies_)
-                         : std::make_unique<PolicyContainerPolicies>());
-  } else {
-    SetFinalPolicies(std::move(delivered_policies_));
+    SetFinalPolicies(parent_policies_->Clone());
+    return;
   }
+
+  if (HasLocalScheme(url)) {
+    SetFinalPolicies(initiator_policies_
+                         ? initiator_policies_->Clone()
+                         : std::make_unique<PolicyContainerPolicies>());
+    return;
+  }
+
+  SetFinalPolicies(delivered_policies_->Clone());
 }
 
-bool PolicyContainerNavigationBundle::IsFinalized() const {
+bool PolicyContainerNavigationBundle::HasComputedPolicies() const {
   return host_ != nullptr;
 }
 
 void PolicyContainerNavigationBundle::SetFinalPolicies(
     std::unique_ptr<PolicyContainerPolicies> policies) {
-  DCHECK(!IsFinalized());
+  DCHECK(!HasComputedPolicies());
 
   host_ = base::MakeRefCounted<PolicyContainerHost>(std::move(policies));
 }
 
 const PolicyContainerPolicies& PolicyContainerNavigationBundle::FinalPolicies()
     const {
-  DCHECK(IsFinalized());
+  DCHECK(HasComputedPolicies());
 
   return host_->policies();
 }
 
 blink::mojom::PolicyContainerPtr
 PolicyContainerNavigationBundle::CreatePolicyContainerForBlink() {
-  DCHECK(IsFinalized());
+  DCHECK(HasComputedPolicies());
 
   return host_->CreatePolicyContainerForBlink();
 }
 
 scoped_refptr<PolicyContainerHost>
 PolicyContainerNavigationBundle::TakePolicyContainerHost() && {
-  DCHECK(IsFinalized());
+  DCHECK(HasComputedPolicies());
 
   return std::move(host_);
 }
diff --git a/content/browser/renderer_host/policy_container_navigation_bundle.h b/content/browser/renderer_host/policy_container_navigation_bundle.h
index 9e48e664..a8a5a56 100644
--- a/content/browser/renderer_host/policy_container_navigation_bundle.h
+++ b/content/browser/renderer_host/policy_container_navigation_bundle.h
@@ -31,9 +31,12 @@
 // Setters can be called as the navigation progresses to record interesting
 // properties for later.
 //
-// At ready-to-commit time, |FinalizePolicies()| or |FinalizePoliciesForError()|
-// can be called to set the final policies of the new document and create a new
-// policy container host.
+// When the potential response to commit is known, |ComputePolicies()| can be
+// called to set the final polices of the new document and create a new policy
+// container host.
+// For error documents, |ComputePoliciesForError()| should be used instead. It
+// can also be called after |ComputePolicies()| in some cases when the error is
+// only detected after receiving a response
 //
 // At commit time, |TakePolicyContainerHost()| can be called to transfer
 // ownership of the policy container host to the target RenderFrameHostImpl.
@@ -78,20 +81,26 @@
 
   // Sets the IP address space of the delivered policies of the new document.
   //
-  // This instance must not be finalized.
+  // This must be called before |ComputePolicies()|.
   void SetIPAddressSpace(network::mojom::IPAddressSpace address_space);
 
   // Sets whether the origin of the document being navigated to is
   // potentially-trustworthy, as defined in:
   // https://w3c.github.io/webappsec-secure-contexts/#is-origin-trustworthy.
   //
-  // This instance must not be frozen.
+  // This must be called before |ComputePolicies()|.
   void SetIsOriginPotentiallyTrustworthy(bool value);
 
+  // Records an additional Content Security Policy that will apply to the new
+  // document. |policy| must not be null. Policies added this way are ignored
+  // for failed navigations and history navigations.
+  void AddContentSecurityPolicy(
+      network::mojom::ContentSecurityPolicyPtr policy);
+
   // Returns the delivered policies, as set so far by:
   //
   //  - |SetIPAddressSpace()| for |ip_address_space|
-  //  - |SetIsOriginPotentiallyTrustworthy()| and |FinalizePolicies()| for
+  //  - |SetIsOriginPotentiallyTrustworthy()| and |ComputePolicies()| for
   //    |is_web_secure_context|
   //
   // TODO(titouan): Consider exposing individual accessors instead, since the
@@ -102,9 +111,9 @@
   // Sets final policies to defaults suitable for error pages, and builds a
   // policy container host.
   //
-  // This method must only be called once, and is mutually exclusive with
-  // |FinalizePolicies()|.
-  void FinalizePoliciesForError();
+  // This method must only be called once. However it can be called after
+  // |ComputePolicies()|.
+  void ComputePoliciesForError();
 
   // Sets final policies to their correct values and builds a policy container
   // host.
@@ -114,56 +123,59 @@
   //
   // Also sets |DeliveredPolicies().is_web_secure_context| to its final value.
   //
-  // This method must only be called once, and is mutually exclusive with
-  // |FinalizePoliciesForError()|.
-  void FinalizePolicies(const GURL& url);
+  // This method must only be called once. |ComputePoliciesForError()| may be
+  // called later and this override the final policies.
+  void ComputePolicies(const GURL& url);
 
   // Returns a reference to the policies of the new document, i.e. the policies
   // in the policy container host to be committed.
   //
-  // This instance must be finalized.
+  // |ComputePolicies()| or |ComputePoliciesForError()| must have been called
+  // previously.
   const PolicyContainerPolicies& FinalPolicies() const;
 
   // Creates a PolicyContainer connected to this bundle's PolicyContainerHost.
   //
-  // Should only be called once. This instance must be finalized.
+  // Should only be called once. |ComputePolicies()| or
+  // |ComputePoliciesForError()| must have been called previously.
   blink::mojom::PolicyContainerPtr CreatePolicyContainerForBlink();
 
   // Moves the PolicyContainerHost out of this bundle. The returned host
   // contains the same policies as |FinalPolicies()|.
   //
-  // This instance must be finalized.
+  // |ComputePolicies()| or |ComputePoliciesForError()| must have been called
+  // previously.
   scoped_refptr<PolicyContainerHost> TakePolicyContainerHost() &&;
 
  private:
-  // Whether either of |FinalizePolicies()| or |FinalizePoliciesForError()| has
+  // Whether either of |ComputePolicies()| or |ComputePoliciesForError()| has
   // been called yet.
-  bool IsFinalized() const;
+  bool HasComputedPolicies() const;
 
   // Sets |delivered_policies_.is_web_secure_context| to its final value.
   //
-  // Helper for |FreezeFinalPolicies()|.
-  void FinalizeIsWebSecureContext();
+  // Helper for |ComputePolicies()|.
+  void ComputeIsWebSecureContext();
 
   // Sets |host_|.
   void SetFinalPolicies(std::unique_ptr<PolicyContainerPolicies> policies);
 
   // The policies of the parent document, if any.
-  std::unique_ptr<PolicyContainerPolicies> parent_policies_;
+  const std::unique_ptr<PolicyContainerPolicies> parent_policies_;
 
   // The policies of the document that initiated the navigation, if any.
-  std::unique_ptr<PolicyContainerPolicies> initiator_policies_;
+  const std::unique_ptr<PolicyContainerPolicies> initiator_policies_;
 
   // The policies restored from the history navigation entry, if any.
-  std::unique_ptr<PolicyContainerPolicies> history_policies_;
+  const std::unique_ptr<PolicyContainerPolicies> history_policies_;
 
   // The policies extracted from the response as it is loaded.
   //
   // See the comment on |SetIsOriginPotentiallyTrustworthy()| regarding this
   // member's |is_web_secure_context| field.
-  std::unique_ptr<PolicyContainerPolicies> delivered_policies_;
+  const std::unique_ptr<PolicyContainerPolicies> delivered_policies_;
 
-  // Nullptr until |FinalizePolicies()| or |FinalizePoliciesForError()| is
+  // Nullptr until |ComputePolicies()| or |ComputePoliciesForError()| is
   // called, then moved from by |TakePolicyContainerHost()|.
   scoped_refptr<PolicyContainerHost> host_;
 };
diff --git a/content/browser/renderer_host/policy_container_navigation_bundle_browsertest.cc b/content/browser/renderer_host/policy_container_navigation_bundle_browsertest.cc
index fbcccd0..d8034e14 100644
--- a/content/browser/renderer_host/policy_container_navigation_bundle_browsertest.cc
+++ b/content/browser/renderer_host/policy_container_navigation_bundle_browsertest.cc
@@ -142,7 +142,7 @@
   PolicyContainerNavigationBundle bundle(nullptr, nullptr, nullptr);
   bundle.SetIPAddressSpace(network::mojom::IPAddressSpace::kPublic);
 
-  bundle.FinalizePolicies(GURL());
+  bundle.ComputePolicies(GURL());
 
   // This must be called on a task runner, hence the need for this test to be
   // a browser test and not a simple unit test.
@@ -186,7 +186,7 @@
 
   std::unique_ptr<PolicyContainerPolicies> history_policies =
       bundle.HistoryPolicies()->Clone();
-  bundle.FinalizePolicies(AboutBlankUrl());
+  bundle.ComputePolicies(AboutBlankUrl());
 
   EXPECT_EQ(bundle.FinalPolicies(), *history_policies);
 }
@@ -225,7 +225,7 @@
 
   std::unique_ptr<PolicyContainerPolicies> history_policies =
       bundle.HistoryPolicies()->Clone();
-  bundle.FinalizePolicies(AboutSrcdocUrl());
+  bundle.ComputePolicies(AboutSrcdocUrl());
 
   EXPECT_EQ(bundle.FinalPolicies(), *history_policies);
 }
@@ -244,11 +244,36 @@
   PolicyContainerNavigationBundle bundle(
       nullptr, nullptr, GetLastCommittedFrameNavigationEntry());
 
-  bundle.FinalizePoliciesForError();
+  bundle.ComputePoliciesForError();
 
   // Error pages commit with default policies, ignoring the history policies.
   EXPECT_EQ(bundle.FinalPolicies(), PolicyContainerPolicies());
 }
 
+// After |ComputePolicies()| or |ComputePoliciesForError()|, the history
+// policies are still accessible.
+IN_PROC_BROWSER_TEST_F(PolicyContainerNavigationBundleBrowserTest,
+                       AccessHistoryAfterComputingPolicies) {
+  // First navigate to a local scheme with non-default policies. To do that, we
+  // first navigate to a document with a public address space, then have that
+  // document navigate itself to `about:blank`. The final blank document
+  // inherits its policies from the first document, and stores them in its
+  // frame navigation entry for restoring later.
+  EXPECT_TRUE(NavigateToURL(shell()->web_contents(), PublicUrl()));
+  EXPECT_TRUE(NavigateToURLFromRenderer(root_frame_host(), AboutBlankUrl()));
+
+  PolicyContainerNavigationBundle bundle(
+      nullptr, nullptr, GetLastCommittedFrameNavigationEntry());
+
+  std::unique_ptr<PolicyContainerPolicies> history_policies =
+      bundle.HistoryPolicies()->Clone();
+
+  bundle.ComputePolicies(AboutBlankUrl());
+  EXPECT_THAT(bundle.HistoryPolicies(), Pointee(Eq(ByRef(*history_policies))));
+
+  bundle.ComputePoliciesForError();
+  EXPECT_THAT(bundle.HistoryPolicies(), Pointee(Eq(ByRef(*history_policies))));
+}
+
 }  // namespace
 }  // namespace content
diff --git a/content/browser/renderer_host/policy_container_navigation_bundle_unittest.cc b/content/browser/renderer_host/policy_container_navigation_bundle_unittest.cc
index 7a86066..60886bf 100644
--- a/content/browser/renderer_host/policy_container_navigation_bundle_unittest.cc
+++ b/content/browser/renderer_host/policy_container_navigation_bundle_unittest.cc
@@ -9,6 +9,7 @@
 
 #include "base/files/file_path.h"
 #include "base/test/bind.h"
+#include "base/test/gtest_util.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/test/navigation_simulator.h"
 #include "content/test/test_render_view_host.h"
@@ -27,6 +28,7 @@
 using ::testing::IsNull;
 using ::testing::NotNull;
 using ::testing::Pointee;
+using ::testing::SizeIs;
 
 // Returns non-default policies for use in tests.
 std::unique_ptr<PolicyContainerPolicies> MakeTestPolicies() {
@@ -107,7 +109,7 @@
 // and are equal to the policies of the bundle's policy container host.
 TEST_F(PolicyContainerNavigationBundleTest, DefaultFinalPolicies) {
   PolicyContainerNavigationBundle bundle(nullptr, nullptr, nullptr);
-  bundle.FinalizePolicies(GURL());
+  bundle.ComputePolicies(GURL());
 
   PolicyContainerPolicies expected_policies;
   EXPECT_EQ(bundle.FinalPolicies(), expected_policies);
@@ -126,7 +128,7 @@
   bundle.SetIPAddressSpace(network::mojom::IPAddressSpace::kPublic);
   std::unique_ptr<PolicyContainerPolicies> delivered_policies =
       bundle.DeliveredPolicies().Clone();
-  bundle.FinalizePolicies(GURL("https://foo.test"));
+  bundle.ComputePolicies(GURL("https://foo.test"));
 
   EXPECT_EQ(bundle.FinalPolicies(), *delivered_policies);
 }
@@ -137,7 +139,7 @@
        FinalPoliciesAboutBlankWithoutInitiator) {
   PolicyContainerNavigationBundle bundle(nullptr, nullptr, nullptr);
   bundle.SetIPAddressSpace(network::mojom::IPAddressSpace::kPublic);
-  bundle.FinalizePolicies(AboutBlankUrl());
+  bundle.ComputePolicies(AboutBlankUrl());
 
   EXPECT_EQ(bundle.FinalPolicies(), PolicyContainerPolicies());
 }
@@ -146,7 +148,7 @@
 TEST_F(PolicyContainerNavigationBundleTest, DefaultFinalPoliciesForErrorPage) {
   PolicyContainerNavigationBundle bundle(nullptr, nullptr, nullptr);
 
-  bundle.FinalizePoliciesForError();
+  bundle.ComputePoliciesForError();
 
   // Error pages commit with default policies, mostly ignoring the delivered
   // policies and the document's URL.
@@ -159,13 +161,43 @@
   PolicyContainerNavigationBundle bundle(nullptr, nullptr, nullptr);
 
   bundle.SetIPAddressSpace(network::mojom::IPAddressSpace::kPublic);
-  bundle.FinalizePoliciesForError();
+  bundle.ComputePoliciesForError();
 
   PolicyContainerPolicies expected_policies;
   expected_policies.ip_address_space = network::mojom::IPAddressSpace::kPublic;
   EXPECT_EQ(bundle.FinalPolicies(), expected_policies);
 }
 
+// Variation of: PolicyContainerNavigationBundleTest.ErrorPageIPAddressSpace
+// The decision to commit an error happens after receiving the response.
+TEST_F(PolicyContainerNavigationBundleTest,
+       ErrorPageIPAddressSpaceAfterResponse) {
+  PolicyContainerNavigationBundle bundle(nullptr, nullptr, nullptr);
+
+  bundle.SetIPAddressSpace(network::mojom::IPAddressSpace::kPrivate);
+  PolicyContainerPolicies expected_policies;
+  expected_policies.ip_address_space = network::mojom::IPAddressSpace::kPrivate;
+
+  bundle.ComputePolicies(GURL("https://foo.test"));
+  EXPECT_EQ(bundle.FinalPolicies(), expected_policies);
+
+  bundle.ComputePoliciesForError();
+  EXPECT_EQ(bundle.FinalPolicies(), expected_policies);
+}
+
+// CSP delivered by the HTTP response are ignored for error document.
+TEST_F(PolicyContainerNavigationBundleTest,
+       DeliveredCSPIgnoredForErrorDocument) {
+  PolicyContainerNavigationBundle bundle(nullptr, nullptr, nullptr);
+  bundle.AddContentSecurityPolicy(network::mojom::ContentSecurityPolicy::New());
+
+  bundle.ComputePolicies(GURL("https://foo.test"));
+  EXPECT_THAT(bundle.FinalPolicies().content_security_policies, SizeIs(1));
+
+  bundle.ComputePoliciesForError();
+  EXPECT_THAT(bundle.FinalPolicies().content_security_policies, SizeIs(0));
+}
+
 // Verifies that InitiatorPolicies() returns nullptr in the absence of an
 // initiator frame token.
 TEST_F(PolicyContainerNavigationBundleTest, InitiatorPoliciesWithoutInitiator) {
@@ -209,7 +241,7 @@
   // Force implicit conversion from LocalFrameToken to UnguessableToken.
   const blink::LocalFrameToken& token = initiator->GetFrameToken();
   PolicyContainerNavigationBundle bundle(nullptr, &token, nullptr);
-  bundle.FinalizePolicies(AboutBlankUrl());
+  bundle.ComputePolicies(AboutBlankUrl());
 
   EXPECT_EQ(bundle.FinalPolicies(), *initiator_policies);
 }
@@ -244,7 +276,7 @@
   parent->SetPolicyContainerHost(NewHost(parent_policies->Clone()));
 
   PolicyContainerNavigationBundle bundle(parent, nullptr, nullptr);
-  bundle.FinalizePolicies(AboutSrcdocUrl());
+  bundle.ComputePolicies(AboutSrcdocUrl());
 
   EXPECT_EQ(bundle.FinalPolicies(), *parent_policies);
 }
@@ -261,7 +293,7 @@
       bundle.DeliveredPolicies().Clone();
   EXPECT_TRUE(delivered_policies->is_web_secure_context);
 
-  bundle.FinalizePolicies(GURL());
+  bundle.ComputePolicies(GURL());
 
   EXPECT_EQ(bundle.FinalPolicies(), *delivered_policies);
 }
@@ -278,7 +310,7 @@
       bundle.DeliveredPolicies().Clone();
   EXPECT_FALSE(delivered_policies->is_web_secure_context);
 
-  bundle.FinalizePolicies(GURL());
+  bundle.ComputePolicies(GURL());
 
   EXPECT_EQ(bundle.FinalPolicies(), *delivered_policies);
 }
@@ -297,7 +329,7 @@
 
   bundle.SetIsOriginPotentiallyTrustworthy(true);
 
-  bundle.FinalizePolicies(GURL("https://foo.test"));
+  bundle.ComputePolicies(GURL("https://foo.test"));
 
   EXPECT_FALSE(bundle.FinalPolicies().is_web_secure_context);
 }
@@ -320,7 +352,7 @@
       bundle.DeliveredPolicies().Clone();
   EXPECT_FALSE(delivered_policies->is_web_secure_context);
 
-  bundle.FinalizePolicies(GURL("http://foo.test"));
+  bundle.ComputePolicies(GURL("http://foo.test"));
 
   EXPECT_EQ(bundle.FinalPolicies(), *delivered_policies);
 }
@@ -343,10 +375,67 @@
       bundle.DeliveredPolicies().Clone();
   EXPECT_TRUE(delivered_policies->is_web_secure_context);
 
-  bundle.FinalizePolicies(GURL("https://foo.test"));
+  bundle.ComputePolicies(GURL("https://foo.test"));
 
   EXPECT_EQ(bundle.FinalPolicies(), *delivered_policies);
 }
 
+// Calling ComputePolicies() twice triggers a DCHECK.
+TEST_F(PolicyContainerNavigationBundleTest, ComputePoliciesTwiceDCHECK) {
+  PolicyContainerNavigationBundle bundle(nullptr, nullptr, nullptr);
+  GURL url("https://foo.test");
+  bundle.ComputePolicies(url);
+  EXPECT_DCHECK_DEATH(bundle.ComputePolicies(url));
+}
+
+// Calling ComputePolicies() followed by ComputePoliciesForError() is
+// supported.
+TEST_F(PolicyContainerNavigationBundleTest, ComputePoliciesThenError) {
+  PolicyContainerNavigationBundle bundle(nullptr, nullptr, nullptr);
+  bundle.ComputePolicies(GURL("https://foo.test"));
+  bundle.ComputePoliciesForError();
+}
+
+// After ComputePolicies() or ComputePoliciesForError(), the initiator
+// policies are still accessible.
+TEST_F(PolicyContainerNavigationBundleTest,
+       AccessInitiatorAfterComputingPolicies) {
+  std::unique_ptr<PolicyContainerPolicies> initiator_policies =
+      MakeTestPolicies();
+  TestRenderFrameHost* initiator = contents()->GetMainFrame();
+  initiator->SetPolicyContainerHost(NewHost(initiator_policies->Clone()));
+  const blink::LocalFrameToken& token = initiator->GetFrameToken();
+
+  PolicyContainerNavigationBundle bundle(nullptr, &token, nullptr);
+  EXPECT_THAT(bundle.InitiatorPolicies(),
+              Pointee(Eq(ByRef(*initiator_policies))));
+
+  bundle.ComputePolicies(GURL("https://foo.test"));
+  EXPECT_THAT(bundle.InitiatorPolicies(),
+              Pointee(Eq(ByRef(*initiator_policies))));
+
+  bundle.ComputePoliciesForError();
+  EXPECT_THAT(bundle.InitiatorPolicies(),
+              Pointee(Eq(ByRef(*initiator_policies))));
+}
+
+// After ComputePolicies() or ComputePoliciesForError(), the parent
+// policies are still accessible.
+TEST_F(PolicyContainerNavigationBundleTest,
+       AccessParentAfterComputingPolicies) {
+  std::unique_ptr<PolicyContainerPolicies> parent_policies = MakeTestPolicies();
+  TestRenderFrameHost* parent = contents()->GetMainFrame();
+  parent->SetPolicyContainerHost(NewHost(parent_policies->Clone()));
+
+  PolicyContainerNavigationBundle bundle(parent, nullptr, nullptr);
+  EXPECT_THAT(bundle.ParentPolicies(), Pointee(Eq(ByRef(*parent_policies))));
+
+  bundle.ComputePolicies(GURL("https://foo.test"));
+  EXPECT_THAT(bundle.ParentPolicies(), Pointee(Eq(ByRef(*parent_policies))));
+
+  bundle.ComputePoliciesForError();
+  EXPECT_THAT(bundle.ParentPolicies(), Pointee(Eq(ByRef(*parent_policies))));
+}
+
 }  // namespace
 }  // namespace content
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 8a2b656e..603500c 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -35,6 +35,7 @@
 #include "base/task/post_task.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
+#include "base/trace_event/base_tracing.h"
 #include "base/trace_event/optional_trace_event.h"
 #include "base/trace_event/trace_conversion_helper.h"
 #include "base/trace_event/traced_value.h"
@@ -834,6 +835,37 @@
   return true;
 }
 
+perfetto::protos::pbzero::FrameDeleteIntention FrameDeleteIntentionToProto(
+    mojom::FrameDeleteIntention intent) {
+  using ProtoLevel = perfetto::protos::pbzero::FrameDeleteIntention;
+  switch (intent) {
+    case mojom::FrameDeleteIntention::kNotMainFrame:
+      return ProtoLevel::FRAME_DELETE_INTENTION_NOT_MAIN_FRAME;
+    case mojom::FrameDeleteIntention::kSpeculativeMainFrameForShutdown:
+      return ProtoLevel::
+          FRAME_DELETE_INTENTION_SPECULATIVE_MAIN_FRAME_FOR_SHUTDOWN;
+    case mojom::FrameDeleteIntention::
+        kSpeculativeMainFrameForNavigationCancelled:
+      return ProtoLevel::
+          FRAME_DELETE_INTENTION_SPECULATIVE_MAIN_FRAME_FOR_NAVIGATION_CANCELLED;
+  }
+  // All cases should've been handled by the switch case above.
+  NOTREACHED();
+  return ProtoLevel::FRAME_DELETE_INTENTION_NOT_MAIN_FRAME;
+}
+
+void WriteRenderFrameImplDeletion(perfetto::EventContext& ctx,
+                                  RenderFrameHostImpl* rfh,
+                                  mojom::FrameDeleteIntention intent) {
+  auto* event = ctx.event<perfetto::protos::pbzero::ChromeTrackEvent>();
+  auto* data = event->set_render_frame_impl_deletion();
+  data->set_has_pending_commit(rfh->HasPendingCommitNavigation());
+  data->set_has_pending_cross_document_commit(
+      rfh->HasPendingCommitForCrossDocumentNavigation());
+  data->set_frame_tree_node_id(rfh->GetFrameTreeNodeId());
+  data->set_intent(FrameDeleteIntentionToProto(intent));
+}
+
 }  // namespace
 
 #if BUILDFLAG(ENABLE_PLUGINS)
@@ -2393,6 +2425,10 @@
 
 void RenderFrameHostImpl::DeleteRenderFrame(
     mojom::FrameDeleteIntention intent) {
+  TRACE_EVENT("navigation", "RenderFrameHostImpl::DeleteRenderFrame",
+              [&](perfetto::EventContext ctx) {
+                WriteRenderFrameImplDeletion(ctx, this, intent);
+              });
   if (IsPendingDeletion())
     return;
 
@@ -8690,9 +8726,6 @@
   // banned URLs into the navigation controller in the first place.
   process->FilterURL(false, &params->url);
   process->FilterURL(true, &params->referrer->url);
-  for (auto& redirect : params->redirects) {
-    process->FilterURL(false, &redirect);
-  }
 
   // Without this check, the renderer can trick the browser into using
   // filenames it can't access in a future session restore.
@@ -8825,12 +8858,25 @@
     // WebContentsObservers.
     DCHECK(is_initial_empty_commit || is_same_document_navigation);
 
+    // Fill the redirect chain for the NavigationRequest. Since this is only for
+    // initial empty commits or same-document navigation, we should just push
+    // the client-redirect URL (if it is a client redirect) and the final URL.
+    std::vector<GURL> redirects;
+    if (is_same_document_navigation &&
+        same_document_params->is_client_redirect) {
+      // If it is a same-document navigation, it might be a client redirect, in
+      // which case we should put the previous URL at the front of the redirect
+      // chain.
+      redirects.push_back(GetLastCommittedURL());
+    }
+    redirects.push_back(params->url);
+
     // TODO(https://crbug.com/1131832): Do not use |params| to get the values,
     // depend on values known at commit time instead.
     navigation_request = CreateNavigationRequestForCommit(
         params->url, params->origin, params->referrer.Clone(),
         params->transition, params->should_replace_current_entry,
-        params->gesture, params->redirects, params->url, params->page_state,
+        params->gesture, redirects, params->url, params->page_state,
         is_same_document_navigation,
         same_document_params &&
             same_document_params->is_history_api_navigation);
@@ -9985,7 +10031,7 @@
   SCOPED_CRASH_KEY_BOOL("VerifyDidCommit", "is_server_redirect",
                         request->WasServerRedirect());
   SCOPED_CRASH_KEY_NUMBER("VerifyDidCommit", "redirects_size",
-                          params.redirects.size());
+                          request->GetRedirectChain().size());
 
   SCOPED_CRASH_KEY_NUMBER("VerifyDidCommit", "entry_offset",
                           request->GetNavigationEntryOffset());
diff --git a/content/browser/renderer_host/render_frame_host_manager.cc b/content/browser/renderer_host/render_frame_host_manager.cc
index d2dc3f5..d3cc62fa 100644
--- a/content/browser/renderer_host/render_frame_host_manager.cc
+++ b/content/browser/renderer_host/render_frame_host_manager.cc
@@ -20,6 +20,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/notreached.h"
 #include "base/stl_util.h"
+#include "base/trace_event/base_tracing.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
 #include "content/browser/child_process_security_policy_impl.h"
@@ -198,6 +199,46 @@
             static_cast<size_t>(base::debug::CrashKeySize::Size256));
 }
 
+void WriteFrameTreeNodeInfo(perfetto::EventContext& ctx,
+                            FrameTreeNode* frame_tree_node) {
+  auto* event = ctx.event<perfetto::protos::pbzero::ChromeTrackEvent>();
+  auto* ftn_info = event->set_frame_tree_node_info();
+  ftn_info->set_is_main_frame(frame_tree_node->IsMainFrame());
+  ftn_info->set_frame_tree_node_id(frame_tree_node->frame_tree_node_id());
+  ftn_info->set_has_speculative_render_frame_host(
+      !!frame_tree_node->render_manager()->speculative_frame_host());
+}
+
+perfetto::protos::pbzero::ShouldSwapBrowsingInstance
+ShouldSwapBrowsingInstanceToProto(ShouldSwapBrowsingInstance result) {
+  using ProtoLevel = perfetto::protos::pbzero::ShouldSwapBrowsingInstance;
+  switch (result) {
+    case ShouldSwapBrowsingInstance::kYes_ForceSwap:
+      return ProtoLevel::SHOULD_SWAP_BROWSING_INSTANCE_YES_FORCE_SWAP;
+    case ShouldSwapBrowsingInstance::kYes_CrossSiteProactiveSwap:
+      return ProtoLevel::
+          SHOULD_SWAP_BROWSING_INSTANCE_YES_CROSS_SITE_PROACTIVE_SWAP;
+    case ShouldSwapBrowsingInstance::kYes_SameSiteProactiveSwap:
+      return ProtoLevel::
+          SHOULD_SWAP_BROWSING_INSTANCE_YES_SAME_SITE_PROACTIVE_SWAP;
+    default:
+      return ProtoLevel::SHOULD_SWAP_BROWSING_INSTANCE_NO;
+  }
+}
+
+void TraceShouldSwapBrowsingInstanceResult(int frame_tree_node_id,
+                                           ShouldSwapBrowsingInstance result) {
+  TRACE_EVENT_INSTANT(
+      "navigation",
+      "RenderFrameHostManager::GetSiteInstanceForNavigation_ShouldSwapResult",
+      [&](perfetto::EventContext ctx) {
+        auto* event = ctx.event<perfetto::protos::pbzero::ChromeTrackEvent>();
+        auto* data = event->set_should_swap_browsing_instances_result();
+        data->set_frame_tree_node_id(frame_tree_node_id);
+        data->set_result(ShouldSwapBrowsingInstanceToProto(result));
+      });
+}
+
 }  // namespace
 
 RenderFrameHostManager::RenderFrameHostManager(FrameTreeNode* frame_tree_node,
@@ -639,8 +680,11 @@
 
 void RenderFrameHostManager::RestoreFromBackForwardCache(
     std::unique_ptr<BackForwardCacheImpl::Entry> entry) {
-  TRACE_EVENT0("navigation",
-               "RenderFrameHostManager::RestoreFromBackForwardCache");
+  TRACE_EVENT("navigation",
+              "RenderFrameHostManager::RestoreFromBackForwardCache",
+              [&](perfetto::EventContext ctx) {
+                WriteFrameTreeNodeInfo(ctx, frame_tree_node_);
+              });
   // Matched in CommitPending().
   entry->render_frame_host->GetProcess()->AddPendingView();
 
@@ -685,6 +729,11 @@
 
 void RenderFrameHostManager::DidCreateNavigationRequest(
     NavigationRequest* request) {
+  TRACE_EVENT("navigation",
+              "RenderFrameHostManager::DidCreateNavigationRequest",
+              [&](perfetto::EventContext ctx) {
+                WriteFrameTreeNodeInfo(ctx, frame_tree_node_);
+              });
   const bool force_use_current_render_frame_host =
       // Since the frame from the back-forward cache is being committed to the
       // SiteInstance we already have, it is treated as current.
@@ -731,6 +780,11 @@
 RenderFrameHostImpl* RenderFrameHostManager::GetFrameHostForNavigation(
     NavigationRequest* request,
     std::string* reason) {
+  TRACE_EVENT("navigation", "RenderFrameHostManager::GetFrameHostForNavigation",
+              [&](perfetto::EventContext ctx) {
+                WriteFrameTreeNodeInfo(ctx, frame_tree_node_);
+              });
+
   DCHECK(!request->common_params().url.SchemeIs(url::kJavaScriptScheme))
       << "Don't call this method for JavaScript URLs as those create a "
          "temporary  NavigationRequest and we don't want to reset an ongoing "
@@ -1035,6 +1089,10 @@
 }
 
 void RenderFrameHostManager::CleanUpNavigation() {
+  TRACE_EVENT("navigation", "RenderFrameHostManager::CleanUpNavigation",
+              [&](perfetto::EventContext ctx) {
+                WriteFrameTreeNodeInfo(ctx, frame_tree_node_);
+              });
   if (speculative_render_frame_host_) {
     bool was_loading = speculative_render_frame_host_->is_loading();
     DiscardUnusedFrame(UnsetSpeculativeRenderFrameHost());
@@ -1055,6 +1113,11 @@
 
 std::unique_ptr<RenderFrameHostImpl>
 RenderFrameHostManager::UnsetSpeculativeRenderFrameHost() {
+  TRACE_EVENT("navigation",
+              "RenderFrameHostManager::UnsetSpeculativeRenderFrameHost",
+              [&](perfetto::EventContext ctx) {
+                WriteFrameTreeNodeInfo(ctx, frame_tree_node_);
+              });
   speculative_render_frame_host_->GetProcess()->RemovePendingView();
   speculative_render_frame_host_->DeleteRenderFrame(
       frame_tree_node_->parent()
@@ -1655,6 +1718,10 @@
           is_failure, is_reload, is_same_document,
           cross_origin_opener_policy_mismatch, was_server_redirect,
           should_replace_current_entry, is_speculative);
+
+  TraceShouldSwapBrowsingInstanceResult(frame_tree_node_->frame_tree_node_id(),
+                                        should_swap_result);
+
   bool proactive_swap =
       (should_swap_result ==
            ShouldSwapBrowsingInstance::kYes_CrossSiteProactiveSwap ||
@@ -2480,6 +2547,12 @@
 RenderFrameHostManager::CreateSpeculativeRenderFrame(
     SiteInstance* instance,
     bool recovering_without_early_commit) {
+  TRACE_EVENT("navigation",
+              "RenderFrameHostManager::CreateSpeculativeRenderFrame",
+              [&](perfetto::EventContext ctx) {
+                WriteFrameTreeNodeInfo(ctx, frame_tree_node_);
+              });
+
   CHECK(instance);
   // This DCHECK is going to be fully removed as part of RenderDocument [1].
   //
@@ -3468,6 +3541,12 @@
 }
 
 void RenderFrameHostManager::CreateNewFrameForInnerDelegateAttachIfNecessary() {
+  TRACE_EVENT(
+      "navigation",
+      "RenderFrameHostManager::CreateNewFrameForInnerDelegateAttachIfNecessary",
+      [&](perfetto::EventContext ctx) {
+        WriteFrameTreeNodeInfo(ctx, frame_tree_node_);
+      });
   DCHECK(is_attaching_inner_delegate());
   // Remove all navigations and any speculative frames which might interfere
   // with the loading state.
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 61ba3df6..bd4c5f7 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -4845,11 +4845,7 @@
   // The proxy in the parent process should also receive the updated name.
   // Now iframe's name and the content window's name differ, so it shouldn't
   // be possible to access to the content window with the updated name.
-  //
-  // TODO(yukishiino): The following expectation should be |true|, but we're
-  // intentionally disabling the name and origin check of the named access on
-  // window.  See also crbug.com/538562 and crbug.com/701489.
-  EXPECT_EQ(false, EvalJs(shell(), "frames['updated-name'] === undefined;"));
+  EXPECT_EQ(true, EvalJs(shell(), "frames['updated-name'] === undefined;"));
   // Change iframe's name to match the content window's name so that it can
   // reference the child frame by its new name in case of cross origin.
   EXPECT_TRUE(ExecuteScript(root, "window['3-1-id'].name = 'updated-name';"));
diff --git a/content/browser/site_per_process_unload_browsertest.cc b/content/browser/site_per_process_unload_browsertest.cc
index 606554c0..e2f0a5c 100644
--- a/content/browser/site_per_process_unload_browsertest.cc
+++ b/content/browser/site_per_process_unload_browsertest.cc
@@ -1036,11 +1036,14 @@
   ASSERT_TRUE(ExecJs(node3, "window.name = 'node3'"));
   ASSERT_TRUE(ExecJs(node4, "window.name = 'node4'"));
 
+  ASSERT_TRUE(ExecJs(node1, "window.node2 = window[0]"));
+  ASSERT_TRUE(ExecJs(node1, "window.node3 = window[0][0]"));
+  ASSERT_TRUE(ExecJs(node1, "window.node4 = window[1]"));
+
   // Test sanity check.
-  EXPECT_EQ(true, EvalJs(node1, "!!top.node2.node3"));
-  EXPECT_EQ(true, EvalJs(node2, "!!top.node2.node3"));
-  EXPECT_EQ(true, EvalJs(node3, "!!top.node2.node3"));
-  EXPECT_EQ(true, EvalJs(node4, "!!top.node2.node3"));
+  EXPECT_EQ(true, EvalJs(node1, "!!window.node2"));
+  EXPECT_EQ(true, EvalJs(node1, "!!window.node3"));
+  EXPECT_EQ(true, EvalJs(node1, "!!window.node4"));
 
   // Simulate a long-running unload handler in |node3|.
   node3->DoNotDeleteForTesting();
@@ -1057,7 +1060,7 @@
 
           var can_node3_be_found = false;
           try {
-            can_node3_be_found = !!top.node2.node3;
+            can_node3_be_found = !!top[0][0];  // top.node2.node3
           } catch(e) {
             can_node3_be_found = false;
           }
@@ -1078,7 +1081,7 @@
       var node2_frame = document.getElementsByTagName('iframe')[0];
       node2_frame.onload = function() {
           console.log('node2_frame.onload ...');
-          node4.postMessage('try to find node3', '*');
+          window.node4.postMessage('try to find node3', '*');
       };
       node2_frame.src = $1;
   )";
@@ -1127,11 +1130,14 @@
   ASSERT_TRUE(ExecJs(node3, "window.name = 'node3'"));
   ASSERT_TRUE(ExecJs(node4, "window.name = 'node4'"));
 
+  ASSERT_TRUE(ExecJs(node1, "window.node2 = window[0]"));
+  ASSERT_TRUE(ExecJs(node1, "window.node3 = window[0][0]"));
+  ASSERT_TRUE(ExecJs(node1, "window.node4 = window[1]"));
+
   // Test sanity check.
-  EXPECT_EQ(true, EvalJs(node1, "!!top.node2.node3"));
-  EXPECT_EQ(true, EvalJs(node2, "!!top.node2.node3"));
-  EXPECT_EQ(true, EvalJs(node3, "!!top.node2.node3"));
-  EXPECT_EQ(true, EvalJs(node4, "!!top.node2.node3"));
+  EXPECT_EQ(true, EvalJs(node1, "!!window.node2"));
+  EXPECT_EQ(true, EvalJs(node1, "!!window.node3"));
+  EXPECT_EQ(true, EvalJs(node1, "!!window.node4"));
 
   // Add a long-running unload handler to |node3|.
   node3->DoNotDeleteForTesting();
@@ -1148,7 +1154,7 @@
 
           var can_node3_be_found = false;
           try {
-            can_node3_be_found = !!top.node2.node3;
+            can_node3_be_found = !!top[0][0];  // top.node2.node3
           } catch(e) {
             can_node3_be_found = false;
           }
@@ -1169,7 +1175,7 @@
       var node2_frame = document.getElementsByTagName('iframe')[0];
       node2_frame.onload = function() {
           console.log('node2_frame.onload ...');
-          node4.postMessage('try to find node3', '*');
+          window.node4.postMessage('try to find node3', '*');
       };
       node2_frame.src = $1;
   )";
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index aa4ae9d..ffabd70 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -2378,6 +2378,15 @@
   GetDelegate()->WebContentsBecamePortal(predecessor_web_contents);
 }
 
+void WebContentsImpl::NotifyPrerenderingPageActivated() {
+  OPTIONAL_TRACE_EVENT0("content",
+                        "WebContentsImpl::NotifyPrerenderingPageActivated");
+  ExecutePageBroadcastMethod(base::BindRepeating([](RenderViewHostImpl* rvh) {
+    if (auto& broadcast = rvh->GetAssociatedPageBroadcast())
+      broadcast->ActivatePrerender();
+  }));
+}
+
 void WebContentsImpl::NotifyInsidePortal(bool inside_portal) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::NotifyInsidePortal",
                         "inside_portal", inside_portal);
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index ff48d4c..91c7bb1 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -1206,6 +1206,10 @@
   void DidActivatePortal(WebContentsImpl* predecessor_web_contents,
                          base::TimeTicks activation_time);
 
+  // Sends a page message to notify every process in the frame tree if the
+  // prerendering page is activated.
+  void NotifyPrerenderingPageActivated();
+
   // Notifies observers that AppCache was accessed. Public so AppCache code can
   // call this directly.
   void OnAppCacheAccessed(const GURL& manifest_url, bool blocked_by_policy);
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc
index 239f82f..0f39c20 100644
--- a/content/browser/web_contents/web_contents_impl_unittest.cc
+++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -268,7 +268,6 @@
   params->origin = url::Origin::Create(params->url);
   params->referrer = blink::mojom::Referrer::New();
   params->transition = ui::PAGE_TRANSITION_TYPED;
-  params->redirects = std::vector<GURL>();
   params->should_update_history = false;
   params->did_create_new_entry = true;
   params->gesture = NavigationGestureUser;
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index 07c6941..5a2f2c7 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -186,6 +186,7 @@
     "//build:chromeos_buildflags",
     "//build/util:webkit_version",
     "//components/discardable_memory/common",
+    "//components/power_scheduler",
     "//components/services/filesystem/public/mojom",
     "//components/tracing:startup_tracing",
     "//content:content_resources",
diff --git a/content/common/navigation_client.mojom b/content/common/navigation_client.mojom
index cd7a4cf..45b889f3 100644
--- a/content/common/navigation_client.mojom
+++ b/content/common/navigation_client.mojom
@@ -72,12 +72,6 @@
   // [Native] enums are by default initialized to 0 (i.e. PAGE_TRANSITION_LINK)
   PageTransition transition;
 
-  // Lists the redirects that occurred on the way to the current page. This
-  // vector has the same format as reported by the WebDataSource in the glue,
-  // with the current page being the last one in the list (so even when
-  // there's no redirect, there will be one entry in the list.
-  array<url.mojom.Url> redirects;
-
   // Set to false if we want to update the session history but not update
   // the browser history.  E.g., on unreachable urls.
   bool should_update_history = false;
@@ -188,6 +182,10 @@
   // TODO(crbug.com/1131832): Port SameDocumentNavigationSource enum to mojo
   // and use that instead of bool here.
   bool is_history_api_navigation = false;
+
+  // Whether the navigation is a result of a client redirect (e.g. a
+  // script-initiated navigation) or not (e.g. a link click).
+  bool is_client_redirect = false;
 };
 
 interface NavigationClient {
diff --git a/content/common/process_visibility_tracker.cc b/content/common/process_visibility_tracker.cc
index 912448d..5d9d95dd 100644
--- a/content/common/process_visibility_tracker.cc
+++ b/content/common/process_visibility_tracker.cc
@@ -4,6 +4,8 @@
 
 #include "content/common/process_visibility_tracker.h"
 
+#include "components/power_scheduler/power_mode_arbiter.h"
+
 namespace content {
 
 // static
@@ -12,7 +14,10 @@
   return instance.get();
 }
 
-ProcessVisibilityTracker::ProcessVisibilityTracker() = default;
+ProcessVisibilityTracker::ProcessVisibilityTracker()
+    : power_mode_visibility_voter_(
+          power_scheduler::PowerModeArbiter::GetInstance()->NewVoter(
+              "PowerModeVoter.Visibility")) {}
 
 ProcessVisibilityTracker::~ProcessVisibilityTracker() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(main_thread_);
@@ -41,6 +46,10 @@
 
   is_visible_ = visible;
 
+  power_mode_visibility_voter_->VoteFor(
+      *is_visible_ ? power_scheduler::PowerMode::kIdle
+                   : power_scheduler::PowerMode::kBackground);
+
   for (ProcessVisibilityObserver& observer : observers_)
     observer.OnVisibilityChanged(*is_visible_);
 }
diff --git a/content/common/process_visibility_tracker.h b/content/common/process_visibility_tracker.h
index 4b65139..808069a 100644
--- a/content/common/process_visibility_tracker.h
+++ b/content/common/process_visibility_tracker.h
@@ -9,6 +9,7 @@
 #include "base/observer_list.h"
 #include "base/optional.h"
 #include "base/sequence_checker.h"
+#include "components/power_scheduler/power_mode_voter.h"
 #include "content/common/content_export.h"
 
 namespace content {
@@ -43,6 +44,7 @@
 
   base::Optional<bool> is_visible_;
   base::ObserverList<ProcessVisibilityObserver> observers_;
+  std::unique_ptr<power_scheduler::PowerModeVoter> power_mode_visibility_voter_;
   SEQUENCE_CHECKER(main_thread_);
 };
 
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index 8fd655e..b9cab15 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -9,7 +9,7 @@
 // declarations instead of including more headers. If that is infeasible, adjust
 // the limit. For more info, see
 // https://chromium.googlesource.com/chromium/src/+/HEAD/docs/wmax_tokens.md
-#pragma clang max_tokens_here 851000
+#pragma clang max_tokens_here 852000
 
 #include <utility>
 
diff --git a/content/public/test/fake_speech_recognition_manager.cc b/content/public/test/fake_speech_recognition_manager.cc
index 9b301d3..6add640 100644
--- a/content/public/test/fake_speech_recognition_manager.cc
+++ b/content/public/test/fake_speech_recognition_manager.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/location.h"
+#include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
@@ -44,9 +45,35 @@
 
 void FakeSpeechRecognitionManager::WaitForRecognitionStarted() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  scoped_refptr<MessageLoopRunner> runner = new MessageLoopRunner;
-  recognition_started_closure_ = runner->QuitClosure();
-  runner->Run();
+  base::RunLoop runner;
+  recognition_started_closure_ = runner.QuitClosure();
+  runner.Run();
+}
+
+void FakeSpeechRecognitionManager::WaitForRecognitionEnded() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  // Take no action if recognition is not currently running.
+  if (session_id_ == 0)
+    return;
+  base::RunLoop runner;
+  recognition_ended_closure_ = runner.QuitClosure();
+  runner.Run();
+}
+
+void FakeSpeechRecognitionManager::OnRecognitionStarted() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  // Complete the closure on the UI thread instead of the IO thread to avoid
+  // threading issues.
+  if (recognition_started_closure_)
+    std::move(recognition_started_closure_).Run();
+}
+
+void FakeSpeechRecognitionManager::OnRecognitionEnded() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  // Complete the closure on the UI thread instead of the IO thread to avoid
+  // threading issues.
+  if (recognition_ended_closure_)
+    std::move(recognition_ended_closure_).Run();
 }
 
 void FakeSpeechRecognitionManager::SetFakeResult(const std::string& value) {
@@ -56,6 +83,7 @@
 int FakeSpeechRecognitionManager::CreateSession(
     const SpeechRecognitionSessionConfig& config) {
   VLOG(1) << "FAKE CreateSession invoked.";
+  // FakeSpeechRecognitionManager only allows one active session at a time.
   EXPECT_EQ(0, session_id_);
   EXPECT_EQ(nullptr, listener_);
   listener_ = config.event_listener.get();
@@ -72,6 +100,8 @@
   EXPECT_EQ(session_id, session_id_);
   EXPECT_TRUE(listener_ != nullptr);
 
+  listener_->OnRecognitionStart(session_id_);
+  // Delegate can get a copy of events.
   if (delegate_)
     delegate_->GetEventListener()->OnRecognitionStart(session_id_);
 
@@ -88,15 +118,22 @@
             // pointer below as required by the real code.
             base::Unretained(this)));
   }
-  if (!recognition_started_closure_.is_null()) {
-    GetUIThreadTaskRunner({})->PostTask(
-        FROM_HERE, std::move(recognition_started_closure_));
-  }
+  GetUIThreadTaskRunner({})->PostTask(
+      FROM_HERE,
+      base::BindOnce(&FakeSpeechRecognitionManager::OnRecognitionStarted,
+                     base::Unretained(this)));
 }
 
 void FakeSpeechRecognitionManager::AbortSession(int session_id) {
   VLOG(1) << "FAKE AbortSession invoked.";
   EXPECT_EQ(session_id_, session_id);
+  // The real SpeechRecognitionManagerImpl::Abort call chain eventually calls to
+  // OnRecognitionEnd from SpeechRecognizerImpl::Abort.
+  listener_->OnRecognitionEnd(session_id_);
+  GetUIThreadTaskRunner({})->PostTask(
+      FROM_HERE,
+      base::BindOnce(&FakeSpeechRecognitionManager::OnRecognitionEnded,
+                     base::Unretained(this)));
   session_id_ = 0;
   listener_ = nullptr;
 }
@@ -132,17 +169,28 @@
 void FakeSpeechRecognitionManager::SetFakeRecognitionResult() {
   if (!session_id_)  // Do a check in case we were cancelled..
     return;
-
   VLOG(1) << "Setting fake recognition result.";
+  listener_->OnAudioStart(session_id_);
+  listener_->OnSoundStart(session_id_);
   listener_->OnAudioEnd(session_id_);
   blink::mojom::SpeechRecognitionResultPtr result =
       blink::mojom::SpeechRecognitionResult::New();
   result->hypotheses.push_back(blink::mojom::SpeechRecognitionHypothesis::New(
-      base::ASCIIToUTF16(kTestResult), 1.0));
+      base::ASCIIToUTF16(fake_result_), 1.0));
   std::vector<blink::mojom::SpeechRecognitionResultPtr> results;
   results.push_back(std::move(result));
   listener_->OnRecognitionResults(session_id_, results);
-  listener_->OnRecognitionEnd(session_id_);
+  // End recognition. Note that in normal SpeechRecognitionManager, a session
+  // is not ended after the final result is sent. This behavior is just
+  // to make testing easier.
+  // Check if the listener has destructed itself after a final result.
+  if (listener_) {
+    listener_->OnRecognitionEnd(session_id_);
+    GetUIThreadTaskRunner({})->PostTask(
+        FROM_HERE,
+        base::BindOnce(&FakeSpeechRecognitionManager::OnRecognitionEnded,
+                       base::Unretained(this)));
+  }
   session_id_ = 0;
   listener_ = nullptr;
   VLOG(1) << "Finished setting fake recognition result.";
diff --git a/content/public/test/fake_speech_recognition_manager.h b/content/public/test/fake_speech_recognition_manager.h
index 5a424c2..9e628fbfa 100644
--- a/content/public/test/fake_speech_recognition_manager.h
+++ b/content/public/test/fake_speech_recognition_manager.h
@@ -43,6 +43,9 @@
   }
 
   void WaitForRecognitionStarted();
+  void WaitForRecognitionEnded();
+  void OnRecognitionStarted();
+  void OnRecognitionEnded();
 
   void SetFakeResult(const std::string& result);
 
@@ -90,6 +93,7 @@
   bool did_cancel_all_;
   bool should_send_fake_response_;
   base::OnceClosure recognition_started_closure_;
+  base::OnceClosure recognition_ended_closure_;
   SpeechRecognitionManagerDelegate* delegate_;  // Not owned.
 
   DISALLOW_COPY_AND_ASSIGN(FakeSpeechRecognitionManager);
diff --git a/content/public/test/render_view_test.cc b/content/public/test/render_view_test.cc
index daf3ef4..70c14e3 100644
--- a/content/public/test/render_view_test.cc
+++ b/content/public/test/render_view_test.cc
@@ -835,7 +835,8 @@
   view->GetMainRenderFrame()->DidFinishSameDocumentNavigation(
       is_new_navigation ? blink::kWebStandardCommit
                         : blink::kWebHistoryInertCommit,
-      false /* content_initiated */, false /* is_history_api_navigation */);
+      false /* content_initiated */, false /* is_history_api_navigation */,
+      false /* is_client_redirect */);
 }
 
 void RenderViewTest::SetUseZoomForDSFEnabled(bool enabled) {
diff --git a/content/renderer/browser_exposed_renderer_interfaces.cc b/content/renderer/browser_exposed_renderer_interfaces.cc
index 578d161f..dec111f 100644
--- a/content/renderer/browser_exposed_renderer_interfaces.cc
+++ b/content/renderer/browser_exposed_renderer_interfaces.cc
@@ -172,6 +172,10 @@
       base::ThreadPool::CreateSingleThreadTaskRunner(
           {base::MayBlock(), base::TaskPriority::USER_BLOCKING,
            base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
+  // TODO(crbug.com/1186912): Bind on `task_runner_for_service_worker_startup`
+  // instead of the main thread, so startup isn't blocked on the main thread.
+  // Currently it's on the main thread as CreateEmbeddedWorker accesses
+  // `cors_exempt_header_list` from `render_thread`.
   binders->Add(base::BindRepeating(&CreateEmbeddedWorker,
                                    task_runner_for_service_worker_startup,
                                    render_thread),
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 7987935..7763c6a 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -46,6 +46,7 @@
 #include "base/task_runner_util.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
+#include "base/trace_event/base_tracing.h"
 #include "base/trace_event/trace_event.h"
 #include "base/unguessable_token.h"
 #include "build/build_config.h"
@@ -1134,6 +1135,25 @@
       ->unique_name();
 }
 
+perfetto::protos::pbzero::FrameDeleteIntention FrameDeleteIntentionToProto(
+    mojom::FrameDeleteIntention intent) {
+  using ProtoLevel = perfetto::protos::pbzero::FrameDeleteIntention;
+  switch (intent) {
+    case mojom::FrameDeleteIntention::kNotMainFrame:
+      return ProtoLevel::FRAME_DELETE_INTENTION_NOT_MAIN_FRAME;
+    case mojom::FrameDeleteIntention::kSpeculativeMainFrameForShutdown:
+      return ProtoLevel::
+          FRAME_DELETE_INTENTION_SPECULATIVE_MAIN_FRAME_FOR_SHUTDOWN;
+    case mojom::FrameDeleteIntention::
+        kSpeculativeMainFrameForNavigationCancelled:
+      return ProtoLevel::
+          FRAME_DELETE_INTENTION_SPECULATIVE_MAIN_FRAME_FOR_NAVIGATION_CANCELLED;
+  }
+  // All cases should've been handled by the switch case above.
+  NOTREACHED();
+  return ProtoLevel::FRAME_DELETE_INTENTION_NOT_MAIN_FRAME;
+}
+
 }  // namespace
 
 RenderFrameImpl::AssertNavigationCommits::AssertNavigationCommits(
@@ -2330,6 +2350,12 @@
 }
 
 void RenderFrameImpl::Delete(mojom::FrameDeleteIntention intent) {
+  TRACE_EVENT(
+      "navigation", "RenderFrameImpl::Delete", [&](perfetto::EventContext ctx) {
+        auto* event = ctx.event<perfetto::protos::pbzero::ChromeTrackEvent>();
+        auto* data = event->set_render_frame_impl_deletion();
+        data->set_intent(FrameDeleteIntentionToProto(intent));
+      });
   // The main frame (when not provisional) is owned by the renderer's frame tree
   // via WebViewImpl. When a provisional main frame is swapped in, the ownership
   // moves from the browser to the renderer, but this happens in the renderer
@@ -4234,7 +4260,8 @@
 void RenderFrameImpl::DidFinishSameDocumentNavigation(
     blink::WebHistoryCommitType commit_type,
     bool content_initiated,
-    bool is_history_api_navigation) {
+    bool is_history_api_navigation,
+    bool is_client_redirect) {
   TRACE_EVENT1("navigation,rail",
                "RenderFrameImpl::didFinishSameDocumentNavigation", "id",
                routing_id_);
@@ -4250,6 +4277,7 @@
   auto same_document_params =
       mojom::DidCommitSameDocumentNavigationParams::New();
   same_document_params->is_history_api_navigation = is_history_api_navigation;
+  same_document_params->is_client_redirect = is_client_redirect;
   DidCommitNavigationInternal(
       commit_type, transition, network::mojom::WebSandboxFlags(),
       blink::ParsedPermissionsPolicy(),     // permissions_policy_header
@@ -4786,8 +4814,6 @@
   if (GURL(frame_document.BaseURL()) != params->url)
     params->base_url = frame_document.BaseURL();
 
-  GetRedirectChain(document_loader, &params->redirects);
-
   // TODO(https://crbug.com/1158101): Reconsider how we calculate
   // should_update_history.
   params->should_update_history =
@@ -4814,8 +4840,13 @@
   // If the page contained a client redirect (meta refresh, document.loc...),
   // set the referrer appropriately.
   if (document_loader->IsClientRedirect()) {
+    // TODO(https://crbug.com/1131832): Remove referrer from
+    // DidCommitProvisionalLoadParams, which also removes the need to save the
+    // redirect chain in the renderer.
+    std::vector<GURL> redirects;
+    GetRedirectChain(document_loader, &redirects);
     params->referrer = blink::mojom::Referrer::New(
-        params->redirects[0], document_loader->GetReferrerPolicy());
+        redirects[0], document_loader->GetReferrerPolicy());
   } else {
     params->referrer = blink::mojom::Referrer::New(
         blink::WebStringToGURL(document_loader->Referrer()),
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 2fe47082..6190d201 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -562,7 +562,8 @@
   void DidFinishLoad() override;
   void DidFinishSameDocumentNavigation(blink::WebHistoryCommitType commit_type,
                                        bool content_initiated,
-                                       bool is_history_api_navigation) override;
+                                       bool is_history_api_navigation,
+                                       bool is_client_redirect) override;
   void DidSetPageLifecycleState() override;
   void DidUpdateCurrentHistoryItem() override;
   base::UnguessableToken GetDevToolsFrameToken() override;
diff --git a/content/renderer/service_worker/embedded_worker_instance_client_impl.h b/content/renderer/service_worker/embedded_worker_instance_client_impl.h
index 085104e8..1b8312d9 100644
--- a/content/renderer/service_worker/embedded_worker_instance_client_impl.h
+++ b/content/renderer/service_worker/embedded_worker_instance_client_impl.h
@@ -26,9 +26,7 @@
 // the Mojo connection to the browser breaks first, the instance waits for the
 // service worker to stop and then deletes itself.
 //
-// All methods are called on the thread that creates the instance of this class.
-// Currently it's the main thread but it could be a background thread in the
-// future. https://crbug.com/692909
+// Created and lives on a ThreadPool background thread.
 class CONTENT_EXPORT EmbeddedWorkerInstanceClientImpl
     : public blink::mojom::EmbeddedWorkerInstanceClient {
  public:
diff --git a/content/test/data/accessibility/event/aria-hidden-single-descendant-display-none-expected-uia-win.txt b/content/test/data/accessibility/event/aria-hidden-single-descendant-display-none-expected-uia-win.txt
index 8b13789..6838414 100644
--- a/content/test/data/accessibility/event/aria-hidden-single-descendant-display-none-expected-uia-win.txt
+++ b/content/test/data/accessibility/event/aria-hidden-single-descendant-display-none-expected-uia-win.txt
@@ -1 +1 @@
-
+=== Start Continuation ===
diff --git a/content/test/data/accessibility/event/aria-hidden-single-descendant-display-none-expected-win.txt b/content/test/data/accessibility/event/aria-hidden-single-descendant-display-none-expected-win.txt
index 8b13789..6838414 100644
--- a/content/test/data/accessibility/event/aria-hidden-single-descendant-display-none-expected-win.txt
+++ b/content/test/data/accessibility/event/aria-hidden-single-descendant-display-none-expected-win.txt
@@ -1 +1 @@
-
+=== Start Continuation ===
diff --git a/content/test/data/accessibility/event/aria-hidden-single-descendant-display-none.html b/content/test/data/accessibility/event/aria-hidden-single-descendant-display-none.html
index 06f21ca..5cffb9d 100644
--- a/content/test/data/accessibility/event/aria-hidden-single-descendant-display-none.html
+++ b/content/test/data/accessibility/event/aria-hidden-single-descendant-display-none.html
@@ -15,10 +15,17 @@
     </div>
   </div>
   <script>
+    var current_pass = 0;
+    var test_cases = document.querySelectorAll('.test-case[aria-hidden]');
+
+    function run_test_case(element) {
+      let hidden = element.getAttribute('aria-hidden') == 'true';
+      element.setAttribute('aria-hidden', !hidden);
+    }
+
     function go() {
-      document.querySelectorAll('.test-case[aria-hidden]').forEach((element) => {
-        let hidden = element.getAttribute('aria-hidden') == 'true';
-        element.setAttribute('aria-hidden', !hidden);
+      run_test_case(test_cases.item(current_pass++));
+      return current_pass < test_cases.length;
     }
   </script>
 </body>
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
index 76847e3..0d50b03 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
@@ -210,7 +210,7 @@
 # Intel flaky issues
 crbug.com/1122744 [ win angle-d3d11 intel ] conformance/textures/misc/texparameter-test.html [ RetryOnFailure ]
 crbug.com/912579 [ angle-opengl win passthrough intel ] conformance2/rendering/out-of-bounds-index-buffers-after-copying.html [ RetryOnFailure ]
-crbug.com/1114780 [ win intel ] deqp/functional/gles3/multisample.html [ RetryOnFailure ]
+crbug.com/1114780 [ win intel ] deqp/functional/gles3/multisample.html [ Skip ]
 crbug.com/1127867 [ win angle-d3d11 intel ] conformance2/textures/image_data/tex-3d-r16f-red-half_float.html [ RetryOnFailure ]
 # Flakily times out on driver 26.20.100.8141.
 crbug.com/1093482 [ win10 intel-0x3e92 ] deqp/functional/gles3/shadermatrix/div_dynamic.html [ RetryOnFailure ]
diff --git a/content/test/navigation_simulator_impl.cc b/content/test/navigation_simulator_impl.cc
index b8b9bc3..4d45508 100644
--- a/content/test/navigation_simulator_impl.cc
+++ b/content/test/navigation_simulator_impl.cc
@@ -1329,7 +1329,6 @@
     // Note: Error pages must commit in a unique origin. So it is left unset.
     params->url_is_unreachable = true;
   } else {
-    params->redirects.push_back(navigation_url_);
     params->should_update_history = true;
     if (same_document) {
       params->sandbox_flags = current_rfh->active_sandbox_flags();
diff --git a/content/test/test_render_frame_host.cc b/content/test/test_render_frame_host.cc
index 505a119b4..7a5beea 100644
--- a/content/test/test_render_frame_host.cc
+++ b/content/test/test_render_frame_host.cc
@@ -526,7 +526,6 @@
   params->http_status_code = response_code;
   params->history_list_was_cleared = simulate_history_list_was_cleared_;
   params->post_id = -1;
-  params->redirects.push_back(url);
 
   // Simulate Blink assigning an item and document sequence number to the
   // navigation.
diff --git a/content/web_test/renderer/web_ax_object_proxy.cc b/content/web_test/renderer/web_ax_object_proxy.cc
index ba58757..a44c2667 100644
--- a/content/web_test/renderer/web_ax_object_proxy.cc
+++ b/content/web_test/renderer/web_ax_object_proxy.cc
@@ -31,10 +31,12 @@
 // Map role value to string, matching Safari/Mac platform implementation to
 // avoid rebaselining web tests.
 std::string RoleToString(ax::mojom::Role role) {
-  constexpr int kSkipPrefixLen = 7;  /// Length of "Role::k"
+  std::string prefix = "k";
   std::ostringstream result;
   result << role;
-  return "AXRole: AX" + result.str().substr(kSkipPrefixLen);
+  // Check that |result| starts with |prefix|.
+  DCHECK_EQ(result.str().find(prefix), 0ull);
+  return "AXRole: AX" + result.str().substr(prefix.size());
 }
 
 std::string GetStringValue(const blink::WebAXObject& object) {
diff --git a/extensions/browser/extension_prefs.cc b/extensions/browser/extension_prefs.cc
index a1c2815..5d6b633 100644
--- a/extensions/browser/extension_prefs.cc
+++ b/extensions/browser/extension_prefs.cc
@@ -940,14 +940,6 @@
   return g_run_alerts_in_first_run_for_testing;  // Note: normally false.
 }
 
-bool ExtensionPrefs::IsPinnedExtensionsMigrationComplete() {
-  return prefs_->GetBoolean(pref_names::kPinnedExtensionsMigrationComplete);
-}
-
-void ExtensionPrefs::MarkPinnedExtensionsMigrationComplete() {
-  prefs_->SetBoolean(pref_names::kPinnedExtensionsMigrationComplete, true);
-}
-
 bool ExtensionPrefs::DidExtensionEscalatePermissions(
     const std::string& extension_id) const {
   return HasDisableReason(extension_id,
@@ -2326,8 +2318,6 @@
   registry->RegisterListPref(pref_names::kPinnedExtensions,
                              user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
   registry->RegisterIntegerPref(pref_names::kToolbarSize, -1);
-  registry->RegisterBooleanPref(pref_names::kPinnedExtensionsMigrationComplete,
-                                false);
   registry->RegisterListPref(pref_names::kDeletedComponentExtensions);
   registry->RegisterDictionaryPref(kExtensionsBlocklistUpdate);
   registry->RegisterListPref(pref_names::kInstallAllowList);
diff --git a/extensions/browser/extension_prefs.h b/extensions/browser/extension_prefs.h
index 536782da..0bf3375 100644
--- a/extensions/browser/extension_prefs.h
+++ b/extensions/browser/extension_prefs.h
@@ -417,12 +417,6 @@
   // reset it. Don't call it unless you mean it!
   bool SetAlertSystemFirstRun();
 
-  // Whether extensions that were previously visible in the toolbar from
-  // |BrowserActionsContainer| have been migrated to pinned extensions in the
-  // |ExtensionsToolbarContainer|.
-  bool IsPinnedExtensionsMigrationComplete();
-  void MarkPinnedExtensionsMigrationComplete();
-
   // Returns the last value set via SetLastPingDay. If there isn't such a
   // pref, the returned Time will return true for is_null().
   base::Time LastPingDay(const std::string& extension_id) const;
diff --git a/extensions/browser/guest_view/web_view/web_view_content_script_manager.cc b/extensions/browser/guest_view/web_view/web_view_content_script_manager.cc
index f02d805..bb3e9bb6 100644
--- a/extensions/browser/guest_view/web_view/web_view_content_script_manager.cc
+++ b/extensions/browser/guest_view/web_view/web_view_content_script_manager.cc
@@ -26,8 +26,7 @@
 
 WebViewContentScriptManager::WebViewContentScriptManager(
     content::BrowserContext* browser_context)
-    : user_script_loader_observer_(this), browser_context_(browser_context)  {
-}
+    : browser_context_(browser_context) {}
 
 WebViewContentScriptManager::~WebViewContentScriptManager() {
 }
@@ -65,7 +64,7 @@
   GuestMapKey key = std::pair<int, int>(embedder_process_id, view_instance_id);
   auto iter = guest_content_script_map_.find(key);
 
-  // Step 1: finds the entry in guest_content_script_map_ by the given |key|.
+  // Step 1: Finds the entry in guest_content_script_map_ by the given |key|.
   // If there isn't any content script added for the given guest yet, insert an
   // empty map first.
   if (iter == guest_content_script_map_.end()) {
@@ -74,7 +73,7 @@
         std::pair<GuestMapKey, ContentScriptMap>(key, ContentScriptMap()));
   }
 
-  // Step 2: updates the guest_content_script_map_.
+  // Step 2: Updates the guest_content_script_map_.
   ContentScriptMap& map = iter->second;
   std::set<UserScriptIDPair> to_delete;
   for (const std::unique_ptr<UserScript>& script : *scripts) {
@@ -90,28 +89,29 @@
     ids_to_add.insert(script->id());
   }
 
-  if (!to_delete.empty())
-    loader->RemoveScripts(to_delete, UserScriptLoader::ScriptsLoadedCallback());
+  if (!to_delete.empty()) {
+    pending_operation_count_++;
+    loader->RemoveScripts(
+        to_delete,
+        base::BindOnce(&WebViewContentScriptManager::OnScriptsUpdated,
+                       weak_factory_.GetWeakPtr()));
+  }
 
-  // Step 3: makes WebViewContentScriptManager become an observer of the
-  // |loader| for scripts loaded event.
-  // TODO(crbug.com/1180408): Use callbacks instead to remove the need to
-  // observe this loader for when the load has finished.
-  if (!user_script_loader_observer_.IsObserving(loader))
-    user_script_loader_observer_.Add(loader);
+  // Step 3: Adds new scripts to the set.
+  pending_operation_count_++;
+  loader->AddScripts(
+      std::move(scripts), embedder_process_id,
+      render_frame_host->GetRoutingID(),
+      base::BindOnce(&WebViewContentScriptManager::OnScriptsUpdated,
+                     weak_factory_.GetWeakPtr()));
 
-  // Step 4: adds new scripts to the set.
-  loader->AddScripts(std::move(scripts), embedder_process_id,
-                     render_frame_host->GetRoutingID(),
-                     UserScriptLoader::ScriptsLoadedCallback());
-
-  // Step 5: creates an entry in |webview_host_id_map_| for the given
+  // Step 4: Creates an entry in |webview_host_id_map_| for the given
   // |embedder_process_id| and |view_instance_id| if it doesn't exist.
   auto host_it = webview_host_id_map_.find(key);
   if (host_it == webview_host_id_map_.end())
     webview_host_id_map_.insert(std::make_pair(key, host_id));
 
-  // Step 6: updates WebViewRenderState.
+  // Step 5: Updates WebViewRenderState.
   if (!ids_to_add.empty()) {
     WebViewRendererState::GetInstance()->AddContentScriptIDs(
         embedder_process_id, view_instance_id, ids_to_add);
@@ -157,7 +157,7 @@
   std::set<std::string> ids_to_delete;
   std::set<UserScriptIDPair> scripts_to_delete;
 
-  // Step 1: removes content scripts from |set| and updates
+  // Step 1: Removes content scripts from |set| and updates
   // |guest_content_script_map_|.
   std::map<std::string, UserScriptIDPair>& map = script_map_iter->second;
   // If the |script_name_list| is empty, all the content scripts added by the
@@ -182,18 +182,14 @@
     }
   }
 
-  // Step 2: makes WebViewContentScriptManager become an observer of the
-  // |loader| for scripts loaded event.
-  // TODO(crbug.com/1180408): Use callbacks instead to remove the need to
-  // observe this loader for when the load has finished.
-  if (!user_script_loader_observer_.IsObserving(loader))
-    user_script_loader_observer_.Add(loader);
+  // Step 2: Removes content scripts from set.
+  pending_operation_count_++;
+  loader->RemoveScripts(
+      scripts_to_delete,
+      base::BindOnce(&WebViewContentScriptManager::OnScriptsUpdated,
+                     weak_factory_.GetWeakPtr()));
 
-  // Step 3: removes content scripts from set.
-  loader->RemoveScripts(scripts_to_delete,
-                        UserScriptLoader::ScriptsLoadedCallback());
-
-  // Step 4: updates WebViewRenderState.
+  // Step 3: Updates WebViewRenderState.
   if (!ids_to_delete.empty()) {
     WebViewRendererState::GetInstance()->RemoveContentScriptIDs(
         embedder_process_id, view_instance_id, ids_to_delete);
@@ -217,30 +213,25 @@
   return ids;
 }
 
-void WebViewContentScriptManager::SignalOnScriptsLoaded(
+void WebViewContentScriptManager::SignalOnScriptsUpdated(
     base::OnceClosure callback) {
-  if (!user_script_loader_observer_.IsObservingSources()) {
+  if (pending_operation_count_ == 0) {
     std::move(callback).Run();
     return;
   }
   pending_scripts_loading_callbacks_.push_back(std::move(callback));
 }
 
-void WebViewContentScriptManager::OnScriptsLoaded(
+void WebViewContentScriptManager::OnScriptsUpdated(
     UserScriptLoader* loader,
-    content::BrowserContext* browser_context) {
-  user_script_loader_observer_.Remove(loader);
-  RunCallbacksIfReady();
-}
-
-void WebViewContentScriptManager::OnUserScriptLoaderDestroyed(
-    UserScriptLoader* loader) {
-  user_script_loader_observer_.Remove(loader);
+    const base::Optional<std::string>& error) {
+  --pending_operation_count_;
+  DCHECK_GE(pending_operation_count_, 0);
   RunCallbacksIfReady();
 }
 
 void WebViewContentScriptManager::RunCallbacksIfReady() {
-  if (user_script_loader_observer_.IsObservingSources())
+  if (pending_operation_count_ > 0)
     return;
   for (auto& callback : pending_scripts_loading_callbacks_)
     std::move(callback).Run();
diff --git a/extensions/browser/guest_view/web_view/web_view_content_script_manager.h b/extensions/browser/guest_view/web_view/web_view_content_script_manager.h
index 9ee9978..29e96c5 100644
--- a/extensions/browser/guest_view/web_view/web_view_content_script_manager.h
+++ b/extensions/browser/guest_view/web_view/web_view_content_script_manager.h
@@ -12,9 +12,13 @@
 
 #include "base/callback.h"
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
 #include "base/supports_user_data.h"
-#include "extensions/browser/user_script_loader.h"
 #include "extensions/common/mojom/host_id.mojom-forward.h"
+#include "extensions/common/user_script.h"
+
+struct HostID;
 
 namespace content {
 class BrowserContext;
@@ -22,11 +26,11 @@
 }
 
 namespace extensions {
+class UserScriptLoader;
 
 // WebViewContentScriptManager manages the content scripts that each webview
 // guest adds and removes programmatically.
-class WebViewContentScriptManager : public base::SupportsUserData::Data,
-                                    public UserScriptLoader::Observer {
+class WebViewContentScriptManager : public base::SupportsUserData::Data {
  public:
   explicit WebViewContentScriptManager(
       content::BrowserContext* browser_context);
@@ -62,24 +66,25 @@
   std::set<std::string> GetContentScriptIDSet(int embedder_process_id,
                                               int view_instance_id);
 
-  // Checks if there is any pending content scripts to load.
-  // If no, run |callback| immediately; otherwise caches the |callback|, and
+  // Checks if there is any pending content script updates.
+  // If not, run |callback| immediately; otherwise caches the |callback|, and
   // the |callback| will be called after all the pending content scripts are
   // loaded.
-  void SignalOnScriptsLoaded(base::OnceClosure callback);
+  void SignalOnScriptsUpdated(base::OnceClosure callback);
 
  private:
   using GuestMapKey = std::pair<int, int>;
   using ContentScriptMap = std::map<std::string, UserScriptIDPair>;
   using GuestContentScriptMap = std::map<GuestMapKey, ContentScriptMap>;
 
-  // UserScriptLoader::Observer implementation:
-  void OnScriptsLoaded(UserScriptLoader* loader,
-                       content::BrowserContext* browser_context) override;
-  void OnUserScriptLoaderDestroyed(UserScriptLoader* loader) override;
+  // Invoked when scripts are updated from any kind of operation or when a
+  // UserScriptLoader is about to be destroyed. This may be called multiple
+  // times per script load.
+  void OnScriptsUpdated(UserScriptLoader* loader,
+                        const base::Optional<std::string>& error);
 
-  // If |user_script_loader_observer_| doesn't observe any source, we will run
-  // all the remaining callbacks in |pending_scripts_loading_callbacks_|.
+  // If there are no pending script loads, we will run all the remaining
+  // callbacks in |pending_scripts_loading_callbacks_|.
   void RunCallbacksIfReady();
 
   // A map from embedder process ID and view instance ID (uniquely identifying
@@ -90,16 +95,17 @@
 
   GuestContentScriptMap guest_content_script_map_;
 
-  // WebViewContentScriptManager observes UserScriptLoader to wait for scripts
-  // loaded event.
-  ScopedObserver<UserScriptLoader, UserScriptLoader::Observer>
-      user_script_loader_observer_;
+  // Tracks the number of pending Add/Remove content script operations initiated
+  // from this class.
+  int pending_operation_count_ = 0;
 
   // Caches callbacks and resumes them when all the scripts are loaded.
   std::vector<base::OnceClosure> pending_scripts_loading_callbacks_;
 
   content::BrowserContext* browser_context_;
 
+  base::WeakPtrFactory<WebViewContentScriptManager> weak_factory_{this};
+
   DISALLOW_COPY_AND_ASSIGN(WebViewContentScriptManager);
 };
 
diff --git a/extensions/browser/guest_view/web_view/web_view_guest.cc b/extensions/browser/guest_view/web_view/web_view_guest.cc
index 9d514c5..0afb0ced 100644
--- a/extensions/browser/guest_view/web_view/web_view_guest.cc
+++ b/extensions/browser/guest_view/web_view/web_view_guest.cc
@@ -1126,7 +1126,7 @@
 
 void WebViewGuest::SignalWhenReady(base::OnceClosure callback) {
   auto* manager = WebViewContentScriptManager::Get(browser_context());
-  manager->SignalOnScriptsLoaded(std::move(callback));
+  manager->SignalOnScriptsUpdated(std::move(callback));
 }
 
 void WebViewGuest::WillAttachToEmbedder() {
diff --git a/extensions/browser/pref_names.cc b/extensions/browser/pref_names.cc
index f516115c1..c4dd0dbb 100644
--- a/extensions/browser/pref_names.cc
+++ b/extensions/browser/pref_names.cc
@@ -47,8 +47,6 @@
 const char kStorageGarbageCollect[] = "extensions.storage.garbagecollect";
 const char kToolbar[] = "extensions.toolbar";
 const char kToolbarSize[] = "extensions.toolbarsize";
-const char kPinnedExtensionsMigrationComplete[] =
-    "extensions.pinned_extension_migration";
 const char kDeletedComponentExtensions[] =
     "extensions.deleted_component_extensions";
 
diff --git a/extensions/browser/pref_names.h b/extensions/browser/pref_names.h
index bd92e38..eb73ef6 100644
--- a/extensions/browser/pref_names.h
+++ b/extensions/browser/pref_names.h
@@ -103,10 +103,6 @@
 // actions toolbar.
 extern const char kToolbarSize[];
 
-// Indicates whether extensions have been migrated from BrowserActionsContainer
-// to the ExtensionsToolbarContainer.
-extern const char kPinnedExtensionsMigrationComplete[];
-
 // A preference for a list of Component extensions that have been
 // uninstalled/removed and should not be reloaded.
 extern const char kDeletedComponentExtensions[];
diff --git a/extensions/browser/script_executor.cc b/extensions/browser/script_executor.cc
index f023869f..d3b63a1 100644
--- a/extensions/browser/script_executor.cc
+++ b/extensions/browser/script_executor.cc
@@ -55,13 +55,13 @@
 
   Handler(ScriptsExecutedOnceCallback observer,
           content::WebContents* web_contents,
-          const ExtensionMsg_ExecuteCode_Params& params,
+          const mojom::ExecuteCodeParams& params,
           ScriptExecutor::FrameScope scope,
           const std::vector<int>& frame_ids,
           ScriptExecutor::ScriptFinishedCallback callback)
       : content::WebContentsObserver(web_contents),
         observer_(std::move(observer)),
-        host_id_(params.host_id),
+        host_id_(params.host_id->type, params.host_id->id),
         request_id_(params.request_id),
         callback_(std::move(callback)) {
     for (int frame_id : frame_ids) {
@@ -183,7 +183,7 @@
 
   // Sends an ExecuteCode message to the given frame host, and increments
   // the number of pending messages.
-  void SendExecuteCode(const ExtensionMsg_ExecuteCode_Params& params,
+  void SendExecuteCode(const mojom::ExecuteCodeParams& params,
                        content::RenderFrameHost* frame) {
     DCHECK(frame->IsRenderFrameLive());
     DCHECK(base::Contains(pending_render_frames_, frame));
@@ -316,9 +316,9 @@
     CHECK(process_type == WEB_VIEW_PROCESS);
   }
 
-  ExtensionMsg_ExecuteCode_Params params;
+  mojom::ExecuteCodeParams params;
   params.request_id = next_request_id_++;
-  params.host_id = host_id;
+  params.host_id = mojom::HostID::New(host_id.type, host_id.id);
   params.action_type = action_type;
   params.code = code;
   params.match_about_blank = (about_blank == MATCH_ABOUT_BLANK);
diff --git a/extensions/browser/script_executor.h b/extensions/browser/script_executor.h
index 2abf990..0ad4f85 100644
--- a/extensions/browser/script_executor.h
+++ b/extensions/browser/script_executor.h
@@ -20,7 +20,6 @@
 #include "extensions/common/user_script.h"
 
 class GURL;
-struct ExtensionMsg_ExecuteCode_Params;
 
 namespace content {
 class WebContents;
@@ -40,7 +39,7 @@
     void(content::WebContents*, const ExecutingScriptsMap&, const GURL&)>;
 
 // Interface for executing extension content scripts (e.g. executeScript) as
-// described by the ExtensionMsg_ExecuteCode_Params IPC, and notifying the
+// described by the mojom::ExecuteCodeParams IPC, and notifying the
 // caller when responded with ExtensionHostMsg_ExecuteCodeFinished.
 class ScriptExecutor {
  public:
@@ -97,8 +96,8 @@
   using ScriptFinishedCallback =
       base::OnceCallback<void(std::vector<FrameResult> frame_results)>;
 
-  // Executes a script. The arguments match ExtensionMsg_ExecuteCode_Params in
-  // extension_messages.h (request_id is populated automatically).
+  // Executes a script. The arguments match mojom::ExecuteCodeParams in
+  // frame.mojom (request_id is populated automatically).
   //
   // The script will be executed in the frames identified by |frame_ids| (which
   // are extension API frame IDs). If |frame_scope| is INCLUDE_SUB_FRAMES,
@@ -130,7 +129,7 @@
   }
 
  private:
-  // The next value to use for request_id in ExtensionMsg_ExecuteCode_Params.
+  // The next value to use for request_id in mojom::ExecuteCodeParams.
   int next_request_id_ = 0;
 
   content::WebContents* web_contents_;
diff --git a/extensions/browser/user_script_loader.cc b/extensions/browser/user_script_loader.cc
index 000c729a..7c78ca5 100644
--- a/extensions/browser/user_script_loader.cc
+++ b/extensions/browser/user_script_loader.cc
@@ -30,10 +30,15 @@
 namespace {
 
 // The error message passed inside ScriptsLoadedCallback if the shared memory
-// region where scripts are supposed to b e loaded into is invalid.
+// region where scripts are supposed to be loaded into is invalid.
 const char kSharedMemoryInvalidErrorMsg[] =
     "Script could not be loaded into invalid shared memory.";
 
+// The error message passed inside ScriptsLoadedCallback if the callback is
+// fired when the UserScriptLoader is destroyed.
+const char kUserScriptLoaderDestroyedErrorMsg[] =
+    "Scripts could not be loaded as the script loader has been destroyed.";
+
 #if DCHECK_IS_ON()
 bool AreScriptsUnique(const UserScriptList& scripts) {
   std::set<std::string> script_ids;
@@ -172,6 +177,18 @@
       host_id_(host_id) {}
 
 UserScriptLoader::~UserScriptLoader() {
+  base::Optional<std::string> error =
+      base::make_optional(kUserScriptLoaderDestroyedErrorMsg);
+
+  // Clean up state by firing all remaining callbacks with |error| populated to
+  // alert consumers that scripts are not loaded.
+  std::list<ScriptsLoadedCallback> remaining_callbacks;
+  remaining_callbacks.splice(remaining_callbacks.end(), queued_load_callbacks_);
+  remaining_callbacks.splice(remaining_callbacks.end(), loading_callbacks_);
+  for (auto& callback : remaining_callbacks)
+    std::move(callback).Run(this, error);
+  remaining_callbacks.clear();
+
   for (auto& observer : observers_)
     observer.OnUserScriptLoaderDestroyed(this);
 }
diff --git a/extensions/common/BUILD.gn b/extensions/common/BUILD.gn
index 2da55be..6f9bfa7 100644
--- a/extensions/common/BUILD.gn
+++ b/extensions/common/BUILD.gn
@@ -172,6 +172,8 @@
       "extension_message_generator.h",
       "extension_messages.cc",
       "extension_messages.h",
+      "extension_messages_param_traits.cc",
+      "extension_messages_param_traits.h",
       "extension_paths.cc",
       "extension_paths.h",
       "extension_resource.cc",
@@ -463,6 +465,7 @@
       "extension_builder_unittest.cc",
       "extension_icon_set_unittest.cc",
       "extension_l10n_util_unittest.cc",
+      "extension_messages_param_traits_unittest.cc",
       "extension_messages_unittest.cc",
       "extension_resource_path_normalizer_unittest.cc",
       "extension_resource_unittest.cc",
diff --git a/extensions/common/extension_messages.h b/extensions/common/extension_messages.h
index 988a37f9..b1cd5bd 100644
--- a/extensions/common/extension_messages.h
+++ b/extensions/common/extension_messages.h
@@ -31,11 +31,13 @@
 #include "extensions/common/event_filtering_info.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_guid.h"
+#include "extensions/common/extension_messages_param_traits.h"
 #include "extensions/common/extensions_client.h"
 #include "extensions/common/message_bundle.h"
 #include "extensions/common/mojom/action_type.mojom-shared.h"
 #include "extensions/common/mojom/css_origin.mojom-shared.h"
 #include "extensions/common/mojom/feature_session_type.mojom.h"
+#include "extensions/common/mojom/frame.mojom.h"
 #include "extensions/common/mojom/host_id.mojom.h"
 #include "extensions/common/mojom/run_location.mojom-shared.h"
 #include "extensions/common/permissions/permission_set.h"
@@ -170,48 +172,48 @@
 IPC_STRUCT_TRAITS_END()
 
 // Allows an extension to execute code in a tab.
-IPC_STRUCT_BEGIN(ExtensionMsg_ExecuteCode_Params)
+IPC_STRUCT_TRAITS_BEGIN(extensions::mojom::ExecuteCodeParams)
   // The extension API request id, for responding.
-  IPC_STRUCT_MEMBER(int, request_id)
+  IPC_STRUCT_TRAITS_MEMBER(request_id)
 
   // The ID of the requesting injection host.
-  IPC_STRUCT_MEMBER(extensions::mojom::HostID, host_id)
+  IPC_STRUCT_TRAITS_MEMBER(host_id)
 
   // Whether the code is JavaScript or CSS.
-  IPC_STRUCT_MEMBER(extensions::mojom::ActionType, action_type)
+  IPC_STRUCT_TRAITS_MEMBER(action_type)
 
   // String of code to execute.
-  IPC_STRUCT_MEMBER(std::string, code)
+  IPC_STRUCT_TRAITS_MEMBER(code)
 
   // The webview guest source who calls to execute code.
-  IPC_STRUCT_MEMBER(GURL, webview_src)
+  IPC_STRUCT_TRAITS_MEMBER(webview_src)
 
   // Whether to inject into about:blank (sub)frames.
-  IPC_STRUCT_MEMBER(bool, match_about_blank)
+  IPC_STRUCT_TRAITS_MEMBER(match_about_blank)
 
   // When to inject the code.
-  IPC_STRUCT_MEMBER(extensions::mojom::RunLocation, run_at)
+  IPC_STRUCT_TRAITS_MEMBER(run_at)
 
   // Whether the request is coming from a <webview>.
-  IPC_STRUCT_MEMBER(bool, is_web_view)
+  IPC_STRUCT_TRAITS_MEMBER(is_web_view)
 
   // Whether the caller is interested in the result value. Manifest-declared
   // content scripts and executeScript() calls without a response callback
   // are examples of when this will be false.
-  IPC_STRUCT_MEMBER(bool, wants_result)
+  IPC_STRUCT_TRAITS_MEMBER(wants_result)
 
   // The URL of the script that was injected, if any.
-  IPC_STRUCT_MEMBER(GURL, script_url)
+  IPC_STRUCT_TRAITS_MEMBER(script_url)
 
   // Whether the code to be executed should be associated with a user gesture.
-  IPC_STRUCT_MEMBER(bool, user_gesture)
+  IPC_STRUCT_TRAITS_MEMBER(user_gesture)
 
   // The origin of the CSS.
-  IPC_STRUCT_MEMBER(extensions::mojom::CSSOrigin, css_origin)
+  IPC_STRUCT_TRAITS_MEMBER(css_origin)
 
   // The autogenerated key for the CSS injection.
-  IPC_STRUCT_MEMBER(base::Optional<std::string>, injection_key)
-IPC_STRUCT_END()
+  IPC_STRUCT_TRAITS_MEMBER(injection_key)
+IPC_STRUCT_TRAITS_END()
 
 // Struct containing information about the sender of connect() calls that
 // originate from a tab.
@@ -549,7 +551,7 @@
 
 // Notification that renderer should run some JavaScript code.
 IPC_MESSAGE_ROUTED1(ExtensionMsg_ExecuteCode,
-                    ExtensionMsg_ExecuteCode_Params)
+                    extensions::mojom::ExecuteCodeParams)
 
 // Notification that the user scripts have been updated. It has one
 // ReadOnlySharedMemoryRegion argument consisting of the pickled script data.
@@ -571,13 +573,6 @@
                      std::set<extensions::mojom::HostID> /* changed hosts */,
                      bool /* whitelisted_only */)
 
-// Trigger to execute declarative content script under browser control.
-IPC_MESSAGE_ROUTED4(ExtensionMsg_ExecuteDeclarativeScript,
-                    int /* tab identifier */,
-                    extensions::ExtensionId /* extension identifier */,
-                    std::string /* script identifier */,
-                    GURL /* page URL where script should be injected */)
-
 // Tell the render view which browser window it's being attached to.
 IPC_MESSAGE_ROUTED1(ExtensionMsg_UpdateBrowserWindowId,
                     int /* id of browser window */)
diff --git a/extensions/common/extension_messages_param_traits.cc b/extensions/common/extension_messages_param_traits.cc
new file mode 100644
index 0000000..6b587fc6
--- /dev/null
+++ b/extensions/common/extension_messages_param_traits.cc
@@ -0,0 +1,36 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/common/extension_messages_param_traits.h"
+
+#include "base/pickle.h"
+#include "extensions/common/extension_messages.h"
+
+namespace IPC {
+
+using extensions::mojom::HostIDPtr;
+
+void ParamTraits<HostIDPtr>::Write(base::Pickle* m, const param_type& p) {
+  WriteParam(m, p->type);
+  m->WriteString(p->id);
+}
+
+bool ParamTraits<HostIDPtr>::Read(const base::Pickle* m,
+                                  base::PickleIterator* iter,
+                                  param_type* p) {
+  bool success = true;
+
+  extensions::mojom::HostID::HostType type;
+  success &= ReadParam(m, iter, &type);
+  std::string id;
+  success &= iter->ReadString(&id);
+
+  if (success)
+    *p = extensions::mojom::HostID::New(type, id);
+  return success;
+}
+
+void ParamTraits<HostIDPtr>::Log(const param_type& p, std::string* l) {}
+
+}  // namespace IPC
diff --git a/extensions/common/extension_messages_param_traits.h b/extensions/common/extension_messages_param_traits.h
new file mode 100644
index 0000000..e62b438d
--- /dev/null
+++ b/extensions/common/extension_messages_param_traits.h
@@ -0,0 +1,36 @@
+// Copyright 2021 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.
+
+// TODO(crbug.com/1180858): These traits files,
+// extension_messages_param_traits.{cc,h}, are required for sending extension
+// mojom types to legacy IPCs. Once the mojofication of extension is done, these
+// traits should be removed.
+
+#ifndef EXTENSIONS_COMMON_EXTENSION_MESSAGES_PARAM_TRAITS_H_
+#define EXTENSIONS_COMMON_EXTENSION_MESSAGES_PARAM_TRAITS_H_
+
+#include "extensions/common/mojom/host_id.mojom.h"
+
+#include "ipc/ipc_message_utils.h"
+
+namespace base {
+class Pickle;
+class PickleIterator;
+}  // namespace base
+
+namespace IPC {
+
+template <>
+struct ParamTraits<extensions::mojom::HostIDPtr> {
+  typedef extensions::mojom::HostIDPtr param_type;
+  static void Write(base::Pickle* m, const param_type& p);
+  static bool Read(const base::Pickle* m,
+                   base::PickleIterator* iter,
+                   param_type* r);
+  static void Log(const param_type& p, std::string* l);
+};
+
+}  // namespace IPC
+
+#endif  // EXTENSIONS_COMMON_EXTENSION_MESSAGES_PARAM_TRAITS_H_
diff --git a/extensions/common/extension_messages_param_traits_unittest.cc b/extensions/common/extension_messages_param_traits_unittest.cc
new file mode 100644
index 0000000..4614c8a5
--- /dev/null
+++ b/extensions/common/extension_messages_param_traits_unittest.cc
@@ -0,0 +1,27 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/common/extension_messages_param_traits.h"
+
+#include "extensions/common/mojom/host_id.mojom.h"
+#include "ipc/ipc_message_macros.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(ExtensionsParamTraitsTest, HostIDPtrTest) {
+  constexpr char kTestId[] = "aaaaaaaaaaaaa";
+
+  extensions::mojom::HostIDPtr params = extensions::mojom::HostID::New();
+  params->type = extensions::mojom::HostID::HostType::kWebUi;
+  params->id = kTestId;
+
+  IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
+  IPC::WriteParam(&msg, params);
+
+  base::PickleIterator iter(msg);
+  extensions::mojom::HostIDPtr output;
+
+  EXPECT_TRUE(IPC::ReadParam(&msg, &iter, &output));
+  EXPECT_EQ(output->type, extensions::mojom::HostID::HostType::kWebUi);
+  EXPECT_EQ(output->id, kTestId);
+}
diff --git a/extensions/common/mojom/frame.mojom b/extensions/common/mojom/frame.mojom
index 88862311..c6d8e3fd 100644
--- a/extensions/common/mojom/frame.mojom
+++ b/extensions/common/mojom/frame.mojom
@@ -4,8 +4,45 @@
 
 module extensions.mojom;
 
+import "extensions/common/mojom/action_type.mojom";
+import "extensions/common/mojom/css_origin.mojom";
+import "extensions/common/mojom/host_id.mojom";
+import "extensions/common/mojom/run_location.mojom";
 import "extensions/common/mojom/view_type.mojom";
 import "mojo/public/mojom/base/values.mojom";
+import "url/mojom/url.mojom";
+
+// Allows an extension to execute code in a tab.
+struct ExecuteCodeParams {
+  // The extension API request id, for responding.
+  int32 request_id;
+  // The ID of the requesting injection host.
+  HostID host_id;
+  // Whether the code is JavaScript or CSS.
+  ActionType action_type;
+  // String of code to execute.
+  string code;
+  // The webview guest source who calls to execute code.
+  url.mojom.Url webview_src;
+  // Whether to inject into about:blank (sub)frames.
+  bool match_about_blank;
+  // When to inject the code.
+  RunLocation run_at;
+  // Whether the request is coming from a <webview>.
+  bool is_web_view;
+  // Whether the caller is interested in the result value. Manifest-declared
+  // content scripts and executeScript() calls without a response callback
+  // are examples of when this will be false.
+  bool wants_result;
+  // The URL of the script that was injected, if any.
+  url.mojom.Url script_url;
+  // Whether the code to be executed should be associated with a user gesture.
+  bool user_gesture;
+  // The origin of the CSS.
+  CSSOrigin css_origin;
+  // The autogenerated key for the CSS injection.
+  string? injection_key;
+};
 
 // Implemented in the renderer, this interface defines the local frame specific
 // methods.
@@ -33,4 +70,10 @@
                 string module_name,
                 string function_name,
                 mojo_base.mojom.ListValue args);
+
+  // Trigger to execute declarative content script under browser control.
+  ExecuteDeclarativeScript(int32 tab_id,
+                           string extension_id,
+                           string script_id,
+                           url.mojom.Url url);
 };
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc
index 936cb6f..482ee9dc 100644
--- a/extensions/renderer/dispatcher.cc
+++ b/extensions/renderer/dispatcher.cc
@@ -712,6 +712,15 @@
                           &args));
 }
 
+void Dispatcher::ExecuteDeclarativeScript(content::RenderFrame* render_frame,
+                                          int tab_id,
+                                          const ExtensionId& extension_id,
+                                          const std::string& script_id,
+                                          const GURL& url) {
+  script_injection_manager_->ExecuteDeclarativeScript(
+      render_frame, tab_id, extension_id, script_id, url);
+}
+
 // static
 std::vector<Dispatcher::JsResourceInfo> Dispatcher::GetJsResources() {
   // Libraries.
diff --git a/extensions/renderer/dispatcher.h b/extensions/renderer/dispatcher.h
index 30f0081..3f918de 100644
--- a/extensions/renderer/dispatcher.h
+++ b/extensions/renderer/dispatcher.h
@@ -182,6 +182,12 @@
                                 const std::string& function_name,
                                 const base::ListValue& args);
 
+  void ExecuteDeclarativeScript(content::RenderFrame* render_frame,
+                                int tab_id,
+                                const ExtensionId& extension_id,
+                                const std::string& script_id,
+                                const GURL& url);
+
   struct JsResourceInfo {
     const char* name = nullptr;
     int id = 0;
diff --git a/extensions/renderer/extension_frame_helper.cc b/extensions/renderer/extension_frame_helper.cc
index 7ff52b4..f83ba12 100644
--- a/extensions/renderer/extension_frame_helper.cc
+++ b/extensions/renderer/extension_frame_helper.cc
@@ -500,6 +500,21 @@
       ->SetSpatialNavigationEnabled(enabled);
 }
 
+void ExtensionFrameHelper::ExecuteDeclarativeScript(
+    int32_t tab_id,
+    const std::string& extension_id,
+    const std::string& script_id,
+    const GURL& url) {
+  // TODO(https://crbug.com/1186220): URL-checking isn't the best approach to
+  // avoid user data leak. Consider what we can do to mitigate this case.
+  // Begin script injection workflow only if the current URL is identical to the
+  // one that matched declarative conditions in the browser.
+  if (GURL(render_frame()->GetWebFrame()->GetDocument().Url()) == url) {
+    extension_dispatcher_->ExecuteDeclarativeScript(
+        render_frame(), tab_id, extension_id, script_id, url);
+  }
+}
+
 void ExtensionFrameHelper::OnDestruct() {
   delete this;
 }
diff --git a/extensions/renderer/extension_frame_helper.h b/extensions/renderer/extension_frame_helper.h
index 326e137..f70c4a5 100644
--- a/extensions/renderer/extension_frame_helper.h
+++ b/extensions/renderer/extension_frame_helper.h
@@ -109,6 +109,10 @@
                      const std::string& module_name,
                      const std::string& function_name,
                      const base::Value args) override;
+  void ExecuteDeclarativeScript(int32_t tab_id,
+                                const std::string& extension_id,
+                                const std::string& script_id,
+                                const GURL& url) override;
 
   // Called when the document element has been inserted in this frame. This
   // method may invoke untrusted JavaScript code that invalidate the frame and
diff --git a/extensions/renderer/programmatic_script_injector.cc b/extensions/renderer/programmatic_script_injector.cc
index 4f7e788..ef864854 100644
--- a/extensions/renderer/programmatic_script_injector.cc
+++ b/extensions/renderer/programmatic_script_injector.cc
@@ -14,6 +14,7 @@
 #include "extensions/common/extension_messages.h"
 #include "extensions/common/manifest_constants.h"
 #include "extensions/common/mojom/action_type.mojom-shared.h"
+#include "extensions/common/mojom/frame.mojom.h"
 #include "extensions/common/mojom/host_id.mojom.h"
 #include "extensions/common/permissions/api_permission.h"
 #include "extensions/common/permissions/permissions_data.h"
@@ -29,10 +30,8 @@
 namespace extensions {
 
 ProgrammaticScriptInjector::ProgrammaticScriptInjector(
-    const ExtensionMsg_ExecuteCode_Params& params)
-    : params_(new ExtensionMsg_ExecuteCode_Params(params)),
-      finished_(false) {
-}
+    mojom::ExecuteCodeParamsPtr params)
+    : params_(std::move(params)), finished_(false) {}
 
 ProgrammaticScriptInjector::~ProgrammaticScriptInjector() {
 }
@@ -179,10 +178,10 @@
 }
 
 bool ProgrammaticScriptInjector::CanShowUrlInError() const {
-  if (params_->host_id.type != mojom::HostID::HostType::kExtensions)
+  if (params_->host_id->type != mojom::HostID::HostType::kExtensions)
     return false;
   const Extension* extension =
-      RendererExtensionRegistry::Get()->GetByID(params_->host_id.id);
+      RendererExtensionRegistry::Get()->GetByID(params_->host_id->id);
   if (!extension)
     return false;
   return extension->permissions_data()->active_permissions().HasAPIPermission(
diff --git a/extensions/renderer/programmatic_script_injector.h b/extensions/renderer/programmatic_script_injector.h
index 659756e4..c8ed5d0 100644
--- a/extensions/renderer/programmatic_script_injector.h
+++ b/extensions/renderer/programmatic_script_injector.h
@@ -11,12 +11,11 @@
 #include "base/optional.h"
 #include "base/values.h"
 #include "extensions/common/mojom/css_origin.mojom-shared.h"
+#include "extensions/common/mojom/frame.mojom-forward.h"
 #include "extensions/common/mojom/run_location.mojom-shared.h"
 #include "extensions/renderer/script_injection.h"
 #include "url/gurl.h"
 
-struct ExtensionMsg_ExecuteCode_Params;
-
 namespace content {
 class RenderFrame;
 }
@@ -26,8 +25,7 @@
 // A ScriptInjector to handle tabs.executeScript().
 class ProgrammaticScriptInjector : public ScriptInjector {
  public:
-  explicit ProgrammaticScriptInjector(
-      const ExtensionMsg_ExecuteCode_Params& params);
+  explicit ProgrammaticScriptInjector(mojom::ExecuteCodeParamsPtr params);
   ~ProgrammaticScriptInjector() override;
 
  private:
@@ -71,7 +69,7 @@
   void Finish(const std::string& error, content::RenderFrame* render_frame);
 
   // The parameters for injecting the script.
-  std::unique_ptr<ExtensionMsg_ExecuteCode_Params> params_;
+  mojom::ExecuteCodeParamsPtr params_;
 
   // The url of the frame into which we are injecting.
   GURL url_;
diff --git a/extensions/renderer/script_injection_manager.cc b/extensions/renderer/script_injection_manager.cc
index ae2b981..7fbc3142 100644
--- a/extensions/renderer/script_injection_manager.cc
+++ b/extensions/renderer/script_injection_manager.cc
@@ -21,6 +21,7 @@
 #include "extensions/common/extension_features.h"
 #include "extensions/common/extension_messages.h"
 #include "extensions/common/extension_set.h"
+#include "extensions/common/mojom/frame.mojom.h"
 #include "extensions/common/mojom/host_id.mojom.h"
 #include "extensions/renderer/extension_frame_helper.h"
 #include "extensions/renderer/extension_injection_host.h"
@@ -63,6 +64,17 @@
   NOTREACHED();
 }
 
+// TODO(crbug.com/1180858): Remove once ExtensionMsg_ExecuteCode is converted to
+// mojo as the mojo method will get mojom::ExecuteCodeParamsPtr.
+mojom::ExecuteCodeParamsPtr CreateExecuteCodeParamsPtr(
+    const mojom::ExecuteCodeParams& params) {
+  return mojom::ExecuteCodeParams::New(
+      params.request_id, params.host_id.Clone(), params.action_type,
+      params.code, params.webview_src, params.match_about_blank, params.run_at,
+      params.is_web_view, params.wants_result, params.script_url,
+      params.user_gesture, params.css_origin, params.injection_key);
+}
+
 }  // namespace
 
 class ScriptInjectionManager::RFOHelper : public content::RenderFrameObserver {
@@ -84,11 +96,7 @@
   void OnDestruct() override;
   void OnStop() override;
 
-  virtual void OnExecuteCode(const ExtensionMsg_ExecuteCode_Params& params);
-  virtual void OnExecuteDeclarativeScript(int tab_id,
-                                          const ExtensionId& extension_id,
-                                          const std::string& script_id,
-                                          const GURL& url);
+  virtual void OnExecuteCode(const mojom::ExecuteCodeParams& params);
   virtual void OnPermitScriptInjection(int64_t request_id);
 
   // Tells the ScriptInjectionManager to run tasks associated with
@@ -142,8 +150,6 @@
     IPC_MESSAGE_HANDLER(ExtensionMsg_ExecuteCode, OnExecuteCode)
     IPC_MESSAGE_HANDLER(ExtensionMsg_PermitScriptInjection,
                         OnPermitScriptInjection)
-    IPC_MESSAGE_HANDLER(ExtensionMsg_ExecuteDeclarativeScript,
-                        OnExecuteDeclarativeScript)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   return handled;
@@ -235,27 +241,10 @@
 }
 
 void ScriptInjectionManager::RFOHelper::OnExecuteCode(
-    const ExtensionMsg_ExecuteCode_Params& params) {
+    const mojom::ExecuteCodeParams& params) {
   manager_->HandleExecuteCode(params, render_frame());
 }
 
-void ScriptInjectionManager::RFOHelper::OnExecuteDeclarativeScript(
-    int tab_id,
-    const ExtensionId& extension_id,
-    const std::string& script_id,
-    const GURL& url) {
-  // TODO(markdittmer): URL-checking isn't the best security measure.
-  // Begin script injection workflow only if the current URL is identical to
-  // the one that matched declarative conditions in the browser.
-  if (GURL(render_frame()->GetWebFrame()->GetDocument().Url()) == url) {
-    manager_->HandleExecuteDeclarativeScript(render_frame(),
-                                             tab_id,
-                                             extension_id,
-                                             script_id,
-                                             url);
-  }
-}
-
 void ScriptInjectionManager::RFOHelper::OnPermitScriptInjection(
     int64_t request_id) {
   manager_->HandlePermitScriptInjection(request_id);
@@ -476,22 +465,22 @@
 }
 
 void ScriptInjectionManager::HandleExecuteCode(
-    const ExtensionMsg_ExecuteCode_Params& params,
+    const mojom::ExecuteCodeParams& params,
     content::RenderFrame* render_frame) {
   std::unique_ptr<const InjectionHost> injection_host;
-  if (params.host_id.type == mojom::HostID::HostType::kExtensions) {
-    injection_host = ExtensionInjectionHost::Create(params.host_id.id);
+  if (params.host_id->type == mojom::HostID::HostType::kExtensions) {
+    injection_host = ExtensionInjectionHost::Create(params.host_id->id);
     if (!injection_host)
       return;
-  } else if (params.host_id.type == mojom::HostID::HostType::kWebUi) {
-    injection_host.reset(
-        new WebUIInjectionHost(params.host_id));
+  } else if (params.host_id->type == mojom::HostID::HostType::kWebUi) {
+    injection_host.reset(new WebUIInjectionHost(*params.host_id));
   }
 
-  std::unique_ptr<ScriptInjection> injection(new ScriptInjection(
-      std::unique_ptr<ScriptInjector>(new ProgrammaticScriptInjector(params)),
+  auto injection = std::make_unique<ScriptInjection>(
+      std::make_unique<ProgrammaticScriptInjector>(
+          CreateExecuteCodeParamsPtr(params)),
       render_frame, std::move(injection_host), params.run_at,
-      activity_logging_enabled_));
+      activity_logging_enabled_);
 
   FrameStatusMap::const_iterator iter = frame_statuses_.find(render_frame);
   mojom::RunLocation run_location = iter == frame_statuses_.end()
@@ -502,7 +491,7 @@
   TryToInject(std::move(injection), run_location, &scripts_run_info);
 }
 
-void ScriptInjectionManager::HandleExecuteDeclarativeScript(
+void ScriptInjectionManager::ExecuteDeclarativeScript(
     content::RenderFrame* render_frame,
     int tab_id,
     const ExtensionId& extension_id,
@@ -514,7 +503,8 @@
   if (injection.get()) {
     ScriptsRunInfo scripts_run_info(render_frame,
                                     mojom::RunLocation::kBrowserDriven);
-    // TODO(markdittmer): Use return value of TryToInject for error handling.
+    // TODO(https://crbug.com/1186525): Use return value of TryToInject for
+    // error handling.
     TryToInject(std::move(injection), mojom::RunLocation::kBrowserDriven,
                 &scripts_run_info);
 
diff --git a/extensions/renderer/script_injection_manager.h b/extensions/renderer/script_injection_manager.h
index fe2a0db..c919b00 100644
--- a/extensions/renderer/script_injection_manager.h
+++ b/extensions/renderer/script_injection_manager.h
@@ -15,14 +15,13 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/scoped_observer.h"
+#include "extensions/common/mojom/frame.mojom-forward.h"
 #include "extensions/common/mojom/host_id.mojom-forward.h"
 #include "extensions/common/mojom/run_location.mojom-shared.h"
 #include "extensions/common/user_script.h"
 #include "extensions/renderer/script_injection.h"
 #include "extensions/renderer/user_script_set_manager.h"
 
-struct ExtensionMsg_ExecuteCode_Params;
-
 namespace content {
 class RenderFrame;
 }
@@ -45,6 +44,12 @@
   // Removes pending injections of the unloaded extension.
   void OnExtensionUnloaded(const std::string& extension_id);
 
+  void ExecuteDeclarativeScript(content::RenderFrame* render_frame,
+                                int tab_id,
+                                const ExtensionId& extension_id,
+                                const std::string& script_id,
+                                const GURL& url);
+
   void set_activity_logging_enabled(bool enabled) {
     activity_logging_enabled_ = enabled;
   }
@@ -86,16 +91,9 @@
                    ScriptsRunInfo* scripts_run_info);
 
   // Handle the ExecuteCode extension message.
-  void HandleExecuteCode(const ExtensionMsg_ExecuteCode_Params& params,
+  void HandleExecuteCode(const mojom::ExecuteCodeParams& params,
                          content::RenderFrame* render_frame);
 
-  // Handle the ExecuteDeclarativeScript extension message.
-  void HandleExecuteDeclarativeScript(content::RenderFrame* web_frame,
-                                      int tab_id,
-                                      const ExtensionId& extension_id,
-                                      const std::string& script_id,
-                                      const GURL& url);
-
   // Handle the GrantInjectionPermission extension message.
   void HandlePermitScriptInjection(int64_t request_id);
 
diff --git a/extensions/shell/browser/shell_browser_main_parts.cc b/extensions/shell/browser/shell_browser_main_parts.cc
index afe5284d..f385009 100644
--- a/extensions/shell/browser/shell_browser_main_parts.cc
+++ b/extensions/shell/browser/shell_browser_main_parts.cc
@@ -164,7 +164,7 @@
 }
 
 int ShellBrowserMainParts::PreCreateThreads() {
-  // TODO(jamescook): Initialize chromeos::CrosSettings here?
+  // TODO(jamescook): Initialize ash::CrosSettings here?
 
   content::ChildProcessSecurityPolicy::GetInstance()->RegisterWebSafeScheme(
       kExtensionScheme);
diff --git a/gpu/command_buffer/service/framebuffer_manager.h b/gpu/command_buffer/service/framebuffer_manager.h
index 794df67..3b14720 100644
--- a/gpu/command_buffer/service/framebuffer_manager.h
+++ b/gpu/command_buffer/service/framebuffer_manager.h
@@ -12,6 +12,7 @@
 #include <unordered_map>
 #include <vector>
 
+#include "base/containers/small_map.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "gpu/command_buffer/service/context_group.h"
@@ -286,7 +287,8 @@
   unsigned framebuffer_complete_state_count_id_;
 
   // A map of attachments.
-  typedef std::unordered_map<GLenum, scoped_refptr<Attachment>> AttachmentMap;
+  using AttachmentMap =
+      base::small_map<std::unordered_map<GLenum, scoped_refptr<Attachment>>, 8>;
   AttachmentMap attachments_;
 
   // User's draw buffers setting through DrawBuffers() call.
diff --git a/ios/chrome/app/strings/resources/ios_chromium_strings_de.xtb b/ios/chrome/app/strings/resources/ios_chromium_strings_de.xtb
index c51f5fdc..faf3977 100644
--- a/ios/chrome/app/strings/resources/ios_chromium_strings_de.xtb
+++ b/ios/chrome/app/strings/resources/ios_chromium_strings_de.xtb
@@ -73,6 +73,7 @@
 <translation id="7746854981345936341">Chromium-Tipp: Manche Schaltflächen wie "Zurück", "Weiter" und "Suche" befinden sich jetzt unten auf dem Bildschirm.</translation>
 <translation id="786327964234957808">Sie stellen die Kontosynchronisierung von <ph name="USER_EMAIL1" /> auf <ph name="USER_EMAIL2" /> um. Ihre bestehenden Chromium-Daten werden von <ph name="DOMAIN" /> verwaltet. Dadurch werden Ihre Daten von diesem Gerät gelöscht, bleiben jedoch in <ph name="USER_EMAIL1" /> erhalten.</translation>
 <translation id="7890287942691234100">Jetzt Chromium-Scanner verwenden</translation>
+<translation id="7931842119211730154">Inkognitotabs sperren, wenn Chromium geschlossen wird</translation>
 <translation id="7980860476903281594">Chromium teilt Ihren Standort mit Websites, für die Sie das zulassen.</translation>
 <translation id="8013573822802650211">Melden Sie sich auf allen Ihren Geräten an, um Ihre Tabs überall dort aufzurufen, wo Sie Chromium verwenden</translation>
 <translation id="8073677936375100957">Ihre Chromium-Daten von diesem Gerät löschen?</translation>
diff --git a/ios/chrome/app/strings/resources/ios_chromium_strings_eu.xtb b/ios/chrome/app/strings/resources/ios_chromium_strings_eu.xtb
index eb16202..13f8af3 100644
--- a/ios/chrome/app/strings/resources/ios_chromium_strings_eu.xtb
+++ b/ios/chrome/app/strings/resources/ios_chromium_strings_eu.xtb
@@ -25,7 +25,7 @@
 <translation id="2650312721222849884">Chromium erabiltzen duzun gailu guztietan zure fitxak eskura izateko, aktibatu sinkronizazioa</translation>
 <translation id="2730884209570016437">Chromium-ek ezin du erabili kamera, beste aplikazio bat ari delako hura erabiltzen</translation>
 <translation id="2915596697727466327">Chromium-ek aurpegi bidezko identifikazioa erabiltzen du pasahitzak baimena dutenek bakarrik atzitzen dituztela ziurtatzeko.</translation>
-<translation id="2918709798697875261">Chromium-en saioa amaituta edukitzea eskatzen dizu erakundeak.</translation>
+<translation id="2918709798697875261">Chromium-en saioa amaituta edukitzea eskatzen dizu zure erakundeak.</translation>
 <translation id="2977470724722393594">Eguneratuta dago Chromium</translation>
 <translation id="3256316712990552818">Chromium-en kopiatu da</translation>
 <translation id="3344973607274501920">Chromium-ek ezin izan ditu egiaztatu pasahitzak. Egiaztatu Internetera konektatuta zaudela.</translation>
diff --git a/ios/chrome/app/strings/resources/ios_chromium_strings_pa.xtb b/ios/chrome/app/strings/resources/ios_chromium_strings_pa.xtb
index 34fa72a..c4828cd8 100644
--- a/ios/chrome/app/strings/resources/ios_chromium_strings_pa.xtb
+++ b/ios/chrome/app/strings/resources/ios_chromium_strings_pa.xtb
@@ -74,6 +74,7 @@
 <translation id="7746854981345936341">Chromium ਨੁਕਤਾ। ਹੁਣ ਕੁਝ ਬਟਨ ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ ਦੇ ਹੇਠਾਂ ਹਨ, ਜਿਵੇਂ ਕਿ ਪਿੱਛੇ, ਅੱਗੇ ਅਤੇ ਖੋਜੋ।</translation>
 <translation id="786327964234957808">ਤੁਸੀਂ ਸਮਕਾਲੀਕਿਰਤ ਖਾਤਿਆਂ ਨੂੰ <ph name="USER_EMAIL1" /> ਤੋਂ <ph name="USER_EMAIL2" /> ਵਿੱਚ ਬਦਲ ਰਹੇ ਹੋ। ਤੁਹਾਡਾ ਮੌਜੂਦਾ Chromium ਡਾਟਾ <ph name="DOMAIN" /> ਦੁਆਰਾ ਪ੍ਰਬੰਧਿਤ ਕੀਤਾ ਜਾਂਦਾ ਹੈ। ਇਸ ਨਾਲ ਤੁਹਾਡੇ ਡਾਟੇ ਨੂੰ ਇਸ ਡੀਵਾਈਸ ਤੋਂ ਮਿਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ, ਪਰ ਤੁਹਾਡਾ ਡਾਟਾ <ph name="USER_EMAIL1" /> ਵਿੱਚ ਮੌਜੂਦ ਰਹੇਗਾ।</translation>
 <translation id="7890287942691234100">Chromium ਸਕੈਨਰ ਵਰਤਣਾ ਸ਼ੁਰੂ ਕਰੋ</translation>
+<translation id="7931842119211730154">ਤੁਹਾਡੇ ਵੱਲੋਂ Chromium ਨੂੰ ਬੰਦ ਕੀਤੇ ਜਾਣ 'ਤੇ ਇਨਕੋਗਨਿਟੋ ਟੈਬਾਂ ਨੂੰ ਲਾਕ ਕਰੋ</translation>
 <translation id="7980860476903281594">Chromium ਤੁਹਾਡੇ ਵੱਲੋਂ ਆਗਿਆ ਦਿੱਤੀਆਂ ਸਾਈਟਾਂ ਨਾਲ ਤੁਹਾਡਾ ਟਿਕਾਣਾ ਸਾਂਝਾ ਕਰਦਾ ਹੈ।</translation>
 <translation id="8013573822802650211">ਜਿਸ ਡੀਵਾਈਸ 'ਤੇ ਵੀ ਤੁਸੀਂ Chromium ਵਰਤਦੇ ਹੋ, ਉੱਥੇ ਆਪਣੀਆਂ ਟੈਬਾਂ ਦੇਖਣ ਲਈ ਸਾਈਨ-ਇਨ ਕਰੋ</translation>
 <translation id="8073677936375100957">ਕੀ ਇਸ ਡੀਵਾਈਸ ਤੋਂ ਤੁਹਾਡਾ Chromium ਡਾਟਾ ਕਲੀਅਰ ਕਰਨਾ ਹੈ?</translation>
diff --git a/ios/chrome/app/strings/resources/ios_chromium_strings_uk.xtb b/ios/chrome/app/strings/resources/ios_chromium_strings_uk.xtb
index 7307abf..6717a54 100644
--- a/ios/chrome/app/strings/resources/ios_chromium_strings_uk.xtb
+++ b/ios/chrome/app/strings/resources/ios_chromium_strings_uk.xtb
@@ -74,7 +74,7 @@
 <translation id="7746854981345936341">Порада щодо Chromium. Деякі кнопки зараз розташовані внизу екрана, як-от "Назад", "Уперед" і "Пошук".</translation>
 <translation id="786327964234957808">Ви переходите з облікового запису <ph name="USER_EMAIL1" /> в обліковий запис <ph name="USER_EMAIL2" />. Наявними даними Chromium керує домен <ph name="DOMAIN" />. Ваші дані буде видалено з пристрою, але вони залишаться в обліковому записі <ph name="USER_EMAIL1" />.</translation>
 <translation id="7890287942691234100">Використовуйте сканер у Chromium</translation>
-<translation id="7931842119211730154">Блокувати анонімні вкладки після закриття Chromium</translation>
+<translation id="7931842119211730154">Блокувати доступ до анонімних вкладок після закриття Chromium</translation>
 <translation id="7980860476903281594">Chromium надає доступ до ваших геоданих тим сайтам, яким ви дозволили доступ до відповідної інформації.</translation>
 <translation id="8013573822802650211">Щоб переглядати свої вкладки Chromium на будь-якому пристрої, увійдіть на ньому в обліковий запис</translation>
 <translation id="8073677936375100957">Видалити дані Chromium із цього пристрою?</translation>
diff --git a/ios/chrome/app/strings/resources/ios_chromium_strings_zh-CN.xtb b/ios/chrome/app/strings/resources/ios_chromium_strings_zh-CN.xtb
index 3589417..3135c8e6 100644
--- a/ios/chrome/app/strings/resources/ios_chromium_strings_zh-CN.xtb
+++ b/ios/chrome/app/strings/resources/ios_chromium_strings_zh-CN.xtb
@@ -74,6 +74,7 @@
 <translation id="7746854981345936341">Chromium 提示。现在屏幕底部会显示“后退”、“前进”和“搜索”等按钮。</translation>
 <translation id="786327964234957808">您正要将同步帐号从 <ph name="USER_EMAIL1" /> 切换到 <ph name="USER_EMAIL2" />。您现有的 Chromium 数据由 <ph name="DOMAIN" /> 管理。切换同步帐号后,您的数据将从这台设备上删除,但仍会保留在 <ph name="USER_EMAIL1" /> 中。</translation>
 <translation id="7890287942691234100">开始使用 Chromium 扫描器</translation>
+<translation id="7931842119211730154">在您关闭 Chromium 时锁定无痕式标签页</translation>
 <translation id="7980860476903281594">Chromium 会将您的位置信息分享给您允许的网站。</translation>
 <translation id="8013573822802650211">要查看您在其他设备上用 Chromium 打开的标签页,请在所有设备上登录</translation>
 <translation id="8073677936375100957">从这部设备中清除您的 Chromium 数据?</translation>
diff --git a/ios/chrome/app/strings/resources/ios_google_chrome_strings_eu.xtb b/ios/chrome/app/strings/resources/ios_google_chrome_strings_eu.xtb
index 6327548..84ea6a6 100644
--- a/ios/chrome/app/strings/resources/ios_google_chrome_strings_eu.xtb
+++ b/ios/chrome/app/strings/resources/ios_google_chrome_strings_eu.xtb
@@ -34,7 +34,7 @@
 <translation id="384394811301901750">Google Chrome-k ezin du erabili kamera une honetan</translation>
 <translation id="38949020760388809">Erabaki gailu honetatik Chrome-ko datuak garbitu nahi dituzun ala ez.</translation>
 <translation id="3980220367029651214"><ph name="USER_EMAIL2" /> ezarri duzu sinkronizazio-kontu gisa, orain arte zenerabilen <ph name="USER_EMAIL1" /> kontuaren ordez. Lehendik dituzun Chrome datuak <ph name="DOMAIN" /> domeinuak kudeatzen ditu. Horrela, datuak gailutik ezabatuko dira, baina <ph name="USER_EMAIL1" /> kontuan egoten jarraituko dute.</translation>
-<translation id="3984746313391923992">Chrome-n saioa amaituta edukitzea eskatzen du erakundeak.</translation>
+<translation id="3984746313391923992">Chrome-n saioa amaituta edukitzea eskatzen dizu zure erakundeak.</translation>
 <translation id="3988789688219830639">Google Chrome-k ez du argazki eta bideoetarako sarbiderik. Gaitu ezazu iOS sistemako Settings &gt; Privacy &gt; Photos atalean.</translation>
 <translation id="4099578267706723511">Hobetu Chrome Google-ri erabilera-estatistikak eta hutsegite-txostenak bidalita.</translation>
 <translation id="415767770115540173">Atera etekin handiagoa Chrome-ri Google-n, zure kokapenaren arabera.</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_ar.xtb b/ios/chrome/app/strings/resources/ios_strings_ar.xtb
index 7e7eae3..27828b4b 100644
--- a/ios/chrome/app/strings/resources/ios_strings_ar.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_ar.xtb
@@ -584,7 +584,7 @@
 <translation id="6988572888918530647">‏إدارة حسابك على Google</translation>
 <translation id="6995899638241819463">التحذير إذا تم الكشف عن كلمات المرور في عملية اختراق بيانات</translation>
 <translation id="6998989275928107238">إلى</translation>
-<translation id="7004032350256606903">تطلُب مؤسستك منك التصفُّح بخصوصية تامّة.
+<translation id="7004032350256606903">تفرض مؤسستك سياسة التصفُّح بخصوصية تامّة.
 <ph name="BEGIN_LINK" />مزيد من المعلومات<ph name="END_LINK" /></translation>
 <translation id="7004499039102548441">علامات التبويب الأخيرة</translation>
 <translation id="7006788746334555276">إعدادات المحتوى</translation>
@@ -747,7 +747,7 @@
 <translation id="8756969031206844760">هل تريد تحديث كلمة المرور؟</translation>
 <translation id="8775144690796719618">‏عنوان URL غير صالح</translation>
 <translation id="8803639129939845298">آمن</translation>
-<translation id="8806823403540278281">تطلُب مؤسستك منك التصفُّح بخصوصية تامّة. ولن يتم حفظ علامات التبويب في "وضع التصفُّح المتخفي".
+<translation id="8806823403540278281">تفرض مؤسستك سياسة التصفُّح بخصوصية تامّة. ولن يتم حفظ علامات التبويب في "وضع التصفُّح المتخفي".
 <ph name="BEGIN_LINK" />مزيد من المعلومات<ph name="END_LINK" /></translation>
 <translation id="8820817407110198400">الإشارات المرجعية</translation>
 <translation id="8840513115188359703">‏لن يتم تسجيل خروجك من حساب Google.</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_de.xtb b/ios/chrome/app/strings/resources/ios_strings_de.xtb
index 8e1c065..1b451753 100644
--- a/ios/chrome/app/strings/resources/ios_strings_de.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_de.xtb
@@ -538,6 +538,8 @@
 <translation id="6524918542306337007">Inkognitomodus ist nicht verfügbar</translation>
 <translation id="6561262006871132942">Heranzoomen</translation>
 <translation id="6585618849026997638">Sie können Lesezeichen setzen, damit Sie zu Seiten zurückfinden, die für Sie interessant sind</translation>
+<translation id="6603393121510733479">Ihre Organisation hat das private Surfen deaktiviert.
+<ph name="BEGIN_LINK" />Weitere Informationen<ph name="END_LINK" /></translation>
 <translation id="6610002944194042868">Übersetzungsoptionen</translation>
 <translation id="6620279676667515405">Abbrechen</translation>
 <translation id="6624219055418309072">Im Inkognitomodus blockieren</translation>
@@ -582,6 +584,8 @@
 <translation id="6988572888918530647">Google-Konto verwalten</translation>
 <translation id="6995899638241819463">Warnen, wenn Passwörter durch eine Datenpanne preisgegeben werden</translation>
 <translation id="6998989275928107238">An</translation>
+<translation id="7004032350256606903">Ihre Organisation verlangt, dass Sie im privaten Modus surfen.
+<ph name="BEGIN_LINK" />Weitere Informationen<ph name="END_LINK" /></translation>
 <translation id="7004499039102548441">Zuletzt geöffnete Tabs</translation>
 <translation id="7006788746334555276">Inhaltseinstellungen</translation>
 <translation id="7015203776128479407">Die erstmalige Einrichtung der Synchronisierung wurde nicht abgeschlossen. Synchronisierung ist deaktiviert.</translation>
@@ -743,6 +747,8 @@
 <translation id="8756969031206844760">Passwort aktualisieren?</translation>
 <translation id="8775144690796719618">Ungültige URL</translation>
 <translation id="8803639129939845298">Sicher</translation>
+<translation id="8806823403540278281">Ihre Organisation verlangt, dass Sie im privaten Modus surfen. Tabs werden im Inkognitomodus nicht gespeichert.
+<ph name="BEGIN_LINK" />Weitere Informationen<ph name="END_LINK" /></translation>
 <translation id="8820817407110198400">Lesezeichen</translation>
 <translation id="8840513115188359703">Sie werden nicht von Ihrem Google-Konto abgemeldet.</translation>
 <translation id="8870413625673593573">Kürzlich geschlossen</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_gu.xtb b/ios/chrome/app/strings/resources/ios_strings_gu.xtb
index 958891e..1e6ce20 100644
--- a/ios/chrome/app/strings/resources/ios_strings_gu.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_gu.xtb
@@ -708,7 +708,7 @@
 <translation id="8407669440184693619">આ સાઇટ માટે કોઈ પાસવર્ડ મળ્યાં નથી</translation>
 <translation id="842017693807136194">ની સાથે સાઇન ઇન કરેલ</translation>
 <translation id="8428045167754449968">શહેર/નગર</translation>
-<translation id="8428213095426709021">સેટિંગ્સ</translation>
+<translation id="8428213095426709021">સેટિંગ</translation>
 <translation id="8446884382197647889">વધુ જાણો</translation>
 <translation id="8458397775385147834">1 આઇટમ કાઢી નાખી</translation>
 <translation id="8459333855531264009">સુરક્ષિત નથી</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_or.xtb b/ios/chrome/app/strings/resources/ios_strings_or.xtb
index c92eff9..5ce2018 100644
--- a/ios/chrome/app/strings/resources/ios_strings_or.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_or.xtb
@@ -536,7 +536,7 @@
 <translation id="6524918542306337007">ଇନକଗ୍ନିଟୋ ମୋଡ୍ ଉପଲବ୍ଧ ନାହିଁ</translation>
 <translation id="6561262006871132942">ଜୁମ୍ ଇନ୍ କରନ୍ତୁ</translation>
 <translation id="6585618849026997638">ଆପଣ ଏକ ବୁକମାର୍କ ଯୋଗ କରି ଆପଣଙ୍କ ପାଇଁ ଗୁରୁତ୍ୱପୂର୍ଣ୍ଣ ଥିବା ଏକ ପୃଷ୍ଠାକୁ ଫେରି ପାରିବେ</translation>
-<translation id="6603393121510733479">ଆପଣଙ୍କ ସଂସ୍ଥା ବ୍ୟକ୍ତିଗତ ବ୍ରାଉଜିଂକୁ ବନ୍ଦ କରି ଦେଇଛି।
+<translation id="6603393121510733479">ଆପଣଙ୍କ ସଂସ୍ଥା ପ୍ରାଇଭେଟ୍ ବ୍ରାଉଜିଂକୁ ବନ୍ଦ କରି ଦେଇଛି।
 <ph name="BEGIN_LINK" />ଅଧିକ ଜାଣନ୍ତୁ<ph name="END_LINK" /></translation>
 <translation id="6610002944194042868">ଅନୁବାଦର ବିକଳ୍ପଗୁଡ଼ିକ</translation>
 <translation id="6620279676667515405">ବାତିଲ୍ କରନ୍ତୁ</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_pa.xtb b/ios/chrome/app/strings/resources/ios_strings_pa.xtb
index 8aa2c03..c0207af 100644
--- a/ios/chrome/app/strings/resources/ios_strings_pa.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_pa.xtb
@@ -536,6 +536,8 @@
 <translation id="6524918542306337007">ਇਨਕੋਗਨਿਟੋ ਮੋਡ ਉਪਲਬਧ ਨਹੀਂ ਹੈ</translation>
 <translation id="6561262006871132942">ਜ਼ੂਮ ਵਧਾਓ</translation>
 <translation id="6585618849026997638">ਬੁੱਕਮਾਰਕ ਸ਼ਾਮਲ ਕਰਕੇ ਤੁਸੀਂ ਉਸ ਪੰਨੇ 'ਤੇ ਆਸਾਨੀ ਨਾਲ ਵਾਪਸ ਜਾ ਸਕਦੇ ਹੋ ਜੋ ਤੁਹਾਡੇ ਲਈ ਮਹੱਤਵਪੂਰਨ ਹੈ</translation>
+<translation id="6603393121510733479">ਤੁਹਾਡੀ ਸੰਸਥਾ ਨੇ ਨਿੱਜੀ ਬ੍ਰਾਊਜ਼ਿੰਗ ਨੂੰ ਬੰਦ ਕਰ ਦਿੱਤਾ ਹੈ।
+<ph name="BEGIN_LINK" />ਹੋਰ ਜਾਣੋ<ph name="END_LINK" /></translation>
 <translation id="6610002944194042868">ਅਨੁਵਾਦ ਵਿਕਲਪ</translation>
 <translation id="6620279676667515405">ਰੱਦ ਕਰੋ</translation>
 <translation id="6624219055418309072">ਇਨਕੋਗਨਿਟੋ ਵਿੱਚ ਬਲਾਕ ਕਰੋ</translation>
@@ -580,6 +582,8 @@
 <translation id="6988572888918530647">ਆਪਣੇ Google ਖਾਤੇ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ</translation>
 <translation id="6995899638241819463">ਡਾਟਾ ਉਲੰਘਣਾ ਵਜੋਂ ਪਾਸਵਰਡਾਂ ਦਾ ਖੁਲਾਸਾ ਹੋਣ 'ਤੇ ਤੁਹਾਨੂੰ ਚਿਤਾਵਨੀ ਦਿੱਤੀ ਜਾਵੇ</translation>
 <translation id="6998989275928107238">ਨੂੰ</translation>
+<translation id="7004032350256606903">ਤੁਹਾਡੀ ਸੰਸਥਾ ਲਈ ਤੁਹਾਨੂੰ ਨਿੱਜੀ ਤੌਰ 'ਤੇ ਬ੍ਰਾਊਜ਼ ਕਰਨ ਦੀ ਲੋੜ ਹੈ।
+<ph name="BEGIN_LINK" />ਹੋਰ ਜਾਣੋ<ph name="END_LINK" /></translation>
 <translation id="7004499039102548441">ਹਾਲੀਆ ਟੈਬਸ</translation>
 <translation id="7006788746334555276">ਸਮੱਗਰੀ ਸੈਟਿੰਗਾਂ</translation>
 <translation id="7015203776128479407">ਮੁੱਢਲਾ ਸਮਕਾਲੀਕਰਨ ਸੈੱਟਅੱਪ ਪੂਰਾ ਨਹੀਂ ਹੋਇਆ। ਸਮਕਾਲੀਕਰਨ ਬੰਦ ਹੈ।</translation>
@@ -741,6 +745,8 @@
 <translation id="8756969031206844760">ਕੀ ਪਾਸਵਰਡ ਅੱਪਡੇਟ ਕਰਨਾ ਹੈ?</translation>
 <translation id="8775144690796719618">ਅਵੈਧ URL</translation>
 <translation id="8803639129939845298">ਸੁਰੱਖਿਅਤ</translation>
+<translation id="8806823403540278281">ਤੁਹਾਡੀ ਸੰਸਥਾ ਲਈ ਤੁਹਾਨੂੰ ਨਿੱਜੀ ਤੌਰ 'ਤੇ ਬ੍ਰਾਊਜ਼ ਕਰਨ ਦੀ ਲੋੜ ਹੈ। ਇਨਕੋਗਨਿਟੋ ਮੋਡ ਵਿੱਚ ਟੈਬਾਂ ਰੱਖਿਅਤ ਨਹੀਂ ਹੁੰਦੀਆਂ ਹਨ।
+<ph name="BEGIN_LINK" />ਹੋਰ ਜਾਣੋ<ph name="END_LINK" /></translation>
 <translation id="8820817407110198400">Bookmarks</translation>
 <translation id="8840513115188359703">ਤੁਸੀਂ ਆਪਣੇ 'Google ਖਾਤੇ' ਤੋਂ ਸਾਈਨ-ਆਊਟ ਨਹੀਂ ਹੋਵੋਗੇ।</translation>
 <translation id="8870413625673593573">ਹੁਣੇ ਜਿਹੇ ਬੰਦ ਕੀਤੀਆਂ</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_zh-CN.xtb b/ios/chrome/app/strings/resources/ios_strings_zh-CN.xtb
index 0dc91d9..711cdd3 100644
--- a/ios/chrome/app/strings/resources/ios_strings_zh-CN.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_zh-CN.xtb
@@ -538,6 +538,8 @@
 <translation id="6524918542306337007">无痕模式不可用</translation>
 <translation id="6561262006871132942">放大</translation>
 <translation id="6585618849026997638">您可以为重要网页添加书签以便返回查看</translation>
+<translation id="6603393121510733479">贵单位关闭了无痕浏览。
+<ph name="BEGIN_LINK" />了解详情<ph name="END_LINK" /></translation>
 <translation id="6610002944194042868">翻译选项</translation>
 <translation id="6620279676667515405">取消</translation>
 <translation id="6624219055418309072">在无痕模式下阻止</translation>
@@ -582,6 +584,8 @@
 <translation id="6988572888918530647">管理 Google 帐号</translation>
 <translation id="6995899638241819463">当密码遭遇数据泄露时,发送警告</translation>
 <translation id="6998989275928107238">至</translation>
+<translation id="7004032350256606903">贵单位要求您进行无痕浏览。
+<ph name="BEGIN_LINK" />了解详情<ph name="END_LINK" /></translation>
 <translation id="7004499039102548441">最近打开的标签页</translation>
 <translation id="7006788746334555276">内容设置</translation>
 <translation id="7015203776128479407">初始同步设置未完成。同步功能处于关闭状态。</translation>
@@ -743,6 +747,8 @@
 <translation id="8756969031206844760">要更新密码吗?</translation>
 <translation id="8775144690796719618">网址无效</translation>
 <translation id="8803639129939845298">安全</translation>
+<translation id="8806823403540278281">贵单位要求您进行无痕浏览。在无痕模式下,系统不会保存标签页。
+<ph name="BEGIN_LINK" />了解详情<ph name="END_LINK" /></translation>
 <translation id="8820817407110198400">书签</translation>
 <translation id="8840513115188359703">您不会因此而退出自己的 Google 帐号。</translation>
 <translation id="8870413625673593573">最近关闭的标签页</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_zh-HK.xtb b/ios/chrome/app/strings/resources/ios_strings_zh-HK.xtb
index b37049a..3922f53 100644
--- a/ios/chrome/app/strings/resources/ios_strings_zh-HK.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_zh-HK.xtb
@@ -685,7 +685,7 @@
 <translation id="8059533439631660104">收合這個專區。</translation>
 <translation id="8065292699993359127">在 Chrome 中以無痕模式開啟網址</translation>
 <translation id="806745655614357130">分開保留我的資料</translation>
-<translation id="8073670137947914548">已經下載完成</translation>
+<translation id="8073670137947914548">下載完畢</translation>
 <translation id="8073872304774253879">改善搜尋和瀏覽體驗</translation>
 <translation id="8076014560081431679">系統不會刪除已儲存的網站設定,這可能會反映您的瀏覽習慣。<ph name="BEGIN_LINK" />瞭解詳情<ph name="END_LINK" /></translation>
 <translation id="8079602123447022758">呢個設定已經受管理,㩒兩下就可以了解詳情</translation>
diff --git a/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_view_controller.mm b/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_view_controller.mm
index 3607e4e8..ad9d17ab 100644
--- a/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_view_controller.mm
+++ b/ios/chrome/browser/ui/authentication/unified_consent/unified_consent_view_controller.mm
@@ -365,6 +365,7 @@
       GURL(kSettingsSyncURL), GetApplicationContext()->GetApplicationLocale());
   NSString* text = self.customizeSyncLabel.text;
 
+  // TODO(crbug.com/1184151): Move to use AttributedStringFromStringWithLink.
   const StringWithTag parsedString = ParseStringWithLink(text);
   DCHECK(parsedString.range != NSMakeRange(NSNotFound, 0));
   self.customizeSyncLabel.text = parsedString.string;
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_learn_more_item.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_learn_more_item.mm
index 013b036..58e3a53f 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_learn_more_item.mm
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_learn_more_item.mm
@@ -8,7 +8,6 @@
 #import <MaterialComponents/MaterialTypography.h>
 
 #include "base/check_op.h"
-#include "base/ios/ns_range.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_constants.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
 #include "ios/chrome/common/string_util.h"
@@ -113,26 +112,19 @@
   label.textColor = [[MDCPalette greyPalette] tint700];
   label.font = [UIFont preferredFontForTextStyle:UIFontTextStyleFootnote];
 
-  const StringWithTag parsedString = ParseStringWithLink(text);
-  DCHECK(parsedString.range != NSMakeRange(NSNotFound, 0));
-
-  NSMutableAttributedString* attributedText =
-      [[NSMutableAttributedString alloc] initWithString:parsedString.string];
-
-  // Sets the styling to mimic a link.
-  UIColor* linkColor = [UIColor colorNamed:kBlueColor];
-  [attributedText addAttribute:NSForegroundColorAttributeName
-                         value:linkColor
-                         range:parsedString.range];
-
   // Sets the line spacing on the attributed string.
-  NSInteger strLength = parsedString.string.length;
   NSMutableParagraphStyle* style = [[NSMutableParagraphStyle alloc] init];
   [style setLineSpacing:kLabelLineSpacing];
-  [attributedText addAttribute:NSParagraphStyleAttributeName
-                         value:style
-                         range:NSMakeRange(0, strLength)];
 
+  NSDictionary* textAttributes = @{
+    NSParagraphStyleAttributeName : style,
+  };
+  // Sets the styling to mimic a link.
+  NSDictionary* linkAttributes =
+      @{NSForegroundColorAttributeName : [UIColor colorNamed:kBlueColor]};
+
+  NSAttributedString* attributedText =
+      AttributedStringFromStringWithLink(text, textAttributes, linkAttributes);
   [label setAttributedText:attributedText];
 }
 
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_whats_new_item.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_whats_new_item.mm
index 59ed479..5ce858a 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_whats_new_item.mm
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_whats_new_item.mm
@@ -7,7 +7,6 @@
 #import <MaterialComponents/MaterialTypography.h>
 
 #include "base/check_op.h"
-#include "base/ios/ns_range.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
 #include "ios/chrome/common/string_util.h"
 #import "ios/chrome/common/ui/colors/semantic_color_names.h"
@@ -162,31 +161,22 @@
   promoLabel.textColor = [UIColor colorNamed:kTextPrimaryColor];
   promoLabel.numberOfLines = 0;
 
-  const StringWithTag parsedString = ParseStringWithLink(text);
-  DCHECK(parsedString.range != NSMakeRange(NSNotFound, 0));
-
-  NSMutableAttributedString* attributedText =
-      [[NSMutableAttributedString alloc] initWithString:parsedString.string];
-
-  // Sets the styling to mimic a link.
-  UIColor* linkColor = [UIColor colorNamed:kBlueColor];
-  [attributedText addAttribute:NSForegroundColorAttributeName
-                         value:linkColor
-                         range:parsedString.range];
-  [attributedText addAttribute:NSUnderlineStyleAttributeName
-                         value:@(NSUnderlineStyleSingle)
-                         range:parsedString.range];
-  [attributedText addAttribute:NSUnderlineColorAttributeName
-                         value:linkColor
-                         range:parsedString.range];
-
   // Sets the line spacing on the attributed string.
-  NSInteger strLength = parsedString.string.length;
   NSMutableParagraphStyle* style = [[NSMutableParagraphStyle alloc] init];
   [style setLineSpacing:kLabelLineSpacing];
-  [attributedText addAttribute:NSParagraphStyleAttributeName
-                         value:style
-                         range:NSMakeRange(0, strLength)];
+  NSDictionary* textAttributes = @{
+    NSParagraphStyleAttributeName : style,
+  };
+
+  // Sets the styling to mimic a link.
+  NSDictionary* linkAttributes = @{
+    NSForegroundColorAttributeName : [UIColor colorNamed:kBlueColor],
+    NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle),
+    NSUnderlineColorAttributeName : [UIColor colorNamed:kBlueColor],
+  };
+
+  NSAttributedString* attributedText =
+      AttributedStringFromStringWithLink(text, textAttributes, linkAttributes);
 
   [promoLabel setAttributedText:attributedText];
 }
diff --git a/ios/chrome/browser/ui/popup_menu/cells/popup_menu_text_item.mm b/ios/chrome/browser/ui/popup_menu/cells/popup_menu_text_item.mm
index 8d77964e..8d5e077 100644
--- a/ios/chrome/browser/ui/popup_menu/cells/popup_menu_text_item.mm
+++ b/ios/chrome/browser/ui/popup_menu/cells/popup_menu_text_item.mm
@@ -30,26 +30,21 @@
 
 NSMutableAttributedString* GetAttributedString(NSString* imageName,
                                                NSString* message) {
-  // Add a space to have a distance with the leading icon.
-  const StringWithTag parsedString =
-      ParseStringWithLink([@" " stringByAppendingString:message]);
-
-  NSDictionary* generalAttributes = @{
+  NSDictionary* textAttributes = @{
     NSForegroundColorAttributeName : [UIColor colorNamed:kTextSecondaryColor],
     NSFontAttributeName :
         [UIFont preferredFontForTextStyle:UIFontTextStyleFootnote]
   };
 
-  NSMutableAttributedString* attributedString =
-      [[NSMutableAttributedString alloc] initWithString:parsedString.string
-                                             attributes:generalAttributes];
-
   NSDictionary* linkAttributes = @{
     NSForegroundColorAttributeName : [UIColor colorNamed:kBlueColor],
     NSFontAttributeName :
         [UIFont preferredFontForTextStyle:UIFontTextStyleFootnote]
   };
-  [attributedString setAttributes:linkAttributes range:parsedString.range];
+
+  // Add a space to have a distance with the leading icon.
+  NSAttributedString* attributedString = AttributedStringFromStringWithLink(
+      [@" " stringByAppendingString:message], textAttributes, linkAttributes);
 
   // Create the leading enterprise icon.
   NSTextAttachment* attachment = [[NSTextAttachment alloc] init];
@@ -63,12 +58,11 @@
   CGFloat verticalOffset = roundf(capHeight - height) / 2.f;
   attachment.bounds = CGRectMake(0, verticalOffset, height, height);
 
-  NSAttributedString* attachmentString =
-      [NSAttributedString attributedStringWithAttachment:attachment];
+  NSMutableAttributedString* outputString = [[NSAttributedString
+      attributedStringWithAttachment:attachment] mutableCopy];
+  [outputString appendAttributedString:attributedString];
 
-  [attributedString insertAttributedString:attachmentString atIndex:0];
-
-  return attributedString;
+  return outputString;
 }
 
 }  // namespace
diff --git a/ios/chrome/browser/ui/settings/elements/enterprise_info_popover_view_controller.mm b/ios/chrome/browser/ui/settings/elements/enterprise_info_popover_view_controller.mm
index a923541..d743a4c 100644
--- a/ios/chrome/browser/ui/settings/elements/enterprise_info_popover_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/elements/enterprise_info_popover_view_controller.mm
@@ -46,18 +46,11 @@
         IDS_IOS_ENTERPRISE_MANAGED_SETTING_DESC_WITHOUT_COMPANY_NAME);
   }
 
-  // Add a space to have a distanse with the leading icon.
-  const StringWithTag parsedString =
-      ParseStringWithLink([@" " stringByAppendingString:message]);
-
-  NSDictionary* generalAttributes = @{
+  NSDictionary* textAttributes = @{
     NSForegroundColorAttributeName : [UIColor colorNamed:kTextSecondaryColor],
     NSFontAttributeName :
         [UIFont preferredFontForTextStyle:UIFontTextStyleFootnote]
   };
-  NSMutableAttributedString* attributedString =
-      [[NSMutableAttributedString alloc] initWithString:parsedString.string
-                                             attributes:generalAttributes];
 
   NSDictionary* linkAttributes = @{
     NSForegroundColorAttributeName : [UIColor colorNamed:kBlueColor],
@@ -66,7 +59,10 @@
     NSLinkAttributeName :
         [NSString stringWithUTF8String:kChromeUIManagementURL],
   };
-  [attributedString setAttributes:linkAttributes range:parsedString.range];
+
+  // Add a space to have a distance with the leading icon.
+  NSAttributedString* attributedString = AttributedStringFromStringWithLink(
+      [@" " stringByAppendingString:message], textAttributes, linkAttributes);
 
   // Create the leading enterprise icon.
   NSTextAttachment* attachment = [[NSTextAttachment alloc] init];
diff --git a/ios/chrome/browser/ui/settings/password/passwords_mediator.mm b/ios/chrome/browser/ui/settings/password/passwords_mediator.mm
index 614b64c..606de41 100644
--- a/ios/chrome/browser/ui/settings/password/passwords_mediator.mm
+++ b/ios/chrome/browser/ui/settings/password/passwords_mediator.mm
@@ -4,7 +4,6 @@
 
 #import "ios/chrome/browser/ui/settings/password/passwords_mediator.h"
 
-#include "base/ios/ns_range.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
@@ -160,7 +159,11 @@
     return nil;
 
   NSString* message;
-  GURL linkURL;
+  NSDictionary* textAttributes = @{
+    NSForegroundColorAttributeName : [UIColor colorNamed:kTextSecondaryColor],
+    NSFontAttributeName :
+        [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline]
+  };
 
   switch (_currentState) {
     case PasswordCheckState::kRunning:
@@ -178,8 +181,14 @@
       if ([self canUseAccountPasswordCheckup]) {
         message = l10n_util::GetNSString(
             IDS_IOS_PASSWORD_CHECK_ERROR_QUOTA_LIMIT_VISIT_GOOGLE);
-        linkURL = password_manager::GetPasswordCheckupURL(
-            password_manager::PasswordCheckupReferrer::kPasswordCheck);
+        NSDictionary* linkAttributes = @{
+          NSLinkAttributeName :
+              net::NSURLWithGURL(password_manager::GetPasswordCheckupURL(
+                  password_manager::PasswordCheckupReferrer::kPasswordCheck))
+        };
+
+        return AttributedStringFromStringWithLink(message, textAttributes,
+                                                  linkAttributes);
       } else {
         message =
             l10n_util::GetNSString(IDS_IOS_PASSWORD_CHECK_ERROR_QUOTA_LIMIT);
@@ -189,7 +198,8 @@
       message = l10n_util::GetNSString(IDS_IOS_PASSWORD_CHECK_ERROR_OTHER);
       break;
   }
-  return [self configureTextWithLink:message link:linkURL];
+  return [[NSMutableAttributedString alloc] initWithString:message
+                                                attributes:textAttributes];
 }
 
 #pragma mark - PasswordCheckObserver
@@ -260,33 +270,6 @@
          !_syncService->IsEncryptEverythingEnabled();
 }
 
-// Configures text for Error Info Popover.
-- (NSAttributedString*)configureTextWithLink:(NSString*)text link:(GURL)link {
-  const StringWithTag parsedString = ParseStringWithLink(text);
-
-  NSRange fullRange = NSMakeRange(0, parsedString.string.length);
-  NSMutableAttributedString* attributedText =
-      [[NSMutableAttributedString alloc] initWithString:parsedString.string];
-  [attributedText addAttribute:NSForegroundColorAttributeName
-                         value:[UIColor colorNamed:kTextSecondaryColor]
-                         range:fullRange];
-
-  [attributedText
-      addAttribute:NSFontAttributeName
-             value:[UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline]
-             range:fullRange];
-
-  if (parsedString.range != NSMakeRange(NSNotFound, 0)) {
-    NSURL* URL = net::NSURLWithGURL(link);
-    id linkValue = URL ? URL : @"";
-    [attributedText addAttribute:NSLinkAttributeName
-                           value:linkValue
-                           range:parsedString.range];
-  }
-
-  return attributedText;
-}
-
 #pragma mark - PasswordStoreObserver
 
 - (void)loginsDidChange {
diff --git a/ios/chrome/browser/ui/settings/safety_check/safety_check_mediator.mm b/ios/chrome/browser/ui/settings/safety_check/safety_check_mediator.mm
index c4929df..0ed239c 100644
--- a/ios/chrome/browser/ui/settings/safety_check/safety_check_mediator.mm
+++ b/ios/chrome/browser/ui/settings/safety_check/safety_check_mediator.mm
@@ -4,7 +4,6 @@
 
 #import "ios/chrome/browser/ui/settings/safety_check/safety_check_mediator.h"
 
-#include "base/ios/ns_range.h"
 #include "base/mac/foundation_util.h"
 #import "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
@@ -554,7 +553,6 @@
 // Computes the appropriate error info to be displayed in the updates popover.
 - (NSAttributedString*)updateCheckErrorInfoString {
   NSString* message;
-  GURL linkURL;
 
   switch (self.updateCheckRowState) {
     case UpdateCheckRowStateDefault:
@@ -574,7 +572,7 @@
     case UpdateCheckRowStateChannel:
       break;
   }
-  return [self attributedStringWithText:message link:linkURL];
+  return [self attributedStringWithText:message link:GURL()];
 }
 
 // Computes the appropriate error info to be displayed in the passwords popover.
@@ -628,28 +626,21 @@
 // Configures check error info with a link for popovers.
 - (NSAttributedString*)attributedStringWithText:(NSString*)text
                                            link:(GURL)link {
-  const StringWithTag parsedString = ParseStringWithLink(text);
+  NSDictionary* textAttributes = @{
+    NSFontAttributeName :
+        [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline],
+    NSForegroundColorAttributeName : [UIColor colorNamed:kTextSecondaryColor]
+  };
 
-  NSRange fullRange = NSMakeRange(0, parsedString.string.length);
-  NSMutableAttributedString* attributedText =
-      [[NSMutableAttributedString alloc] initWithString:parsedString.string];
-  [attributedText addAttribute:NSForegroundColorAttributeName
-                         value:[UIColor colorNamed:kTextSecondaryColor]
-                         range:fullRange];
-
-  [attributedText
-      addAttribute:NSFontAttributeName
-             value:[UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline]
-             range:fullRange];
-
-  if (parsedString.range != NSMakeRange(NSNotFound, 0)) {
-    NSURL* URL = net::NSURLWithGURL(link);
-    id linkValue = URL ? URL : @"";
-    [attributedText addAttribute:NSLinkAttributeName
-                           value:linkValue
-                           range:parsedString.range];
+  if (link.is_empty()) {
+    return [[NSMutableAttributedString alloc] initWithString:text
+                                                  attributes:textAttributes];
   }
-  return attributedText;
+  NSDictionary* linkAttributes =
+      @{NSLinkAttributeName : net::NSURLWithGURL(link)};
+
+  return AttributedStringFromStringWithLink(text, textAttributes,
+                                            linkAttributes);
 }
 
 // Upon a tap of checkStartItem either starts or cancels a safety check.
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/disabled_tab_view_controller.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/disabled_tab_view_controller.mm
index 23c544c3..52d2be6f 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/disabled_tab_view_controller.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/disabled_tab_view_controller.mm
@@ -4,7 +4,6 @@
 
 #import "ios/chrome/browser/ui/tab_switcher/tab_grid/disabled_tab_view_controller.h"
 
-#include "base/ios/ns_range.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_constants.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_constants.h"
@@ -53,7 +52,7 @@
 }
 
 // Creates an attribute string with link for the body message.
-NSMutableAttributedString* GetBodyString(TabGridPage page) {
+NSAttributedString* GetBodyString(TabGridPage page) {
   int messageID;
   switch (page) {
     case TabGridPageIncognitoTabs:
@@ -68,12 +67,8 @@
   }
 
   NSString* fullText = l10n_util::GetNSString(messageID);
-  const StringWithTag parsedString = ParseStringWithLink(fullText);
-  DCHECK(parsedString.range != NSMakeRange(NSNotFound, 0));
 
-  NSMutableAttributedString* attributedString =
-      [[NSMutableAttributedString alloc] initWithString:parsedString.string];
-
+  // Sets the styling to mimic a link.
   NSDictionary* linkAttributes = @{
     NSForegroundColorAttributeName : [UIColor colorNamed:kBlueColor],
     NSLinkAttributeName :
@@ -82,9 +77,8 @@
         [UIFont preferredFontForTextStyle:UIFontTextStyleFootnote],
     NSUnderlineStyleAttributeName : @(NSUnderlineStyleNone),
   };
-  [attributedString setAttributes:linkAttributes range:parsedString.range];
 
-  return attributedString;
+  return AttributedStringFromStringWithLink(fullText, @{}, linkAttributes);
 }
 
 }  // namespace
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_link_header_footer_item.mm b/ios/chrome/browser/ui/table_view/cells/table_view_link_header_footer_item.mm
index 0bc6a7e1..10381ac 100644
--- a/ios/chrome/browser/ui/table_view/cells/table_view_link_header_footer_item.mm
+++ b/ios/chrome/browser/ui/table_view/cells/table_view_link_header_footer_item.mm
@@ -4,7 +4,6 @@
 
 #import "ios/chrome/browser/ui/table_view/cells/table_view_link_header_footer_item.h"
 
-#include "base/ios/ns_range.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h"
 #include "ios/chrome/browser/ui/ui_feature_flags.h"
 #import "ios/chrome/browser/ui/util/ui_util.h"
@@ -109,26 +108,22 @@
 }
 
 - (void)setText:(NSString*)text {
-  const StringWithTag parsedString = ParseStringWithLink(text);
-  NSRange fullRange = NSMakeRange(0, parsedString.string.length);
-  NSMutableAttributedString* attributedText =
-      [[NSMutableAttributedString alloc] initWithString:parsedString.string];
-  [attributedText addAttribute:NSForegroundColorAttributeName
-                         value:UIColor.cr_secondaryLabelColor
-                         range:fullRange];
+  NSDictionary* textAttributes = @{
+    NSFontAttributeName :
+        [UIFont preferredFontForTextStyle:kTableViewSublabelFontStyle],
+    NSForegroundColorAttributeName : UIColor.cr_secondaryLabelColor
+  };
 
-  [attributedText
-      addAttribute:NSFontAttributeName
-             value:[UIFont
-                       preferredFontForTextStyle:kTableViewSublabelFontStyle]
-             range:fullRange];
-
-  if (parsedString.range != NSMakeRange(NSNotFound, 0)) {
-    NSURL* URL = net::NSURLWithGURL(self.linkURL);
-    id linkValue = URL ? URL : @"";
-    [attributedText addAttribute:NSLinkAttributeName
-                           value:linkValue
-                           range:parsedString.range];
+  NSAttributedString* attributedText;
+  if (self.linkURL.is_empty()) {
+    attributedText =
+        [[NSMutableAttributedString alloc] initWithString:text
+                                               attributes:textAttributes];
+  } else {
+    NSDictionary* linkAttributes =
+        @{NSLinkAttributeName : net::NSURLWithGURL(self.linkURL)};
+    attributedText = AttributedStringFromStringWithLink(text, textAttributes,
+                                                        linkAttributes);
   }
 
   self.textView.attributedText = attributedText;
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_text_link_item.mm b/ios/chrome/browser/ui/table_view/cells/table_view_text_link_item.mm
index e95a2d5..a40fc7d7 100644
--- a/ios/chrome/browser/ui/table_view/cells/table_view_text_link_item.mm
+++ b/ios/chrome/browser/ui/table_view/cells/table_view_text_link_item.mm
@@ -106,6 +106,7 @@
   // before being added to the controller because modifying the label text
   // clears all added links.
   if (URL.is_valid()) {
+    // TODO(crbug.com/1184151): Move to use AttributedStringFromStringWithLink.
     const StringWithTag parsedString = ParseStringWithLink(self.textLabel.text);
     DCHECK(parsedString.range != NSMakeRange(NSNotFound, 0));
     self.textLabel.text = parsedString.string;
diff --git a/ios/chrome/common/BUILD.gn b/ios/chrome/common/BUILD.gn
index 93dfe60..41ce893 100644
--- a/ios/chrome/common/BUILD.gn
+++ b/ios/chrome/common/BUILD.gn
@@ -63,6 +63,8 @@
     ":common",
     ":noarc_unit_tests",
     "//base",
+    "//base/test:test_support",
+    "//ios/chrome/common/ui/colors",
     "//testing/gtest",
   ]
   configs += [ "//build/config/compiler:enable_arc" ]
diff --git a/ios/chrome/common/string_util.h b/ios/chrome/common/string_util.h
index c7cf0c0..d0045dcd 100644
--- a/ios/chrome/common/string_util.h
+++ b/ios/chrome/common/string_util.h
@@ -37,6 +37,17 @@
 };
 
 // Parses a string with an embedded link inside, delineated by "BEGIN_LINK" and
+// "END_LINK". Returns an attributed string with the text set as the parsed
+// string with given |text_attributes| and the link range with
+// |link_attributes|. The function asserts that there is one link.
+NSAttributedString* AttributedStringFromStringWithLink(
+    NSString* text,
+    NSDictionary* text_attributes,
+    NSDictionary* link_attributes);
+
+// Deprecated.
+// Prefer |AttributedStringFromStringWithLink|. Do not use LabelLinkController.
+// Parses a string with an embedded link inside, delineated by "BEGIN_LINK" and
 // "END_LINK". Returns the string without the delimiters. The function
 // asserts that there is at most one link.
 StringWithTag ParseStringWithLink(NSString* text);
diff --git a/ios/chrome/common/string_util.mm b/ios/chrome/common/string_util.mm
index bc5c91ec..ae1ab54 100644
--- a/ios/chrome/common/string_util.mm
+++ b/ios/chrome/common/string_util.mm
@@ -45,6 +45,21 @@
   return ParseStringWithTags(text, kBeginLinkTag, kEndLinkTag);
 }
 
+NSAttributedString* AttributedStringFromStringWithLink(
+    NSString* text,
+    NSDictionary* text_attributes,
+    NSDictionary* link_attributes) {
+  StringWithTag parsed_string = ParseStringWithLink(text);
+  NSMutableAttributedString* attributed_string =
+      [[NSMutableAttributedString alloc] initWithString:parsed_string.string
+                                             attributes:text_attributes];
+
+  DCHECK(parsed_string.range.location != NSNotFound);
+  [attributed_string setAttributes:link_attributes range:parsed_string.range];
+
+  return attributed_string;
+}
+
 StringWithTag ParseStringWithTag(NSString* text,
                                  NSString* begin_tag,
                                  NSString* end_tag) {
diff --git a/ios/chrome/common/string_util_unittest.mm b/ios/chrome/common/string_util_unittest.mm
index 3d5ec3e..f22b2f7 100644
--- a/ios/chrome/common/string_util_unittest.mm
+++ b/ios/chrome/common/string_util_unittest.mm
@@ -7,6 +7,8 @@
 #import <UIKit/UIKit.h>
 
 #include "base/ios/ns_range.h"
+#include "base/test/gtest_util.h"
+#import "ios/chrome/common/ui/colors/semantic_color_names.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
 #include "testing/platform_test.h"
@@ -19,6 +21,125 @@
 
 using StringUtilTest = PlatformTest;
 
+TEST_F(StringUtilTest, AttributedStringFromStringWithLink) {
+  struct TestCase {
+    NSString* input;
+    NSDictionary* textAttributes;
+    NSDictionary* linkAttributes;
+    NSString* expectedString;
+    NSRange expectedRange;
+  };
+
+  const TestCase kAllTestCases[] = {
+      TestCase{@"Text with valid BEGIN_LINK link END_LINK and spaces.", @{},
+               @{NSLinkAttributeName : @"google.com"},
+               @"Text with valid link and spaces.", NSRange{16, 4}},
+      TestCase{
+          @"Text with valid BEGIN_LINK link END_LINK and spaces.",
+          @{NSForegroundColorAttributeName : [UIColor colorNamed:kBlueColor]},
+          @{}, @"Text with valid link and spaces.", NSRange{16, 4}},
+      TestCase{
+          @"Text with valid BEGIN_LINK link END_LINK and spaces.",
+          @{NSForegroundColorAttributeName : [UIColor colorNamed:kBlueColor]},
+          @{NSLinkAttributeName : @"google.com"},
+          @"Text with valid link and spaces.",
+          NSRange{16, 4},
+      },
+      TestCase{
+          @"Text with valid BEGIN_LINKlinkEND_LINK and no spaces.",
+          @{NSForegroundColorAttributeName : [UIColor colorNamed:kBlueColor]},
+          @{NSLinkAttributeName : @"google.com"},
+          @"Text with valid link and no spaces.",
+          NSRange{16, 4},
+      },
+  };
+
+  for (const TestCase& test_case : kAllTestCases) {
+    const NSAttributedString* result = AttributedStringFromStringWithLink(
+        test_case.input, test_case.textAttributes, test_case.linkAttributes);
+    EXPECT_NSEQ(result.string, test_case.expectedString);
+
+    // Text at index 0 has text attributes applied until the link location.
+    NSRange textRange;
+    NSDictionary* resultTextAttributes = [result attributesAtIndex:0
+                                                    effectiveRange:&textRange];
+    EXPECT_TRUE(NSEqualRanges(NSMakeRange(0, test_case.expectedRange.location),
+                              textRange));
+    EXPECT_NSEQ(test_case.textAttributes, resultTextAttributes);
+
+    // Text at index |expectedRange.location| has link attributes applied.
+    NSRange linkRange;
+    NSDictionary* resultLinkAttributes =
+        [result attributesAtIndex:test_case.expectedRange.location
+                   effectiveRange:&linkRange];
+    EXPECT_TRUE(NSEqualRanges(test_case.expectedRange, linkRange));
+    EXPECT_NSEQ(test_case.linkAttributes, resultLinkAttributes);
+  }
+}
+
+TEST_F(StringUtilTest, AttributedStringFromStringWithLinkFailures) {
+  struct TestCase {
+    NSString* input;
+    NSDictionary* textAttributes;
+    NSDictionary* linkAttributes;
+  };
+
+  const TestCase kAllTestCases[] = {
+      TestCase{
+          @"Text without link.",
+          @{NSForegroundColorAttributeName : [UIColor colorNamed:kBlueColor]},
+          @{NSLinkAttributeName : @"google.com"},
+      },
+      TestCase{
+          @"Text with BEGIN_LINK and no end link.",
+          @{NSForegroundColorAttributeName : [UIColor colorNamed:kBlueColor]},
+          @{NSLinkAttributeName : @"google.com"},
+      },
+      TestCase{
+          @"Text with no begin link and END_LINK.",
+          @{NSForegroundColorAttributeName : [UIColor colorNamed:kBlueColor]},
+          @{NSLinkAttributeName : @"google.com"},
+      },
+      TestCase{
+          @"Text with END_LINK before BEGIN_LINK.",
+          @{NSForegroundColorAttributeName : [UIColor colorNamed:kBlueColor]},
+          @{NSLinkAttributeName : @"google.com"},
+      },
+
+  };
+
+  for (const TestCase& test_case : kAllTestCases) {
+    EXPECT_CHECK_DEATH(AttributedStringFromStringWithLink(
+        test_case.input, test_case.textAttributes, test_case.linkAttributes));
+  }
+}
+
+TEST_F(StringUtilTest, AttributedStringFromStringWithLinkWithEmptyLink) {
+  struct TestCase {
+    NSString* input;
+    NSDictionary* textAttributes;
+    NSDictionary* linkAttributes;
+    NSString* expectedString;
+  };
+  const TestCase test_case = TestCase {
+    @"Text with empty link BEGIN_LINK END_LINK.",
+        @{NSForegroundColorAttributeName : [UIColor colorNamed:kBlueColor]},
+        @{NSLinkAttributeName : @"google.com"}, @"Text with empty link .",
+  };
+
+  const NSAttributedString* result = AttributedStringFromStringWithLink(
+      test_case.input, test_case.textAttributes, test_case.linkAttributes);
+  EXPECT_NSEQ(result.string, test_case.expectedString);
+
+  // Text attributes apply to the full range of the result string.
+  NSRange textRange;
+  NSDictionary* resultTextAttributes = [result attributesAtIndex:0
+                                                  effectiveRange:&textRange];
+  EXPECT_TRUE(NSEqualRanges(NSMakeRange(0, test_case.expectedString.length),
+                            textRange));
+  EXPECT_NSEQ(test_case.textAttributes, resultTextAttributes);
+}
+
 TEST_F(StringUtilTest, ParseStringWithLink) {
   struct TestCase {
     NSString* input;
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
index 12d4f2a..292cd13 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-ea28072ba40610a3f84ec618562ac20e966019a3
\ No newline at end of file
+0d83c3a6ab529f2ec76e0fc27207a057439ba3ee
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
index 4519219..7d71303 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-c70c332192f209b984b939f88166674db7d32e84
\ No newline at end of file
+734469e1fd7fb2b4d5c622d3602ffb9cfdcaba9b
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1
index 24695d6..daa7f33a 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-b067b2a1fcc529843f6a920f60dcf1b0fbc674b7
\ No newline at end of file
+c73fa6cedb0e2a1933bafcd99c2db0220b4e3029
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1
index 10ac9b7..457831f 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-7003d9d7ab8ce86586427f33a56a76a2e9d12483
\ No newline at end of file
+878b9ce26e61d31eb5c1bcb1f8c8a91891eae5ea
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
index ada1e36..4e71f7c 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-7ba5c08e3811282ed0cc01240b73cdda95a90d23
\ No newline at end of file
+e943f2ede91d89e0e48076852a2a997838295a84
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
index 44bcb382..80d565f 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-9be78a5452f11f8ff03f631101f9f29f717413bb
\ No newline at end of file
+ce0854bd20cf23c9538bf4f96a44b4c5d343245d
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
index b8bd251e..97db80b7 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-31fae7915fbe361eea2c529ecf132b82251a40ff
\ No newline at end of file
+06b452d2b00a6adf0beab25c75dc3c2e907d623c
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
index 46e05ac..6b99c26b 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-b58f64d3f82dead980e411b88ca1911bff23dd37
\ No newline at end of file
+119085ce5fbd01fb1d72dcd8150c9bea024de073
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
index b3c25870..ea78fe6d 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-0fc7f0569cb87a9cd286cace77150806b5d72dbe
\ No newline at end of file
+d39442c83e4d38c214afa51c291e96f81b285f46
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
index dd17545..a48924c 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-5efc072914a5f69776865d26b0172085ab99eb06
\ No newline at end of file
+8c349a049877dddb3048278762b8daf82403226b
\ No newline at end of file
diff --git a/media/audio/cras/cras_input.cc b/media/audio/cras/cras_input.cc
index 84a13201a..a6a4ef922 100644
--- a/media/audio/cras/cras_input.cc
+++ b/media/audio/cras/cras_input.cc
@@ -20,6 +20,7 @@
                                  AudioManagerCrasBase* manager,
                                  const std::string& device_id)
     : audio_manager_(manager),
+      bytes_per_frame_(0),
       callback_(NULL),
       client_(NULL),
       params_(params),
@@ -64,43 +65,42 @@
   }
 
   // Create the client and connect to the CRAS server.
-  client_ = libcras_client_create();
-  if (!client_) {
+  if (cras_client_create(&client_) < 0) {
     DLOG(WARNING) << "Couldn't create CRAS client.\n";
     client_ = NULL;
     return false;
   }
 
-  if (libcras_client_connect(client_)) {
+  if (cras_client_connect(client_)) {
     DLOG(WARNING) << "Couldn't connect CRAS client.\n";
-    libcras_client_destroy(client_);
+    cras_client_destroy(client_);
     client_ = NULL;
     return false;
   }
 
   // Then start running the client.
-  if (libcras_client_run_thread(client_)) {
+  if (cras_client_run_thread(client_)) {
     DLOG(WARNING) << "Couldn't run CRAS client.\n";
-    libcras_client_destroy(client_);
+    cras_client_destroy(client_);
     client_ = NULL;
     return false;
   }
 
   if (is_loopback_) {
-    if (libcras_client_connected_wait(client_) < 0) {
+    if (cras_client_connected_wait(client_) < 0) {
       DLOG(WARNING) << "Couldn't synchronize data.";
       // TODO(chinyue): Add a DestroyClientOnError method to de-duplicate the
       // cleanup code.
-      libcras_client_destroy(client_);
+      cras_client_destroy(client_);
       client_ = NULL;
       return false;
     }
 
-    pin_device_ = cras_client_get_first_dev_type_idx(
-        client_->client_, CRAS_NODE_TYPE_POST_MIX_PRE_DSP, CRAS_STREAM_INPUT);
+    pin_device_ = cras_client_get_first_dev_type_idx(client_,
+        CRAS_NODE_TYPE_POST_MIX_PRE_DSP, CRAS_STREAM_INPUT);
     if (pin_device_ < 0) {
       DLOG(WARNING) << "Couldn't find CRAS loopback device.";
-      libcras_client_destroy(client_);
+      cras_client_destroy(client_);
       client_ = NULL;
       return false;
     }
@@ -113,8 +113,8 @@
   Stop();
 
   if (client_) {
-    libcras_client_stop(client_);
-    libcras_client_destroy(client_);
+    cras_client_stop(client_);
+    cras_client_destroy(client_);
     client_ = NULL;
   }
 
@@ -157,36 +157,17 @@
 
   callback_ = callback;
 
-  CRAS_STREAM_TYPE type = CRAS_STREAM_TYPE_DEFAULT;
-  uint32_t flags = 0;
-  if (params_.effects() & AudioParameters::PlatformEffectsMask::HOTWORD) {
-    flags = HOTWORD_STREAM;
-    type = CRAS_STREAM_TYPE_SPEECH_RECOGNITION;
-  }
-
-  unsigned int frames_per_packet = params_.frames_per_buffer();
-  struct libcras_stream_params* stream_params = libcras_stream_params_create();
-  if (!stream_params) {
-    DLOG(ERROR) << "Error creating stream params";
+  // Prepare |audio_format| and |stream_params| for the stream we
+  // will create.
+  cras_audio_format* audio_format = cras_audio_format_create(
+      SND_PCM_FORMAT_S16, params_.sample_rate(), params_.channels());
+  if (!audio_format) {
+    DLOG(WARNING) << "Error setting up audio parameters.";
     callback_->OnError();
     callback_ = NULL;
     return;
   }
 
-  int rc = libcras_stream_params_set(
-      stream_params, stream_direction_, frames_per_packet, frames_per_packet,
-      type, audio_manager_->GetClientType(), flags, this,
-      CrasInputStream::SamplesReady, CrasInputStream::StreamError,
-      params_.sample_rate(), SND_PCM_FORMAT_S16, params_.channels());
-
-  if (rc) {
-    DLOG(WARNING) << "Error setting up stream parameters.";
-    callback_->OnError();
-    callback_ = NULL;
-    libcras_stream_params_destroy(stream_params);
-    return;
-  }
-
   // Initialize channel layout to all -1 to indicate that none of
   // the channels is set in the layout.
   int8_t layout[CRAS_CH_MAX];
@@ -199,36 +180,62 @@
     layout[kChannelMap[i]] = ChannelOrder(params_.channel_layout(),
                                           static_cast<Channels>(i));
   }
-
-  rc = libcras_stream_params_set_channel_layout(stream_params, CRAS_CH_MAX,
-                                                layout);
-  if (rc) {
-    DLOG(WARNING) << "Error setting up the channel layout.";
-    callback_->OnError();
-    callback_ = NULL;
-    libcras_stream_params_destroy(stream_params);
+  if (cras_audio_format_set_channel_layout(audio_format, layout) != 0) {
+    DLOG(WARNING) << "Error setting channel layout.";
+    callback->OnError();
     return;
   }
 
+  CRAS_STREAM_TYPE type = CRAS_STREAM_TYPE_DEFAULT;
+  uint32_t flags = 0;
+  if (params_.effects() & AudioParameters::PlatformEffectsMask::HOTWORD) {
+    flags = HOTWORD_STREAM;
+    type = CRAS_STREAM_TYPE_SPEECH_RECOGNITION;
+  }
+
+  unsigned int frames_per_packet = params_.frames_per_buffer();
+  cras_stream_params* stream_params = cras_client_stream_params_create(
+      stream_direction_,
+      frames_per_packet,  // Total latency.
+      frames_per_packet,  // Call back when this many ready.
+      frames_per_packet,  // Minimum Callback level ignored for capture streams.
+      type, flags, this, CrasInputStream::SamplesReady,
+      CrasInputStream::StreamError, audio_format);
+  if (!stream_params) {
+    DLOG(WARNING) << "Error setting up stream parameters.";
+    callback_->OnError();
+    callback_ = NULL;
+    cras_audio_format_destroy(audio_format);
+    return;
+  }
+
+  cras_client_stream_params_set_client_type(stream_params,
+                                            audio_manager_->GetClientType());
+
   if (UseCrasAec())
-    libcras_stream_params_enable_aec(stream_params);
+    cras_client_stream_params_enable_aec(stream_params);
+
+  // Before starting the stream, save the number of bytes in a frame for use in
+  // the callback.
+  bytes_per_frame_ = cras_client_format_bytes_per_frame(audio_format);
 
   // Adding the stream will start the audio callbacks.
-  if (libcras_client_add_pinned_stream(client_, pin_device_, &stream_id_,
-                                       stream_params)) {
+  if (cras_client_add_pinned_stream(client_, pin_device_, &stream_id_,
+                                    stream_params)) {
     DLOG(WARNING) << "Failed to add the stream.";
     callback_->OnError();
     callback_ = NULL;
   }
 
   // Mute system audio if requested.
-  if (mute_system_audio_ && !cras_client_get_system_muted(client_->client_)) {
-    cras_client_set_system_mute(client_->client_, 1);
+  if (mute_system_audio_ && !cras_client_get_system_muted(client_)) {
+    cras_client_set_system_mute(client_, 1);
     mute_done_ = true;
   }
 
   // Done with config params.
-  libcras_stream_params_destroy(stream_params);
+  cras_audio_format_destroy(audio_format);
+  cras_client_stream_params_destroy(stream_params);
 
   started_ = true;
 }
@@ -241,31 +248,28 @@
     return;
 
   if (mute_system_audio_ && mute_done_) {
-    cras_client_set_system_mute(client_->client_, 0);
+    cras_client_set_system_mute(client_, 0);
     mute_done_ = false;
   }
 
   StopAgc();
 
   // Removing the stream from the client stops audio.
-  libcras_client_rm_stream(client_, stream_id_);
+  cras_client_rm_stream(client_, stream_id_);
 
   started_ = false;
   callback_ = NULL;
 }
 
 // Static callback asking for samples.  Run on high priority thread.
-int CrasInputStream::SamplesReady(struct libcras_stream_cb_data* data) {
-  unsigned int frames;
-  uint8_t* buf;
-  struct timespec latency;
-  void* usr_arg;
-  libcras_stream_cb_data_get_frames(data, &frames);
-  libcras_stream_cb_data_get_buf(data, &buf);
-  libcras_stream_cb_data_get_latency(data, &latency);
-  libcras_stream_cb_data_get_usr_arg(data, &usr_arg);
-  CrasInputStream* me = static_cast<CrasInputStream*>(usr_arg);
-  me->ReadAudio(frames, buf, &latency);
+int CrasInputStream::SamplesReady(cras_client* client,
+                                  cras_stream_id_t stream_id,
+                                  uint8_t* samples,
+                                  size_t frames,
+                                  const timespec* sample_ts,
+                                  void* arg) {
+  CrasInputStream* me = static_cast<CrasInputStream*>(arg);
+  me->ReadAudio(frames, samples, sample_ts);
   return frames;
 }
 
@@ -281,7 +285,7 @@
 
 void CrasInputStream::ReadAudio(size_t frames,
                                 uint8_t* buffer,
-                                const timespec* latency_ts) {
+                                const timespec* sample_ts) {
   DCHECK(callback_);
 
   // Update the AGC volume level once every second. Note that, |volume| is
@@ -290,8 +294,15 @@
   double normalized_volume = 0.0;
   GetAgcVolume(&normalized_volume);
 
+  // Don't just assume sample_ts is from the same clock as base::TimeTicks (it
+  // is not). Instead, convert it to a latency with a cras utility function
+  // (guaranteed to use the same clock) and apply that latency to
+  // TimeTicks::Now().
+  timespec latency_ts = {0, 0};
+  cras_client_calc_capture_latency(sample_ts, &latency_ts);
+
   const base::TimeDelta delay =
-      std::max(base::TimeDelta::FromTimeSpec(*latency_ts), base::TimeDelta());
+      std::max(base::TimeDelta::FromTimeSpec(latency_ts), base::TimeDelta());
 
   // The delay says how long ago the capture was, so we subtract the delay from
   // Now() to find the capture time.
@@ -316,7 +327,7 @@
 
   // Set the volume ratio to CRAS's softare and stream specific gain.
   input_volume_ = volume;
-  libcras_client_set_stream_volume(client_, stream_id_, input_volume_);
+  cras_client_set_stream_volume(client_, stream_id_, input_volume_);
 
   // Update the AGC volume level based on the last setting above. Note that,
   // the volume-level resolution is not infinite and it is therefore not
diff --git a/media/audio/cras/cras_input.h b/media/audio/cras/cras_input.h
index 17fa790..f9ebad9 100644
--- a/media/audio/cras/cras_input.h
+++ b/media/audio/cras/cras_input.h
@@ -52,7 +52,12 @@
  private:
   // Handles requests to get samples from the provided buffer.  This will be
   // called by the audio server when it has samples ready.
-  static int SamplesReady(struct libcras_stream_cb_data* data);
+  static int SamplesReady(cras_client* client,
+                          cras_stream_id_t stream_id,
+                          uint8_t* samples,
+                          size_t frames,
+                          const timespec* sample_ts,
+                          void* arg);
 
   // Handles notification that there was an error with the playback stream.
   static int StreamError(cras_client* client,
@@ -62,7 +67,7 @@
 
   // Reads one or more buffers of audio from the device, passes on to the
   // registered callback. Called from SamplesReady().
-  void ReadAudio(size_t frames, uint8_t* buffer, const timespec* latency_ts);
+  void ReadAudio(size_t frames, uint8_t* buffer, const timespec* sample_ts);
 
   // Deals with an error that occured in the stream.  Called from StreamError().
   void NotifyStreamError(int err);
@@ -83,11 +88,14 @@
   // the manager from that thread.
   AudioManagerCrasBase* const audio_manager_;
 
+  // Size of frame in bytes.
+  uint32_t bytes_per_frame_;
+
   // Callback to pass audio samples too, valid while recording.
   AudioInputCallback* callback_;
 
   // The client used to communicate with the audio server.
-  struct libcras_client* client_;
+  cras_client* client_;
 
   // PCM parameters for the stream.
   const AudioParameters params_;
diff --git a/media/audio/cras/cras_unified.cc b/media/audio/cras/cras_unified.cc
index a92915c1..8158ed0 100644
--- a/media/audio/cras/cras_unified.cc
+++ b/media/audio/cras/cras_unified.cc
@@ -71,6 +71,7 @@
     : client_(NULL),
       stream_id_(0),
       params_(params),
+      bytes_per_frame_(0),
       is_playing_(false),
       volume_(1.0),
       manager_(manager),
@@ -94,24 +95,23 @@
   }
 
   // Create the client and connect to the CRAS server.
-  client_ = libcras_client_create();
-  if (!client_) {
+  if (cras_client_create(&client_)) {
     LOG(WARNING) << "Couldn't create CRAS client.\n";
     client_ = NULL;
     return false;
   }
 
-  if (libcras_client_connect(client_)) {
+  if (cras_client_connect(client_)) {
     LOG(WARNING) << "Couldn't connect CRAS client.\n";
-    libcras_client_destroy(client_);
+    cras_client_destroy(client_);
     client_ = NULL;
     return false;
   }
 
   // Then start running the client.
-  if (libcras_client_run_thread(client_)) {
+  if (cras_client_run_thread(client_)) {
     LOG(WARNING) << "Couldn't run CRAS client.\n";
-    libcras_client_destroy(client_);
+    cras_client_destroy(client_);
     client_ = NULL;
     return false;
   }
@@ -121,8 +121,8 @@
 
 void CrasUnifiedStream::Close() {
   if (client_) {
-    libcras_client_stop(client_);
-    libcras_client_destroy(client_);
+    cras_client_stop(client_);
+    cras_client_destroy(client_);
     client_ = NULL;
   }
 
@@ -160,23 +160,13 @@
   if (is_playing_)
     return;
 
-  struct libcras_stream_params* stream_params = libcras_stream_params_create();
-  if (!stream_params) {
-    DLOG(ERROR) << "Error creating stream params.";
+  // Prepare |audio_format| and |stream_params| for the stream we
+  // will create.
+  cras_audio_format* audio_format = cras_audio_format_create(
+      SND_PCM_FORMAT_S16, params_.sample_rate(), params_.channels());
+  if (!audio_format) {
+    LOG(WARNING) << "Error setting up audio parameters.";
     callback->OnError(AudioSourceCallback::ErrorType::kUnknown);
-  }
-
-  unsigned int frames_per_packet = params_.frames_per_buffer();
-  int rc = libcras_stream_params_set(
-      stream_params, stream_direction_, frames_per_packet * 2,
-      frames_per_packet, CRAS_STREAM_TYPE_DEFAULT, manager_->GetClientType(), 0,
-      this, CrasUnifiedStream::UnifiedCallback, CrasUnifiedStream::StreamError,
-      params_.sample_rate(), SND_PCM_FORMAT_S16, params_.channels());
-
-  if (rc) {
-    LOG(WARNING) << "Error setting up stream parameters.";
-    callback->OnError(AudioSourceCallback::ErrorType::kUnknown);
-    libcras_stream_params_destroy(stream_params);
     return;
   }
 
@@ -190,29 +180,51 @@
     layout[kChannelMap[i]] = ChannelOrder(params_.channel_layout(),
                                           static_cast<Channels>(i));
 
-  rc = libcras_stream_params_set_channel_layout(stream_params, CRAS_CH_MAX,
-                                                layout);
-  if (rc) {
-    DLOG(WARNING) << "Error setting up the channel layout.";
+  if (cras_audio_format_set_channel_layout(audio_format, layout)) {
+    LOG(WARNING) << "Error setting channel layout.";
     callback->OnError(AudioSourceCallback::ErrorType::kUnknown);
-    libcras_stream_params_destroy(stream_params);
     return;
   }
 
+  cras_stream_params* stream_params = cras_client_unified_params_create(
+      stream_direction_,
+      params_.frames_per_buffer(),
+      CRAS_STREAM_TYPE_DEFAULT,
+      0,
+      this,
+      CrasUnifiedStream::UnifiedCallback,
+      CrasUnifiedStream::StreamError,
+      audio_format);
+  if (!stream_params) {
+    LOG(WARNING) << "Error setting up stream parameters.";
+    callback->OnError(AudioSourceCallback::ErrorType::kUnknown);
+    cras_audio_format_destroy(audio_format);
+    return;
+  }
+
+  cras_client_stream_params_set_client_type(stream_params,
+                                            manager_->GetClientType());
+
+  // Before starting the stream, save the number of bytes in a frame for use in
+  // the callback.
+  bytes_per_frame_ = cras_client_format_bytes_per_frame(audio_format);
+
   // Adding the stream will start the audio callbacks requesting data.
-  if (libcras_client_add_pinned_stream(client_, pin_device_, &stream_id_,
-                                       stream_params)) {
+  if (cras_client_add_pinned_stream(client_, pin_device_, &stream_id_,
+                                    stream_params)) {
     LOG(WARNING) << "Failed to add the stream.";
     callback->OnError(AudioSourceCallback::ErrorType::kUnknown);
-    libcras_stream_params_destroy(stream_params);
+    cras_audio_format_destroy(audio_format);
+    cras_client_stream_params_destroy(stream_params);
     return;
   }
 
   // Set initial volume.
-  libcras_client_set_stream_volume(client_, stream_id_, volume_);
+  cras_client_set_stream_volume(client_, stream_id_, volume_);
 
   // Done with config params.
-  libcras_stream_params_destroy(stream_params);
+  cras_audio_format_destroy(audio_format);
+  cras_client_stream_params_destroy(stream_params);
 
   is_playing_ = true;
 }
@@ -222,7 +234,7 @@
     return;
 
   // Removing the stream from the client stops audio.
-  libcras_client_rm_stream(client_, stream_id_);
+  cras_client_rm_stream(client_, stream_id_);
 
   is_playing_ = false;
 }
@@ -231,7 +243,7 @@
   if (!client_)
     return;
   volume_ = static_cast<float>(volume);
-  libcras_client_set_stream_volume(client_, stream_id_, volume_);
+  cras_client_set_stream_volume(client_, stream_id_, volume_);
 }
 
 void CrasUnifiedStream::GetVolume(double* volume) {
@@ -239,17 +251,20 @@
 }
 
 // Static callback asking for samples.
-int CrasUnifiedStream::UnifiedCallback(struct libcras_stream_cb_data* data) {
-  unsigned int frames;
-  uint8_t* buf;
-  struct timespec latency;
-  void* usr_arg;
-  libcras_stream_cb_data_get_frames(data, &frames);
-  libcras_stream_cb_data_get_buf(data, &buf);
-  libcras_stream_cb_data_get_latency(data, &latency);
-  libcras_stream_cb_data_get_usr_arg(data, &usr_arg);
-  CrasUnifiedStream* me = static_cast<CrasUnifiedStream*>(usr_arg);
-  return me->WriteAudio(frames, buf, &latency);
+int CrasUnifiedStream::UnifiedCallback(cras_client* client,
+                                       cras_stream_id_t stream_id,
+                                       uint8_t* input_samples,
+                                       uint8_t* output_samples,
+                                       unsigned int frames,
+                                       const timespec* input_ts,
+                                       const timespec* output_ts,
+                                       void* arg) {
+  CrasUnifiedStream* me = static_cast<CrasUnifiedStream*>(arg);
+  return me->DispatchCallback(frames,
+                              input_samples,
+                              output_samples,
+                              input_ts,
+                              output_ts);
 }
 
 // Static callback for stream errors.
@@ -262,14 +277,37 @@
   return 0;
 }
 
+// Calls the appropriate rendering function for this type of stream.
+uint32_t CrasUnifiedStream::DispatchCallback(size_t frames,
+                                             uint8_t* input_samples,
+                                             uint8_t* output_samples,
+                                             const timespec* input_ts,
+                                             const timespec* output_ts) {
+  switch (stream_direction_) {
+    case CRAS_STREAM_OUTPUT:
+      return WriteAudio(frames, output_samples, output_ts);
+    case CRAS_STREAM_INPUT:
+      NOTREACHED() << "CrasUnifiedStream doesn't support input streams.";
+      return 0;
+    default:
+      break;
+  }
+
+  return 0;
+}
+
 uint32_t CrasUnifiedStream::WriteAudio(size_t frames,
                                        uint8_t* buffer,
-                                       const timespec* latency_ts) {
+                                       const timespec* sample_ts) {
   DCHECK_EQ(frames, static_cast<size_t>(output_bus_->frames()));
 
+  // Determine latency and pass that on to the source.
+  timespec latency_ts  = {0, 0};
+  cras_client_calc_playback_latency(sample_ts, &latency_ts);
+
   // Treat negative latency (if we are too slow to render) as 0.
   const base::TimeDelta delay =
-      std::max(base::TimeDelta::FromTimeSpec(*latency_ts), base::TimeDelta());
+      std::max(base::TimeDelta::FromTimeSpec(latency_ts), base::TimeDelta());
 
   int frames_filled = source_callback_->OnMoreData(
       delay, base::TimeTicks::Now(), 0, output_bus_.get());
diff --git a/media/audio/cras/cras_unified.h b/media/audio/cras/cras_unified.h
index eb57e01..f5732d4 100644
--- a/media/audio/cras/cras_unified.h
+++ b/media/audio/cras/cras_unified.h
@@ -53,8 +53,15 @@
   void GetVolume(double* volume) override;
 
  private:
-  // Handles captured audio and fills the output with audio to be played.
-  static int UnifiedCallback(struct libcras_stream_cb_data* data);
+  // Handles captured audio and fills the ouput with audio to be played.
+  static int UnifiedCallback(cras_client* client,
+                             cras_stream_id_t stream_id,
+                             uint8_t* input_samples,
+                             uint8_t* output_samples,
+                             unsigned int frames,
+                             const timespec* input_ts,
+                             const timespec* output_ts,
+                             void* arg);
 
   // Handles notification that there was an error with the playback stream.
   static int StreamError(cras_client* client,
@@ -62,16 +69,23 @@
                          int err,
                          void* arg);
 
+  // Chooses the correct audio callback based on stream direction.
+  uint32_t DispatchCallback(size_t frames,
+                            uint8_t* input_samples,
+                            uint8_t* output_samples,
+                            const timespec* input_ts,
+                            const timespec* output_ts);
+
   // Writes audio for a playback stream.
   uint32_t WriteAudio(size_t frames,
                       uint8_t* buffer,
-                      const timespec* latency_ts);
+                      const timespec* sample_ts);
 
   // Deals with an error that occured in the stream.  Called from StreamError().
   void NotifyStreamError(int err);
 
   // The client used to communicate with the audio server.
-  struct libcras_client* client_;
+  cras_client* client_;
 
   // ID of the playing stream.
   cras_stream_id_t stream_id_;
@@ -79,6 +93,9 @@
   // PCM parameters for the stream.
   AudioParameters params_;
 
+  // Size of frame in bytes.
+  uint32_t bytes_per_frame_;
+
   // True if stream is playing.
   bool is_playing_;
 
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index 670d8b99..161c0a1a 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -375,7 +375,7 @@
 // If enabled, a media player uses mojo interface that communicates with blink
 // instead of a legacy IPC messages.
 const base::Feature kUseMediaPlayerMojoInterface{
-    "UseMediaPlayerMojoInterface", base::FEATURE_DISABLED_BY_DEFAULT};
+    "UseMediaPlayerMojoInterface", base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Show toolbar button that opens dialog for controlling media sessions.
 const base::Feature kGlobalMediaControls {
diff --git a/media/base/video_encoder.h b/media/base/video_encoder.h
index d1a590a..4a5eb6b 100644
--- a/media/base/video_encoder.h
+++ b/media/base/video_encoder.h
@@ -30,6 +30,7 @@
 
   base::TimeDelta timestamp;
   bool key_frame = false;
+  int temporal_id = 0;
 };
 
 class MEDIA_EXPORT VideoEncoder {
@@ -50,6 +51,9 @@
 
     base::Optional<int> keyframe_interval = 10000;
 
+    // Requested number of SVC temporal layers.
+    int temporal_layers = 1;
+
     // Only used for H264 encoding.
     AvcOptions avc;
   };
diff --git a/media/capture/mojom/image_capture.mojom b/media/capture/mojom/image_capture.mojom
index b71f4c5..52489e71 100644
--- a/media/capture/mojom/image_capture.mojom
+++ b/media/capture/mojom/image_capture.mojom
@@ -7,6 +7,7 @@
 // Equivalent to idl MediaSettingsRange, arbitrary range representing the
 // allowed variations of a Capability or an Option.
 // https://w3c.github.io/mediacapture-image/#mediasettingsrange-section
+[Stable]
 struct Range {
   double max;
   double min;
@@ -15,16 +16,20 @@
 };
 
 // https://w3c.github.io/mediacapture-image/#meteringmode-section
+[Stable, Extensible]
 enum MeteringMode { NONE, MANUAL, SINGLE_SHOT, CONTINUOUS };
 
 // https://w3c.github.io/mediacapture-image/#redeyereduction-section
+[Stable, Extensible]
 enum RedEyeReduction { NEVER, ALWAYS, CONTROLLABLE };
 
 //  https://www.w3.org/TR/image-capture/#FillLightMode
+[Stable, Extensible]
 enum FillLightMode { OFF, AUTO, FLASH };
 
 // Equivalent to idl's MediaTrackCapabilities plus PhotoCapabilities and their
 // associated settings.
+[Stable]
 struct PhotoState {
   // https://w3c.github.io/mediacapture-image/#mediatrackcapabilities-section
   // and https://w3c.github.io/mediacapture-image/#mediatracksettings-section
@@ -66,6 +71,7 @@
 // Equivalent to idl Point2D.
 // https://w3c.github.io/mediacapture-image/#point2d-section
 // TODO(mcasas): use gfx::mojom::PointF after https://crbug.com/640049.
+[Stable]
 struct Point2D {
   double x;
   double y;
@@ -73,6 +79,7 @@
 
 // Equivalent to idl PhotoSettings + MediaTrackSettings/MediaTrackConstraintSet.
 // PODs cannot be nullable, i.e. uint32? bla doesn't work, use |has_bla| flags.
+[Stable]
 struct PhotoSettings {
   // https://w3c.github.io/mediacapture-image/#mediatracksettings-section and
   // https://w3c.github.io/mediacapture-image/#mediatrackconstraintset-section
@@ -127,6 +134,7 @@
 };
 
 // This is a mojo move-only equivalent of a Blob, i.e. MIME type and Data.
+[Stable]
 struct Blob {
   string mime_type;
   array<uint8> data;
diff --git a/media/capture/mojom/video_capture_types.mojom b/media/capture/mojom/video_capture_types.mojom
index ea17088..995c95bd 100644
--- a/media/capture/mojom/video_capture_types.mojom
+++ b/media/capture/mojom/video_capture_types.mojom
@@ -7,6 +7,7 @@
 import "mojo/public/mojom/base/time.mojom";
 import "ui/gfx/geometry/mojom/geometry.mojom";
 
+[Stable, Extensible]
 enum VideoCapturePixelFormat {
   UNKNOWN,
   I420,
@@ -41,24 +42,28 @@
   RGBAF16,
 };
 
+[Stable, Extensible]
 enum ResolutionChangePolicy {
   FIXED_RESOLUTION,
   FIXED_ASPECT_RATIO,
   ANY_WITHIN_LIMIT,
 };
 
+[Stable, Extensible]
 enum PowerLineFrequency {
   DEFAULT,
   HZ_50,
   HZ_60
 };
 
+[Stable, Extensible]
 enum VideoFacingMode {
   NONE,
   USER,
   ENVIRONMENT
 };
 
+[Stable, Extensible]
 enum VideoCaptureApi {
   LINUX_V4L2_SINGLE_PLANE,
   WIN_MEDIA_FOUNDATION,
@@ -75,12 +80,14 @@
   UNKNOWN
 };
 
+[Stable, Extensible]
 enum VideoCaptureTransportType {
   // For MACOSX_AVFOUNDATION Api, identifies devices that are built-in or USB.
   MACOSX_USB_OR_BUILT_IN,
   OTHER_TRANSPORT
 };
 
+[Stable, Extensible]
 enum VideoCaptureBufferType {
   kSharedMemory,
 
@@ -96,12 +103,14 @@
 };
 
 // Represents capture device's support for different controls.
+[Stable]
 struct VideoCaptureControlSupport {
   bool pan;
   bool tilt;
   bool zoom;
 };
 
+[Stable, Extensible]
 enum VideoCaptureError {
   kNone,
   kVideoCaptureControllerInvalidOrUnsupportedVideoCaptureParametersRequested,
@@ -228,8 +237,10 @@
   kCrosHalV3DeviceContextDuplicatedClient,
   kDesktopCaptureDeviceMacFailedStreamCreate,
   kDesktopCaptureDeviceMacFailedStreamStart,
+  kCrosHalV3BufferManagerFailedToReserveBuffers,
 };
 
+[Stable, Extensible]
 enum VideoCaptureFrameDropReason {
   kNone,
   kDeviceClientFrameHasInvalidFormat,
@@ -259,12 +270,14 @@
   kRendererSinkFrameDelivererIsNotStarted
 };
 
+[Stable]
 struct VideoCaptureFormat {
   gfx.mojom.Size frame_size;
   float frame_rate;
   VideoCapturePixelFormat pixel_format;
 };
 
+[Stable]
 struct VideoCaptureParams {
   VideoCaptureFormat requested_format;
   VideoCaptureBufferType buffer_type;
@@ -288,6 +301,7 @@
 // int::max used to signal no limit.
 //
 // |require_mapped_frame| reports that the consumer needs a cpu readable frame.
+[Stable]
 struct VideoFrameFeedback {
   double resource_utilization;
 
@@ -312,6 +326,7 @@
 // |device_id| represents a unique id of a physical device. Since the same
 // physical device may be accessible through different APIs |capture_api|
 // disambiguates the API.
+[Stable]
 struct VideoCaptureDeviceDescriptor {
   string display_name;
   string device_id;
@@ -324,6 +339,7 @@
 
 // Bundles a VideoCaptureDeviceDescriptor with corresponding supported
 // video formats.
+[Stable]
 struct VideoCaptureDeviceInfo {
   VideoCaptureDeviceDescriptor descriptor;
   array<VideoCaptureFormat> supported_formats;
diff --git a/media/capture/mojom/video_capture_types_mojom_traits.cc b/media/capture/mojom/video_capture_types_mojom_traits.cc
index 21cbe57..9db4faad 100644
--- a/media/capture/mojom/video_capture_types_mojom_traits.cc
+++ b/media/capture/mojom/video_capture_types_mojom_traits.cc
@@ -714,6 +714,10 @@
     case media::VideoCaptureError::kDesktopCaptureDeviceMacFailedStreamStart:
       return media::mojom::VideoCaptureError::
           kDesktopCaptureDeviceMacFailedStreamStart;
+    case media::VideoCaptureError::
+        kCrosHalV3BufferManagerFailedToReserveBuffers:
+      return media::mojom::VideoCaptureError::
+          kCrosHalV3BufferManagerFailedToReserveBuffers;
   }
   NOTREACHED();
   return media::mojom::VideoCaptureError::kNone;
@@ -1271,6 +1275,11 @@
       *output =
           media::VideoCaptureError::kDesktopCaptureDeviceMacFailedStreamStart;
       return true;
+    case media::mojom::VideoCaptureError::
+        kCrosHalV3BufferManagerFailedToReserveBuffers:
+      *output = media::VideoCaptureError::
+          kCrosHalV3BufferManagerFailedToReserveBuffers;
+      return true;
   }
   NOTREACHED();
   return false;
diff --git a/media/capture/video/chromeos/camera_app_device_impl.cc b/media/capture/video/chromeos/camera_app_device_impl.cc
index 3aba77a..cf36811 100644
--- a/media/capture/video/chromeos/camera_app_device_impl.cc
+++ b/media/capture/video/chromeos/camera_app_device_impl.cc
@@ -6,6 +6,7 @@
 
 #include "media/base/bind_to_current_loop.h"
 #include "media/capture/video/chromeos/camera_app_device_bridge_impl.h"
+#include "media/capture/video/chromeos/camera_device_context.h"
 #include "media/capture/video/chromeos/camera_metadata_utils.h"
 
 namespace media {
@@ -65,7 +66,8 @@
       camera_info_(std::move(camera_info)),
       capture_intent_(cros::mojom::CaptureIntent::DEFAULT),
       next_metadata_observer_id_(0),
-      next_camera_event_observer_id_(0) {}
+      next_camera_event_observer_id_(0),
+      camera_device_context_(nullptr) {}
 
 CameraAppDeviceImpl::~CameraAppDeviceImpl() {
   // If the instance is bound, then this instance should only be destroyed when
@@ -154,6 +156,12 @@
                      weak_ptr_factory_for_mojo_.GetWeakPtr()));
 }
 
+void CameraAppDeviceImpl::SetCameraDeviceContext(
+    CameraDeviceContext* camera_device_context) {
+  base::AutoLock lock(camera_device_context_lock_);
+  camera_device_context_ = camera_device_context;
+}
+
 void CameraAppDeviceImpl::GetCameraInfo(GetCameraInfoCallback callback) {
   DCHECK(mojo_task_runner_->BelongsToCurrentThread());
   DCHECK(camera_info_);
@@ -294,6 +302,39 @@
   std::move(callback).Run(is_success);
 }
 
+void CameraAppDeviceImpl::SetCameraFrameRotationEnabledAtSource(
+    bool is_enabled,
+    SetCameraFrameRotationEnabledAtSourceCallback callback) {
+  DCHECK(mojo_task_runner_->BelongsToCurrentThread());
+
+  bool is_success = false;
+  {
+    base::AutoLock lock(camera_device_context_lock_);
+    if (camera_device_context_) {
+      camera_device_context_->SetCameraFrameRotationEnabledAtSource(is_enabled);
+      is_success = true;
+    }
+  }
+  std::move(callback).Run(is_success);
+}
+
+void CameraAppDeviceImpl::GetCameraFrameRotation(
+    GetCameraFrameRotationCallback callback) {
+  DCHECK(mojo_task_runner_->BelongsToCurrentThread());
+
+  uint32_t rotation = 0;
+  {
+    base::AutoLock lock(camera_device_context_lock_);
+    if (camera_device_context_ &&
+        !camera_device_context_->IsCameraFrameRotationEnabledAtSource()) {
+      // The camera rotation value can only be [0, 90, 180, 270].
+      rotation = static_cast<uint32_t>(
+          camera_device_context_->GetCameraFrameRotation());
+    }
+  }
+  std::move(callback).Run(rotation);
+}
+
 // static
 void CameraAppDeviceImpl::DisableEeNr(ReprocessTask* task) {
   auto ee_entry =
diff --git a/media/capture/video/chromeos/camera_app_device_impl.h b/media/capture/video/chromeos/camera_app_device_impl.h
index 4bdd999..7663aec 100644
--- a/media/capture/video/chromeos/camera_app_device_impl.h
+++ b/media/capture/video/chromeos/camera_app_device_impl.h
@@ -25,6 +25,8 @@
 
 namespace media {
 
+class CameraDeviceContext;
+
 struct ReprocessTask {
  public:
   ReprocessTask();
@@ -99,6 +101,10 @@
   // Notifies the camera event observers that the shutter is finished.
   void OnShutterDone();
 
+  // Sets the pointer to the camera device context instance associated with the
+  // opened camera.  Used to configure and query camera frame rotation.
+  void SetCameraDeviceContext(CameraDeviceContext* device_context);
+
   // cros::mojom::CameraAppDevice implementations.
   void GetCameraInfo(GetCameraInfoCallback callback) override;
   void SetReprocessOption(cros::mojom::Effect effect,
@@ -123,6 +129,10 @@
   void RemoveCameraEventObserver(
       uint32_t id,
       RemoveCameraEventObserverCallback callback) override;
+  void SetCameraFrameRotationEnabledAtSource(
+      bool is_enabled,
+      SetCameraFrameRotationEnabledAtSourceCallback callback) override;
+  void GetCameraFrameRotation(GetCameraFrameRotationCallback callback) override;
 
  private:
   static void DisableEeNr(ReprocessTask* task);
@@ -174,6 +184,10 @@
   base::flat_map<uint32_t, mojo::Remote<cros::mojom::CameraEventObserver>>
       camera_event_observers_;
 
+  base::Lock camera_device_context_lock_;
+  CameraDeviceContext* camera_device_context_
+      GUARDED_BY(camera_device_context_lock_);
+
   // The weak pointers should be dereferenced and invalidated on camera device
   // ipc thread.
   base::WeakPtrFactory<CameraAppDeviceImpl> weak_ptr_factory_{this};
diff --git a/media/capture/video/chromeos/camera_device_context.cc b/media/capture/video/chromeos/camera_device_context.cc
index 6f5f659..dbc3882 100644
--- a/media/capture/video/chromeos/camera_device_context.cc
+++ b/media/capture/video/chromeos/camera_device_context.cc
@@ -5,11 +5,15 @@
 #include "media/capture/video/chromeos/camera_device_context.h"
 
 #include "base/strings/string_number_conversions.h"
+#include "media/capture/video/chromeos/video_capture_features_chromeos.h"
 
 namespace media {
 
 CameraDeviceContext::CameraDeviceContext()
-    : state_(State::kStopped), sensor_orientation_(0), screen_rotation_(0) {
+    : state_(State::kStopped),
+      sensor_orientation_(0),
+      screen_rotation_(0),
+      frame_rotation_at_source_(true) {
   DETACH_FROM_SEQUENCE(sequence_checker_);
 }
 
@@ -113,6 +117,7 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(sensor_orientation >= 0 && sensor_orientation < 360 &&
          sensor_orientation % 90 == 0);
+  base::AutoLock lock(rotation_state_lock_);
   sensor_orientation_ = sensor_orientation;
 }
 
@@ -120,19 +125,26 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(screen_rotation >= 0 && screen_rotation < 360 &&
          screen_rotation % 90 == 0);
+  base::AutoLock lock(rotation_state_lock_);
   screen_rotation_ = screen_rotation;
 }
 
+void CameraDeviceContext::SetCameraFrameRotationEnabledAtSource(
+    bool is_enabled) {
+  base::AutoLock lock(rotation_state_lock_);
+  frame_rotation_at_source_ = is_enabled;
+}
+
 int CameraDeviceContext::GetCameraFrameRotation() {
+  base::AutoLock lock(rotation_state_lock_);
   return (sensor_orientation_ + screen_rotation_) % 360;
 }
 
-int CameraDeviceContext::GetRotationForDisplay() {
-  return screen_rotation_;
-}
-
-int CameraDeviceContext::GetRotationFromSensorOrientation() {
-  return sensor_orientation_;
+bool CameraDeviceContext::IsCameraFrameRotationEnabledAtSource() {
+  base::AutoLock lock(rotation_state_lock_);
+  return !base::FeatureList::IsEnabled(
+             features::kDisableCameraFrameRotationAtSource) &&
+         frame_rotation_at_source_;
 }
 
 bool CameraDeviceContext::ReserveVideoCaptureBufferFromPool(
diff --git a/media/capture/video/chromeos/camera_device_context.h b/media/capture/video/chromeos/camera_device_context.h
index b7c64d5..1d40dcc 100644
--- a/media/capture/video/chromeos/camera_device_context.h
+++ b/media/capture/video/chromeos/camera_device_context.h
@@ -146,17 +146,18 @@
 
   void SetScreenRotation(int screen_rotation);
 
+  // Controls whether the Chrome OS video capture device applies frame rotation
+  // according to sensor and UI rotation.
+  void SetCameraFrameRotationEnabledAtSource(bool is_enabled);
+
   // Gets the accumulated rotation that the camera frame needs to be rotated
   // to match the display orientation.  This includes the sensor orientation and
   // the screen rotation.
   int GetCameraFrameRotation();
 
-  // Gets the rotation needed to match the camera frame to the display, assuming
-  // the camera frame has 0 degree orientation.
-  int GetRotationForDisplay();
-
-  // Gets the rotation needed to get the camera frame to 0 degree orientation.
-  int GetRotationFromSensorOrientation();
+  // Gets whether the camera frame rotation is enabled inside the video capture
+  // device.
+  bool IsCameraFrameRotationEnabledAtSource();
 
   // Reserves a video capture buffer from the buffer pool provided by the video
   // |client_|.  Returns true if the operation succeeds; false otherwise.
@@ -177,14 +178,22 @@
   // The state the CameraDeviceDelegate currently is in.
   State state_;
 
+  // Lock to serialize the access to the various camera rotation state variables
+  // since they are access on multiple threads.
+  base::Lock rotation_state_lock_;
+
   // Clockwise angle through which the output image needs to be rotated to be
   // upright on the device screen in its native orientation.  This value should
   // be 0, 90, 180, or 270.
-  int sensor_orientation_;
+  int sensor_orientation_ GUARDED_BY(rotation_state_lock_);
 
   // Clockwise screen rotation in degrees. This value should be 0, 90, 180, or
   // 270.
-  int screen_rotation_;
+  int screen_rotation_ GUARDED_BY(rotation_state_lock_);
+
+  // Whether the camera frame rotation is enabled inside the video capture
+  // device.
+  bool frame_rotation_at_source_ GUARDED_BY(rotation_state_lock_);
 
   base::Lock client_lock_;
   // A map for client type and client instance.
diff --git a/media/capture/video/chromeos/camera_device_delegate.cc b/media/capture/video/chromeos/camera_device_delegate.cc
index d4a5336..b7d497c 100644
--- a/media/capture/video/chromeos/camera_device_delegate.cc
+++ b/media/capture/video/chromeos/camera_device_delegate.cc
@@ -279,10 +279,7 @@
     scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner)
     : device_descriptor_(device_descriptor),
       camera_hal_delegate_(std::move(camera_hal_delegate)),
-      ipc_task_runner_(std::move(ipc_task_runner)),
-      camera_app_device_(
-          CameraAppDeviceBridgeImpl::GetInstance()->GetWeakCameraAppDevice(
-              device_descriptor_.device_id)) {}
+      ipc_task_runner_(std::move(ipc_task_runner)) {}
 
 CameraDeviceDelegate::~CameraDeviceDelegate() = default;
 
@@ -310,6 +307,10 @@
   device_context_ = device_context;
   device_context_->SetState(CameraDeviceContext::State::kStarting);
 
+  if (camera_app_device_) {
+    camera_app_device_->SetCameraDeviceContext(device_context_);
+  }
+
   auto camera_info = camera_hal_delegate_->GetCameraInfoFromDeviceId(
       device_descriptor_.device_id);
   if (camera_info.is_null()) {
@@ -368,6 +369,10 @@
   // CameraDeviceContext::State::kStopping.
   DCHECK_NE(device_context_->GetState(), CameraDeviceContext::State::kStopping);
 
+  if (camera_app_device_) {
+    camera_app_device_->SetCameraDeviceContext(nullptr);
+  }
+
   device_close_callback_ = std::move(device_close_callback);
   device_context_->SetState(CameraDeviceContext::State::kStopping);
   if (device_ops_.is_bound()) {
@@ -779,13 +784,13 @@
   mojo::PendingRemote<cros::mojom::Camera3CallbackOps> callback_ops;
   // Assumes the buffer_type will be the same for all |chrome_capture_params|.
   request_manager_ = std::make_unique<RequestManager>(
+      device_descriptor_.device_id,
       callback_ops.InitWithNewPipeAndPassReceiver(),
       std::make_unique<StreamCaptureInterfaceImpl>(GetWeakPtr()),
       device_context_,
       chrome_capture_params_[ClientType::kPreviewClient].buffer_type,
       std::make_unique<CameraBufferFactory>(),
-      base::BindRepeating(&RotateAndBlobify), ipc_task_runner_,
-      camera_app_device_);
+      base::BindRepeating(&RotateAndBlobify), ipc_task_runner_);
   camera_3a_controller_ = std::make_unique<Camera3AController>(
       static_metadata_, request_manager_.get(), ipc_task_runner_);
   device_ops_->Initialize(
@@ -813,10 +818,13 @@
   }
   device_context_->SetState(CameraDeviceContext::State::kInitialized);
   bool require_photo = [&] {
-    if (!camera_app_device_) {
+    auto camera_app_device =
+        CameraAppDeviceBridgeImpl::GetInstance()->GetWeakCameraAppDevice(
+            device_descriptor_.device_id);
+    if (!camera_app_device) {
       return false;
     }
-    auto capture_intent = camera_app_device_->GetCaptureIntent();
+    auto capture_intent = camera_app_device->GetCaptureIntent();
     switch (capture_intent) {
       case cros::mojom::CaptureIntent::DEFAULT:
         return false;
@@ -1066,9 +1074,12 @@
   if (stream_type == StreamType::kPreviewOutput) {
     // CCA uses the same stream for preview and video recording. Choose proper
     // template here so the underlying camera HAL can set 3A tuning accordingly.
+    auto camera_app_device =
+        CameraAppDeviceBridgeImpl::GetInstance()->GetWeakCameraAppDevice(
+            device_descriptor_.device_id);
     auto request_template =
-        camera_app_device_ && camera_app_device_->GetCaptureIntent() ==
-                                  cros::mojom::CaptureIntent::VIDEO_RECORD
+        camera_app_device && camera_app_device->GetCaptureIntent() ==
+                                 cros::mojom::CaptureIntent::VIDEO_RECORD
             ? cros::mojom::Camera3RequestTemplate::CAMERA3_TEMPLATE_VIDEO_RECORD
             : cros::mojom::Camera3RequestTemplate::CAMERA3_TEMPLATE_PREVIEW;
     device_ops_->ConstructDefaultRequestSettings(
@@ -1110,8 +1121,11 @@
   device_context_->SetState(CameraDeviceContext::State::kCapturing);
   camera_3a_controller_->SetAutoFocusModeForStillCapture();
 
+  auto camera_app_device =
+      CameraAppDeviceBridgeImpl::GetInstance()->GetWeakCameraAppDevice(
+          device_descriptor_.device_id);
   auto specified_fps_range =
-      camera_app_device_ ? camera_app_device_->GetFpsRange() : base::nullopt;
+      camera_app_device ? camera_app_device->GetFpsRange() : base::nullopt;
   if (specified_fps_range) {
     SetFpsRangeInMetadata(&settings, specified_fps_range->GetMin(),
                           specified_fps_range->GetMax());
@@ -1123,8 +1137,8 @@
     bool prefer_constant_frame_rate =
         base::FeatureList::IsEnabled(
             chromeos::features::kPreferConstantFrameRate) ||
-        (camera_app_device_ && camera_app_device_->GetCaptureIntent() ==
-                                   cros::mojom::CaptureIntent::VIDEO_RECORD);
+        (camera_app_device && camera_app_device->GetCaptureIntent() ==
+                                  cros::mojom::CaptureIntent::VIDEO_RECORD);
     int32_t target_min, target_max;
     std::tie(target_min, target_max) = GetTargetFrameRateRange(
         static_metadata_, requested_frame_rate, prefer_constant_frame_rate);
@@ -1154,13 +1168,17 @@
     cros::mojom::CameraMetadataPtr settings) {
   DCHECK(ipc_task_runner_->BelongsToCurrentThread());
 
+  auto camera_app_device =
+      CameraAppDeviceBridgeImpl::GetInstance()->GetWeakCameraAppDevice(
+          device_descriptor_.device_id);
+
   while (!take_photo_callbacks_.empty()) {
     auto take_photo_callback = base::BindOnce(
         &TakePhotoCallbackBundle, std::move(take_photo_callbacks_.front()),
         base::BindOnce(&Camera3AController::SetAutoFocusModeForStillCapture,
                        camera_3a_controller_->GetWeakPtr()));
-    if (camera_app_device_) {
-      camera_app_device_->ConsumeReprocessOptions(
+    if (camera_app_device) {
+      camera_app_device->ConsumeReprocessOptions(
           std::move(take_photo_callback),
           media::BindToCurrentLoop(base::BindOnce(
               &RequestManager::TakePhoto, request_manager_->GetWeakPtr(),
@@ -1194,9 +1212,12 @@
     return *new_blob_resolution;
   }
 
-  if (camera_app_device_) {
+  auto camera_app_device =
+      CameraAppDeviceBridgeImpl::GetInstance()->GetWeakCameraAppDevice(
+          device_descriptor_.device_id);
+  if (camera_app_device) {
     auto specified_capture_resolution =
-        camera_app_device_->GetStillCaptureResolution();
+        camera_app_device->GetStillCaptureResolution();
     if (!specified_capture_resolution.IsEmpty() &&
         base::Contains(blob_resolutions, specified_capture_resolution)) {
       return specified_capture_resolution;
diff --git a/media/capture/video/chromeos/camera_hal_delegate.cc b/media/capture/video/chromeos/camera_hal_delegate.cc
index 83137c9..fcc92b23 100644
--- a/media/capture/video/chromeos/camera_hal_delegate.cc
+++ b/media/capture/video/chromeos/camera_hal_delegate.cc
@@ -463,6 +463,13 @@
   }
 }
 
+void CameraHalDelegate::DisableAllVirtualDevices() {
+  base::AutoLock lock(enable_virtual_device_lock_);
+  for (auto& it : enable_virtual_device_) {
+    it.second = false;
+  }
+}
+
 const VendorTagInfo* CameraHalDelegate::GetVendorTagInfoByName(
     const std::string& full_name) {
   return vendor_tag_ops_delegate_.GetInfoByName(full_name);
diff --git a/media/capture/video/chromeos/camera_hal_delegate.h b/media/capture/video/chromeos/camera_hal_delegate.h
index 2aba005a..0658c432 100644
--- a/media/capture/video/chromeos/camera_hal_delegate.h
+++ b/media/capture/video/chromeos/camera_hal_delegate.h
@@ -93,6 +93,8 @@
 
   void EnableVirtualDevice(const std::string& device_id, bool enable);
 
+  void DisableAllVirtualDevices();
+
  private:
   friend class base::RefCountedThreadSafe<CameraHalDelegate>;
 
diff --git a/media/capture/video/chromeos/mojom/camera_app.mojom b/media/capture/video/chromeos/mojom/camera_app.mojom
index 59df9f82..76848f1 100644
--- a/media/capture/video/chromeos/mojom/camera_app.mojom
+++ b/media/capture/video/chromeos/mojom/camera_app.mojom
@@ -80,8 +80,10 @@
   SetMultipleStreamsEnabled(string device_id, bool enabled) => (bool success);
 };
 
-// Interface for communication between Chrome Camera App (Remote) and camera
-// device (Receiver).
+// Interface for communication from the Chrome Camera App (Remote) to the camera
+// device (Receiver). The Chrome Camera App is a system web app and runs inside
+// a renderer process, with all the code resides in the Chrome OS rootfs. The
+// camera device runs inside the browser process.
 interface CameraAppDevice {
   // Gets camera information |camera_info| which includes camera facing,
   // characteristics, orientation, etc.
@@ -131,6 +133,16 @@
   // Removes the camera events observer according to given observer |id|. Sets
   // |is_success| to true if remove successfully, false otherwise.
   RemoveCameraEventObserver(uint32 id) => (bool is_success);
+
+  // Sets whether to disable the camera frame rotation at source. Sets
+  // |is_success| to true if |is_enabled| is correctly set.
+  SetCameraFrameRotationEnabledAtSource(bool is_enabled) => (bool is_success);
+
+  // Gets the clock-wise rotation in degree applied, or needs to be applied if
+  // the rotation is disabled at source, on the raw camera frame in order to
+  // display the camera preview upright in the UI. The only valid values for
+  // |rotation| are 0, 90, 180, and 270.
+  GetCameraFrameRotation() => (uint32 rotation);
 };
 
 // Interface for camera device to send camera metadata to Chrome Camera App.
diff --git a/media/capture/video/chromeos/request_manager.cc b/media/capture/video/chromeos/request_manager.cc
index b918ab6c..14cfdab 100644
--- a/media/capture/video/chromeos/request_manager.cc
+++ b/media/capture/video/chromeos/request_manager.cc
@@ -17,7 +17,7 @@
 #include "base/posix/safe_strerror.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/trace_event/trace_event.h"
-#include "media/capture/video/chromeos/camera_app_device_impl.h"
+#include "media/capture/video/chromeos/camera_app_device_bridge_impl.h"
 #include "media/capture/video/chromeos/camera_buffer_factory.h"
 #include "media/capture/video/chromeos/camera_metadata_utils.h"
 #include "media/capture/video/chromeos/video_capture_features_chromeos.h"
@@ -35,6 +35,7 @@
 }  // namespace
 
 RequestManager::RequestManager(
+    const std::string& device_id,
     mojo::PendingReceiver<cros::mojom::Camera3CallbackOps>
         callback_ops_receiver,
     std::unique_ptr<StreamCaptureInterface> capture_interface,
@@ -42,9 +43,9 @@
     VideoCaptureBufferType buffer_type,
     std::unique_ptr<CameraBufferFactory> camera_buffer_factory,
     BlobifyCallback blobify_callback,
-    scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner,
-    base::WeakPtr<CameraAppDeviceImpl> camera_app_device)
-    : callback_ops_(this, std::move(callback_ops_receiver)),
+    scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner)
+    : device_id_(device_id),
+      callback_ops_(this, std::move(callback_ops_receiver)),
       capture_interface_(std::move(capture_interface)),
       device_context_(device_context),
       video_capture_use_gmb_(buffer_type ==
@@ -57,8 +58,7 @@
       ipc_task_runner_(std::move(ipc_task_runner)),
       capturing_(false),
       partial_result_count_(1),
-      first_frame_shutter_time_(base::TimeTicks()),
-      camera_app_device_(camera_app_device) {
+      first_frame_shutter_time_(base::TimeTicks()) {
   DCHECK(ipc_task_runner_->BelongsToCurrentThread());
   DCHECK(callback_ops_.is_bound());
   DCHECK(device_context_);
@@ -702,8 +702,12 @@
       first_frame_shutter_time_ = reference_time;
     }
     pending_result.timestamp = reference_time - first_frame_shutter_time_;
-    if (camera_app_device_ && pending_result.still_capture_callback) {
-      camera_app_device_->OnShutterDone();
+
+    auto camera_app_device =
+        CameraAppDeviceBridgeImpl::GetInstance()->GetWeakCameraAppDevice(
+            device_id_);
+    if (camera_app_device && pending_result.still_capture_callback) {
+      camera_app_device->OnShutterDone();
     }
 
     TrySubmitPendingBuffers(frame_number);
@@ -797,8 +801,11 @@
     observer->OnResultMetadataAvailable(frame_number, pending_result.metadata);
   }
 
-  if (camera_app_device_) {
-    camera_app_device_->OnResultMetadataAvailable(
+  auto camera_app_device =
+      CameraAppDeviceBridgeImpl::GetInstance()->GetWeakCameraAppDevice(
+          device_id_);
+  if (camera_app_device) {
+    camera_app_device->OnResultMetadataAvailable(
         pending_result.metadata,
         static_cast<cros::mojom::StreamType>(stream_type));
   }
@@ -884,8 +891,7 @@
     // to populate the camera metadata with the color space reported by the V4L2
     // device.
     VideoFrameMetadata metadata;
-    if (base::FeatureList::IsEnabled(
-            features::kDisableCameraFrameRotationAtSource)) {
+    if (!device_context_->IsCameraFrameRotationEnabledAtSource()) {
       // Camera frame rotation at source is disabled, so we record the intended
       // video frame rotation in the metadata.  The consumer of the video frame
       // is responsible for taking care of the frame rotation.
@@ -903,7 +909,7 @@
         return VIDEO_ROTATION_0;
       };
       metadata.transformation =
-          translate_rotation(device_context_->GetRotationForDisplay());
+          translate_rotation(device_context_->GetCameraFrameRotation());
     } else {
       // All frames are pre-rotated to the display orientation.
       metadata.transformation = VIDEO_ROTATION_0;
diff --git a/media/capture/video/chromeos/request_manager.h b/media/capture/video/chromeos/request_manager.h
index 7af8f43..8739cea 100644
--- a/media/capture/video/chromeos/request_manager.h
+++ b/media/capture/video/chromeos/request_manager.h
@@ -99,15 +99,15 @@
     int32_t orientation;
   };
 
-  RequestManager(mojo::PendingReceiver<cros::mojom::Camera3CallbackOps>
+  RequestManager(const std::string& device_id,
+                 mojo::PendingReceiver<cros::mojom::Camera3CallbackOps>
                      callback_ops_receiver,
                  std::unique_ptr<StreamCaptureInterface> capture_interface,
                  CameraDeviceContext* device_context,
                  VideoCaptureBufferType buffer_type,
                  std::unique_ptr<CameraBufferFactory> camera_buffer_factory,
                  BlobifyCallback blobify_callback,
-                 scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner,
-                 base::WeakPtr<CameraAppDeviceImpl> camera_app_device);
+                 scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner);
   ~RequestManager() override;
 
   // Sets up the stream context and allocate buffers according to the
@@ -267,6 +267,9 @@
   // SetRepeatingCaptureMetadata(), update them onto |capture_settings|.
   void UpdateCaptureSettings(cros::mojom::CameraMetadataPtr* capture_settings);
 
+  // The unique device id which is retrieved from VideoCaptureDeviceDescriptor.
+  std::string device_id_;
+
   mojo::Receiver<cros::mojom::Camera3CallbackOps> callback_ops_;
 
   std::unique_ptr<StreamCaptureInterface> capture_interface_;
diff --git a/media/capture/video/chromeos/request_manager_unittest.cc b/media/capture/video/chromeos/request_manager_unittest.cc
index 429769a..90b9e83 100644
--- a/media/capture/video/chromeos/request_manager_unittest.cc
+++ b/media/capture/video/chromeos/request_manager_unittest.cc
@@ -94,8 +94,9 @@
     if (device_context_->AddClient(
             client_type_,
             std::make_unique<unittest_internal::MockVideoCaptureClient>())) {
+      std::string fake_device_id = "0";
       request_manager_ = std::make_unique<RequestManager>(
-          mock_callback_ops_.BindNewPipeAndPassReceiver(),
+          fake_device_id, mock_callback_ops_.BindNewPipeAndPassReceiver(),
           std::make_unique<MockStreamCaptureInterface>(), device_context_.get(),
           VideoCaptureBufferType::kSharedMemory,
           std::make_unique<FakeCameraBufferFactory>(),
@@ -103,7 +104,7 @@
               [](const uint8_t* buffer, const uint32_t bytesused,
                  const VideoCaptureFormat& capture_format,
                  const int rotation) { return mojom::Blob::New(); }),
-          base::ThreadTaskRunnerHandle::Get(), nullptr);
+          base::ThreadTaskRunnerHandle::Get());
     }
   }
 
diff --git a/media/capture/video/chromeos/stream_buffer_manager.cc b/media/capture/video/chromeos/stream_buffer_manager.cc
index 4e3f277f..21bf391 100644
--- a/media/capture/video/chromeos/stream_buffer_manager.cc
+++ b/media/capture/video/chromeos/stream_buffer_manager.cc
@@ -11,13 +11,13 @@
 #include "base/callback_helpers.h"
 #include "base/posix/safe_strerror.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
 #include "base/trace_event/trace_event.h"
 #include "gpu/ipc/common/gpu_memory_buffer_support.h"
 #include "media/capture/video/chromeos/camera_buffer_factory.h"
 #include "media/capture/video/chromeos/camera_metadata_utils.h"
 #include "media/capture/video/chromeos/pixel_format_utils.h"
 #include "media/capture/video/chromeos/request_builder.h"
-#include "media/capture/video/chromeos/video_capture_features_chromeos.h"
 #include "mojo/public/cpp/platform/platform_handle.h"
 #include "mojo/public/cpp/system/platform_handle.h"
 #include "third_party/libyuv/include/libyuv.h"
@@ -82,16 +82,8 @@
   DCHECK_EQ(format->pixel_format, PIXEL_FORMAT_NV12);
 
   int rotation = device_context_->GetCameraFrameRotation();
-  if (base::FeatureList::IsEnabled(
-          features::kDisableCameraFrameRotationAtSource)) {
-    // For a device that don't have the camera sensor installed to match the
-    // device's natural orientation, we have to fix the sensor orientation here.
-    // Otherwise the recorded video in Chrome camera app would have wrong
-    // orientation because we no longer rotate the frames for the video encoder.
-    rotation = device_context_->GetRotationFromSensorOrientation();
-  }
-
-  if (rotation == 0) {
+  if (rotation == 0 ||
+      !device_context_->IsCameraFrameRotationEnabledAtSource()) {
     return std::move(buffer_pair.vcd_buffer);
   }
 
@@ -301,10 +293,22 @@
          ++j) {
       ReserveBuffer(stream_type);
     }
-    CHECK_EQ(stream_context_[stream_type]->free_buffers.size(),
-             stream_context_[stream_type]->stream->max_buffers);
     DVLOG(2) << "Allocated "
              << stream_context_[stream_type]->stream->max_buffers << " buffers";
+
+    if (stream_context_[stream_type]->free_buffers.size() !=
+        stream_context_[stream_type]->stream->max_buffers) {
+      device_context_->SetErrorState(
+          media::VideoCaptureError::
+              kCrosHalV3BufferManagerFailedToReserveBuffers,
+          FROM_HERE,
+          StreamTypeToString(stream_type) +
+              base::StringPrintf(
+                  " needs %d buffers but only allocated %zd",
+                  stream_context_[stream_type]->stream->max_buffers,
+                  stream_context_[stream_type]->free_buffers.size()));
+      return;
+    }
   }
 }
 
diff --git a/media/capture/video/chromeos/video_capture_device_chromeos_delegate.cc b/media/capture/video/chromeos/video_capture_device_chromeos_delegate.cc
index 6cea464a..8de83522 100644
--- a/media/capture/video/chromeos/video_capture_device_chromeos_delegate.cc
+++ b/media/capture/video/chromeos/video_capture_device_chromeos_delegate.cc
@@ -138,6 +138,7 @@
     DCHECK(!camera_device_ipc_thread_.IsRunning());
     screen_observer_delegate_->RemoveObserver();
     power_manager_client_proxy_->Shutdown();
+    camera_hal_delegate_->DisableAllVirtualDevices();
     std::move(cleanup_callback_).Run();
   }
 }
diff --git a/media/capture/video_capture_types.h b/media/capture/video_capture_types.h
index 48eba6a9..051b976 100644
--- a/media/capture/video_capture_types.h
+++ b/media/capture/video_capture_types.h
@@ -192,7 +192,8 @@
   kCrosHalV3DeviceContextDuplicatedClient = 123,
   kDesktopCaptureDeviceMacFailedStreamCreate = 124,
   kDesktopCaptureDeviceMacFailedStreamStart = 125,
-  kMaxValue = 125
+  kCrosHalV3BufferManagerFailedToReserveBuffers = 126,
+  kMaxValue = 126
 };
 
 // WARNING: Do not change the values assigned to the entries. They are used for
diff --git a/media/gpu/chromeos/video_decoder_pipeline.cc b/media/gpu/chromeos/video_decoder_pipeline.cc
index 2d8e1db..5c452d1 100644
--- a/media/gpu/chromeos/video_decoder_pipeline.cc
+++ b/media/gpu/chromeos/video_decoder_pipeline.cc
@@ -262,30 +262,26 @@
                                 base::BindOnce(std::move(init_cb_), status));
 }
 
-void VideoDecoderPipeline::Reset(base::OnceClosure closure) {
+void VideoDecoderPipeline::Reset(base::OnceClosure reset_cb) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
   DVLOGF(3);
 
   decoder_task_runner_->PostTask(
       FROM_HERE, base::BindOnce(&VideoDecoderPipeline::ResetTask,
-                                decoder_weak_this_, std::move(closure)));
+                                decoder_weak_this_, std::move(reset_cb)));
 }
 
-void VideoDecoderPipeline::ResetTask(base::OnceClosure closure) {
+void VideoDecoderPipeline::ResetTask(base::OnceClosure reset_cb) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
-  DCHECK(decoder_);
-  DCHECK(!client_reset_cb_);
   DVLOGF(3);
 
   need_apply_new_resolution = false;
-  client_reset_cb_ = std::move(closure);
-  decoder_->Reset(
-      base::BindOnce(&VideoDecoderPipeline::OnResetDone, decoder_weak_this_));
+  decoder_->Reset(base::BindOnce(&VideoDecoderPipeline::OnResetDone,
+                                 decoder_weak_this_, std::move(reset_cb)));
 }
 
-void VideoDecoderPipeline::OnResetDone() {
+void VideoDecoderPipeline::OnResetDone(base::OnceClosure reset_cb) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
-  DCHECK(client_reset_cb_);
   DVLOGF(3);
 
   if (image_processor_)
@@ -294,7 +290,7 @@
 
   CallFlushCbIfNeeded(DecodeStatus::ABORTED);
 
-  client_task_runner_->PostTask(FROM_HERE, std::move(client_reset_cb_));
+  client_task_runner_->PostTask(FROM_HERE, std::move(reset_cb));
 }
 
 void VideoDecoderPipeline::Decode(scoped_refptr<DecoderBuffer> buffer,
diff --git a/media/gpu/chromeos/video_decoder_pipeline.h b/media/gpu/chromeos/video_decoder_pipeline.h
index 7d48647..ea17d27 100644
--- a/media/gpu/chromeos/video_decoder_pipeline.h
+++ b/media/gpu/chromeos/video_decoder_pipeline.h
@@ -157,7 +157,7 @@
                   InitCB init_cb,
                   const OutputCB& output_cb,
                   const WaitingCB& waiting_cb) override;
-  void Reset(base::OnceClosure closure) override;
+  void Reset(base::OnceClosure reset_cb) override;
   void Decode(scoped_refptr<DecoderBuffer> buffer, DecodeCB decode_cb) override;
 
   // DecoderInterface::Client implementation.
@@ -184,13 +184,13 @@
                       InitCB init_cb,
                       const OutputCB& output_cb,
                       const WaitingCB& waiting_cb);
-  void ResetTask(base::OnceClosure closure);
+  void ResetTask(base::OnceClosure reset_cb);
   void DecodeTask(scoped_refptr<DecoderBuffer> buffer, DecodeCB decode_cb);
 
   void OnInitializeDone(Status status);
 
   void OnDecodeDone(bool eos_buffer, DecodeCB decode_cb, Status status);
-  void OnResetDone();
+  void OnResetDone(base::OnceClosure reset_cb);
   void OnError(const std::string& msg);
 
   // Called when |decoder_| finishes decoding a frame.
@@ -250,7 +250,6 @@
   InitCB init_cb_;
   OutputCB client_output_cb_;
   DecodeCB client_flush_cb_;
-  base::OnceClosure client_reset_cb_;
 
   // True if we need to notify |decoder_| that the pipeline is flushed via
   // DecoderInterface::ApplyResolutionChange().
diff --git a/media/gpu/chromeos/video_decoder_pipeline_unittest.cc b/media/gpu/chromeos/video_decoder_pipeline_unittest.cc
index 41dc6e8..9582d94 100644
--- a/media/gpu/chromeos/video_decoder_pipeline_unittest.cc
+++ b/media/gpu/chromeos/video_decoder_pipeline_unittest.cc
@@ -103,13 +103,24 @@
   }
   MOCK_METHOD1(OnInit, void(Status));
   MOCK_METHOD1(OnOutput, void(scoped_refptr<VideoFrame>));
+  MOCK_METHOD0(OnResetDone, void());
 
   void SetCreateDecoderFunctionCB(
       VideoDecoderPipeline::CreateDecoderFunctionCB function) {
     decoder_->create_decoder_function_cb_ = std::move(function);
   }
 
-  void InitializeDecoder() {
+  // Constructs |decoder_| with a given |create_decoder_function_cb| and
+  // verifying |status_code| is received back in OnInit().
+  void InitializeDecoder(
+      VideoDecoderPipeline::CreateDecoderFunctionCB create_decoder_function_cb,
+      StatusCode status_code) {
+    SetCreateDecoderFunctionCB(create_decoder_function_cb);
+
+    base::RunLoop run_loop;
+    EXPECT_CALL(*this, OnInit(MatchesStatusCode(status_code)))
+        .WillOnce(RunClosure(run_loop.QuitClosure()));
+
     decoder_->Initialize(
         config_, false /* low_delay */, nullptr /* cdm_context */,
         base::BindOnce(&VideoDecoderPipelineTest::OnInit,
@@ -117,6 +128,7 @@
         base::BindRepeating(&VideoDecoderPipelineTest::OnOutput,
                             base::Unretained(this)),
         base::DoNothing());
+    run_loop.Run();
   }
 
   static std::unique_ptr<DecoderInterface> CreateNullMockDecoder(
@@ -162,14 +174,8 @@
 
 // Verifies the status code for several typical CreateDecoderFunctionCB cases.
 TEST_P(VideoDecoderPipelineTest, Initialize) {
-  SetCreateDecoderFunctionCB(GetParam().create_decoder_function_cb);
-
-  base::RunLoop run_loop;
-  EXPECT_CALL(*this, OnInit(MatchesStatusCode(GetParam().status_code)))
-      .WillOnce(RunClosure(run_loop.QuitClosure()));
-
-  InitializeDecoder();
-  run_loop.Run();
+  InitializeDecoder(GetParam().create_decoder_function_cb,
+                    GetParam().status_code);
 
   EXPECT_EQ(GetParam().status_code == StatusCode::kOk,
             !!GetUnderlyingDecoder());
@@ -196,4 +202,25 @@
                          VideoDecoderPipelineTest,
                          testing::ValuesIn(kDecoderPipelineTestParams));
 
+// Verifies the Reset sequence.
+TEST_F(VideoDecoderPipelineTest, Reset) {
+  InitializeDecoder(
+      base::BindRepeating(&VideoDecoderPipelineTest::CreateGoodMockDecoder),
+      StatusCode::kOk);
+
+  // When we call Reset(), we expect GetUnderlyingDecoder()'s Reset() method to
+  // be called, and when that method Run()s its argument closure, then
+  // OnResetDone() is expected to be called.
+
+  base::RunLoop run_loop;
+  EXPECT_CALL(*reinterpret_cast<MockDecoder*>(GetUnderlyingDecoder()), Reset(_))
+      .WillOnce(::testing::WithArgs<0>(
+          [](base::OnceClosure closure) { std::move(closure).Run(); }));
+
+  EXPECT_CALL(*this, OnResetDone())
+      .WillOnce(RunClosure(run_loop.QuitClosure()));
+
+  decoder_->Reset(base::BindOnce(&VideoDecoderPipelineTest::OnResetDone,
+                                 base::Unretained(this)));
+}
 }  // namespace media
diff --git a/media/mojo/mojom/speech_recognition_service.mojom b/media/mojo/mojom/speech_recognition_service.mojom
index e251ef1..8afe1f3 100644
--- a/media/mojo/mojom/speech_recognition_service.mojom
+++ b/media/mojo/mojom/speech_recognition_service.mojom
@@ -98,6 +98,9 @@
 interface SpeechRecognitionRecognizerClient {
   // Triggered by speech recognition process on a speech recognition event.
   OnSpeechRecognitionRecognitionEvent(SpeechRecognitionResult result);
+
+  // Triggered by an error within the speech recognition service.
+  OnSpeechRecognitionError();
 };
 
 // A speech recognition result created by the speech service and passed to the
diff --git a/media/video/BUILD.gn b/media/video/BUILD.gn
index 77850ed..009c45cc 100644
--- a/media/video/BUILD.gn
+++ b/media/video/BUILD.gn
@@ -125,6 +125,7 @@
     "h264_parser_unittest.cc",
     "h264_poc_unittest.cc",
     "half_float_maker_unittest.cc",
+    "software_video_encoder_test.cc",
     "video_encode_accelerator_adapter_test.cc",
   ]
   if (enable_platform_hevc) {
diff --git a/media/video/openh264_video_encoder.cc b/media/video/openh264_video_encoder.cc
index bc75f01..8aab812 100644
--- a/media/video/openh264_video_encoder.cc
+++ b/media/video/openh264_video_encoder.cc
@@ -11,6 +11,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/system/sys_info.h"
 #include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/video_frame.h"
 #include "media/base/video_util.h"
@@ -44,6 +45,7 @@
     params->iRCMode = RC_OFF_MODE;
   }
 
+  params->iTemporalLayerNum = options.temporal_layers;
   params->iSpatialLayerNum = 1;
   params->sSpatialLayers[0].fFrameRate = params->fMaxFrameRate;
   params->sSpatialLayers[0].iMaxSpatialBitrate = params->iTargetBitrate;
@@ -86,6 +88,12 @@
   }
 
   profile_ = profile;
+  if (profile != H264PROFILE_BASELINE) {
+    auto status =
+        Status(StatusCode::kEncoderInitializationError, "Unsupported profile");
+    std::move(done_cb).Run(status);
+    return;
+  }
 
   ISVCEncoder* raw_codec = nullptr;
   if (WelsCreateSVCEncoder(&raw_codec) != 0) {
@@ -141,6 +149,78 @@
   std::move(done_cb).Run(OkStatus());
 }
 
+Status OpenH264VideoEncoder::DrainOutputs(const SFrameBSInfo& frame_info,
+                                          base::TimeDelta timestamp) {
+  VideoEncoderOutput result;
+  result.key_frame = (frame_info.eFrameType == videoFrameTypeIDR);
+  result.timestamp = timestamp;
+
+  DCHECK_GT(frame_info.iFrameSizeInBytes, 0);
+  size_t total_chunk_size = frame_info.iFrameSizeInBytes;
+  result.data.reset(new uint8_t[total_chunk_size]);
+  auto* gather_buffer = result.data.get();
+
+  if (h264_converter_) {
+    // Copy data to a temporary buffer instead.
+    conversion_buffer_.resize(total_chunk_size);
+    gather_buffer = conversion_buffer_.data();
+  }
+
+  result.temporal_id = -1;
+  size_t written_size = 0;
+  for (int layer_idx = 0; layer_idx < frame_info.iLayerNum; ++layer_idx) {
+    const SLayerBSInfo& layer_info = frame_info.sLayerInfo[layer_idx];
+
+    // All layers in the same frame must have the same temporal_id.
+    if (result.temporal_id == -1)
+      result.temporal_id = layer_info.uiTemporalId;
+    else if (result.temporal_id != layer_info.uiTemporalId)
+      return Status(StatusCode::kEncoderFailedEncode);
+
+    size_t layer_len = 0;
+    for (int nal_idx = 0; nal_idx < layer_info.iNalCount; ++nal_idx)
+      layer_len += layer_info.pNalLengthInByte[nal_idx];
+    if (written_size + layer_len > total_chunk_size)
+      return Status(StatusCode::kEncoderFailedEncode);
+
+    memcpy(gather_buffer + written_size, layer_info.pBsBuf, layer_len);
+    written_size += layer_len;
+  }
+  DCHECK_EQ(written_size, total_chunk_size);
+
+  if (!h264_converter_) {
+    result.size = total_chunk_size;
+
+    output_cb_.Run(std::move(result), base::Optional<CodecDescription>());
+    return OkStatus();
+  }
+
+  size_t converted_output_size = 0;
+  bool config_changed = false;
+  auto status = h264_converter_->ConvertChunk(
+      conversion_buffer_,
+      base::span<uint8_t>(result.data.get(), total_chunk_size), &config_changed,
+      &converted_output_size);
+
+  if (!status.is_ok())
+    return status;
+
+  result.size = converted_output_size;
+
+  base::Optional<CodecDescription> desc;
+  if (config_changed) {
+    const auto& config = h264_converter_->GetCurrentConfig();
+    desc = CodecDescription();
+    if (!config.Serialize(desc.value())) {
+      return Status(StatusCode::kEncoderFailedEncode,
+                    "Failed to serialize AVC decoder config");
+    }
+  }
+
+  output_cb_.Run(std::move(result), std::move(desc));
+  return OkStatus();
+}
+
 void OpenH264VideoEncoder::Encode(scoped_refptr<VideoFrame> frame,
                                   bool key_frame,
                                   StatusCB done_cb) {
@@ -223,6 +303,7 @@
   }
 
   SFrameBSInfo frame_info = {};
+  TRACE_EVENT0("media", "OpenH264::EncodeFrame");
   if (int err = codec_->EncodeFrame(&picture, &frame_info)) {
     std::move(done_cb).Run(Status(StatusCode::kEncoderFailedEncode,
                                   "Failed to encode using OpenH264.")
@@ -230,75 +311,8 @@
     return;
   }
 
-  VideoEncoderOutput result;
-  result.key_frame = (frame_info.eFrameType == videoFrameTypeIDR);
-  result.timestamp = frame->timestamp();
-
-  DCHECK_GT(frame_info.iFrameSizeInBytes, 0);
-  size_t total_chunk_size = frame_info.iFrameSizeInBytes;
-
-  result.data.reset(new uint8_t[total_chunk_size]);
-
-  auto* gather_buffer = result.data.get();
-
-  if (h264_converter_) {
-    // Copy data to a temporary buffer instead.
-    conversion_buffer_.resize(total_chunk_size);
-    gather_buffer = conversion_buffer_.data();
-  }
-
-  size_t written_size = 0;
-  for (int layer_idx = 0; layer_idx < frame_info.iLayerNum; ++layer_idx) {
-    SLayerBSInfo& layer_info = frame_info.sLayerInfo[layer_idx];
-    size_t layer_len = 0;
-    for (int nal_idx = 0; nal_idx < layer_info.iNalCount; ++nal_idx)
-      layer_len += layer_info.pNalLengthInByte[nal_idx];
-    if (written_size + layer_len > total_chunk_size) {
-      std::move(done_cb).Run(Status(StatusCode::kEncoderFailedEncode,
-                                    "Inconsistent size of the encoded frame."));
-      return;
-    }
-
-    memcpy(gather_buffer + written_size, layer_info.pBsBuf, layer_len);
-    written_size += layer_len;
-  }
-  DCHECK_EQ(written_size, total_chunk_size);
-
-  if (!h264_converter_) {
-    result.size = total_chunk_size;
-
-    output_cb_.Run(std::move(result), base::Optional<CodecDescription>());
-    std::move(done_cb).Run(OkStatus());
-    return;
-  }
-
-  size_t converted_output_size = 0;
-  bool config_changed = false;
-  status = h264_converter_->ConvertChunk(
-      conversion_buffer_,
-      base::span<uint8_t>(result.data.get(), total_chunk_size), &config_changed,
-      &converted_output_size);
-
-  if (!status.is_ok()) {
-    std::move(done_cb).Run(std::move(status).AddHere(FROM_HERE));
-    return;
-  }
-
-  result.size = converted_output_size;
-
-  base::Optional<CodecDescription> desc;
-  if (config_changed) {
-    const auto& config = h264_converter_->GetCurrentConfig();
-    desc = CodecDescription();
-    if (!config.Serialize(desc.value())) {
-      std::move(done_cb).Run(Status(StatusCode::kEncoderFailedEncode,
-                                    "Failed to serialize AVC decoder config"));
-      return;
-    }
-  }
-
-  output_cb_.Run(std::move(result), std::move(desc));
-  std::move(done_cb).Run(OkStatus());
+  status = DrainOutputs(frame_info, frame->timestamp());
+  std::move(done_cb).Run(std::move(status));
 }
 
 void OpenH264VideoEncoder::ChangeOptions(const Options& options,
diff --git a/media/video/openh264_video_encoder.h b/media/video/openh264_video_encoder.h
index d737b3d..3a4a57b 100644
--- a/media/video/openh264_video_encoder.h
+++ b/media/video/openh264_video_encoder.h
@@ -37,7 +37,8 @@
   void Flush(StatusCB done_cb) override;
 
  private:
-  void DrainOutputs();
+  Status DrainOutputs(const SFrameBSInfo& frame_info,
+                      base::TimeDelta timestamp);
 
   class ISVCEncoderDeleter {
    public:
diff --git a/media/video/software_video_encoder_test.cc b/media/video/software_video_encoder_test.cc
new file mode 100644
index 0000000..0cb47bf
--- /dev/null
+++ b/media/video/software_video_encoder_test.cc
@@ -0,0 +1,724 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/video/video_encode_accelerator_adapter.h"
+
+#include <memory>
+#include <string>
+
+#include "base/logging.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/sequenced_task_runner.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/bind.h"
+#include "base/test/gmock_callback_support.h"
+#include "base/test/task_environment.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "media/base/decoder_buffer.h"
+#include "media/base/mock_media_log.h"
+#include "media/base/video_encoder.h"
+#include "media/base/video_frame.h"
+#include "media/base/video_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/libyuv/include/libyuv.h"
+
+#if BUILDFLAG(ENABLE_OPENH264)
+#include "media/video/openh264_video_encoder.h"
+#endif
+
+#if BUILDFLAG(ENABLE_FFMPEG_VIDEO_DECODERS)
+#include "media/filters/ffmpeg_video_decoder.h"
+#endif
+
+#if BUILDFLAG(ENABLE_LIBVPX)
+#include "media/filters/vpx_video_decoder.h"
+#include "media/video/vpx_video_encoder.h"
+#endif
+
+namespace media {
+
+struct SwVideoTestParams {
+  VideoCodec codec;
+  VideoCodecProfile profile;
+  VideoPixelFormat pixel_format;
+  int temporal_layers = 1;
+};
+
+class SoftwareVideoEncoderTest
+    : public ::testing::TestWithParam<SwVideoTestParams> {
+ public:
+  SoftwareVideoEncoderTest() = default;
+
+  void SetUp() override {
+    auto args = GetParam();
+    profile_ = args.profile;
+    pixel_format_ = args.pixel_format;
+    codec_ = args.codec;
+    encoder_ = CreateEncoder(codec_);
+  }
+
+  void TearDown() override {
+    encoder_.reset();
+    decoder_.reset();
+    RunUntilIdle();
+  }
+
+  void PrepareDecoder(
+      gfx::Size size,
+      VideoDecoder::OutputCB output_cb,
+      std::vector<uint8_t> extra_data = std::vector<uint8_t>()) {
+    gfx::Rect visible_rect(size.width(), size.height());
+    VideoDecoderConfig config(
+        codec_, profile_, VideoDecoderConfig::AlphaMode::kIsOpaque,
+        VideoColorSpace::JPEG(), VideoTransformation(), size, visible_rect,
+        size, extra_data, EncryptionScheme::kUnencrypted);
+
+    if (codec_ == kCodecH264 || codec_ == kCodecVP8) {
+#if BUILDFLAG(ENABLE_FFMPEG_VIDEO_DECODERS)
+      decoder_ = std::make_unique<FFmpegVideoDecoder>(&media_log_);
+#endif
+    } else if (codec_ == kCodecVP9) {
+#if BUILDFLAG(ENABLE_LIBVPX)
+      decoder_ = std::make_unique<VpxVideoDecoder>();
+#endif
+    }
+
+    EXPECT_NE(decoder_, nullptr);
+    decoder_->Initialize(config, false, nullptr, ValidatingStatusCB(),
+                         std::move(output_cb), base::NullCallback());
+    RunUntilIdle();
+  }
+
+  void RunUntilIdle() { task_environment_.RunUntilIdle(); }
+
+  scoped_refptr<VideoFrame> CreateI420Frame(gfx::Size size,
+                                            uint32_t color,
+                                            base::TimeDelta timestamp) {
+    auto frame = VideoFrame::CreateFrame(PIXEL_FORMAT_I420, size,
+                                         gfx::Rect(size), size, timestamp);
+    auto y = color & 0xFF;
+    auto u = (color >> 8) & 0xFF;
+    auto v = (color >> 16) & 0xFF;
+    libyuv::I420Rect(
+        frame->data(VideoFrame::kYPlane), frame->stride(VideoFrame::kYPlane),
+        frame->data(VideoFrame::kUPlane), frame->stride(VideoFrame::kUPlane),
+        frame->data(VideoFrame::kVPlane), frame->stride(VideoFrame::kVPlane),
+        0,                               // left
+        0,                               // top
+        frame->visible_rect().width(),   // right
+        frame->visible_rect().height(),  // bottom
+        y,                               // Y color
+        u,                               // U color
+        v);                              // V color
+    return frame;
+  }
+
+  scoped_refptr<VideoFrame> CreateRGBFrame(gfx::Size size,
+                                           uint32_t color,
+                                           base::TimeDelta timestamp) {
+    auto frame = VideoFrame::CreateFrame(PIXEL_FORMAT_XRGB, size,
+                                         gfx::Rect(size), size, timestamp);
+
+    libyuv::ARGBRect(frame->data(VideoFrame::kARGBPlane),
+                     frame->stride(VideoFrame::kARGBPlane),
+                     0,                               // left
+                     0,                               // top
+                     frame->visible_rect().width(),   // right
+                     frame->visible_rect().height(),  // bottom
+                     color);
+
+    return frame;
+  }
+
+  scoped_refptr<VideoFrame> CreateFrame(gfx::Size size,
+                                        VideoPixelFormat format,
+                                        base::TimeDelta timestamp,
+                                        uint32_t color = 0x964050) {
+    switch (format) {
+      case PIXEL_FORMAT_I420:
+        return CreateI420Frame(size, color, timestamp);
+      case PIXEL_FORMAT_XRGB:
+        return CreateRGBFrame(size, color, timestamp);
+      default:
+        EXPECT_TRUE(false) << "not supported pixel format";
+        return nullptr;
+    }
+  }
+
+  std::unique_ptr<VideoEncoder> CreateEncoder(VideoCodec codec) {
+    switch (codec) {
+      case media::kCodecVP8:
+      case media::kCodecVP9:
+#if BUILDFLAG(ENABLE_LIBVPX)
+        return std::make_unique<media::VpxVideoEncoder>();
+#else
+        return nullptr;
+#endif
+      case media::kCodecH264:
+#if BUILDFLAG(ENABLE_OPENH264)
+        return std::make_unique<OpenH264VideoEncoder>();
+#else
+        return nullptr;
+#endif
+      default:
+        return nullptr;
+    }
+  }
+
+  VideoEncoder::StatusCB ValidatingStatusCB(base::Location loc = FROM_HERE) {
+    struct CallEnforcer {
+      bool called = false;
+      std::string location;
+      ~CallEnforcer() {
+        EXPECT_TRUE(called) << "Callback created: " << location;
+      }
+    };
+    auto enforcer = std::make_unique<CallEnforcer>();
+    enforcer->location = loc.ToString();
+    return base::BindLambdaForTesting(
+        [enforcer{std::move(enforcer)}](Status s) {
+          EXPECT_TRUE(s.is_ok())
+              << " Callback created: " << enforcer->location
+              << " Code: " << s.code() << " Error: " << s.message();
+          enforcer->called = true;
+        });
+  }
+
+  int CountDifferentPixels(VideoFrame& frame1, VideoFrame& frame2) {
+    int diff_cnt = 0;
+    uint8_t tolerance = 10;
+
+    if (frame1.format() != frame2.format() ||
+        frame1.visible_rect() != frame2.visible_rect()) {
+      return frame1.coded_size().GetArea();
+    }
+
+    VideoPixelFormat format = frame1.format();
+    size_t num_planes = VideoFrame::NumPlanes(format);
+    gfx::Size visible_size = frame1.visible_rect().size();
+    for (size_t plane = 0; plane < num_planes; ++plane) {
+      uint8_t* data1 = frame1.visible_data(plane);
+      int stride1 = frame1.stride(plane);
+      uint8_t* data2 = frame2.visible_data(plane);
+      int stride2 = frame2.stride(plane);
+      size_t rows = VideoFrame::Rows(plane, format, visible_size.height());
+      int row_bytes = VideoFrame::RowBytes(plane, format, visible_size.width());
+
+      for (size_t r = 0; r < rows; ++r) {
+        for (int c = 0; c < row_bytes; ++c) {
+          uint8_t b1 = data1[(stride1 * r) + c];
+          uint8_t b2 = data2[(stride2 * r) + c];
+          uint8_t diff = std::max(b1, b2) - std::min(b1, b2);
+          if (diff > tolerance)
+            diff_cnt++;
+        }
+      }
+    }
+    return diff_cnt;
+  }
+
+ protected:
+  VideoCodec codec_;
+  VideoCodecProfile profile_;
+  VideoPixelFormat pixel_format_;
+
+  MockMediaLog media_log_;
+  base::test::TaskEnvironment task_environment_;
+  std::unique_ptr<VideoEncoder> encoder_;
+  std::unique_ptr<VideoDecoder> decoder_;
+};
+
+class H264VideoEncoderTest : public SoftwareVideoEncoderTest {};
+class SVCVideoEncoderTest : public SoftwareVideoEncoderTest {};
+
+TEST_P(SoftwareVideoEncoderTest, InitializeAndFlush) {
+  VideoEncoder::Options options;
+  options.frame_size = gfx::Size(640, 480);
+  bool output_called = false;
+  VideoEncoder::OutputCB output_cb = base::BindLambdaForTesting(
+      [&](VideoEncoderOutput, base::Optional<VideoEncoder::CodecDescription>) {
+        output_called = true;
+      });
+
+  encoder_->Initialize(profile_, options, std::move(output_cb),
+                       ValidatingStatusCB());
+  RunUntilIdle();
+  encoder_->Flush(ValidatingStatusCB());
+  RunUntilIdle();
+  EXPECT_FALSE(output_called) << "Output callback shouldn't be called";
+}
+
+TEST_P(SoftwareVideoEncoderTest, ForceAllKeyFrames) {
+  int outputs_count = 0;
+  int frames = 10;
+  VideoEncoder::Options options;
+  options.frame_size = gfx::Size(640, 480);
+  auto frame_duration = base::TimeDelta::FromSecondsD(1.0 / 60);
+
+  VideoEncoder::OutputCB output_cb = base::BindLambdaForTesting(
+      [&](VideoEncoderOutput output,
+          base::Optional<VideoEncoder::CodecDescription> desc) {
+        EXPECT_TRUE(output.key_frame);
+        outputs_count++;
+      });
+
+  encoder_->Initialize(profile_, options, std::move(output_cb),
+                       ValidatingStatusCB());
+  RunUntilIdle();
+
+  for (int i = 0; i < frames; i++) {
+    auto timestamp = i * frame_duration;
+    auto frame = CreateFrame(options.frame_size, pixel_format_, timestamp);
+    encoder_->Encode(frame, true, ValidatingStatusCB());
+  }
+
+  encoder_->Flush(ValidatingStatusCB());
+  RunUntilIdle();
+  EXPECT_EQ(outputs_count, frames);
+}
+
+TEST_P(SoftwareVideoEncoderTest, ResizeFrames) {
+  int outputs_count = 0;
+  VideoEncoder::Options options;
+  options.frame_size = gfx::Size(640, 480);
+  auto sec = base::TimeDelta::FromSeconds(1);
+
+  VideoEncoder::OutputCB output_cb = base::BindLambdaForTesting(
+      [&](VideoEncoderOutput output,
+          base::Optional<VideoEncoder::CodecDescription> desc) {
+        outputs_count++;
+      });
+
+  encoder_->Initialize(profile_, options, std::move(output_cb),
+                       ValidatingStatusCB());
+  RunUntilIdle();
+
+  auto frame1 = CreateFrame(gfx::Size(320, 200), pixel_format_, 0 * sec);
+  auto frame2 = CreateFrame(gfx::Size(800, 600), pixel_format_, 1 * sec);
+  auto frame3 = CreateFrame(gfx::Size(720, 1280), pixel_format_, 2 * sec);
+  encoder_->Encode(frame1, false, ValidatingStatusCB());
+  encoder_->Encode(frame2, false, ValidatingStatusCB());
+  encoder_->Encode(frame3, false, ValidatingStatusCB());
+
+  encoder_->Flush(ValidatingStatusCB());
+  RunUntilIdle();
+  EXPECT_EQ(outputs_count, 3);
+}
+
+TEST_P(SoftwareVideoEncoderTest, OutputCountEqualsFrameCount) {
+  VideoEncoder::Options options;
+  options.frame_size = gfx::Size(320, 200);
+  options.bitrate = 1e6;  // 1Mbps
+  options.framerate = 25;
+  options.keyframe_interval = options.framerate.value() * 3;  // every 3s
+  int total_frames_count =
+      options.framerate.value() * 10;  // total duration 20s
+  int outputs_count = 0;
+
+  auto frame_duration =
+      base::TimeDelta::FromSecondsD(1.0 / options.framerate.value());
+
+  VideoEncoder::OutputCB output_cb = base::BindLambdaForTesting(
+      [&](VideoEncoderOutput output,
+          base::Optional<VideoEncoder::CodecDescription> desc) {
+        EXPECT_NE(output.data, nullptr);
+        EXPECT_EQ(output.timestamp, frame_duration * outputs_count);
+        outputs_count++;
+      });
+
+  encoder_->Initialize(profile_, options, std::move(output_cb),
+                       ValidatingStatusCB());
+
+  RunUntilIdle();
+  uint32_t color = 0x964050;
+  for (int frame_index = 0; frame_index < total_frames_count; frame_index++) {
+    auto timestamp = frame_index * frame_duration;
+    auto frame =
+        CreateFrame(options.frame_size, pixel_format_, timestamp, color);
+    color = (color << 1) + frame_index;
+    encoder_->Encode(frame, false, ValidatingStatusCB());
+    RunUntilIdle();
+  }
+
+  encoder_->Flush(ValidatingStatusCB());
+  RunUntilIdle();
+  EXPECT_EQ(outputs_count, total_frames_count);
+}
+
+#if BUILDFLAG(ENABLE_FFMPEG_VIDEO_DECODERS)
+TEST_P(SoftwareVideoEncoderTest, EncodeAndDecode) {
+  VideoEncoder::Options options;
+  options.frame_size = gfx::Size(320, 200);
+  options.bitrate = 1e6;  // 1Mbps
+  options.framerate = 25;
+  if (codec_ == kCodecH264)
+    options.avc.produce_annexb = true;
+  options.keyframe_interval = options.framerate.value() * 3;  // every 3s
+  std::vector<scoped_refptr<VideoFrame>> frames_to_encode;
+  std::vector<scoped_refptr<VideoFrame>> decoded_frames;
+  int total_frames_count =
+      options.framerate.value() * 10;  // total duration 10s
+
+  auto frame_duration =
+      base::TimeDelta::FromSecondsD(1.0 / options.framerate.value());
+
+  VideoEncoder::OutputCB encoder_output_cb = base::BindLambdaForTesting(
+      [&, this](VideoEncoderOutput output,
+                base::Optional<VideoEncoder::CodecDescription> desc) {
+        auto buffer =
+            DecoderBuffer::FromArray(std::move(output.data), output.size);
+        buffer->set_timestamp(output.timestamp);
+        buffer->set_is_key_frame(output.key_frame);
+        decoder_->Decode(std::move(buffer), ValidatingStatusCB());
+      });
+
+  VideoDecoder::OutputCB decoder_output_cb =
+      base::BindLambdaForTesting([&](scoped_refptr<VideoFrame> frame) {
+        decoded_frames.push_back(frame);
+      });
+
+  PrepareDecoder(options.frame_size, std::move(decoder_output_cb));
+
+  encoder_->Initialize(profile_, options, std::move(encoder_output_cb),
+                       ValidatingStatusCB());
+  RunUntilIdle();
+
+  uint32_t color = 0x964050;
+  for (int frame_index = 0; frame_index < total_frames_count; frame_index++) {
+    auto timestamp = frame_index * frame_duration;
+    auto frame =
+        CreateFrame(options.frame_size, pixel_format_, timestamp, color);
+    frames_to_encode.push_back(frame);
+    color = (color << 1) + frame_index;
+    encoder_->Encode(frame, false, ValidatingStatusCB());
+    RunUntilIdle();
+  }
+
+  encoder_->Flush(ValidatingStatusCB());
+  decoder_->Decode(DecoderBuffer::CreateEOSBuffer(), ValidatingStatusCB());
+  RunUntilIdle();
+  EXPECT_EQ(decoded_frames.size(), frames_to_encode.size());
+  for (auto i = 0u; i < decoded_frames.size(); i++) {
+    auto original_frame = frames_to_encode[i];
+    auto decoded_frame = decoded_frames[i];
+    EXPECT_EQ(decoded_frame->timestamp(), original_frame->timestamp());
+    EXPECT_EQ(decoded_frame->visible_rect(), original_frame->visible_rect());
+    EXPECT_EQ(decoded_frame->format(), PIXEL_FORMAT_I420);
+    if (decoded_frame->format() == original_frame->format()) {
+      EXPECT_LE(CountDifferentPixels(*decoded_frame, *original_frame),
+                original_frame->visible_rect().width());
+    }
+  }
+}
+
+TEST_P(SVCVideoEncoderTest, EncodeClipTemporalSvc) {
+  VideoEncoder::Options options;
+  options.frame_size = gfx::Size(320, 200);
+  options.bitrate = 1e6;  // 1Mbps
+  options.framerate = 25;
+  options.temporal_layers = GetParam().temporal_layers;
+  if (codec_ == kCodecH264)
+    options.avc.produce_annexb = true;
+  std::vector<scoped_refptr<VideoFrame>> frames_to_encode;
+
+  std::vector<VideoEncoderOutput> chunks;
+  size_t total_frames_count = 80;
+
+  // Encoder all frames with 3 temporal layers and put all outputs in |chunks|
+  auto frame_duration =
+      base::TimeDelta::FromSecondsD(1.0 / options.framerate.value());
+
+  VideoEncoder::OutputCB encoder_output_cb = base::BindLambdaForTesting(
+      [&](VideoEncoderOutput output,
+          base::Optional<VideoEncoder::CodecDescription> desc) {
+        chunks.push_back(std::move(output));
+      });
+
+  encoder_->Initialize(profile_, options, std::move(encoder_output_cb),
+                       ValidatingStatusCB());
+  RunUntilIdle();
+
+  uint32_t color = 0x964050;
+  for (auto frame_index = 0u; frame_index < total_frames_count; frame_index++) {
+    auto timestamp = frame_index * frame_duration;
+    auto frame =
+        CreateFrame(options.frame_size, pixel_format_, timestamp, color);
+    color = (color << 1) + frame_index;
+    frames_to_encode.push_back(frame);
+    encoder_->Encode(frame, false, ValidatingStatusCB());
+    RunUntilIdle();
+  }
+
+  encoder_->Flush(ValidatingStatusCB());
+  RunUntilIdle();
+  EXPECT_EQ(chunks.size(), total_frames_count);
+
+  // Try decoding saved outputs dropping varying number of layers
+  // and check that decoded frames indeed match the pattern:
+  // Layer Index 0: |0| | | |4| | | |8| |  |  |12|
+  // Layer Index 1: | | |2| | | |6| | | |10|  |  |
+  // Layer Index 2: | |1| |3| |5| |7| |9|  |11|  |
+  for (int max_layer = 0; max_layer < options.temporal_layers; max_layer++) {
+    std::vector<scoped_refptr<VideoFrame>> decoded_frames;
+    VideoDecoder::OutputCB decoder_output_cb =
+        base::BindLambdaForTesting([&](scoped_refptr<VideoFrame> frame) {
+          decoded_frames.push_back(frame);
+        });
+    PrepareDecoder(options.frame_size, std::move(decoder_output_cb));
+
+    for (auto& chunk : chunks) {
+      if (chunk.temporal_id <= max_layer && chunk.data) {
+        auto buffer = DecoderBuffer::CopyFrom(chunk.data.get(), chunk.size);
+        buffer->set_timestamp(chunk.timestamp);
+        buffer->set_is_key_frame(chunk.key_frame);
+        decoder_->Decode(std::move(buffer), ValidatingStatusCB());
+        RunUntilIdle();
+      }
+    }
+    decoder_->Decode(DecoderBuffer::CreateEOSBuffer(), ValidatingStatusCB());
+    RunUntilIdle();
+
+    int rate_decimator =
+        (1 << (options.temporal_layers - 1)) / (1 << max_layer);
+    ASSERT_EQ(decoded_frames.size(),
+              size_t{total_frames_count / rate_decimator});
+    for (auto i = 0u; i < decoded_frames.size(); i++) {
+      auto decoded_frame = decoded_frames[i];
+      auto original_frame = frames_to_encode[i * rate_decimator];
+      EXPECT_EQ(decoded_frame->timestamp(), original_frame->timestamp());
+    }
+  }
+}
+#endif  // ENABLE_FFMPEG_VIDEO_DECODERS
+
+TEST_P(H264VideoEncoderTest, AvcExtraData) {
+  int outputs_count = 0;
+  VideoEncoder::Options options;
+  options.frame_size = gfx::Size(640, 480);
+  auto sec = base::TimeDelta::FromSeconds(1);
+
+  VideoEncoder::OutputCB output_cb = base::BindLambdaForTesting(
+      [&](VideoEncoderOutput output,
+          base::Optional<VideoEncoder::CodecDescription> desc) {
+        switch (outputs_count) {
+          case 0:
+            // First frame should have extra_data
+            EXPECT_TRUE(desc.has_value());
+            break;
+          case 1:
+            // Regular non-key frame shouldn't have extra_data
+            EXPECT_FALSE(desc.has_value());
+            break;
+          case 2:
+            // Forced Key frame should have extra_data
+            EXPECT_TRUE(desc.has_value());
+            break;
+        }
+
+        EXPECT_NE(output.data, nullptr);
+        outputs_count++;
+      });
+
+  encoder_->Initialize(profile_, options, std::move(output_cb),
+                       ValidatingStatusCB());
+  RunUntilIdle();
+
+  auto frame1 = CreateFrame(options.frame_size, pixel_format_, 0 * sec);
+  auto frame2 = CreateFrame(options.frame_size, pixel_format_, 1 * sec);
+  auto frame3 = CreateFrame(options.frame_size, pixel_format_, 2 * sec);
+  encoder_->Encode(frame1, false, ValidatingStatusCB());
+  encoder_->Encode(frame2, false, ValidatingStatusCB());
+  encoder_->Encode(frame3, true, ValidatingStatusCB());
+
+  encoder_->Flush(ValidatingStatusCB());
+  RunUntilIdle();
+  EXPECT_EQ(outputs_count, 3);
+}
+
+TEST_P(H264VideoEncoderTest, AnnexB) {
+  int outputs_count = 0;
+  VideoEncoder::Options options;
+  options.frame_size = gfx::Size(640, 480);
+  options.avc.produce_annexb = true;
+  auto sec = base::TimeDelta::FromSeconds(1);
+
+  VideoEncoder::OutputCB output_cb = base::BindLambdaForTesting(
+      [&](VideoEncoderOutput output,
+          base::Optional<VideoEncoder::CodecDescription> desc) {
+        EXPECT_FALSE(desc.has_value());
+        EXPECT_NE(output.data, nullptr);
+
+        // Check for a start code, it's either {0, 0, 1} or {0, 0, 0, 1}
+        EXPECT_EQ(output.data[0], 0);
+        EXPECT_EQ(output.data[1], 0);
+        if (output.data[2] == 0)
+          EXPECT_EQ(output.data[3], 1);
+        else
+          EXPECT_EQ(output.data[2], 1);
+        outputs_count++;
+      });
+
+  encoder_->Initialize(profile_, options, std::move(output_cb),
+                       ValidatingStatusCB());
+  RunUntilIdle();
+
+  auto frame1 = CreateFrame(options.frame_size, pixel_format_, 0 * sec);
+  auto frame2 = CreateFrame(options.frame_size, pixel_format_, 1 * sec);
+  auto frame3 = CreateFrame(options.frame_size, pixel_format_, 2 * sec);
+  encoder_->Encode(frame1, false, ValidatingStatusCB());
+  encoder_->Encode(frame2, false, ValidatingStatusCB());
+  encoder_->Encode(frame3, true, ValidatingStatusCB());
+
+  encoder_->Flush(ValidatingStatusCB());
+  RunUntilIdle();
+  EXPECT_EQ(outputs_count, 3);
+}
+
+// This test is different from EncodeAndDecode:
+// 1. It sets produce_annexb = false
+// 2. It recreates the decoder each time there is new AVC extra data (SPS/PPS)
+//    available.
+TEST_P(H264VideoEncoderTest, EncodeAndDecodeWithConfig) {
+  VideoEncoder::Options options;
+  options.frame_size = gfx::Size(320, 200);
+  options.bitrate = 1e6;  // 1Mbps
+  options.framerate = 25;
+  options.avc.produce_annexb = false;
+  struct ChunkWithConfig {
+    VideoEncoderOutput output;
+    base::Optional<VideoEncoder::CodecDescription> desc;
+  };
+  std::vector<scoped_refptr<VideoFrame>> frames_to_encode;
+  std::vector<scoped_refptr<VideoFrame>> decoded_frames;
+  std::vector<ChunkWithConfig> chunks;
+  size_t total_frames_count = 30;
+  auto frame_duration =
+      base::TimeDelta::FromSecondsD(1.0 / options.framerate.value());
+
+  VideoEncoder::OutputCB encoder_output_cb = base::BindLambdaForTesting(
+      [&](VideoEncoderOutput output,
+          base::Optional<VideoEncoder::CodecDescription> desc) {
+        chunks.push_back({std::move(output), std::move(desc)});
+      });
+
+  encoder_->Initialize(profile_, options, std::move(encoder_output_cb),
+                       ValidatingStatusCB());
+  RunUntilIdle();
+
+  uint32_t color = 0x964050;
+  for (auto frame_index = 0u; frame_index < total_frames_count; frame_index++) {
+    const auto timestamp = frame_index * frame_duration;
+    const bool key_frame = (frame_index % 5) == 0;
+    auto frame =
+        CreateFrame(options.frame_size, pixel_format_, timestamp, color);
+    frames_to_encode.push_back(frame);
+    encoder_->Encode(frame, key_frame, ValidatingStatusCB());
+    RunUntilIdle();
+  }
+  encoder_->Flush(ValidatingStatusCB());
+  RunUntilIdle();
+
+  EXPECT_EQ(chunks.size(), total_frames_count);
+  for (auto& chunk : chunks) {
+    VideoDecoder::OutputCB decoder_output_cb =
+        base::BindLambdaForTesting([&](scoped_refptr<VideoFrame> frame) {
+          decoded_frames.push_back(frame);
+        });
+
+    if (chunk.desc.has_value()) {
+      if (decoder_)
+        decoder_->Decode(DecoderBuffer::CreateEOSBuffer(),
+                         ValidatingStatusCB());
+      RunUntilIdle();
+      PrepareDecoder(options.frame_size, std::move(decoder_output_cb),
+                     chunk.desc.value());
+    }
+    auto& output = chunk.output;
+    auto buffer = DecoderBuffer::FromArray(std::move(output.data), output.size);
+    buffer->set_timestamp(output.timestamp);
+    buffer->set_is_key_frame(output.key_frame);
+    decoder_->Decode(std::move(buffer), ValidatingStatusCB());
+    RunUntilIdle();
+  }
+  decoder_->Decode(DecoderBuffer::CreateEOSBuffer(), ValidatingStatusCB());
+  RunUntilIdle();
+  EXPECT_EQ(decoded_frames.size(), total_frames_count);
+}
+
+std::string PrintTestParams(
+    const testing::TestParamInfo<SwVideoTestParams>& info) {
+  auto result = GetCodecName(info.param.codec) + "__" +
+                GetProfileName(info.param.profile) + "__" +
+                VideoPixelFormatToString(info.param.pixel_format) + "__" +
+                base::NumberToString(info.param.temporal_layers);
+
+  // GTest doesn't like spaces, but profile names have spaces, so we need
+  // to replace them with underscores.
+  for (auto& c : result) {
+    if (c == ' ')
+      c = '_';
+  }
+  return result;
+}
+
+#if BUILDFLAG(ENABLE_OPENH264)
+SwVideoTestParams kH264Params[] = {
+    {kCodecH264, H264PROFILE_BASELINE, PIXEL_FORMAT_I420},
+    {kCodecH264, H264PROFILE_BASELINE, PIXEL_FORMAT_XRGB}};
+
+INSTANTIATE_TEST_SUITE_P(H264Specific,
+                         H264VideoEncoderTest,
+                         ::testing::ValuesIn(kH264Params),
+                         PrintTestParams);
+
+INSTANTIATE_TEST_SUITE_P(H264Generic,
+                         SoftwareVideoEncoderTest,
+                         ::testing::ValuesIn(kH264Params),
+                         PrintTestParams);
+
+SwVideoTestParams kH264SVCParams[] = {
+    {kCodecH264, H264PROFILE_BASELINE, PIXEL_FORMAT_I420, 1},
+    {kCodecH264, H264PROFILE_BASELINE, PIXEL_FORMAT_I420, 2},
+    {kCodecH264, H264PROFILE_BASELINE, PIXEL_FORMAT_I420, 3}};
+
+INSTANTIATE_TEST_SUITE_P(H264TemporalSvc,
+                         SVCVideoEncoderTest,
+                         ::testing::ValuesIn(kH264SVCParams),
+                         PrintTestParams);
+#endif  // ENABLE_OPENH264
+
+#if BUILDFLAG(ENABLE_LIBVPX)
+SwVideoTestParams kVpxParams[] = {
+    {kCodecVP9, VP9PROFILE_PROFILE0, PIXEL_FORMAT_I420},
+    {kCodecVP9, VP9PROFILE_PROFILE0, PIXEL_FORMAT_XRGB},
+    {kCodecVP8, VP8PROFILE_ANY, PIXEL_FORMAT_I420},
+    {kCodecVP8, VP8PROFILE_ANY, PIXEL_FORMAT_XRGB}};
+
+INSTANTIATE_TEST_SUITE_P(VpxGeneric,
+                         SoftwareVideoEncoderTest,
+                         ::testing::ValuesIn(kVpxParams),
+                         PrintTestParams);
+
+SwVideoTestParams kVpxSVCParams[] = {
+    {kCodecVP9, VP9PROFILE_PROFILE0, PIXEL_FORMAT_I420, 1},
+    {kCodecVP9, VP9PROFILE_PROFILE0, PIXEL_FORMAT_I420, 2},
+    {kCodecVP9, VP9PROFILE_PROFILE0, PIXEL_FORMAT_I420, 3},
+    {kCodecVP8, VP8PROFILE_ANY, PIXEL_FORMAT_I420, 1},
+    {kCodecVP8, VP8PROFILE_ANY, PIXEL_FORMAT_I420, 2},
+    {kCodecVP8, VP8PROFILE_ANY, PIXEL_FORMAT_I420, 3}};
+
+INSTANTIATE_TEST_SUITE_P(VpxTemporalSvc,
+                         SVCVideoEncoderTest,
+                         ::testing::ValuesIn(kVpxSVCParams),
+                         PrintTestParams);
+#endif  // ENABLE_LIBVPX
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(H264VideoEncoderTest);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SVCVideoEncoderTest);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SoftwareVideoEncoderTest);
+
+}  // namespace media
diff --git a/media/video/vpx_video_encoder.cc b/media/video/vpx_video_encoder.cc
index 1d3be74..f3b8b35 100644
--- a/media/video/vpx_video_encoder.cc
+++ b/media/video/vpx_video_encoder.cc
@@ -4,11 +4,13 @@
 
 #include "media/video/vpx_video_encoder.h"
 
+#include "base/logging.h"
 #include "base/numerics/checked_math.h"
 #include "base/numerics/ranges.h"
 #include "base/strings/stringprintf.h"
 #include "base/system/sys_info.h"
 #include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/video_frame.h"
 #include "media/base/video_util.h"
@@ -19,6 +21,44 @@
 
 namespace {
 
+constexpr vpx_enc_frame_flags_t VP8_UPDATE_NOTHING =
+    VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_LAST;
+
+// Frame Pattern:
+// Layer Index 0: |0| |2| |4| |6| |8|
+// Layer Index 1: | |1| |3| |5| |7| |
+vpx_enc_frame_flags_t vp8_2layers_temporal_flags[] = {
+    // Layer 0 : update and reference only last frame
+    VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF |
+        VP8_EFLAG_NO_UPD_ARF,
+
+    // Layer 1: only reference last frame, no updates
+    VP8_UPDATE_NOTHING | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_REF_GF};
+
+// Frame Pattern:
+// Layer Index 0: |0| | | |4| | | |8| |  |  |12|
+// Layer Index 1: | | |2| | | |6| | | |10|  |  |
+// Layer Index 2: | |1| |3| |5| |7| |9|  |11|  |
+vpx_enc_frame_flags_t vp8_3layers_temporal_flags[] = {
+    // Layer 0 : update and reference only last frame
+    // It only depends on layer 0
+    VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_GF |
+        VP8_EFLAG_NO_UPD_ARF,
+
+    // Layer 2: only reference last frame, no updates
+    // It only depends on layer 0
+    VP8_UPDATE_NOTHING | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_REF_GF,
+
+    // Layer 1: only reference last frame, update gold frame
+    // It only depends on layer 0
+    VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_UPD_ARF |
+        VP8_EFLAG_NO_UPD_LAST,
+
+    // Layer 2: reference last frame and gold frame, no updates
+    // It depends on layer 0 and layer 1
+    VP8_UPDATE_NOTHING | VP8_EFLAG_NO_REF_ARF,
+};
+
 // Returns the number of threads.
 int GetNumberOfThreads(int width) {
   // Default to 1 thread for less than VGA.
@@ -51,6 +91,8 @@
 
   config->g_pass = VPX_RC_ONE_PASS;
   config->g_lag_in_frames = 0;
+  config->rc_max_quantizer = 58;
+  config->rc_min_quantizer = 2;
   config->rc_resize_allowed = 0;
   config->rc_dropframe_thresh = 0;  // Don't drop frames
   config->g_timebase.num = 1;
@@ -79,6 +121,58 @@
   config->g_w = opts.frame_size.width();
   config->g_h = opts.frame_size.height();
 
+  switch (opts.temporal_layers) {
+    case 1:
+      break;
+    case 2:
+      // Frame Pattern:
+      // Layer Index 0: |0| |2| |4| |6| |8|
+      // Layer Index 1: | |1| |3| |5| |7| |
+      config->ts_number_layers = 2;
+      config->ts_periodicity = 2;
+      DCHECK_EQ(config->ts_periodicity,
+                sizeof(vp8_2layers_temporal_flags) /
+                    sizeof(vp8_2layers_temporal_flags[0]));
+      config->ts_layer_id[0] = 0;
+      config->ts_layer_id[1] = 1;
+      config->ts_rate_decimator[0] = 2;
+      config->ts_rate_decimator[1] = 1;
+      // Bitrate allocation L0: 60% L1: 40%
+      config->ts_target_bitrate[0] = 60 * config->rc_target_bitrate / 100;
+      config->ts_target_bitrate[1] = config->rc_target_bitrate;
+      config->temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_0101;
+      config->g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT;
+      break;
+    case 3:
+      // Frame Pattern:
+      // Layer Index 0: |0| | | |4| | | |8| |  |  |12|
+      // Layer Index 1: | | |2| | | |6| | | |10|  |  |
+      // Layer Index 2: | |1| |3| |5| |7| |9|  |11|  |
+      config->ts_number_layers = 3;
+      config->ts_periodicity = 4;
+      DCHECK_EQ(config->ts_periodicity,
+                sizeof(vp8_3layers_temporal_flags) /
+                    sizeof(vp8_3layers_temporal_flags[0]));
+      config->ts_layer_id[0] = 0;
+      config->ts_layer_id[1] = 2;
+      config->ts_layer_id[2] = 1;
+      config->ts_layer_id[3] = 2;
+      config->ts_rate_decimator[0] = 4;
+      config->ts_rate_decimator[1] = 2;
+      config->ts_rate_decimator[2] = 1;
+      // Bitrate allocation L0: 50% L1: 20% L2: 30%
+      config->ts_target_bitrate[0] = 50 * config->rc_target_bitrate / 100;
+      config->ts_target_bitrate[1] = 70 * config->rc_target_bitrate / 100;
+      config->ts_target_bitrate[2] = config->rc_target_bitrate;
+      config->temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_0212;
+      config->g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT;
+      break;
+    default: {
+      return Status(StatusCode::kEncoderUnsupportedConfig,
+                    "Unsupported number of temporal layers.");
+    }
+  }
+
   return Status();
 }
 
@@ -188,20 +282,24 @@
     std::string msg = base::StringPrintf(
         "VPX encoder initialization error: %s %s",
         vpx_codec_err_to_string(vpx_error), codec->err_detail);
-
+    DLOG(ERROR) << msg;
     status = Status(StatusCode::kEncoderInitializationError, msg);
     std::move(done_cb).Run(status);
     return;
   }
 
-  // Due to https://bugs.chromium.org/p/webm/issues/detail?id=1684
-  // values less than 5 crash VP9 encoder.
-  vpx_error = vpx_codec_control(codec.get(), VP8E_SET_CPUUSED, 5);
+  // For VP9 the values used for real-time encoding mode are 5, 6, 7,
+  // 8, 9. Higher means faster encoding, but lower quality.
+  // For VP8 typical values used for real-time encoding are -4, -6,
+  // -8, -10. Again larger magnitude means faster encoding but lower
+  // quality.
+  int cpu_used = is_vp9 ? 7 : -6;
+  vpx_error = vpx_codec_control(codec.get(), VP8E_SET_CPUUSED, cpu_used);
   if (vpx_error != VPX_CODEC_OK) {
     std::string msg =
         base::StringPrintf("VPX encoder VP8E_SET_CPUUSED error: %s",
                            vpx_codec_err_to_string(vpx_error));
-
+    DLOG(ERROR) << msg;
     status = Status(StatusCode::kEncoderInitializationError, msg);
     std::move(done_cb).Run(status);
     return;
@@ -227,6 +325,10 @@
 
     // Turn on row level multi-threading.
     vpx_codec_control(codec.get(), VP9E_SET_ROW_MT, 1);
+
+    // In CBR mode use aq-mode=3 is enabled for quality improvement
+    if (codec_config_.rc_end_usage == VPX_CBR)
+      vpx_codec_control(codec.get(), VP9E_SET_AQ_MODE, 3);
   }
 
   options_ = options;
@@ -359,6 +461,26 @@
   last_frame_timestamp_ = frame->timestamp();
   auto deadline = VPX_DL_REALTIME;
   vpx_codec_flags_t flags = key_frame ? VPX_EFLAG_FORCE_KF : 0;
+
+  int temporal_id = 0;
+  if (codec_config_.ts_number_layers > 1) {
+    if (key_frame)
+      temporal_svc_frame_index = 0;
+    int index_in_temp_cycle =
+        temporal_svc_frame_index % codec_config_.ts_periodicity;
+    temporal_id = codec_config_.ts_layer_id[index_in_temp_cycle];
+    temporal_svc_frame_index++;
+
+    if (profile_ == VP8PROFILE_ANY) {
+      auto* vp8_layers_flags = codec_config_.ts_number_layers == 2
+                                   ? vp8_2layers_temporal_flags
+                                   : vp8_3layers_temporal_flags;
+      flags |= vp8_layers_flags[index_in_temp_cycle];
+      vpx_codec_control(codec_.get(), VP8E_SET_TEMPORAL_LAYER_ID, temporal_id);
+    }
+  }
+
+  TRACE_EVENT0("media", "vpx_codec_encode");
   auto vpx_error = vpx_codec_encode(codec_.get(), &vpx_image_, timestamp_us,
                                     duration_us, flags, deadline);
 
@@ -366,13 +488,14 @@
     std::string msg = base::StringPrintf("VPX encoding error: %s (%s)",
                                          vpx_codec_err_to_string(vpx_error),
                                          vpx_codec_error_detail(codec_.get()));
+    DLOG(ERROR) << msg;
     status = Status(StatusCode::kEncoderFailedEncode, msg)
                  .WithData("vpx_error", vpx_error);
     std::move(done_cb).Run(std::move(status));
     return;
   }
 
-  DrainOutputs();
+  DrainOutputs(temporal_id);
   std::move(done_cb).Run(Status());
 }
 
@@ -492,22 +615,33 @@
     std::string msg = base::StringPrintf("VPX flushing error: %s (%s)",
                                          vpx_codec_err_to_string(vpx_error),
                                          vpx_codec_error_detail(codec_.get()));
+    DLOG(ERROR) << msg;
     Status status = Status(StatusCode::kEncoderFailedEncode, msg)
                         .WithData("vpx_error", vpx_error);
     std::move(done_cb).Run(std::move(status));
     return;
   }
-  DrainOutputs();
+  DrainOutputs(0);
   std::move(done_cb).Run(Status());
 }
 
-void VpxVideoEncoder::DrainOutputs() {
+void VpxVideoEncoder::DrainOutputs(int temporal_id) {
   vpx_codec_iter_t iter = nullptr;
   const vpx_codec_cx_pkt_t* pkt = nullptr;
   while ((pkt = vpx_codec_get_cx_data(codec_.get(), &iter))) {
     if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
       VideoEncoderOutput result;
       result.key_frame = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0;
+
+      if (result.key_frame) {
+        // If we got an unexpected key frame, temporal_svc_frame_index needs to
+        // be adjusted, because the next frame should have index 1.
+        temporal_svc_frame_index = 1;
+        result.temporal_id = 0;
+      } else {
+        result.temporal_id = temporal_id;
+      }
+
       result.timestamp = base::TimeDelta::FromMicroseconds(pkt->data.frame.pts);
       result.size = pkt->data.frame.sz;
       result.data.reset(new uint8_t[result.size]);
diff --git a/media/video/vpx_video_encoder.h b/media/video/vpx_video_encoder.h
index 9a61353..4fffc12 100644
--- a/media/video/vpx_video_encoder.h
+++ b/media/video/vpx_video_encoder.h
@@ -37,7 +37,7 @@
 
  private:
   base::TimeDelta GetFrameDuration(const VideoFrame& frame);
-  void DrainOutputs();
+  void DrainOutputs(int temporal_id);
 
   using vpx_codec_unique_ptr =
       std::unique_ptr<vpx_codec_ctx_t, void (*)(vpx_codec_ctx_t*)>;
@@ -47,6 +47,7 @@
   vpx_image_t vpx_image_ = {};
   gfx::Size originally_configured_size_;
   base::TimeDelta last_frame_timestamp_;
+  int temporal_svc_frame_index = 0;
   VideoCodecProfile profile_ = VIDEO_CODEC_PROFILE_UNKNOWN;
   VideoFramePool frame_pool_;
   std::vector<uint8_t> resize_buf_;
diff --git a/mojo/public/mojom/base/shared_memory.mojom b/mojo/public/mojom/base/shared_memory.mojom
index 4543ad6c..45226ca3 100644
--- a/mojo/public/mojom/base/shared_memory.mojom
+++ b/mojo/public/mojom/base/shared_memory.mojom
@@ -20,6 +20,7 @@
 // Wraps a shared memory handle with additional type information to convey that
 // the handle is always mappable to writable memory by any client which obtains
 // a handle duplicated from this one.
+[Stable]
 struct UnsafeSharedMemoryRegion {
   handle<shared_buffer> buffer;
 };
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/enum_macros.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/enum_macros.tmpl
index 9ba0112..ec058b6 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/enum_macros.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/enum_macros.tmpl
@@ -67,7 +67,7 @@
   switch(value) {
 {%-   for _, values in enum.fields|groupby('numeric_value') %}
     case {{enum_name}}::{{values[0].name}}:
-      return "{{enum_name}}::
+      return "
 {%-     if values|length > 1 -%}
       {{'{'}}
 {%-     endif -%}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl
index 0df0a69..3f368e5 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl
@@ -27,9 +27,7 @@
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/task/common/task_annotator.h"
-#include "base/trace_event/trace_conversion_helper.h"
-#include "base/trace_event/traced_value.h"
-#include "third_party/perfetto/include/perfetto/tracing/traced_value.h"
+#include "base/trace_event/trace_event.h"
 #include "mojo/public/cpp/bindings/lib/generated_code_util.h"
 #include "mojo/public/cpp/bindings/lib/message_internal.h"
 #include "mojo/public/cpp/bindings/lib/serialization_util.h"
@@ -37,7 +35,9 @@
 #include "mojo/public/cpp/bindings/lib/validate_params.h"
 #include "mojo/public/cpp/bindings/lib/validation_context.h"
 #include "mojo/public/cpp/bindings/lib/validation_errors.h"
+#include "mojo/public/cpp/bindings/mojo_buildflags.h"
 #include "mojo/public/interfaces/bindings/interface_control_messages.mojom.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value.h"
 
 #include "{{module.path}}-params-data.h"
 #include "{{module.path}}-shared-message-ids.h"
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl
index 567eac0..2e0e60d 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl
@@ -49,16 +49,13 @@
 #include "base/macros.h"
 #include "base/optional.h"
 
-#include "mojo/public/cpp/bindings/mojo_buildflags.h"
-#if BUILDFLAG(MOJO_TRACE_ENABLED)
-#include "base/trace_event/trace_event.h"
-#endif  // BUILDFLAG(MOJO_TRACE_ENABLED)
 #include "mojo/public/cpp/bindings/clone_traits.h"
 #include "mojo/public/cpp/bindings/equals_traits.h"
 #include "mojo/public/cpp/bindings/lib/serialization.h"
 #include "mojo/public/cpp/bindings/struct_ptr.h"
 #include "mojo/public/cpp/bindings/struct_traits.h"
 #include "mojo/public/cpp/bindings/union_traits.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h"
 #include "{{module.path}}-shared.h"
 #include "{{variant_path}}-forward.h"
 
@@ -128,14 +125,6 @@
 {%-   endfor %}
 {%- endif %}
 
-// Forward-declare for |AsValueInto| so that we do not have to import the
-// corresponding header.
-namespace base {
-namespace trace_event {
-class TracedValue;
-}  // namespace trace_event
-}  // namespace base
-
 {{namespace_begin()}}
 
 {%- set module_prefix = "%s"|format(namespaces_as_array|join(".")) %}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_definition.tmpl
index b4ed7c63..20c43f8 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_definition.tmpl
@@ -37,8 +37,13 @@
 {%-  for field in struct.fields %}
   perfetto::WriteIntoTracedValueWithFallback(
     dict.AddItem(
-      "{{field.name}}"), {{'this->'+field.name}}, 
-      "<value of type {{field.kind|cpp_wrapper_param_type}}>");
+      "{{field.name}}"), {{'this->'+field.name}},
+#if BUILDFLAG(MOJO_TRACE_ENABLED)
+      "<value of type {{field.kind|cpp_wrapper_param_type}}>"
+#else
+      "<value>"
+#endif  // BUILDFLAG(MOJO_TRACE_ENABLED)
+    );
 {%-  endfor %}
 }
 
diff --git a/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java b/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java
index 596bd92..2cd11cde 100644
--- a/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java
+++ b/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java
@@ -418,7 +418,7 @@
                         Context.CONNECTIVITY_SERVICE);
         if (connectivityManager == null) return false;
 
-        connectivityManager.reportNetworkConnectivity(null, false);
+        ApiHelperForM.reportNetworkConnectivity(connectivityManager, null, false);
         return true;
     }
 
diff --git a/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java b/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java
index 62e28e6..31e5de74 100644
--- a/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java
+++ b/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java
@@ -39,6 +39,7 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.StrictModeContext;
 import org.chromium.base.compat.ApiHelperForM;
+import org.chromium.base.compat.ApiHelperForO;
 import org.chromium.base.compat.ApiHelperForP;
 
 import java.io.IOException;
@@ -372,8 +373,8 @@
                 NetworkRequest networkRequest, NetworkCallback networkCallback, Handler handler) {
             // Starting with Oreo specifying a Handler is allowed.  Use this to avoid thread-hops.
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-                mConnectivityManager.registerNetworkCallback(
-                        networkRequest, networkCallback, handler);
+                ApiHelperForO.registerNetworkCallback(
+                        mConnectivityManager, networkRequest, networkCallback, handler);
             } else {
                 mConnectivityManager.registerNetworkCallback(networkRequest, networkCallback);
             }
@@ -385,7 +386,8 @@
          */
         @TargetApi(Build.VERSION_CODES.P)
         void registerDefaultNetworkCallback(NetworkCallback networkCallback, Handler handler) {
-            mConnectivityManager.registerDefaultNetworkCallback(networkCallback, handler);
+            ApiHelperForO.registerDefaultNetworkCallback(
+                    mConnectivityManager, networkCallback, handler);
         }
 
         /**
diff --git a/pdf/out_of_process_instance.cc b/pdf/out_of_process_instance.cc
index d292678..c1171fe 100644
--- a/pdf/out_of_process_instance.cc
+++ b/pdf/out_of_process_instance.cc
@@ -1423,16 +1423,12 @@
 }
 
 void OutOfProcessInstance::FormTextFieldFocusChange(bool in_focus) {
-  if (!text_input_)
-    return;
-
   pp::VarDictionary message;
   message.Set(pp::Var(kType), pp::Var(kJSFieldFocusType));
   message.Set(pp::Var(kJSFieldFocus), pp::Var(in_focus));
   PostMessage(message);
 
-  text_input_->SetTextInputType(in_focus ? PP_TEXTINPUT_TYPE_DEV_TEXT
-                                         : PP_TEXTINPUT_TYPE_DEV_NONE);
+  SetFormFieldInFocus(in_focus);
 }
 
 void OutOfProcessInstance::ResetRecentlySentFindUpdate(int32_t /* unused */) {
@@ -1767,6 +1763,15 @@
   pp::PDF::Print(this);
 }
 
+void OutOfProcessInstance::SetFormFieldInFocus(bool form_field_in_focus) {
+  if (!text_input_)
+    return;
+
+  text_input_->SetTextInputType(form_field_in_focus
+                                    ? PP_TEXTINPUT_TYPE_DEV_TEXT
+                                    : PP_TEXTINPUT_TYPE_DEV_NONE);
+}
+
 void OutOfProcessInstance::PrintSettings::Clear() {
   is_printing = false;
   print_pages_called = false;
diff --git a/pdf/out_of_process_instance.h b/pdf/out_of_process_instance.h
index fac7aeb..cbaac4e 100644
--- a/pdf/out_of_process_instance.h
+++ b/pdf/out_of_process_instance.h
@@ -245,6 +245,9 @@
   // or not.
   bool SendInputEventToEngine(const pp::InputEvent& event);
 
+  // Sets the text input type for this plugin based on |form_field_in_focus|.
+  void SetFormFieldInFocus(bool form_field_in_focus);
+
   // The Pepper image data that is in sync with image_data().
   pp::ImageData pepper_image_data_;
 
diff --git a/remoting/resources/remoting_strings_gu.xtb b/remoting/resources/remoting_strings_gu.xtb
index 80c6cb0..75bbe93 100644
--- a/remoting/resources/remoting_strings_gu.xtb
+++ b/remoting/resources/remoting_strings_gu.xtb
@@ -165,7 +165,7 @@
 <translation id="8386846956409881180">હોસ્ટ અમાન્ય OAuth ઓળખપત્રો સાથે ગોઠવાયું છે.</translation>
 <translation id="8397385476380433240"><ph name="PRODUCT_NAME" />ને પરવાનગી આપો</translation>
 <translation id="8406498562923498210">તમારા Chrome રીમોટ ડેસ્કટૉપ એન્વાયરમેન્ટ અંતર્ગત લૉન્ચ કરવા માટેનું સત્ર પસંદ કરો. (નોંધ કરો કે અમુક સત્રના પ્રકાર Chrome રીમોટ ડેસ્કટૉપ અંતર્ગત અને સ્થાનિક કન્સોલ પર કદાચ એકસાથે ન ચાલે.)</translation>
-<translation id="8428213095426709021">સેટિંગ્સ</translation>
+<translation id="8428213095426709021">સેટિંગ</translation>
 <translation id="8445362773033888690">Google Play સ્ટોરમાં જુઓ</translation>
 <translation id="8509907436388546015">ડેસ્કટોપ ઇન્ટીગ્રેશન પ્રક્રિયા</translation>
 <translation id="8513093439376855948">હોસ્ટ સંચાલનને રિમોટ કરવા માટે મૂળ મેસેજિંગ હોસ્ટ</translation>
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json
index 291b8fbe..65d39bd3 100644
--- a/testing/buildbot/chromium.android.fyi.json
+++ b/testing/buildbot/chromium.android.fyi.json
@@ -4476,11 +4476,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.88"
+            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.89"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.88",
+        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.89",
         "resultdb": {
           "enable": true
         },
@@ -4490,7 +4490,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M89",
-              "revision": "version:89.0.4389.88"
+              "revision": "version:89.0.4389.89"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -4555,11 +4555,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.20"
+            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.21"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.20",
+        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.21",
         "resultdb": {
           "enable": true
         },
@@ -4569,7 +4569,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M90",
-              "revision": "version:90.0.4430.20"
+              "revision": "version:90.0.4430.21"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -4713,11 +4713,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.88"
+            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.89"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.88",
+        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.89",
         "resultdb": {
           "enable": true
         },
@@ -4727,7 +4727,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M89",
-              "revision": "version:89.0.4389.88"
+              "revision": "version:89.0.4389.89"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -4792,11 +4792,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.20"
+            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.21"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.20",
+        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.21",
         "resultdb": {
           "enable": true
         },
@@ -4806,7 +4806,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M90",
-              "revision": "version:90.0.4430.20"
+              "revision": "version:90.0.4430.21"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -5018,11 +5018,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.88"
+            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.89"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.88",
+        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.89",
         "resultdb": {
           "enable": true
         },
@@ -5032,7 +5032,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M89",
-              "revision": "version:89.0.4389.88"
+              "revision": "version:89.0.4389.89"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -5097,11 +5097,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.20"
+            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.21"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.20",
+        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.21",
         "resultdb": {
           "enable": true
         },
@@ -5111,7 +5111,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M90",
-              "revision": "version:90.0.4430.20"
+              "revision": "version:90.0.4430.21"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -5255,11 +5255,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.88"
+            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.89"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.88",
+        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.89",
         "resultdb": {
           "enable": true
         },
@@ -5269,7 +5269,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M89",
-              "revision": "version:89.0.4389.88"
+              "revision": "version:89.0.4389.89"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -5334,11 +5334,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.20"
+            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.21"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.20",
+        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.21",
         "resultdb": {
           "enable": true
         },
@@ -5348,7 +5348,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M90",
-              "revision": "version:90.0.4430.20"
+              "revision": "version:90.0.4430.21"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index f97237c..393f8e8 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -46567,11 +46567,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.88"
+            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.89"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.88",
+        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.89",
         "resultdb": {
           "enable": true
         },
@@ -46581,7 +46581,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M89",
-              "revision": "version:89.0.4389.88"
+              "revision": "version:89.0.4389.89"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -46646,11 +46646,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.20"
+            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.21"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.20",
+        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.21",
         "resultdb": {
           "enable": true
         },
@@ -46660,7 +46660,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M90",
-              "revision": "version:90.0.4430.20"
+              "revision": "version:90.0.4430.21"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -46804,11 +46804,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.88"
+            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.89"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.88",
+        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.89",
         "resultdb": {
           "enable": true
         },
@@ -46818,7 +46818,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M89",
-              "revision": "version:89.0.4389.88"
+              "revision": "version:89.0.4389.89"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -46883,11 +46883,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.20"
+            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.21"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.20",
+        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.21",
         "resultdb": {
           "enable": true
         },
@@ -46897,7 +46897,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M90",
-              "revision": "version:90.0.4430.20"
+              "revision": "version:90.0.4430.21"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -47108,11 +47108,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.88"
+            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.89"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.88",
+        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.89",
         "resultdb": {
           "enable": true
         },
@@ -47122,7 +47122,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M89",
-              "revision": "version:89.0.4389.88"
+              "revision": "version:89.0.4389.89"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -47187,11 +47187,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.20"
+            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.21"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.20",
+        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.21",
         "resultdb": {
           "enable": true
         },
@@ -47201,7 +47201,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M90",
-              "revision": "version:90.0.4430.20"
+              "revision": "version:90.0.4430.21"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -47345,11 +47345,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.88"
+            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.89"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.88",
+        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.89",
         "resultdb": {
           "enable": true
         },
@@ -47359,7 +47359,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M89",
-              "revision": "version:89.0.4389.88"
+              "revision": "version:89.0.4389.89"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -47424,11 +47424,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.20"
+            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.21"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.20",
+        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.21",
         "resultdb": {
           "enable": true
         },
@@ -47438,7 +47438,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M90",
-              "revision": "version:90.0.4430.20"
+              "revision": "version:90.0.4430.21"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/filters/ozone-linux.wayland_views_unittests.filter b/testing/buildbot/filters/ozone-linux.wayland_views_unittests.filter
index e3d5d1d3..d22d8c1b 100644
--- a/testing/buildbot/filters/ozone-linux.wayland_views_unittests.filter
+++ b/testing/buildbot/filters/ozone-linux.wayland_views_unittests.filter
@@ -1,8 +1,16 @@
-# https://crbug.com/ : Fix this failed and crashed tests.
+# Tests that cannot work on Wayland.
+
+# Tests activation of windows.  Wayland doesn't allow the client to activate its
+# windows so this test makes no sense.
+-DesktopWidgetFocusManagerTest.AnchoredDialogInDesktopNativeWidgetAura
+
+# Tests behaviour that is specific for X11.
+-DesktopWidgetTest.GetWindowPlacement
+
+# crbug.com/1186974 : Fix failed and crashed tests listed below.  Move tests
+# that cannot work on Wayland into sections above and document the decision.
 
 # Failed tests.
--DesktopWidgetFocusManagerTest.AnchoredDialogInDesktopNativeWidgetAura
--DesktopWidgetTest.GetWindowPlacement
 -EditableComboboxTest.AltLeftOrRightDoesNothing
 -EditableComboboxTest.CtrlLeftOrRightMovesToNextWords
 -EditableComboboxTest.EndOrHomeMovesToBeginningOrEndOfText
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index 91026a8b..434305f 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -311,13 +311,13 @@
       '../../weblayer/browser/android/javatests/skew/expectations.txt',
       '--impl-version=90',
     ],
-    'identifier': 'Implementation Library Skew Tests For 90.0.4430.20',
+    'identifier': 'Implementation Library Skew Tests For 90.0.4430.21',
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M90',
-          'revision': 'version:90.0.4430.20',
+          'revision': 'version:90.0.4430.21',
         }
       ],
     },
@@ -335,13 +335,13 @@
       '../../weblayer/browser/android/javatests/skew/expectations.txt',
       '--impl-version=89',
     ],
-    'identifier': 'Implementation Library Skew Tests For 89.0.4389.88',
+    'identifier': 'Implementation Library Skew Tests For 89.0.4389.89',
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M89',
-          'revision': 'version:89.0.4389.88',
+          'revision': 'version:89.0.4389.89',
         }
       ],
     },
@@ -383,13 +383,13 @@
       '../../weblayer/browser/android/javatests/skew/expectations.txt',
       '--impl-version=90',
     ],
-    'identifier': 'Implementation Library Skew Tests For 90.0.4430.20',
+    'identifier': 'Implementation Library Skew Tests For 90.0.4430.21',
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M90',
-          'revision': 'version:90.0.4430.20',
+          'revision': 'version:90.0.4430.21',
         }
       ],
     },
@@ -407,13 +407,13 @@
       '../../weblayer/browser/android/javatests/skew/expectations.txt',
       '--impl-version=89',
     ],
-    'identifier': 'Implementation Library Skew Tests For 89.0.4389.88',
+    'identifier': 'Implementation Library Skew Tests For 89.0.4389.89',
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M89',
-          'revision': 'version:89.0.4389.88',
+          'revision': 'version:89.0.4389.89',
         }
       ],
     },
@@ -455,13 +455,13 @@
       '../../weblayer/browser/android/javatests/skew/expectations.txt',
       '--client-version=90',
     ],
-    'identifier': 'Client Library Skew Tests For 90.0.4430.20',
+    'identifier': 'Client Library Skew Tests For 90.0.4430.21',
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M90',
-          'revision': 'version:90.0.4430.20',
+          'revision': 'version:90.0.4430.21',
         }
       ],
     },
@@ -479,13 +479,13 @@
       '../../weblayer/browser/android/javatests/skew/expectations.txt',
       '--client-version=89',
     ],
-    'identifier': 'Client Library Skew Tests For 89.0.4389.88',
+    'identifier': 'Client Library Skew Tests For 89.0.4389.89',
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M89',
-          'revision': 'version:89.0.4389.88',
+          'revision': 'version:89.0.4389.89',
         }
       ],
     },
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 85b64379..9fe8ceb 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2540,6 +2540,12 @@
             "experiments": [
                 {
                     "name": "Enabled",
+                    "params": {
+                        "availability": "any",
+                        "event_trigger": "name:reading_list_item_added;comparator:==0;window:365;storage:365",
+                        "event_used": "name:reading_list_menu_opened;comparator:==0;window:365;storage:365",
+                        "session_rate": "<3"
+                    },
                     "enable_features": [
                         "ReadLater"
                     ]
@@ -7751,8 +7757,9 @@
                 {
                     "name": "Enabled",
                     "params": {
-                        "base_url": "https://staging-gsaprototype-pa.sandbox.googleapis.com",
+                        "base_url": "https://chromeupboarding-pa.googleapis.com",
                         "default_locale": "en",
+                        "enable_share": "true",
                         "experiment_tag": "",
                         "fetch_frequency": "15",
                         "use_animated_gif_url": "true"
diff --git a/third_party/blink/public/mojom/page/page.mojom b/third_party/blink/public/mojom/page/page.mojom
index e122d4f..464faabf 100644
--- a/third_party/blink/public/mojom/page/page.mojom
+++ b/third_party/blink/public/mojom/page/page.mojom
@@ -65,6 +65,9 @@
   // web contents is adopted as a portal.
   SetInsidePortal(bool is_inside_portal);
 
+  // Notifies the renderer when the prerendering page is activated.
+  ActivatePrerender();
+
   // Notifies the renderer when updating a set of blink preferences.
   UpdateWebPreferences(blink.mojom.WebPreferences preferences);
 
diff --git a/third_party/blink/public/web/web_embedded_worker.h b/third_party/blink/public/web/web_embedded_worker.h
index 2e9162a..d859cef 100644
--- a/third_party/blink/public/web/web_embedded_worker.h
+++ b/third_party/blink/public/web/web_embedded_worker.h
@@ -68,8 +68,8 @@
       manager_host_remote;
 };
 
-// An interface to start and terminate an embedded worker.
-// All methods of this class must be called on the main thread.
+// An interface to start and terminate an embedded worker. Lives on
+// a background thread from the ThreadPool.
 class BLINK_EXPORT WebEmbeddedWorker {
  public:
   // Invoked on the main thread to instantiate a WebEmbeddedWorker.
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 0d065ec..4241f9c 100644
--- a/third_party/blink/public/web/web_local_frame_client.h
+++ b/third_party/blink/public/web/web_local_frame_client.h
@@ -415,8 +415,8 @@
   // named anchor or a PopState event may have been dispatched.
   virtual void DidFinishSameDocumentNavigation(WebHistoryCommitType,
                                                bool content_initiated,
-                                               bool is_history_api_navigation) {
-  }
+                                               bool is_history_api_navigation,
+                                               bool is_client_redirect) {}
 
   // Called when a RenderFrame's page lifecycle state gets updated.
   virtual void DidSetPageLifecycleState() {}
diff --git a/third_party/blink/renderer/bindings/generated_in_modules.gni b/third_party/blink/renderer/bindings/generated_in_modules.gni
index 25034d9a..864ec7d 100644
--- a/third_party/blink/renderer/bindings/generated_in_modules.gni
+++ b/third_party/blink/renderer/bindings/generated_in_modules.gni
@@ -331,6 +331,8 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_bind_group_layout_descriptor.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_bind_group_layout_entry.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_bind_group_layout_entry.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_blend_component.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_blend_component.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_blend_state.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_blend_state.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_buffer_binding.cc",
@@ -341,6 +343,8 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_buffer_descriptor.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_color_dict.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_color_dict.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_color_state_descriptor.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_color_state_descriptor.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_color_target_state.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_color_target_state.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_command_buffer_descriptor.cc",
@@ -351,6 +355,8 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_compute_pass_descriptor.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_compute_pipeline_descriptor.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_compute_pipeline_descriptor.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_depth_stencil_state_descriptor.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_depth_stencil_state_descriptor.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_depth_stencil_state.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_depth_stencil_state.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_device_descriptor.cc",
@@ -419,10 +425,10 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_texture_view_descriptor.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_uncaptured_error_event_init.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_uncaptured_error_event_init.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_attribute_descriptor.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_attribute_descriptor.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_buffer_layout_descriptor.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_buffer_layout_descriptor.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_attribute.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_attribute.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_buffer_layout.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_buffer_layout.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_state_descriptor.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_state_descriptor.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_handwriting_drawing_segment.cc",
@@ -863,8 +869,6 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_frame_metadata.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_frame_plane_init.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_frame_plane_init.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_track_writer_parameters.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_track_writer_parameters.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_watch_advertisements_options.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_watch_advertisements_options.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_wave_shaper_options.cc",
@@ -2171,8 +2175,6 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_playback_quality.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_track.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_track.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_track_reader.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_video_track_reader.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_virtual_keyboard.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_virtual_keyboard.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_virtual_keyboard_geometry_change_event.cc",
diff --git a/third_party/blink/renderer/bindings/idl_in_modules.gni b/third_party/blink/renderer/bindings/idl_in_modules.gni
index 8b17a909..986ca0c 100644
--- a/third_party/blink/renderer/bindings/idl_in_modules.gni
+++ b/third_party/blink/renderer/bindings/idl_in_modules.gni
@@ -808,8 +808,6 @@
           "//third_party/blink/renderer/modules/webcodecs/video_frame_output_callback.idl",
           "//third_party/blink/renderer/modules/webcodecs/video_frame_plane_init.idl",
           "//third_party/blink/renderer/modules/webcodecs/video_pixel_format.idl",
-          "//third_party/blink/renderer/modules/webcodecs/video_track_reader.idl",
-          "//third_party/blink/renderer/modules/webcodecs/video_track_writer_parameters.idl",
           "//third_party/blink/renderer/modules/webcodecs/webcodecs_error_callback.idl",
           "//third_party/blink/renderer/modules/webdatabase/database.idl",
           "//third_party/blink/renderer/modules/webdatabase/sql_error.idl",
@@ -896,6 +894,7 @@
           "//third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.idl",
           "//third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout_descriptor.idl",
           "//third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout_entry.idl",
+          "//third_party/blink/renderer/modules/webgpu/gpu_blend_component.idl",
           "//third_party/blink/renderer/modules/webgpu/gpu_blend_state.idl",
           "//third_party/blink/renderer/modules/webgpu/gpu_buffer.idl",
           "//third_party/blink/renderer/modules/webgpu/gpu_buffer_binding.idl",
@@ -904,6 +903,7 @@
           "//third_party/blink/renderer/modules/webgpu/gpu_buffer_usage.idl",
           "//third_party/blink/renderer/modules/webgpu/gpu_canvas_context.idl",
           "//third_party/blink/renderer/modules/webgpu/gpu_color_dict.idl",
+          "//third_party/blink/renderer/modules/webgpu/gpu_color_state_descriptor.idl",
           "//third_party/blink/renderer/modules/webgpu/gpu_color_target_state.idl",
           "//third_party/blink/renderer/modules/webgpu/gpu_color_write.idl",
           "//third_party/blink/renderer/modules/webgpu/gpu_command_buffer.idl",
@@ -914,6 +914,7 @@
           "//third_party/blink/renderer/modules/webgpu/gpu_compute_pass_encoder.idl",
           "//third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline.idl",
           "//third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline_descriptor.idl",
+          "//third_party/blink/renderer/modules/webgpu/gpu_depth_stencil_state_descriptor.idl",
           "//third_party/blink/renderer/modules/webgpu/gpu_depth_stencil_state.idl",
           "//third_party/blink/renderer/modules/webgpu/gpu_device.idl",
           "//third_party/blink/renderer/modules/webgpu/gpu_device_descriptor.idl",
@@ -973,8 +974,8 @@
           "//third_party/blink/renderer/modules/webgpu/gpu_uncaptured_error_event.idl",
           "//third_party/blink/renderer/modules/webgpu/gpu_uncaptured_error_event_init.idl",
           "//third_party/blink/renderer/modules/webgpu/gpu_validation_error.idl",
-          "//third_party/blink/renderer/modules/webgpu/gpu_vertex_attribute_descriptor.idl",
-          "//third_party/blink/renderer/modules/webgpu/gpu_vertex_buffer_layout_descriptor.idl",
+          "//third_party/blink/renderer/modules/webgpu/gpu_vertex_attribute.idl",
+          "//third_party/blink/renderer/modules/webgpu/gpu_vertex_buffer_layout.idl",
           "//third_party/blink/renderer/modules/webgpu/gpu_vertex_state_descriptor.idl",
           "//third_party/blink/renderer/modules/webgpu/navigator_gpu.idl",
           "//third_party/blink/renderer/modules/webgpu/worker_navigator_gpu.idl",
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index df60552..1b5dee6 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -8438,8 +8438,11 @@
   // TODO(bokan): Portals will change this assumption since they mean an active
   // document can be "adopted" into a portal.
   DCHECK(is_prerendering_);
-
   is_prerendering_ = false;
+
+  if (DocumentLoader* loader = Loader())
+    loader->NotifyPrerenderingDocumentActivated();
+
   DispatchEvent(*Event::Create(event_type_names::kPrerenderingchange));
 }
 
diff --git a/third_party/blink/renderer/core/dom/node.cc b/third_party/blink/renderer/core/dom/node.cc
index e0dbf8f5..2ac23af 100644
--- a/third_party/blink/renderer/core/dom/node.cc
+++ b/third_party/blink/renderer/core/dom/node.cc
@@ -3292,8 +3292,15 @@
   // box may have changed.
   SetForceReattachLayoutTree();
 
-  if (auto* element = DynamicTo<HTMLElement>(this))
-    element->AddCandidateDirectionalityForSlot();
+  AddCandidateDirectionalityForSlot();
+}
+
+void Node::AddCandidateDirectionalityForSlot() {
+  ShadowRoot* root = ShadowRootOfParent();
+  if (!root || !root->HasSlotAssignment())
+    return;
+
+  root->GetSlotAssignment().GetCandidateDirectionality().insert(this);
 }
 
 void Node::RemovedFromFlatTree() {
diff --git a/third_party/blink/renderer/core/dom/node.h b/third_party/blink/renderer/core/dom/node.h
index a3a9a7b..adc9d18 100644
--- a/third_party/blink/renderer/core/dom/node.h
+++ b/third_party/blink/renderer/core/dom/node.h
@@ -1127,6 +1127,8 @@
   }
   ShadowRoot* GetSlotAssignmentRoot() const;
 
+  void AddCandidateDirectionalityForSlot();
+
   uint32_t node_flags_;
   Member<Node> parent_or_shadow_host_node_;
   Member<TreeScope> tree_scope_;
diff --git a/third_party/blink/renderer/core/dom/shadow_root.cc b/third_party/blink/renderer/core/dom/shadow_root.cc
index 1bf8efb..f1ebc56 100644
--- a/third_party/blink/renderer/core/dom/shadow_root.cc
+++ b/third_party/blink/renderer/core/dom/shadow_root.cc
@@ -126,9 +126,8 @@
           html, &host(), kAllowScriptingContent, "innerHTML",
           /*include_shadow_roots=*/false, exception_state)) {
     ReplaceChildrenWithFragment(this, fragment, exception_state);
-    auto* element = DynamicTo<HTMLElement>(host());
-    if (element && !element->NeedsInheritDirectionalityFromParent())
-      element->UpdateDescendantDirectionality(element->CachedDirectionality());
+    if (auto* element = DynamicTo<HTMLElement>(host()))
+      element->AdjustDirectionalityIfNeededAfterShadowRootChanged();
   }
 }
 
diff --git a/third_party/blink/renderer/core/dom/slot_assignment.h b/third_party/blink/renderer/core/dom/slot_assignment.h
index c5a83153..4a8ffac 100644
--- a/third_party/blink/renderer/core/dom/slot_assignment.h
+++ b/third_party/blink/renderer/core/dom/slot_assignment.h
@@ -11,7 +11,6 @@
 
 namespace blink {
 
-class HTMLElement;
 class HTMLSlotElement;
 class Node;
 class ShadowRoot;
@@ -57,7 +56,7 @@
   void RecalcAssignment();
   bool UpdateCandidateNodeAssignedSlot(Node&, HTMLSlotElement&);
   void ClearCandidateNodes(const HeapLinkedHashSet<Member<Node>>& candidates);
-  HeapHashSet<Member<HTMLElement>>& GetCandidateDirectionality() {
+  HeapHashSet<Member<Node>>& GetCandidateDirectionality() {
     return candidate_directionality_set_;
   }
 
@@ -88,7 +87,7 @@
   // TODO: (1067157) Ensure references inside the map are GCed.
   HeapHashMap<Member<Node>, Member<HTMLSlotElement>>
       candidate_assigned_slot_map_;
-  HeapHashSet<Member<HTMLElement>> candidate_directionality_set_;
+  HeapHashSet<Member<Node>> candidate_directionality_set_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/editing/commands/apply_block_element_command_test.cc b/third_party/blink/renderer/core/editing/commands/apply_block_element_command_test.cc
index 1886137..cba351d 100644
--- a/third_party/blink/renderer/core/editing/commands/apply_block_element_command_test.cc
+++ b/third_party/blink/renderer/core/editing/commands/apply_block_element_command_test.cc
@@ -110,7 +110,7 @@
       "<h6><button></button></h6>"
       "<h6><button><table></table></button></h6>"
       "</blockquote>"
-      "<h6><button></button></h6><br>"
+      "<br>"
       "<object></object>"
       "</div>",
       GetDocument().body()->innerHTML());
diff --git a/third_party/blink/renderer/core/editing/commands/composite_edit_command.cc b/third_party/blink/renderer/core/editing/commands/composite_edit_command.cc
index 9c0d976..884b1bd 100644
--- a/third_party/blink/renderer/core/editing/commands/composite_edit_command.cc
+++ b/third_party/blink/renderer/core/editing/commands/composite_edit_command.cc
@@ -1992,13 +1992,15 @@
     GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
 
     // Do not split a node when doing so introduces an empty node.
-    VisiblePosition position_in_parent =
-        VisiblePosition::FirstPositionInNode(*parent_element);
-    VisiblePosition position_in_node =
-        CreateVisiblePosition(FirstPositionInOrBeforeNode(*node));
-    if (position_in_parent.DeepEquivalent() !=
-        position_in_node.DeepEquivalent())
-      SplitElement(parent_element, node);
+    if (node->previousSibling()) {
+      const Position& first_in_parent =
+          Position::FirstPositionInNode(*parent_element);
+      const Position& before_node =
+          Position::BeforeNode(*node).ToOffsetInAnchor();
+      if (MostBackwardCaretPosition(first_in_parent) !=
+          MostBackwardCaretPosition(before_node))
+        SplitElement(parent_element, node);
+    }
   }
 
   return node;
diff --git a/third_party/blink/renderer/core/editing/commands/replace_selection_command_test.cc b/third_party/blink/renderer/core/editing/commands/replace_selection_command_test.cc
index 478bc20..255042e 100644
--- a/third_party/blink/renderer/core/editing/commands/replace_selection_command_test.cc
+++ b/third_party/blink/renderer/core/editing/commands/replace_selection_command_test.cc
@@ -206,4 +206,22 @@
   EXPECT_EQ("<table> <tbody><img><img></tbody><br><img>|<br> </table>",
             GetSelectionTextFromBody());
 }
+
+// https://crbug.com/1186610
+TEST_F(ReplaceSelectionCommandTest, InsertImageAfterEmptyBlockInInline) {
+  GetDocument().setDesignMode("on");
+  Selection().SetSelection(SetSelectionTextToBody("<span><div></div>|a</span>"),
+                           SetSelectionOptions());
+
+  DocumentFragment& fragment = *GetDocument().createDocumentFragment();
+  fragment.appendChild(GetDocument().CreateRawElement(html_names::kImgTag));
+  auto& command = *MakeGarbageCollected<ReplaceSelectionCommand>(
+      GetDocument(), &fragment, ReplaceSelectionCommand::kPreventNesting,
+      InputEvent::InputType::kNone);
+
+  // Should not crash
+  EXPECT_TRUE(command.Apply());
+  EXPECT_EQ("<span><div></div></span><img>|<span>a</span>",
+            GetSelectionTextFromBody());
+}
 }  // namespace blink
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 cdca8529..d898c98 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -3104,6 +3104,10 @@
     web_widget_->SetIsNestedMainFrameWidget(inside_portal);
 }
 
+void WebViewImpl::ActivatePrerender() {
+  GetPage()->ActivateForPrerendering();
+}
+
 void WebViewImpl::RegisterRendererPreferenceWatcher(
     CrossVariantMojoRemote<mojom::RendererPreferenceWatcherInterfaceBase>
         watcher) {
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.h b/third_party/blink/renderer/core/exported/web_view_impl.h
index 79d0d2e..9afdc9a5 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.h
+++ b/third_party/blink/renderer/core/exported/web_view_impl.h
@@ -263,6 +263,7 @@
       SetPageLifecycleStateCallback callback) override;
   void AudioStateChanged(bool is_audio_playing) override;
   void SetInsidePortal(bool is_inside_portal) override;
+  void ActivatePrerender() override;
   void UpdateWebPreferences(
       const blink::web_pref::WebPreferences& preferences) override;
   void UpdateRendererPreferences(
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy.cc b/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
index a891e849..8b7360e 100644
--- a/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
+++ b/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
@@ -1111,9 +1111,9 @@
   PostViolationReport(violation_data, context_frame, report_endpoints,
                       use_reporting_api);
 
-  // Fire a violation event if we're working with a delegate (e.g. we're not
-  // processing 'frame-ancestors').
-  if (delegate_)
+  // Fire a violation event if we're working with a delegate and we don't have a
+  // `context_frame` (i.e. we're not processing 'frame-ancestors').
+  if (delegate_ && !context_frame)
     delegate_->DispatchViolationEvent(*violation_data, element);
 
   ReportContentSecurityPolicyIssue(*violation_data, header_type, violation_type,
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index de35d6fc..0d0e15a 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -880,8 +880,8 @@
                static_cast<int>(load_type));
 
   FrameLoadRequest request(
-      nullptr, loader_.ResourceRequestForReload(
-                   load_type, ClientRedirectPolicy::kClientRedirect));
+      DomWindow(), loader_.ResourceRequestForReload(
+                       load_type, ClientRedirectPolicy::kClientRedirect));
   request.SetClientRedirectReason(ClientNavigationReason::kReload);
   probe::FrameScheduledNavigation(this, request.GetResourceRequest().Url(),
                                   base::TimeDelta(),
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 ea1a2768..94b4a38cc 100644
--- a/third_party/blink/renderer/core/frame/local_frame_client.h
+++ b/third_party/blink/renderer/core/frame/local_frame_client.h
@@ -131,8 +131,8 @@
   virtual void DidFinishSameDocumentNavigation(HistoryItem*,
                                                WebHistoryCommitType,
                                                bool content_initiated,
-                                               bool is_history_api_navigation) {
-  }
+                                               bool is_history_api_navigation,
+                                               bool is_client_redirect) {}
   virtual void DispatchDidReceiveTitle(const String&) = 0;
   virtual void DispatchDidCommitLoad(
       HistoryItem* item,
diff --git a/third_party/blink/renderer/core/frame/local_frame_client_impl.cc b/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
index 3b7be270..7274ad4 100644
--- a/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
@@ -382,13 +382,15 @@
     HistoryItem* item,
     WebHistoryCommitType commit_type,
     bool content_initiated,
-    bool is_history_api_navigation) {
+    bool is_history_api_navigation,
+    bool is_client_redirect) {
   bool should_create_history_entry = commit_type == kWebStandardCommit;
   // TODO(dglazkov): Does this need to be called for subframes?
   web_frame_->ViewImpl()->DidCommitLoad(should_create_history_entry, true);
   if (web_frame_->Client()) {
     web_frame_->Client()->DidFinishSameDocumentNavigation(
-        commit_type, content_initiated, is_history_api_navigation);
+        commit_type, content_initiated, is_history_api_navigation,
+        is_client_redirect);
   }
 }
 
diff --git a/third_party/blink/renderer/core/frame/local_frame_client_impl.h b/third_party/blink/renderer/core/frame/local_frame_client_impl.h
index 63f5370..c0c602a 100644
--- a/third_party/blink/renderer/core/frame/local_frame_client_impl.h
+++ b/third_party/blink/renderer/core/frame/local_frame_client_impl.h
@@ -93,7 +93,8 @@
   void DidFinishSameDocumentNavigation(HistoryItem*,
                                        WebHistoryCommitType,
                                        bool content_initiated,
-                                       bool is_history_api_navigation) override;
+                                       bool is_history_api_navigation,
+                                       bool is_client_redirect) override;
   void DispatchDidReceiveTitle(const String&) override;
   void DispatchDidCommitLoad(
       HistoryItem*,
diff --git a/third_party/blink/renderer/core/frame/web_frame_test.cc b/third_party/blink/renderer/core/frame/web_frame_test.cc
index 428e0eb..434df245 100644
--- a/third_party/blink/renderer/core/frame/web_frame_test.cc
+++ b/third_party/blink/renderer/core/frame/web_frame_test.cc
@@ -7667,10 +7667,10 @@
   ~TestDidNavigateCommitTypeWebFrameClient() override = default;
 
   // frame_test_helpers::TestWebFrameClient:
-  void DidFinishSameDocumentNavigation(
-      WebHistoryCommitType type,
-      bool content_initiated,
-      bool is_history_api_navigation) override {
+  void DidFinishSameDocumentNavigation(WebHistoryCommitType type,
+                                       bool content_initiated,
+                                       bool is_history_api_navigation,
+                                       bool is_client_redirect) override {
     last_commit_type_ = type;
   }
 
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 6a70c4a4..1b180b9 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
@@ -1055,11 +1055,10 @@
       GetFrame()->Loader().ResourceRequestForReload(frame_load_type);
   if (request.IsNull())
     return;
-  request.SetRequestorOrigin(GetFrame()->DomWindow()->GetSecurityOrigin());
   if (GetTextFinder())
     GetTextFinder()->ClearActiveFindMatch();
 
-  FrameLoadRequest frame_load_request(nullptr, request);
+  FrameLoadRequest frame_load_request(GetFrame()->DomWindow(), request);
   GetFrame()->Loader().StartNavigation(frame_load_request, frame_load_type);
 }
 
diff --git a/third_party/blink/renderer/core/html/custom/custom_state_set.cc b/third_party/blink/renderer/core/html/custom/custom_state_set.cc
index 0a17d36..dd105880 100644
--- a/third_party/blink/renderer/core/html/custom/custom_state_set.cc
+++ b/third_party/blink/renderer/core/html/custom/custom_state_set.cc
@@ -10,10 +10,45 @@
 
 namespace blink {
 
+class CustomStateIterationSource : public CustomStateSet::IterationSource {
+ public:
+  explicit CustomStateIterationSource(CustomStateSet& states)
+      : states_(states) {}
+
+  void Trace(Visitor* visitor) const override {
+    visitor->Trace(states_);
+    CustomStateSet::IterationSource::Trace(visitor);
+  }
+
+  bool Next(ScriptState*,
+            String& out_key,
+            String& out_value,
+            ExceptionState&) override {
+    if (index_ >= states_->list_.size())
+      return false;
+    String value = states_->list_[index_++];
+    out_key = value;
+    out_value = value;
+    return true;
+  }
+
+  void DidEraseAt(wtf_size_t erased_index) {
+    // If index_ is N and an item between 0 and N-1 was erased, decrement
+    // index_ in order that Next() will return an item which was at N.
+    if (erased_index < index_)
+      --index_;
+  }
+
+ private:
+  Member<CustomStateSet> states_;
+  wtf_size_t index_ = 0;
+};
+
 CustomStateSet::CustomStateSet(Element& element) : element_(element) {}
 
 void CustomStateSet::Trace(Visitor* visitor) const {
   visitor->Trace(element_);
+  visitor->Trace(iterators_);
   ScriptWrappable::Trace(visitor);
 }
 
@@ -42,27 +77,30 @@
   // 2. Invoke the default add operation, which the setlike<DOMString> would
   // have if CustomStateSet interface had no add(value) operation, with value
   // argument.
-  set_.insert(value);
+  if (!list_.Contains(value))
+    list_.push_back(value);
 
   InvalidateStyle();
 }
 
 uint32_t CustomStateSet::size() const {
-  return set_.size();
+  return list_.size();
 }
 
 void CustomStateSet::clearForBinding(ScriptState*, ExceptionState&) {
-  set_.clear();
+  list_.clear();
   InvalidateStyle();
 }
 
 bool CustomStateSet::deleteForBinding(ScriptState*,
                                       const String& value,
                                       ExceptionState&) {
-  auto iter = set_.find(value);
-  if (iter == set_.cend())
+  wtf_size_t index = list_.Find(value);
+  if (index == WTF::kNotFound)
     return false;
-  set_.erase(iter);
+  list_.EraseAt(index);
+  for (auto& iterator : iterators_)
+    iterator->DidEraseAt(index);
   InvalidateStyle();
   return true;
 }
@@ -74,41 +112,15 @@
 }
 
 bool CustomStateSet::Has(const String& value) const {
-  return set_.Contains(value);
+  return list_.Contains(value);
 }
 
-class CustomStateIterationSource : public CustomStateSet::IterationSource {
- public:
-  explicit CustomStateIterationSource(CustomStateSet& states)
-      : states_(states), iterator_(states.set_.begin()) {}
-
-  void Trace(Visitor* visitor) const override {
-    visitor->Trace(states_);
-    CustomStateSet::IterationSource::Trace(visitor);
-  }
-
-  bool Next(ScriptState*,
-            String& out_key,
-            String& out_value,
-            ExceptionState&) override {
-    if (iterator_ == states_->set_.end())
-      return false;
-    String value = *iterator_;
-    ++iterator_;
-    out_key = value;
-    out_value = value;
-    return true;
-  }
-
- private:
-  Member<CustomStateSet> states_;
-  LinkedHashSet<String>::const_iterator iterator_;
-};
-
 CustomStateSet::IterationSource* CustomStateSet::StartIteration(
     ScriptState*,
     ExceptionState&) {
-  return MakeGarbageCollected<CustomStateIterationSource>(*this);
+  auto* iterator = MakeGarbageCollected<CustomStateIterationSource>(*this);
+  iterators_.insert(iterator);
+  return iterator;
 }
 
 void CustomStateSet::InvalidateStyle() const {
diff --git a/third_party/blink/renderer/core/html/custom/custom_state_set.h b/third_party/blink/renderer/core/html/custom/custom_state_set.h
index f1e3790..92c5484 100644
--- a/third_party/blink/renderer/core/html/custom/custom_state_set.h
+++ b/third_party/blink/renderer/core/html/custom/custom_state_set.h
@@ -7,9 +7,11 @@
 
 #include "third_party/blink/renderer/bindings/core/v8/iterable.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
 
+class CustomStateIterationSource;
 class Element;
 
 // This class is an implementation of 'CustomStateSet' IDL interface.
@@ -22,12 +24,17 @@
   void Trace(Visitor* visitor) const override;
 
   // IDL bindings:
+  //
+  // This operation is O(size()).
   void add(const String& value, ExceptionState& exception_state);
   uint32_t size() const;
   void clearForBinding(ScriptState*, ExceptionState&);
+  // This operation is O(size()).
   bool deleteForBinding(ScriptState*, const String& value, ExceptionState&);
+  // This operation is O(size()).
   bool hasForBinding(ScriptState*, const String& value, ExceptionState&) const;
 
+  // This operation is O(size()).
   bool Has(const String& value) const;
 
  private:
@@ -37,7 +44,14 @@
   void InvalidateStyle() const;
 
   Member<Element> element_;
-  LinkedHashSet<String> set_;
+  // We use neither LinkedHashSet nor ListHashSet because it's difficult to
+  // implement "live" iterators with them.
+  // See crbug.com/1184020.
+  //
+  // If the O(size()) operations are problematic, we should change the type of
+  // the following data member.
+  Vector<String> list_;
+  HeapHashSet<WeakMember<CustomStateIterationSource>> iterators_;
 
   friend class CustomStateIterationSource;
 };
diff --git a/third_party/blink/renderer/core/html/html_element.cc b/third_party/blink/renderer/core/html/html_element.cc
index 92e3fc5d..9ec792d2 100644
--- a/third_party/blink/renderer/core/html/html_element.cc
+++ b/third_party/blink/renderer/core/html/html_element.cc
@@ -1338,24 +1338,53 @@
   }
 }
 
+void HTMLElement::AdjustDirectionalityIfNeededAfterShadowRootChanged() {
+  DCHECK(IsShadowHost(this));
+  if (SelfOrAncestorHasDirAutoAttribute()) {
+    for (auto* element_to_adjust = this; element_to_adjust;
+         element_to_adjust = DynamicTo<HTMLElement>(
+             FlatTreeTraversal::ParentElement(*element_to_adjust))) {
+      if (ElementAffectsDirectionality(element_to_adjust)) {
+        element_to_adjust->CalculateAndAdjustAutoDirectionality(
+            element_to_adjust);
+        return;
+      }
+    }
+  } else if (!NeedsInheritDirectionalityFromParent()) {
+    UpdateDescendantDirectionality(CachedDirectionality());
+  }
+}
+
 void HTMLElement::AdjustCandidateDirectionalityForSlot(
-    HeapHashSet<Member<HTMLElement>> candidate_set) {
+    HeapHashSet<Member<Node>> candidate_set) {
   HeapHashSet<Member<HTMLElement>> directionality_set;
   // Transfer a candidate directionality set to |directionality_set| to avoid
   // the tree walk to the duplicated parent node for the directionality.
-  for (auto& element : candidate_set) {
-    if (!element->SelfOrAncestorHasDirAutoAttribute()) {
+  for (auto& node : candidate_set) {
+    Node* node_to_adjust = node.Get();
+    if (!node->SelfOrAncestorHasDirAutoAttribute()) {
+      auto* slot = node->AssignedSlot();
       auto* parent =
-          DynamicTo<HTMLElement>(FlatTreeTraversal::ParentElement(*element));
-      if (parent && !parent->NeedsInheritDirectionalityFromParent() &&
-          element->NeedsInheritDirectionalityFromParent()) {
-        element->UpdateDirectionalityAndDescendant(
-            parent->CachedDirectionality());
+          DynamicTo<HTMLElement>(FlatTreeTraversal::ParentElement(*node));
+      if (ElementAffectsDirectionality(node))
+        continue;
+      if (slot && slot->SelfOrAncestorHasDirAutoAttribute()) {
+        node_to_adjust = slot;
+      } else if (parent && parent->SelfOrAncestorHasDirAutoAttribute()) {
+        node_to_adjust = parent;
+      } else {
+        if (ElementAffectsDirectionality(slot)) {
+          node->SetCachedDirectionality(slot->CachedDirectionality());
+        } else if (parent && !parent->NeedsInheritDirectionalityFromParent() &&
+                   node->NeedsInheritDirectionalityFromParent()) {
+          node->SetCachedDirectionality(parent->CachedDirectionality());
+        }
+        continue;
       }
-      continue;
     }
 
-    for (auto* element_to_adjust = element.Get(); element_to_adjust;
+    for (auto* element_to_adjust = DynamicTo<HTMLElement>(node_to_adjust);
+         element_to_adjust;
          element_to_adjust = DynamicTo<HTMLElement>(
              FlatTreeTraversal::ParentElement(*element_to_adjust))) {
       if (ElementAffectsDirectionality(element_to_adjust)) {
@@ -1375,14 +1404,6 @@
   }
 }
 
-void HTMLElement::AddCandidateDirectionalityForSlot() {
-  ShadowRoot* root = ShadowRootOfParent();
-  if (!root || !root->HasSlotAssignment())
-    return;
-
-  root->GetSlotAssignment().GetCandidateDirectionality().insert(this);
-}
-
 Node::InsertionNotificationRequest HTMLElement::InsertedInto(
     ContainerNode& insertion_point) {
   // Process the superclass first to ensure that `InActiveDocument()` is
diff --git a/third_party/blink/renderer/core/html/html_element.h b/third_party/blink/renderer/core/html/html_element.h
index fd1d50b..3b903ec 100644
--- a/third_party/blink/renderer/core/html/html_element.h
+++ b/third_party/blink/renderer/core/html/html_element.h
@@ -153,12 +153,12 @@
   virtual FormAssociated* ToFormAssociatedOrNull() { return nullptr; }
   bool IsFormAssociatedCustomElement() const;
 
-  void AddCandidateDirectionalityForSlot();
   static void AdjustCandidateDirectionalityForSlot(
-      HeapHashSet<Member<HTMLElement>> candidate_set);
+      HeapHashSet<Member<Node>> candidate_set);
   void UpdateDescendantHasDirAutoAttribute(bool has_dir_auto);
   void UpdateDirectionalityAndDescendant(TextDirection direction);
   void UpdateDescendantDirectionality(TextDirection direction);
+  void AdjustDirectionalityIfNeededAfterShadowRootChanged();
   void BeginParsingChildren() override;
 
  protected:
diff --git a/third_party/blink/renderer/core/input/mouse_event_manager.cc b/third_party/blink/renderer/core/input/mouse_event_manager.cc
index 042bb65..19f5259 100644
--- a/third_party/blink/renderer/core/input/mouse_event_manager.cc
+++ b/third_party/blink/renderer/core/input/mouse_event_manager.cc
@@ -688,11 +688,8 @@
 
   mouse_down_ = event.Event();
 
-  if (RuntimeEnabledFeatures::TextFragmentIdentifiersEnabled(
-          frame_->DomWindow())) {
-    if (frame_->View())
-      frame_->View()->DismissFragmentAnchor();
-  }
+  if (frame_->View())
+    frame_->View()->DismissFragmentAnchor();
 
   if (frame_->GetDocument()->IsSVGDocument() &&
       frame_->GetDocument()->AccessSVGExtensions().ZoomAndPanEnabled()) {
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc
index 569cced..79ffade 100644
--- a/third_party/blink/renderer/core/loader/document_loader.cc
+++ b/third_party/blink/renderer/core/loader/document_loader.cc
@@ -755,7 +755,7 @@
 
   GetLocalFrameClient().DidFinishSameDocumentNavigation(
       history_item_.Get(), commit_type, is_content_initiated,
-      is_history_api_navigation);
+      is_history_api_navigation, is_client_redirect_);
   probe::DidNavigateWithinDocument(frame_);
   if (!was_loading) {
     GetLocalFrameClient().DidStopLoading();
@@ -2468,6 +2468,12 @@
   return token_value;
 }
 
+void DocumentLoader::NotifyPrerenderingDocumentActivated() {
+  DCHECK(!frame_->GetDocument()->IsPrerendering());
+  DCHECK(is_prerendering_);
+  is_prerendering_ = false;
+}
+
 ContentSecurityPolicy* DocumentLoader::CreateCSP() {
   ContentSecurityPolicy* csp = MakeGarbageCollected<ContentSecurityPolicy>();
 
diff --git a/third_party/blink/renderer/core/loader/document_loader.h b/third_party/blink/renderer/core/loader/document_loader.h
index 93f1b6c..02a12491 100644
--- a/third_party/blink/renderer/core/loader/document_loader.h
+++ b/third_party/blink/renderer/core/loader/document_loader.h
@@ -333,8 +333,9 @@
   // to ensure the token can only be used to invoke a single text fragment.
   bool ConsumeTextFragmentToken();
 
-  // Returns whether the load request was initiated for prerendering.
-  bool IsPrerendering() const { return is_prerendering_; }
+  // Notifies that the prerendering document this loader is working for is
+  // activated.
+  void NotifyPrerenderingDocumentActivated();
 
  protected:
   Vector<KURL> redirect_chain_;
@@ -552,8 +553,8 @@
   // Whether this load request was initiated by the browser.
   const bool is_browser_initiated_ = false;
 
-  // Whether this load request was initiated for prerendering.
-  const bool is_prerendering_ = false;
+  // Whether this loader is working for a prerendering document.
+  bool is_prerendering_ = false;
 
   // Whether this load request was initiated by the same origin.
   bool is_same_origin_navigation_ = false;
diff --git a/third_party/blink/renderer/core/loader/frame_loader.cc b/third_party/blink/renderer/core/loader/frame_loader.cc
index d555181..43b82a8 100644
--- a/third_party/blink/renderer/core/loader/frame_loader.cc
+++ b/third_party/blink/renderer/core/loader/frame_loader.cc
@@ -86,6 +86,7 @@
 #include "third_party/blink/renderer/core/loader/document_loader.h"
 #include "third_party/blink/renderer/core/loader/form_submission.h"
 #include "third_party/blink/renderer/core/loader/frame_load_request.h"
+#include "third_party/blink/renderer/core/loader/frame_loader_types.h"
 #include "third_party/blink/renderer/core/loader/mixed_content_checker.h"
 #include "third_party/blink/renderer/core/loader/progress_tracker.h"
 #include "third_party/blink/renderer/core/page/chrome_client.h"
@@ -153,7 +154,6 @@
 
   ResourceRequest request =
       document_loader_->GetHistoryItem()->GenerateResourceRequest(cache_mode);
-  request.SetRequestorOrigin(frame_->GetSecurityContext()->GetSecurityOrigin());
 
   // ClientRedirectPolicy is an indication that this load was triggered by some
   // direct interaction with the page. If this reload is not a client redirect,
@@ -445,6 +445,7 @@
     const KURL& url,
     const AtomicString& http_method,
     bool has_origin_window,
+    bool is_client_reload,
     const KURL& failing_url,
     WebFrameLoadType frame_load_type) {
   // TODO(dgozman): this method is rewriting the load type, which makes it hard
@@ -471,7 +472,7 @@
   if (url == document_loader_->UrlForHistory()) {
     if (http_method == http_names::kPOST)
       return WebFrameLoadType::kStandard;
-    if (!has_origin_window)
+    if (!has_origin_window || is_client_reload)
       return WebFrameLoadType::kReload;
     return WebFrameLoadType::kReplaceCurrentItem;
   }
@@ -605,7 +606,7 @@
     return;
 
   // Block renderer-initiated loads of data: and filesystem: URLs in the top
-  // frame.
+  // frame (unless they are reload requests).
   //
   // If the mime type of the data URL is supported, the URL will
   // eventually be rendered, so block it here. Otherwise, the load might be
@@ -613,6 +614,7 @@
   // embedder figure out what to do with it. Navigations to filesystem URLs are
   // always blocked here.
   if (frame_->IsMainFrame() && origin_window &&
+      request.ClientRedirectReason() != ClientNavigationReason::kReload &&
       !frame_->Client()->AllowContentInitiatedDataUrlNavigations(
           origin_window->Url()) &&
       (url.ProtocolIs("filesystem") ||
@@ -636,7 +638,8 @@
 
   frame_load_type = DetermineFrameLoadType(
       resource_request.Url(), resource_request.HttpMethod(), origin_window,
-      KURL(), frame_load_type);
+      request.ClientRedirectReason() == ClientNavigationReason::kReload, KURL(),
+      frame_load_type);
 
   bool same_document_navigation =
       request.GetNavigationPolicy() == kNavigationPolicyCurrentTab &&
@@ -952,8 +955,8 @@
 
   navigation_params->frame_load_type = DetermineFrameLoadType(
       navigation_params->url, navigation_params->http_method,
-      false /* has_origin_window */, navigation_params->unreachable_url,
-      navigation_params->frame_load_type);
+      false /* has_origin_window */, false /* is_client_reload */,
+      navigation_params->unreachable_url, navigation_params->frame_load_type);
 
   // Note: we might actually classify this navigation as same document
   // right here in the following circumstances:
diff --git a/third_party/blink/renderer/core/loader/frame_loader.h b/third_party/blink/renderer/core/loader/frame_loader.h
index 381a142..71b8f294 100644
--- a/third_party/blink/renderer/core/loader/frame_loader.h
+++ b/third_party/blink/renderer/core/loader/frame_loader.h
@@ -234,6 +234,7 @@
   WebFrameLoadType DetermineFrameLoadType(const KURL& url,
                                           const AtomicString& http_method,
                                           bool has_origin_window,
+                                          bool is_client_reload,
                                           const KURL& failing_url,
                                           WebFrameLoadType);
 
diff --git a/third_party/blink/renderer/core/messaging/blink_transferable_message_mojom_traits_test.cc b/third_party/blink/renderer/core/messaging/blink_transferable_message_mojom_traits_test.cc
index f92ff31..027689ec 100644
--- a/third_party/blink/renderer/core/messaging/blink_transferable_message_mojom_traits_test.cc
+++ b/third_party/blink/renderer/core/messaging/blink_transferable_message_mojom_traits_test.cc
@@ -49,8 +49,8 @@
     size_t num_elements = 8;
     v8::Local<v8::ArrayBuffer> v8_buffer =
         v8::ArrayBuffer::New(isolate, num_elements);
-    uint8_t* original_data =
-        static_cast<uint8_t*>(v8_buffer->GetContents().Data());
+    auto backing_store = v8_buffer->GetBackingStore();
+    uint8_t* original_data = static_cast<uint8_t*>(backing_store->Data());
     for (size_t i = 0; i < num_elements; i++)
       original_data[i] = static_cast<uint8_t>(i);
 
@@ -88,7 +88,8 @@
   size_t num_elements = 8;
   v8::Local<v8::ArrayBuffer> v8_buffer =
       v8::ArrayBuffer::New(isolate, num_elements);
-  void* originalContentsData = v8_buffer->GetContents().Data();
+  auto backing_store = v8_buffer->GetBackingStore();
+  void* originalContentsData = backing_store->Data();
   uint8_t* contents = static_cast<uint8_t*>(originalContentsData);
   for (size_t i = 0; i < num_elements; i++)
     contents[i] = static_cast<uint8_t>(i);
@@ -116,7 +117,7 @@
   ASSERT_EQ(originalContentsData, deserialized_contents.Data());
 
   // The original ArrayBufferContents should be detached.
-  ASSERT_EQ(nullptr, v8_buffer->GetContents().Data());
+  ASSERT_EQ(nullptr, v8_buffer->GetBackingStore()->Data());
   ASSERT_TRUE(original_array_buffer->IsDetached());
 }
 
diff --git a/third_party/blink/renderer/core/page/chrome_client_impl.cc b/third_party/blink/renderer/core/page/chrome_client_impl.cc
index f8a11f30..ccecd90 100644
--- a/third_party/blink/renderer/core/page/chrome_client_impl.cc
+++ b/third_party/blink/renderer/core/page/chrome_client_impl.cc
@@ -893,6 +893,13 @@
 
 void ChromeClientImpl::RequestBeginMainFrameNotExpected(LocalFrame& frame,
                                                         bool request) {
+  if (!frame.GetWidgetForLocalRoot()) {
+    // We're about to crash due to crbug.com/838348. Record metrics to trigger
+    // Chrometto. We only expect this to be recorded on Android in any
+    // significant numbers (because we CHECK in RenderFrameImpl::Delete).
+    UMA_HISTOGRAM_BOOLEAN("Navigation.RequestBeginMainFrameNotExpectedCrash",
+                          frame.IsMainFrame());
+  }
   frame.GetWidgetForLocalRoot()->RequestBeginMainFrameNotExpected(request);
 }
 
diff --git a/third_party/blink/renderer/core/page/page.cc b/third_party/blink/renderer/core/page/page.cc
index 415b293..a4ddff05 100644
--- a/third_party/blink/renderer/core/page/page.cc
+++ b/third_party/blink/renderer/core/page/page.cc
@@ -1066,6 +1066,26 @@
   return autoplay_flags_;
 }
 
+// https://jeremyroman.github.io/alternate-loading-modes/#prerendering-browsing-context-activate
+void Page::ActivateForPrerendering() {
+  DCHECK(features::IsPrerender2Enabled());
+
+  // Step 8.2. "Let inclusiveDescendants be successorBC extended with
+  // successorBC's active document's list of the descendant browsing contexts."
+  // Step 8.3. "For each bc of inclusiveDescendants, queue a global task on the
+  // networking task source, given bc's active window, to perform the following
+  // steps:"
+  for (Frame* frame = MainFrame(); frame;
+       frame = frame->Tree().TraverseNext()) {
+    if (auto* local_frame = DynamicTo<LocalFrame>(frame)) {
+      local_frame->GetTaskRunner(TaskType::kNetworking)
+          ->PostTask(FROM_HERE,
+                     WTF::Bind(&Document::ActivateForPrerendering,
+                               WrapPersistent(local_frame->GetDocument())));
+    }
+  }
+}
+
 void Page::SetInsidePortal(bool inside_portal) {
   inside_portal_ = inside_portal;
 }
diff --git a/third_party/blink/renderer/core/page/page.h b/third_party/blink/renderer/core/page/page.h
index d2efc89d..61d780c0 100644
--- a/third_party/blink/renderer/core/page/page.h
+++ b/third_party/blink/renderer/core/page/page.h
@@ -336,6 +336,8 @@
 
   int32_t AutoplayFlags() const;
 
+  void ActivateForPrerendering();
+
   void SetInsidePortal(bool inside_portal);
   bool InsidePortal() const;
 
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.cc b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.cc
index bbf710d1..15324f02 100644
--- a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.cc
+++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.h"
 
+#include "components/shared_highlighting/core/common/shared_highlighting_features.h"
 #include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/element.h"
@@ -457,6 +458,10 @@
 }
 
 bool TextFragmentAnchor::Dismiss() {
+  if (base::FeatureList::IsEnabled(
+          shared_highlighting::kSharedHighlightingV2)) {
+    return false;
+  }
   // To decrease the likelihood of the user dismissing the highlight before
   // seeing it, we only dismiss the anchor after search_finished_, at which
   // point we've scrolled it into view or the user has started scrolling the
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_test.cc b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_test.cc
index a21b452b..620eaeb 100644
--- a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_test.cc
+++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_test.cc
@@ -2,7 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
+#include "components/shared_highlighting/core/common/shared_highlighting_features.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 #include "third_party/blink/renderer/core/dom/element.h"
@@ -983,6 +985,9 @@
 
 // Test that user scrolling dismisses the highlight.
 TEST_P(TextFragmentAnchorScrollTest, DismissTextHighlightOnUserScroll) {
+  base::test::ScopedFeatureList feature_list_;
+  feature_list_.InitAndDisableFeature(
+      shared_highlighting::kSharedHighlightingV2);
   SimRequest request(
       "https://example.com/"
       "test.html#:~:text=test%20page&text=more%20text",
@@ -1030,6 +1035,54 @@
   }
 }
 
+// Test that user scrolling doesn't dismiss the highlight, when the
+// SharedHighlightingV2 flag is enabled.
+TEST_P(TextFragmentAnchorScrollTest, DontDismissTextHighlightOnUserScroll) {
+  base::test::ScopedFeatureList feature_list_;
+  feature_list_.InitAndEnableFeature(
+      shared_highlighting::kSharedHighlightingV2);
+  SimRequest request(
+      "https://example.com/"
+      "test.html#:~:text=test%20page&text=more%20text",
+      "text/html");
+  LoadURL(
+      "https://example.com/"
+      "test.html#:~:text=test%20page&text=more%20text");
+  request.Complete(R"HTML(
+    <!DOCTYPE html>
+    <style>
+      body {
+        height: 2200px;
+      }
+      #first {
+        position: absolute;
+        top: 1000px;
+      }
+      #second {
+        position: absolute;
+        top: 2000px;
+      }
+    </style>
+    <p id="first">This is a test page</p>
+    <p id="second">With some more text</p>
+  )HTML");
+  RunAsyncMatchingTasks();
+
+  // Render two frames to handle the async step added by the beforematch event.
+  Compositor().BeginFrame();
+  Compositor().BeginFrame();
+
+  ASSERT_EQ(2u, GetDocument().Markers().Markers().size());
+
+  mojom::blink::ScrollType scroll_type = GetParam();
+  LayoutViewport()->ScrollBy(ScrollOffset(0, -10), scroll_type);
+
+  Compositor().BeginFrame();
+
+  EXPECT_EQ(2u, GetDocument().Markers().Markers().size());
+  EXPECT_TRUE(GetDocument().View()->GetFragmentAnchor());
+}
+
 // Ensure that the text fragment anchor has no effect in an iframe. This is
 // disabled in iframes by design, for security reasons.
 TEST_F(TextFragmentAnchorTest, DisabledInIframes) {
@@ -1482,6 +1535,9 @@
 
 // Test dismissing the text highlight with a click
 TEST_F(TextFragmentAnchorTest, DismissTextHighlightWithClick) {
+  base::test::ScopedFeatureList feature_list_;
+  feature_list_.InitAndDisableFeature(
+      shared_highlighting::kSharedHighlightingV2);
   SimRequest request(
       "https://example.com/"
       "test.html#:~:text=test%20page&text=more%20text",
@@ -1523,8 +1579,58 @@
   EXPECT_FALSE(GetDocument().View()->GetFragmentAnchor());
 }
 
+// Test not dismissing the text highlight with a click, if the
+// SharedHighlightingV2 flag is enabled.
+TEST_F(TextFragmentAnchorTest, DontDismissTextHighlightWithClick) {
+  base::test::ScopedFeatureList feature_list_;
+  feature_list_.InitAndEnableFeature(
+      shared_highlighting::kSharedHighlightingV2);
+  SimRequest request(
+      "https://example.com/"
+      "test.html#:~:text=test%20page&text=more%20text",
+      "text/html");
+  LoadURL(
+      "https://example.com/"
+      "test.html#:~:text=test%20page&text=more%20text");
+  request.Complete(R"HTML(
+    <!DOCTYPE html>
+    <style>
+      body {
+        height: 2200px;
+      }
+      #first {
+        position: absolute;
+        top: 1000px;
+      }
+      #second {
+        position: absolute;
+        top: 2000px;
+      }
+    </style>
+    <p id="first">This is a test page</p>
+    <p id="second">With some more text</p>
+  )HTML");
+  RunAsyncMatchingTasks();
+
+  // Render two frames to handle the async step added by the beforematch event.
+  Compositor().BeginFrame();
+  Compositor().BeginFrame();
+
+  EXPECT_EQ(2u, GetDocument().Markers().Markers().size());
+
+  SimulateClick(100, 100);
+
+  EXPECT_EQ(2u, GetDocument().Markers().Markers().size());
+
+  // Ensure the fragment is still installed
+  EXPECT_TRUE(GetDocument().View()->GetFragmentAnchor());
+}
+
 // Test dismissing the text highlight with a tap
 TEST_F(TextFragmentAnchorTest, DismissTextHighlightWithTap) {
+  base::test::ScopedFeatureList feature_list_;
+  feature_list_.InitAndDisableFeature(
+      shared_highlighting::kSharedHighlightingV2);
   SimRequest request(
       "https://example.com/"
       "test.html#:~:text=test%20page&text=more%20text",
@@ -1566,8 +1672,58 @@
   EXPECT_FALSE(GetDocument().View()->GetFragmentAnchor());
 }
 
+// Test not dismissing the text highlight with a tap, if the
+// SharedHighlightingV2 flag is enabled.
+TEST_F(TextFragmentAnchorTest, DontDismissTextHighlightWithTap) {
+  base::test::ScopedFeatureList feature_list_;
+  feature_list_.InitAndEnableFeature(
+      shared_highlighting::kSharedHighlightingV2);
+  SimRequest request(
+      "https://example.com/"
+      "test.html#:~:text=test%20page&text=more%20text",
+      "text/html");
+  LoadURL(
+      "https://example.com/"
+      "test.html#:~:text=test%20page&text=more%20text");
+  request.Complete(R"HTML(
+    <!DOCTYPE html>
+    <style>
+      body {
+        height: 2200px;
+      }
+      #first {
+        position: absolute;
+        top: 1000px;
+      }
+      #second {
+        position: absolute;
+        top: 2000px;
+      }
+    </style>
+    <p id="first">This is a test page</p>
+    <p id="second">With some more text</p>
+  )HTML");
+  RunAsyncMatchingTasks();
+
+  // Render two frames to handle the async step added by the beforematch event.
+  Compositor().BeginFrame();
+  Compositor().BeginFrame();
+
+  EXPECT_EQ(2u, GetDocument().Markers().Markers().size());
+
+  SimulateTap(100, 100);
+
+  EXPECT_EQ(2u, GetDocument().Markers().Markers().size());
+
+  // Ensure the fragment is installed
+  EXPECT_TRUE(GetDocument().View()->GetFragmentAnchor());
+}
+
 // Test that we don't dismiss a text highlight before it's scrolled into view
 TEST_F(TextFragmentAnchorTest, DismissTextHighlightOutOfView) {
+  base::test::ScopedFeatureList feature_list_;
+  feature_list_.InitAndDisableFeature(
+      shared_highlighting::kSharedHighlightingV2);
   SimRequest request("https://example.com/test.html#:~:text=test", "text/html");
   SimSubresourceRequest css_request("https://example.com/test.css", "text/css");
   LoadURL("https://example.com/test.html#:~:text=test");
@@ -1609,6 +1765,9 @@
 
 // Test dismissing a text highlight that didn't require a scroll into view
 TEST_F(TextFragmentAnchorTest, DismissTextHighlightInView) {
+  base::test::ScopedFeatureList feature_list_;
+  feature_list_.InitAndDisableFeature(
+      shared_highlighting::kSharedHighlightingV2);
   SimRequest request(
       "https://example.com/"
       "test.html#:~:text=test%20page&text=more%20text",
diff --git a/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc b/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
index ffdde2d3..0ae117a 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
@@ -1227,81 +1227,6 @@
   return nullptr;
 }
 
-//
-// Notifications that this object may have changed.
-//
-
-void AXLayoutObject::HandleActiveDescendantChanged() {
-  if (!GetLayoutObject() || !GetNode() || !GetDocument())
-    return;
-
-  Node* focused_node = GetDocument()->FocusedElement();
-  if (focused_node == GetNode()) {
-    AXObject* active_descendant = ActiveDescendant();
-    if (active_descendant && active_descendant->IsSelectedFromFocus()) {
-      // In single selection containers, selection follows focus, so a selection
-      // changed event must be fired. This ensures the AT is notified that the
-      // selected state has changed, so that it does not read "unselected" as
-      // the user navigates through the items.
-      AXObjectCache().HandleAriaSelectedChangedWithCleanLayout(
-          active_descendant->GetNode());
-    }
-
-    // Mark this node dirty. AXEventGenerator will automatically infer
-    // that the active descendant changed.
-    AXObjectCache().MarkAXObjectDirtyWithCleanLayout(this, false);
-  }
-}
-
-void AXLayoutObject::HandleAriaExpandedChanged() {
-  // Find if a parent of this object should handle aria-expanded changes.
-  AXObject* container_parent = this->ParentObject();
-  while (container_parent) {
-    bool found_parent = false;
-
-    switch (container_parent->RoleValue()) {
-      case ax::mojom::blink::Role::kLayoutTable:
-      case ax::mojom::blink::Role::kTree:
-      case ax::mojom::blink::Role::kTreeGrid:
-      case ax::mojom::blink::Role::kGrid:
-      case ax::mojom::blink::Role::kTable:
-        found_parent = true;
-        break;
-      default:
-        break;
-    }
-
-    if (found_parent)
-      break;
-
-    container_parent = container_parent->ParentObject();
-  }
-
-  // Post that the row count changed.
-  if (container_parent) {
-    AXObjectCache().PostNotification(container_parent,
-                                     ax::mojom::blink::Event::kRowCountChanged);
-  }
-
-  // Post that the specific row either collapsed or expanded.
-  AccessibilityExpanded expanded = IsExpanded();
-  if (!expanded)
-    return;
-
-  if (RoleValue() == ax::mojom::blink::Role::kRow ||
-      RoleValue() == ax::mojom::blink::Role::kTreeItem) {
-    ax::mojom::blink::Event notification =
-        ax::mojom::blink::Event::kRowExpanded;
-    if (expanded == kExpandedCollapsed)
-      notification = ax::mojom::blink::Event::kRowCollapsed;
-
-    AXObjectCache().PostNotification(this, notification);
-  } else {
-    AXObjectCache().PostNotification(this,
-                                     ax::mojom::blink::Event::kExpandedChanged);
-  }
-}
-
 void AXLayoutObject::HandleAutofillStateChanged(WebAXAutofillState state) {
   // Autofill state is stored in AXObjectCache.
   AXObjectCache().SetAutofillState(AXObjectID(), state);
diff --git a/third_party/blink/renderer/modules/accessibility/ax_layout_object.h b/third_party/blink/renderer/modules/accessibility/ax_layout_object.h
index 26908b1..8f20d46 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_layout_object.h
+++ b/third_party/blink/renderer/modules/accessibility/ax_layout_object.h
@@ -105,9 +105,6 @@
 
   bool CanHaveChildren() const override;
 
-  // Notifications that this object may have changed.
-  void HandleActiveDescendantChanged() override;
-  void HandleAriaExpandedChanged() override;
   // Called when autofill/autocomplete state changes on a form control.
   void HandleAutofillStateChanged(WebAXAutofillState state) override;
 
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
index 79bc333..47198bb 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
@@ -4433,6 +4433,81 @@
   }
 }
 
+//
+// Notifications that this object may have changed.
+//
+
+void AXNodeObject::HandleAriaExpandedChanged() {
+  // Find if a parent of this object should handle aria-expanded changes.
+  AXObject* container_parent = this->ParentObject();
+  while (container_parent) {
+    bool found_parent = false;
+
+    switch (container_parent->RoleValue()) {
+      case ax::mojom::blink::Role::kLayoutTable:
+      case ax::mojom::blink::Role::kTree:
+      case ax::mojom::blink::Role::kTreeGrid:
+      case ax::mojom::blink::Role::kGrid:
+      case ax::mojom::blink::Role::kTable:
+        found_parent = true;
+        break;
+      default:
+        break;
+    }
+
+    if (found_parent)
+      break;
+
+    container_parent = container_parent->ParentObject();
+  }
+
+  // Post that the row count changed.
+  if (container_parent) {
+    AXObjectCache().PostNotification(container_parent,
+                                     ax::mojom::blink::Event::kRowCountChanged);
+  }
+
+  // Post that the specific row either collapsed or expanded.
+  AccessibilityExpanded expanded = IsExpanded();
+  if (!expanded)
+    return;
+
+  if (RoleValue() == ax::mojom::blink::Role::kRow ||
+      RoleValue() == ax::mojom::blink::Role::kTreeItem) {
+    ax::mojom::blink::Event notification =
+        ax::mojom::blink::Event::kRowExpanded;
+    if (expanded == kExpandedCollapsed)
+      notification = ax::mojom::blink::Event::kRowCollapsed;
+
+    AXObjectCache().PostNotification(this, notification);
+  } else {
+    AXObjectCache().PostNotification(this,
+                                     ax::mojom::blink::Event::kExpandedChanged);
+  }
+}
+
+void AXNodeObject::HandleActiveDescendantChanged() {
+  if (!GetLayoutObject() || !GetNode() || !GetDocument())
+    return;
+
+  Node* focused_node = GetDocument()->FocusedElement();
+  if (focused_node == GetNode()) {
+    AXObject* active_descendant = ActiveDescendant();
+    if (active_descendant && active_descendant->IsSelectedFromFocus()) {
+      // In single selection containers, selection follows focus, so a selection
+      // changed event must be fired. This ensures the AT is notified that the
+      // selected state has changed, so that it does not read "unselected" as
+      // the user navigates through the items.
+      AXObjectCache().HandleAriaSelectedChangedWithCleanLayout(
+          active_descendant->GetNode());
+    }
+
+    // Mark this node dirty. AXEventGenerator will automatically infer
+    // that the active descendant changed.
+    AXObjectCache().MarkAXObjectDirtyWithCleanLayout(this, false);
+  }
+}
+
 AXObject* AXNodeObject::ErrorMessage() const {
   // Check for aria-errormessage.
   Element* existing_error_message =
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.h b/third_party/blink/renderer/modules/accessibility/ax_node_object.h
index ae724c4..0126e0a 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_node_object.h
+++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.h
@@ -257,6 +257,8 @@
   // Notifications that this object may have changed.
   void ChildrenChanged() override;
   void SelectionChanged() final;
+  void HandleAriaExpandedChanged() override;
+  void HandleActiveDescendantChanged() override;
 
   // The aria-errormessage object or native object from a validationMessage
   // alert.
diff --git a/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h b/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h
index 579700a..061ab96 100644
--- a/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h
+++ b/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h
@@ -51,12 +51,11 @@
 struct CrossThreadFetchClientSettingsObjectData;
 
 // The implementation of WebEmbeddedWorker. This is responsible for starting
-// and terminating a service worker thread.
+// and terminating a service worker thread. Lives on a ThreadPool background
+// thread.
 //
-// Currently this starts the worker thread on the main thread. Future plan is to
-// start the worker thread off the main thread. This means that
-// WebEmbeddedWorkerImpl shouldn't create garbage-collected objects during
-// worker startup. See https://crbug.com/988335 for details.
+// Because it lives on a ThreadPool thread, this class does not make
+// GarbageCollected objects (https://crbug.com/988335).
 class MODULES_EXPORT WebEmbeddedWorkerImpl final : public WebEmbeddedWorker {
  public:
   explicit WebEmbeddedWorkerImpl(WebServiceWorkerContextClient*);
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_content_settings_proxy.h b/third_party/blink/renderer/modules/service_worker/service_worker_content_settings_proxy.h
index 4d9514f..375e5c9 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_content_settings_proxy.h
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_content_settings_proxy.h
@@ -14,9 +14,10 @@
 
 namespace blink {
 
-// Provides the content settings information from browser process.
-// This proxy is created and destroyed on the main thread and used on the
-// worker thread.
+// Provides the content settings information from browser process.  This proxy
+// is created by WebEmbeddedWorkerImpl::StartWorkerContext() on a background
+// ThreadPool thread, and destroyed on that thread. But all methods are called
+// on the service worker thread.
 class ServiceWorkerContentSettingsProxy final
     : public blink::WebContentSettingsClient {
  public:
@@ -36,9 +37,9 @@
   // that it was constructed on, this uses ThreadSpecific.
   mojo::Remote<mojom::blink::WorkerContentSettingsProxy>& GetService();
 
-  // This is set on the main thread at the ctor,
-  // and moved to thread local storage on the worker thread
-  // when GetService() is called for the first time.
+  // This is set on the ThreadPool thread at the ctor, and moved to thread
+  // local storage on the service worker thread when GetService() is called for
+  // the first time.
   mojo::PendingRemote<mojom::blink::WorkerContentSettingsProxy> host_info_;
 
   DISALLOW_COPY_AND_ASSIGN(ServiceWorkerContentSettingsProxy);
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h
index c302c09..783dbe19 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h
@@ -52,21 +52,19 @@
 class WebEmbeddedWorkerImpl;
 class WebServiceWorkerContextClient;
 
-// This class is created and destructed on the main thread, but live most
-// of its time as a resident of the worker thread. All methods other than its
-// ctor/dtor and Detach() are called on the worker thread.
+// This class is created and destructed on an "initiator thread" (the
+// background ThreadPool thread that WebEmbeddedWorkerImpl run on), but lives
+// most of its time as a resident of the service worker thread. All methods
+// other than its ctor/dtor and Detach() are called on the service worker
+// thread.
 //
 // This implements WebServiceWorkerContextProxy, which connects ServiceWorker's
 // WorkerGlobalScope and embedder/chrome, and implements ServiceWorker-specific
-// events/upcall methods that are to be called by embedder/chromium,
-// e.g. onfetch.
+// events/upcall methods that are to be called by embedder/chromium, e.g.
+// onfetch.
 //
 // An instance of this class is supposed to outlive until
-// workerThreadTerminated() is called by its corresponding
-// WorkerGlobalScope.
-//
-// TODO(bashi): Update the above comment and method comments once we move
-// creation of this class off the main thread.
+// workerThreadTerminated() is called by its corresponding WorkerGlobalScope.
 class ServiceWorkerGlobalScopeProxy final : public WebServiceWorkerContextProxy,
                                             public WorkerReportingProxy {
  public:
@@ -137,8 +135,8 @@
   // Detaches this proxy object entirely from the outside world, clearing out
   // all references.
   //
-  // It is called on the main thread during WebEmbeddedWorkerImpl finalization
-  // _after_ the worker thread using the proxy has been terminated.
+  // It is called on the initiator thread during WebEmbeddedWorkerImpl
+  // finalization _after_ the worker thread using the proxy has been terminated.
   void Detach();
 
   void TerminateWorkerContext();
diff --git a/third_party/blink/renderer/modules/webcodecs/BUILD.gn b/third_party/blink/renderer/modules/webcodecs/BUILD.gn
index d2e14a3d..113f3a2 100644
--- a/third_party/blink/renderer/modules/webcodecs/BUILD.gn
+++ b/third_party/blink/renderer/modules/webcodecs/BUILD.gn
@@ -56,10 +56,6 @@
     "video_frame_handle.h",
     "video_frame_logger.cc",
     "video_frame_logger.h",
-    "video_track_reader.cc",
-    "video_track_reader.h",
-    "video_track_writer.cc",
-    "video_track_writer.h",
   ]
   deps = [
     "//media",
@@ -90,7 +86,6 @@
     "image_decoder_external_test.cc",
     "video_decoder_broker_test.cc",
     "video_frame_test.cc",
-    "video_track_reader_writer_test.cc",
   ]
 
   configs += [
diff --git a/third_party/blink/renderer/modules/webcodecs/DEPS b/third_party/blink/renderer/modules/webcodecs/DEPS
index e1eae306..236ac02f 100644
--- a/third_party/blink/renderer/modules/webcodecs/DEPS
+++ b/third_party/blink/renderer/modules/webcodecs/DEPS
@@ -29,9 +29,6 @@
 ]
 
 specific_include_rules = {
-  "video_track_reader_writer_test\.cc": [
-    "+base/run_loop.h",
-  ],
   "video_decoder_broker_test\.cc": [
     "+base/run_loop.h",
     "+base/threading/thread.h",
diff --git a/third_party/blink/renderer/modules/webcodecs/idls.gni b/third_party/blink/renderer/modules/webcodecs/idls.gni
index 9e9ef12..4fee9b8 100644
--- a/third_party/blink/renderer/modules/webcodecs/idls.gni
+++ b/third_party/blink/renderer/modules/webcodecs/idls.gni
@@ -13,7 +13,6 @@
   "video_decoder.idl",
   "video_encoder.idl",
   "video_frame.idl",
-  "video_track_reader.idl",
 ]
 
 modules_callback_function_idl_files = [
@@ -48,7 +47,6 @@
   "video_encoder_init.idl",
   "video_frame_init.idl",
   "video_frame_plane_init.idl",
-  "video_track_writer_parameters.idl",
 ]
 
 modules_typedefs_enums_only_idl_files = [
diff --git a/third_party/blink/renderer/modules/webcodecs/video_track_reader.cc b/third_party/blink/renderer/modules/webcodecs/video_track_reader.cc
deleted file mode 100644
index 6f459ff..0000000
--- a/third_party/blink/renderer/modules/webcodecs/video_track_reader.cc
+++ /dev/null
@@ -1,155 +0,0 @@
-// 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 "third_party/blink/renderer/modules/webcodecs/video_track_reader.h"
-
-#include "base/threading/thread_task_runner_handle.h"
-#include "media/base/video_frame.h"
-#include "third_party/blink/public/mojom/web_feature/web_feature.mojom-blink.h"
-#include "third_party/blink/renderer/core/execution_context/execution_context.h"
-#include "third_party/blink/renderer/core/inspector/console_message.h"
-#include "third_party/blink/renderer/modules/mediastream/media_stream_video_track.h"
-#include "third_party/blink/renderer/modules/webcodecs/video_frame.h"
-#include "third_party/blink/renderer/platform/bindings/exception_state.h"
-#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/scheduler/public/post_cross_thread_task.h"
-#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
-
-namespace blink {
-
-VideoTrackReader::VideoTrackReader(ScriptState* script_state,
-                                   MediaStreamTrack* track)
-    : ExecutionContextLifecycleObserver(ExecutionContext::From(script_state)),
-      started_(false),
-      real_time_media_task_runner_(
-          ExecutionContext::From(script_state)
-              ->GetTaskRunner(TaskType::kInternalMediaRealTime)),
-      track_(track) {
-  UseCounter::Count(ExecutionContext::From(script_state),
-                    WebFeature::kWebCodecs);
-
-  ExecutionContext::From(script_state)
-      ->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
-          mojom::blink::ConsoleMessageSource::kDeprecation,
-          mojom::blink::ConsoleMessageLevel::kWarning,
-          "VideoTrackReader is deprecated; use MediaStreamTrackProcessor "
-          "instead."));
-}
-
-void VideoTrackReader::start(V8VideoFrameOutputCallback* callback,
-                             ExceptionState& exception_state) {
-  DCHECK(real_time_media_task_runner_->BelongsToCurrentThread());
-
-  if (started_) {
-    exception_state.ThrowDOMException(
-        DOMExceptionCode::kInvalidStateError,
-        "The VideoTrackReader has already been started.");
-    return;
-  }
-
-  started_ = true;
-  callback_ = callback;
-  ConnectToTrack(WebMediaStreamTrack(track_->Component()),
-                 ConvertToBaseRepeatingCallback(CrossThreadBindRepeating(
-                     &VideoTrackReader::OnFrameFromVideoTrack,
-                     WrapCrossThreadPersistent(this))),
-                 false /* is_sink_secure */);
-}
-
-void VideoTrackReader::stop(ExceptionState& exception_state) {
-  DCHECK(real_time_media_task_runner_->BelongsToCurrentThread());
-
-  if (!started_) {
-    exception_state.ThrowDOMException(
-        DOMExceptionCode::kInvalidStateError,
-        "The VideoTrackReader has already been stopped.");
-    return;
-  }
-
-  StopInternal();
-}
-
-void VideoTrackReader::StopInternal() {
-  DCHECK(real_time_media_task_runner_->BelongsToCurrentThread());
-  started_ = false;
-  callback_ = nullptr;
-  DisconnectFromTrack();
-}
-
-void VideoTrackReader::OnFrameFromVideoTrack(
-    scoped_refptr<media::VideoFrame> media_frame,
-    std::vector<scoped_refptr<media::VideoFrame>> scaled_media_frames,
-    base::TimeTicks estimated_capture_time) {
-  // The value of estimated_capture_time here seems to almost always be the
-  // system clock and most implementations of this callback ignore it.
-  // So, we will also ignore it.
-  DCHECK(media_frame);
-  PostCrossThreadTask(
-      *real_time_media_task_runner_.get(), FROM_HERE,
-      CrossThreadBindOnce(&VideoTrackReader::ExecuteCallbackOnMainThread,
-                          WrapCrossThreadPersistent(this),
-                          std::move(media_frame),
-                          std::move(scaled_media_frames)));
-}
-
-void VideoTrackReader::ExecuteCallbackOnMainThread(
-    scoped_refptr<media::VideoFrame> media_frame,
-    std::vector<scoped_refptr<media::VideoFrame>> /*scaled_media_frames*/) {
-  DCHECK(real_time_media_task_runner_->BelongsToCurrentThread());
-
-  if (!callback_) {
-    // We may have already been stopped.
-    return;
-  }
-
-  // If |track_|'s constraints changed (e.g. the resolution changed from a call
-  // to MediaStreamTrack.applyConstraints() in JS), this |media_frame| might
-  // still have the old constraints, due to the thread hop.
-  // We may want to invalidate |media_frames| when constraints change, but it's
-  // unclear whether this is a problem for now.
-
-  auto* context = GetExecutionContext();
-  if (!context)
-    return;
-
-  // Scaled media frames are currently ignored.
-  callback_->InvokeAndReportException(
-      nullptr,
-      MakeGarbageCollected<VideoFrame>(std::move(media_frame), context));
-}
-
-void VideoTrackReader::OnReadyStateChanged(
-    WebMediaStreamSource::ReadyState state) {
-  if (state == WebMediaStreamSource::kReadyStateEnded)
-    StopInternal();
-}
-
-VideoTrackReader* VideoTrackReader::Create(ScriptState* script_state,
-                                           MediaStreamTrack* track,
-                                           ExceptionState& exception_state) {
-  if (track->kind() != "video") {
-    exception_state.ThrowTypeError(
-        "Can only read video frames from video tracks.");
-    return nullptr;
-  }
-
-  if (!script_state->ContextIsValid()) {  // when the context is detached
-    exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
-                                      "The context has been destroyed");
-
-    return nullptr;
-  }
-
-  return MakeGarbageCollected<VideoTrackReader>(script_state, track);
-}
-
-void VideoTrackReader::Trace(Visitor* visitor) const {
-  visitor->Trace(track_);
-  visitor->Trace(callback_);
-  ScriptWrappable::Trace(visitor);
-  ExecutionContextLifecycleObserver::Trace(visitor);
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/webcodecs/video_track_reader.h b/third_party/blink/renderer/modules/webcodecs/video_track_reader.h
deleted file mode 100644
index 15c22ace..0000000
--- a/third_party/blink/renderer/modules/webcodecs/video_track_reader.h
+++ /dev/null
@@ -1,75 +0,0 @@
-// 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_MODULES_WEBCODECS_VIDEO_TRACK_READER_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_VIDEO_TRACK_READER_H_
-
-#include "third_party/blink/public/web/modules/mediastream/media_stream_video_sink.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_video_frame_output_callback.h"
-#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
-#include "third_party/blink/renderer/modules/mediastream/media_stream_track.h"
-#include "third_party/blink/renderer/modules/modules_export.h"
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-
-namespace blink {
-
-class ScriptState;
-
-// Note: This class is deprecated. Use MediaStreamTrackProcessor instead.
-// TODO(crbug.com/1157610): remove this class.
-class MODULES_EXPORT VideoTrackReader final
-    : public ScriptWrappable,
-      public ExecutionContextLifecycleObserver,
-      public MediaStreamVideoSink {
-  DEFINE_WRAPPERTYPEINFO();
-
- public:
-  static VideoTrackReader* Create(ScriptState*,
-                                  MediaStreamTrack*,
-                                  ExceptionState&);
-  VideoTrackReader(ScriptState*, MediaStreamTrack*);
-
-  // Connects |this| to |track_| and starts delivering frames via |callback_|.
-  void start(V8VideoFrameOutputCallback*, ExceptionState&);
-
-  // Disconnects from |track_| and clears |callback_|.
-  void stop(ExceptionState&);
-
-  void Trace(Visitor* visitor) const override;
-
- private:
-  VideoTrackReader(const VideoTrackReader&) = delete;
-  VideoTrackReader& operator=(const VideoTrackReader&) = delete;
-
-  // ExecutionContextLifecycleObserver implementation.
-  void ContextDestroyed() override { DisconnectFromTrack(); }
-
-  // MediaStreamVideoSink implementation.
-  void OnReadyStateChanged(WebMediaStreamSource::ReadyState) override;
-
-  // Callback For MediaStreamVideoSink::ConnectToTrack.
-  void OnFrameFromVideoTrack(
-      scoped_refptr<media::VideoFrame> media_frame,
-      std::vector<scoped_refptr<media::VideoFrame>> scaled_media_frames,
-      base::TimeTicks estimated_capture_time);
-
-  void StopInternal();
-
-  void ExecuteCallbackOnMainThread(
-      scoped_refptr<media::VideoFrame> media_frame,
-      std::vector<scoped_refptr<media::VideoFrame>> scaled_media_frames);
-
-  // Whether we are connected to |track_| and using |callback_| to deliver
-  // frames.
-  bool started_;
-
-  const scoped_refptr<base::SingleThreadTaskRunner>
-      real_time_media_task_runner_;
-  Member<V8VideoFrameOutputCallback> callback_;
-  Member<MediaStreamTrack> track_;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_VIDEO_TRACK_READER_H_
diff --git a/third_party/blink/renderer/modules/webcodecs/video_track_reader.idl b/third_party/blink/renderer/modules/webcodecs/video_track_reader.idl
deleted file mode 100644
index fecfe4d..0000000
--- a/third_party/blink/renderer/modules/webcodecs/video_track_reader.idl
+++ /dev/null
@@ -1,21 +0,0 @@
-// 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.
-
-// See spec in developement at https://github.com/WICG/web-codecs/blob/master/index.bs
-// and https://github.com/WICG/web-codecs/blob/master/explainer.md.
-[
-    Exposed=Window,
-    RuntimeEnabled=WebCodecs
-] interface VideoTrackReader {
-  // DEPRECATED: use MediaStreamTrackProcessor instead.
-  // TODO(https://crbug.com/1157610): remove this idl.
-  [CallWith=ScriptState, RaisesException, MeasureAs=WebCodecsVideoTrackReader]
-  constructor(MediaStreamTrack track);
-
-  [RaisesException]
-  void start(VideoFrameOutputCallback callback);
-
-  [RaisesException]
-  void stop();
-};
diff --git a/third_party/blink/renderer/modules/webcodecs/video_track_reader_writer_test.cc b/third_party/blink/renderer/modules/webcodecs/video_track_reader_writer_test.cc
deleted file mode 100644
index c19ffe6..0000000
--- a/third_party/blink/renderer/modules/webcodecs/video_track_reader_writer_test.cc
+++ /dev/null
@@ -1,159 +0,0 @@
-// 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 "base/run_loop.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_function.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_video_frame.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_video_track_writer_parameters.h"
-#include "third_party/blink/renderer/core/streams/readable_stream.h"
-#include "third_party/blink/renderer/core/streams/writable_stream.h"
-#include "third_party/blink/renderer/core/streams/writable_stream_default_writer.h"
-#include "third_party/blink/renderer/modules/webcodecs/video_frame.h"
-#include "third_party/blink/renderer/modules/webcodecs/video_track_reader.h"
-#include "third_party/blink/renderer/modules/webcodecs/video_track_writer.h"
-#include "third_party/blink/renderer/platform/bindings/exception_state.h"
-#include "third_party/blink/renderer/platform/bindings/script_state.h"
-#include "third_party/blink/renderer/platform/bindings/to_v8.h"
-#include "third_party/blink/renderer/platform/testing/io_task_runner_testing_platform_support.h"
-
-namespace blink {
-
-class MockFunction : public ScriptFunction {
- public:
-  static testing::StrictMock<MockFunction>* Create(ScriptState* script_state) {
-    return MakeGarbageCollected<testing::StrictMock<MockFunction>>(
-        script_state);
-  }
-
-  v8::Local<v8::Function> Bind() { return BindToV8Function(); }
-
-  MOCK_METHOD1(Call, ScriptValue(ScriptValue));
-
- protected:
-  explicit MockFunction(ScriptState* script_state)
-      : ScriptFunction(script_state) {}
-};
-
-class VideoTrackReaderWriterTest : public testing::Test {
- public:
-  void TearDown() override {
-    RunIOUntilIdle();
-    ThreadState::Current()->CollectAllGarbageForTesting();
-  }
-
- protected:
-  VideoFrame* CreateBlackVideoFrame(ExecutionContext* context) {
-    return MakeGarbageCollected<VideoFrame>(
-        media::VideoFrame::CreateBlackFrame(gfx::Size(100, 100)), context);
-  }
-
-  void RunIOUntilIdle() const {
-    // Tracks use the IO thread to send frames to sinks. Make sure that
-    // tasks on IO thread are completed before moving on.
-    base::RunLoop run_loop;
-    platform_->GetIOTaskRunner()->PostTaskAndReply(
-        FROM_HERE, base::BindOnce([] {}), run_loop.QuitClosure());
-    run_loop.Run();
-    base::RunLoop().RunUntilIdle();
-  }
-
-  V8VideoFrameOutputCallback* GetCallback(MockFunction* function) {
-    return V8VideoFrameOutputCallback::Create(function->Bind());
-  }
-
- private:
-  ScopedTestingPlatformSupport<IOTaskRunnerTestingPlatformSupport> platform_;
-};
-
-TEST_F(VideoTrackReaderWriterTest, WriteAndRead) {
-  V8TestingScope scope;
-  auto* script_state = scope.GetScriptState();
-
-  VideoTrackWriterParameters params;
-  params.setReleaseFrames(false);
-  auto* writer =
-      VideoTrackWriter::Create(script_state, &params, ASSERT_NO_EXCEPTION);
-
-  auto* read_output_function = MockFunction::Create(script_state);
-  auto* reader = VideoTrackReader::Create(script_state, writer->track(),
-                                          ASSERT_NO_EXCEPTION);
-
-  reader->start(GetCallback(read_output_function), ASSERT_NO_EXCEPTION);
-
-  auto* frame = CreateBlackVideoFrame(scope.GetExecutionContext());
-  writer->writable()
-      ->getWriter(script_state, ASSERT_NO_EXCEPTION)
-      ->write(script_state,
-              ScriptValue(scope.GetIsolate(), ToV8(frame, script_state)),
-              ASSERT_NO_EXCEPTION);
-
-  ScriptValue v8_frame;
-  // We don't care about Call()'s return value, so we use undefined.
-  ScriptValue undefined_value =
-      ScriptValue::From(script_state, ToV8UndefinedGenerator());
-  EXPECT_CALL(*read_output_function, Call(testing::_))
-      .WillOnce(
-          testing::DoAll(testing::SaveArg<0>(&v8_frame),
-                         testing::Return(testing::ByMove(undefined_value))));
-
-  RunIOUntilIdle();
-
-  testing::Mock::VerifyAndClear(read_output_function);
-
-  auto* read_frame =
-      V8VideoFrame::ToImplWithTypeCheck(scope.GetIsolate(), v8_frame.V8Value());
-
-  reader->stop(ASSERT_NO_EXCEPTION);
-
-  ASSERT_TRUE(frame);
-  EXPECT_EQ(frame->frame(), read_frame->frame());
-
-  // Auto-release turned off
-  EXPECT_NE(nullptr, frame->frame());
-}
-
-TEST_F(VideoTrackReaderWriterTest, AutoRelease) {
-  V8TestingScope scope;
-  auto* script_state = scope.GetScriptState();
-
-  VideoTrackWriterParameters params;
-  params.setReleaseFrames(true);
-  auto* writer =
-      VideoTrackWriter::Create(script_state, &params, ASSERT_NO_EXCEPTION);
-
-  auto* frame = CreateBlackVideoFrame(scope.GetExecutionContext());
-  writer->writable()
-      ->getWriter(script_state, ASSERT_NO_EXCEPTION)
-      ->write(script_state,
-              ScriptValue(scope.GetIsolate(), ToV8(frame, script_state)),
-              ASSERT_NO_EXCEPTION);
-
-  RunIOUntilIdle();
-
-  // Auto-release worked
-  EXPECT_EQ(nullptr, frame->frame());
-}
-
-TEST_F(VideoTrackReaderWriterTest, Abort) {
-  V8TestingScope scope;
-  auto* script_state = scope.GetScriptState();
-
-  VideoTrackWriterParameters params;
-  params.setReleaseFrames(false);
-  auto* writer =
-      VideoTrackWriter::Create(script_state, &params, ASSERT_NO_EXCEPTION);
-
-  EXPECT_EQ(writer->track()->readyState(), "live");
-
-  writer->writable()->abort(script_state, ASSERT_NO_EXCEPTION);
-
-  RunIOUntilIdle();
-
-  EXPECT_TRUE(writer->track()->Ended());
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/webcodecs/video_track_writer.cc b/third_party/blink/renderer/modules/webcodecs/video_track_writer.cc
deleted file mode 100644
index eccb736..0000000
--- a/third_party/blink/renderer/modules/webcodecs/video_track_writer.cc
+++ /dev/null
@@ -1,144 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this Sink code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/modules/webcodecs/video_track_writer.h"
-
-#include "media/base/video_frame.h"
-#include "third_party/blink/public/mojom/mediastream/media_stream.mojom-blink.h"
-#include "third_party/blink/public/web/modules/mediastream/media_stream_video_source.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_video_frame.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_video_track_writer_parameters.h"
-#include "third_party/blink/renderer/core/execution_context/execution_context.h"
-#include "third_party/blink/renderer/core/streams/underlying_sink_base.h"
-#include "third_party/blink/renderer/core/streams/writable_stream.h"
-#include "third_party/blink/renderer/core/streams/writable_stream_default_controller.h"
-#include "third_party/blink/renderer/modules/mediastream/media_stream_track.h"
-#include "third_party/blink/renderer/modules/mediastream/media_stream_video_track.h"
-#include "third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source.h"
-#include "third_party/blink/renderer/modules/webcodecs/video_frame.h"
-#include "third_party/blink/renderer/platform/bindings/exception_state.h"
-#include "third_party/blink/renderer/platform/bindings/script_state.h"
-#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
-#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
-#include "third_party/blink/renderer/platform/wtf/uuid.h"
-
-namespace blink {
-
-// Implements a WritableStream's UnderlyingSinkBase by pushing frames into a
-// PushableMediaStreamVideoSource.  Also optionally releases the frames.
-class VideoTrackWritableStreamSink final : public UnderlyingSinkBase {
- public:
-  // The source must out live the sink.
-  VideoTrackWritableStreamSink(PushableMediaStreamVideoSource* source,
-                               bool release_frames)
-      : source_(source), release_frames_(release_frames) {}
-
-  // UnderlyingSinkBase overrides.
-  ScriptPromise start(ScriptState* script_state,
-                      WritableStreamDefaultController* controller,
-                      ExceptionState& exception_state) override {
-    // We're ready write away
-    return ScriptPromise::CastUndefined(script_state);
-  }
-
-  ScriptPromise write(ScriptState* script_state,
-                      ScriptValue chunk,
-                      WritableStreamDefaultController* controller,
-                      ExceptionState& exception_state) override {
-    VideoFrame* video_frame = V8VideoFrame::ToImplWithTypeCheck(
-        script_state->GetIsolate(), chunk.V8Value());
-    if (!video_frame) {
-      exception_state.ThrowTypeError("Provided chunk is not a VideoFrame.");
-      return ScriptPromise();
-    }
-
-    base::TimeTicks estimated_capture_time = base::TimeTicks::Now();
-    source_->PushFrame(video_frame->frame(), estimated_capture_time);
-
-    if (release_frames_)
-      video_frame->close();
-
-    return ScriptPromise::CastUndefined(script_state);
-  }
-
-  ScriptPromise abort(ScriptState* script_state,
-                      ScriptValue reason,
-                      ExceptionState& exception_state) override {
-    source_->StopSource();
-    return ScriptPromise::CastUndefined(script_state);
-  }
-
-  ScriptPromise close(ScriptState* script_state,
-                      ExceptionState& exception_state) override {
-    source_->StopSource();
-    return ScriptPromise::CastUndefined(script_state);
-  }
-
-  PushableMediaStreamVideoSource* source_;
-  bool release_frames_;
-};
-
-MediaStreamTrack* CreateVideoTrackFromSource(
-    ScriptState* script_state,
-    std::unique_ptr<MediaStreamVideoSource> video_source) {
-  // Get "video_source.get()" before std::move(source) into owner.
-  auto* video_source_ptr = video_source.get();
-
-  String track_id = WTF::CreateCanonicalUUIDString();
-  MediaStreamSource* video_source_owner =
-      MakeGarbageCollected<MediaStreamSource>(
-          track_id, MediaStreamSource::kTypeVideo, track_id /* name */,
-          false /* remote */);
-  video_source_owner->SetPlatformSource(std::move(video_source));
-
-  return MakeGarbageCollected<MediaStreamTrack>(
-      ExecutionContext::From(script_state),
-      MediaStreamVideoTrack::CreateVideoTrack(
-          video_source_ptr, MediaStreamVideoSource::ConstraintsOnceCallback(),
-          true /* enabled */));
-}
-
-VideoTrackWriter* VideoTrackWriter::Create(
-    ScriptState* script_state,
-    const VideoTrackWriterParameters* params,
-    ExceptionState& exception_state) {
-  if (!script_state->ContextIsValid()) {  // when the context is detached
-    exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
-                                      "The context has been destroyed");
-
-    return nullptr;
-  }
-
-  std::unique_ptr<PushableMediaStreamVideoSource> track_source =
-      std::make_unique<PushableMediaStreamVideoSource>();
-  VideoTrackWritableStreamSink* writable_sink =
-      MakeGarbageCollected<VideoTrackWritableStreamSink>(
-          track_source.get(), params->releaseFrames());
-
-  auto* track =
-      CreateVideoTrackFromSource(script_state, std::move(track_source));
-  auto* writable = WritableStream::Create(
-      script_state, ScriptValue::From(script_state, writable_sink),
-      exception_state);
-  return MakeGarbageCollected<VideoTrackWriter>(track, writable);
-}
-
-VideoTrackWriter::VideoTrackWriter(MediaStreamTrack* track,
-                                   WritableStream* writable)
-    : track_(track), writable_(writable) {}
-
-WritableStream* VideoTrackWriter::writable() {
-  return writable_;
-}
-
-MediaStreamTrack* VideoTrackWriter::track() {
-  return track_;
-}
-
-void VideoTrackWriter::Trace(Visitor* visitor) const {
-  visitor->Trace(track_);
-  visitor->Trace(writable_);
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/webcodecs/video_track_writer.h b/third_party/blink/renderer/modules/webcodecs/video_track_writer.h
deleted file mode 100644
index f9572cb..0000000
--- a/third_party/blink/renderer/modules/webcodecs/video_track_writer.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// 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_MODULES_WEBCODECS_VIDEO_TRACK_WRITER_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_VIDEO_TRACK_WRITER_H_
-
-#include "third_party/blink/renderer/modules/mediastream/media_stream_track.h"
-#include "third_party/blink/renderer/modules/modules_export.h"
-#include "third_party/blink/renderer/platform/heap/heap.h"
-
-namespace blink {
-
-class ScriptState;
-class WritableStream;
-class VideoTrackWriterParameters;
-
-class MODULES_EXPORT VideoTrackWriter final
-    : public GarbageCollected<VideoTrackWriter> {
- public:
-  static VideoTrackWriter* Create(ScriptState* script_state,
-                                  const VideoTrackWriterParameters* params,
-                                  ExceptionState& exception_state);
-  VideoTrackWriter(MediaStreamTrack* track, WritableStream* writable);
-  MediaStreamTrack* track();
-  WritableStream* writable();
-
-  // GarbageCollected override
-  virtual void Trace(Visitor* visitor) const;
-
- private:
-  Member<MediaStreamTrack> track_;
-  Member<WritableStream> writable_;
-
-  DISALLOW_COPY_AND_ASSIGN(VideoTrackWriter);
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_VIDEO_TRACK_WRITER_H_
diff --git a/third_party/blink/renderer/modules/webcodecs/video_track_writer_parameters.idl b/third_party/blink/renderer/modules/webcodecs/video_track_writer_parameters.idl
deleted file mode 100644
index 7687d494..0000000
--- a/third_party/blink/renderer/modules/webcodecs/video_track_writer_parameters.idl
+++ /dev/null
@@ -1,9 +0,0 @@
-// 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.
-
-// See spec in developement at https://github.com/WICG/web-codecs/blob/master/index.bs
-// and https://github.com/WICG/web-codecs/blob/master/explainer.md.
-dictionary VideoTrackWriterParameters {
-  boolean releaseFrames = true;
-};
\ No newline at end of file
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_blend_component.idl b/third_party/blink/renderer/modules/webgpu/gpu_blend_component.idl
new file mode 100644
index 0000000..eaa9b4e5
--- /dev/null
+++ b/third_party/blink/renderer/modules/webgpu/gpu_blend_component.idl
@@ -0,0 +1,35 @@
+// Copyright 2021 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.
+
+// https://gpuweb.github.io/gpuweb/
+
+dictionary GPUBlendComponent {
+    GPUBlendFactor srcFactor = "one";
+    GPUBlendFactor dstFactor = "zero";
+    GPUBlendOperation operation = "add";
+};
+
+enum GPUBlendFactor {
+    "zero",
+    "one",
+    "src-color",
+    "one-minus-src-color",
+    "src-alpha",
+    "one-minus-src-alpha",
+    "dst-color",
+    "one-minus-dst-color",
+    "dst-alpha",
+    "one-minus-dst-alpha",
+    "src-alpha-saturated",
+    "blend-color",
+    "one-minus-blend-color"
+};
+
+enum GPUBlendOperation {
+    "add",
+    "subtract",
+    "reverse-subtract",
+    "min",
+    "max"
+};
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_blend_state.idl b/third_party/blink/renderer/modules/webgpu/gpu_blend_state.idl
index 787ef912..075ffaa6 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_blend_state.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_blend_state.idl
@@ -1,35 +1,10 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2021 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.
 
 // https://gpuweb.github.io/gpuweb/
 
 dictionary GPUBlendState {
-    GPUBlendFactor srcFactor = "one";
-    GPUBlendFactor dstFactor = "zero";
-    GPUBlendOperation operation = "add";
-};
-
-enum GPUBlendFactor {
-    "zero",
-    "one",
-    "src-color",
-    "one-minus-src-color",
-    "src-alpha",
-    "one-minus-src-alpha",
-    "dst-color",
-    "one-minus-dst-color",
-    "dst-alpha",
-    "one-minus-dst-alpha",
-    "src-alpha-saturated",
-    "blend-color",
-    "one-minus-blend-color"
-};
-
-enum GPUBlendOperation {
-    "add",
-    "subtract",
-    "reverse-subtract",
-    "min",
-    "max"
+  required GPUBlendComponent color;
+  required GPUBlendComponent alpha;
 };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_color_state_descriptor.idl b/third_party/blink/renderer/modules/webgpu/gpu_color_state_descriptor.idl
new file mode 100644
index 0000000..76bab55
--- /dev/null
+++ b/third_party/blink/renderer/modules/webgpu/gpu_color_state_descriptor.idl
@@ -0,0 +1,13 @@
+// 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.
+
+// https://gpuweb.github.io/gpuweb/
+
+dictionary GPUColorStateDescriptor {
+    required GPUTextureFormat format;
+
+    GPUBlendComponent alphaBlend = {};
+    GPUBlendComponent colorBlend = {};
+    GPUColorWriteFlags writeMask = 15;  // GPUColorWrite.ALL
+};
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_color_target_state.idl b/third_party/blink/renderer/modules/webgpu/gpu_color_target_state.idl
index 7e18301..172c930 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_color_target_state.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_color_target_state.idl
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2021 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.
 
@@ -6,8 +6,6 @@
 
 dictionary GPUColorTargetState {
     required GPUTextureFormat format;
-
-    GPUBlendState alphaBlend = {};
-    GPUBlendState colorBlend = {};
+    GPUBlendState blend;
     GPUColorWriteFlags writeMask = 15;  // GPUColorWrite.ALL
 };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_depth_stencil_state.idl b/third_party/blink/renderer/modules/webgpu/gpu_depth_stencil_state.idl
index ccd67113..4dffd4a 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_depth_stencil_state.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_depth_stencil_state.idl
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2021 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.
 
@@ -15,4 +15,8 @@
 
     GPUStencilValue stencilReadMask = 0xFFFFFFFF;
     GPUStencilValue stencilWriteMask = 0xFFFFFFFF;
+
+    GPUDepthBias depthBias = 0;
+    float depthBiasSlopeScale = 0;
+    float depthBiasClamp = 0;
 };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_depth_stencil_state_descriptor.idl b/third_party/blink/renderer/modules/webgpu/gpu_depth_stencil_state_descriptor.idl
new file mode 100644
index 0000000..3b08e377e
--- /dev/null
+++ b/third_party/blink/renderer/modules/webgpu/gpu_depth_stencil_state_descriptor.idl
@@ -0,0 +1,18 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://gpuweb.github.io/gpuweb/
+
+dictionary GPUDepthStencilStateDescriptor {
+    required GPUTextureFormat format;
+
+    boolean depthWriteEnabled = false;
+    GPUCompareFunction depthCompare = "always";
+
+    GPUStencilFaceState stencilFront = {};
+    GPUStencilFaceState stencilBack = {};
+
+    GPUStencilValue stencilReadMask = 0xFFFFFFFF;
+    GPUStencilValue stencilWriteMask = 0xFFFFFFFF;
+};
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.cc b/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.cc
index 37463a4..6a6cece 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.cc
@@ -5,14 +5,14 @@
 #include "third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.h"
 
 #include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_blend_state.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_color_target_state.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_depth_stencil_state.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_blend_component.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_color_state_descriptor.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_depth_stencil_state_descriptor.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_rasterization_state_descriptor.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_render_pipeline_descriptor.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_stencil_face_state.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_attribute_descriptor.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_buffer_layout_descriptor.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_attribute.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_buffer_layout.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_state_descriptor.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_device.h"
@@ -24,7 +24,7 @@
 
 namespace {
 
-WGPUBlendDescriptor AsDawnType(const GPUBlendState* webgpu_desc) {
+WGPUBlendDescriptor AsDawnType(const GPUBlendComponent* webgpu_desc) {
   DCHECK(webgpu_desc);
 
   WGPUBlendDescriptor dawn_desc = {};
@@ -38,7 +38,8 @@
 
 }  // anonymous namespace
 
-WGPUColorStateDescriptor AsDawnType(const GPUColorTargetState* webgpu_desc) {
+WGPUColorStateDescriptor AsDawnType(
+    const GPUColorStateDescriptor* webgpu_desc) {
   DCHECK(webgpu_desc);
 
   WGPUColorStateDescriptor dawn_desc = {};
@@ -69,7 +70,7 @@
 }
 
 WGPUDepthStencilStateDescriptor AsDawnType(
-    const GPUDepthStencilState* webgpu_desc) {
+    const GPUDepthStencilStateDescriptor* webgpu_desc) {
   DCHECK(webgpu_desc);
 
   WGPUDepthStencilStateDescriptor dawn_desc = {};
@@ -153,6 +154,89 @@
   }
 }
 
+void AsDawnVertexBufferLayouts(
+    v8::Isolate* isolate,
+    GPUDevice* device,
+    v8::Local<v8::Value> vertex_buffers_value,
+    Vector<WGPUVertexBufferLayoutDescriptor>* dawn_vertex_buffers,
+    Vector<WGPUVertexAttributeDescriptor>* dawn_vertex_attributes,
+    ExceptionState& exception_state) {
+  if (!vertex_buffers_value->IsArray()) {
+    exception_state.ThrowTypeError("vertexBuffers must be an array");
+    return;
+  }
+
+  v8::Local<v8::Context> context = isolate->GetCurrentContext();
+  v8::Local<v8::Array> vertex_buffers = vertex_buffers_value.As<v8::Array>();
+
+  // First we collect all the descriptors but we don't set
+  // WGPUVertexBufferLayoutDescriptor::attributes
+  // TODO(cwallez@chromium.org): Should we validate the Length() first so we
+  // don't risk creating HUGE vectors of WGPUVertexBufferLayoutDescriptor from
+  // the sparse array?
+  for (uint32_t i = 0; i < vertex_buffers->Length(); ++i) {
+    // This array can be sparse. Skip empty slots.
+    v8::MaybeLocal<v8::Value> maybe_value = vertex_buffers->Get(context, i);
+    v8::Local<v8::Value> value;
+    if (!maybe_value.ToLocal(&value) || value.IsEmpty() ||
+        value->IsNullOrUndefined()) {
+      WGPUVertexBufferLayoutDescriptor dawn_vertex_buffer = {};
+      dawn_vertex_buffer.arrayStride = 0;
+      dawn_vertex_buffer.stepMode = WGPUInputStepMode_Vertex;
+      dawn_vertex_buffer.attributeCount = 0;
+      dawn_vertex_buffer.attributes = nullptr;
+      dawn_vertex_buffers->push_back(dawn_vertex_buffer);
+      continue;
+    }
+
+    GPUVertexBufferLayout* vertex_buffer =
+        NativeValueTraits<GPUVertexBufferLayout>::NativeValue(isolate, value,
+                                                              exception_state);
+    if (exception_state.HadException()) {
+      return;
+    }
+
+    WGPUVertexBufferLayoutDescriptor dawn_vertex_buffer = {};
+    dawn_vertex_buffer.arrayStride = vertex_buffer->arrayStride();
+    dawn_vertex_buffer.stepMode =
+        AsDawnEnum<WGPUInputStepMode>(vertex_buffer->stepMode());
+    dawn_vertex_buffer.attributeCount =
+        static_cast<uint32_t>(vertex_buffer->attributes().size());
+    dawn_vertex_buffer.attributes = nullptr;
+    dawn_vertex_buffers->push_back(dawn_vertex_buffer);
+
+    for (wtf_size_t j = 0; j < vertex_buffer->attributes().size(); ++j) {
+      const GPUVertexAttribute* attribute = vertex_buffer->attributes()[j];
+      WGPUVertexAttributeDescriptor dawn_vertex_attribute = {};
+      dawn_vertex_attribute.shaderLocation = attribute->shaderLocation();
+      dawn_vertex_attribute.offset = attribute->offset();
+      dawn_vertex_attribute.format =
+          AsDawnEnum<WGPUVertexFormat>(attribute->format());
+      if (dawn_vertex_attribute.format >= WGPUVertexFormat_UChar2) {
+        WTF::String message =
+            String("The vertex format '") +
+            IDLEnumAsString(attribute->format()) +
+            String("' has been deprecated in favor of '") +
+            GetUpdatedVertexFormat(dawn_vertex_attribute.format) + "'.";
+        device->AddConsoleWarning(message.Utf8().data());
+      }
+      dawn_vertex_attributes->push_back(dawn_vertex_attribute);
+    }
+  }
+
+  // Set up pointers in DawnVertexBufferLayoutDescriptor::attributes only
+  // after we stopped appending to the vector so the pointers aren't
+  // invalidated.
+  uint32_t attributeIndex = 0;
+  for (WGPUVertexBufferLayoutDescriptor& buffer : *dawn_vertex_buffers) {
+    if (buffer.attributeCount == 0) {
+      continue;
+    }
+    buffer.attributes = &(*dawn_vertex_attributes)[attributeIndex];
+    attributeIndex += buffer.attributeCount;
+  }
+}
+
 void GPUVertexStateAsWGPUVertexState(
     v8::Isolate* isolate,
     GPUDevice* device,
@@ -177,81 +261,9 @@
     // TODO(crbug.com/951629): Use a sequence of nullable descriptors.
     v8::Local<v8::Value> vertex_buffers_value =
         descriptor->vertexBuffers().V8Value();
-    if (!vertex_buffers_value->IsArray()) {
-      exception_state.ThrowTypeError("vertexBuffers must be an array");
-      return;
-    }
-
-    v8::Local<v8::Context> context = isolate->GetCurrentContext();
-    v8::Local<v8::Array> vertex_buffers = vertex_buffers_value.As<v8::Array>();
-
-    // First we collect all the descriptors but we don't set
-    // WGPUVertexBufferLayoutDescriptor::attributes
-    // TODO(cwallez@chromium.org): Should we validate the Length() first so we
-    // don't risk creating HUGE vectors of WGPUVertexBufferLayoutDescriptor from
-    // the sparse array?
-    for (uint32_t i = 0; i < vertex_buffers->Length(); ++i) {
-      // This array can be sparse. Skip empty slots.
-      v8::MaybeLocal<v8::Value> maybe_value = vertex_buffers->Get(context, i);
-      v8::Local<v8::Value> value;
-      if (!maybe_value.ToLocal(&value) || value.IsEmpty() ||
-          value->IsNullOrUndefined()) {
-        WGPUVertexBufferLayoutDescriptor dawn_vertex_buffer = {};
-        dawn_vertex_buffer.arrayStride = 0;
-        dawn_vertex_buffer.stepMode = WGPUInputStepMode_Vertex;
-        dawn_vertex_buffer.attributeCount = 0;
-        dawn_vertex_buffer.attributes = nullptr;
-        dawn_vertex_buffers->push_back(dawn_vertex_buffer);
-        continue;
-      }
-
-      GPUVertexBufferLayoutDescriptor* vertex_buffer =
-          NativeValueTraits<GPUVertexBufferLayoutDescriptor>::NativeValue(
-              isolate, value, exception_state);
-      if (exception_state.HadException()) {
-        return;
-      }
-
-      WGPUVertexBufferLayoutDescriptor dawn_vertex_buffer = {};
-      dawn_vertex_buffer.arrayStride = vertex_buffer->arrayStride();
-      dawn_vertex_buffer.stepMode =
-          AsDawnEnum<WGPUInputStepMode>(vertex_buffer->stepMode());
-      dawn_vertex_buffer.attributeCount =
-          static_cast<uint32_t>(vertex_buffer->attributes().size());
-      dawn_vertex_buffer.attributes = nullptr;
-      dawn_vertex_buffers->push_back(dawn_vertex_buffer);
-
-      for (wtf_size_t j = 0; j < vertex_buffer->attributes().size(); ++j) {
-        const GPUVertexAttributeDescriptor* attribute =
-            vertex_buffer->attributes()[j];
-        WGPUVertexAttributeDescriptor dawn_vertex_attribute = {};
-        dawn_vertex_attribute.shaderLocation = attribute->shaderLocation();
-        dawn_vertex_attribute.offset = attribute->offset();
-        dawn_vertex_attribute.format =
-            AsDawnEnum<WGPUVertexFormat>(attribute->format());
-        if (dawn_vertex_attribute.format >= WGPUVertexFormat_UChar2) {
-          WTF::String message =
-              String("The vertex format '") +
-              IDLEnumAsString(attribute->format()) +
-              String("' has been deprecated in favor of '") +
-              GetUpdatedVertexFormat(dawn_vertex_attribute.format) + "'.";
-          device->AddConsoleWarning(message.Utf8().data());
-        }
-        dawn_vertex_attributes->push_back(dawn_vertex_attribute);
-      }
-    }
-
-    // Set up pointers in DawnVertexBufferLayoutDescriptor::attributes only
-    // after we stopped appending to the vector so the pointers aren't
-    // invalidated.
-    uint32_t attributeIndex = 0;
-    for (WGPUVertexBufferLayoutDescriptor& buffer : *dawn_vertex_buffers) {
-      if (buffer.attributeCount == 0) {
-        continue;
-      }
-      buffer.attributes = &(*dawn_vertex_attributes)[attributeIndex];
-      attributeIndex += buffer.attributeCount;
-    }
+    AsDawnVertexBufferLayouts(isolate, device, vertex_buffers_value,
+                              dawn_vertex_buffers, dawn_vertex_attributes,
+                              exception_state);
   }
 
   dawn_desc->vertexBufferCount =
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline_descriptor.idl b/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline_descriptor.idl
index 84aeb20..9dcba3d3 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline_descriptor.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline_descriptor.idl
@@ -10,8 +10,8 @@
 
     required GPUPrimitiveTopology primitiveTopology;
     GPURasterizationStateDescriptor rasterizationState = {};
-    required sequence<GPUColorTargetState> colorStates;
-    GPUDepthStencilState depthStencilState;
+    required sequence<GPUColorStateDescriptor> colorStates;
+    GPUDepthStencilStateDescriptor depthStencilState;
     GPUVertexStateDescriptor vertexState = {};
 
     GPUSize32 sampleCount = 1;
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_vertex_attribute_descriptor.idl b/third_party/blink/renderer/modules/webgpu/gpu_vertex_attribute.idl
similarity index 96%
rename from third_party/blink/renderer/modules/webgpu/gpu_vertex_attribute_descriptor.idl
rename to third_party/blink/renderer/modules/webgpu/gpu_vertex_attribute.idl
index 0e0cd89e..0409aff 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_vertex_attribute_descriptor.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_vertex_attribute.idl
@@ -4,7 +4,7 @@
 
 // https://gpuweb.github.io/gpuweb/
 
-dictionary GPUVertexAttributeDescriptor {
+dictionary GPUVertexAttribute {
     required GPUVertexFormat format;
     required GPUSize64 offset;
     required GPUIndex32 shaderLocation;
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_vertex_buffer_layout_descriptor.idl b/third_party/blink/renderer/modules/webgpu/gpu_vertex_buffer_layout.idl
similarity index 75%
rename from third_party/blink/renderer/modules/webgpu/gpu_vertex_buffer_layout_descriptor.idl
rename to third_party/blink/renderer/modules/webgpu/gpu_vertex_buffer_layout.idl
index 672ef1e..42c754d 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_vertex_buffer_layout_descriptor.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_vertex_buffer_layout.idl
@@ -4,10 +4,10 @@
 
 // https://gpuweb.github.io/gpuweb/
 
-dictionary GPUVertexBufferLayoutDescriptor {
+dictionary GPUVertexBufferLayout {
     required GPUSize64 arrayStride;
     GPUInputStepMode stepMode = "vertex";
-    required sequence<GPUVertexAttributeDescriptor> attributes;
+    required sequence<GPUVertexAttribute> attributes;
 };
 
 enum GPUInputStepMode {
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_vertex_state_descriptor.idl b/third_party/blink/renderer/modules/webgpu/gpu_vertex_state_descriptor.idl
index 7073c0f6..3a14015d 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_vertex_state_descriptor.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_vertex_state_descriptor.idl
@@ -7,7 +7,7 @@
 dictionary GPUVertexStateDescriptor {
     GPUIndexFormat indexFormat;
     // TODO(crbug.com/951629): Make this a sequence of nullables.
-    object vertexBuffers; // We validate this is an array of nullable GPUVertexBufferLayoutDescriptor
+    object vertexBuffers; // We validate this is an array of nullable GPUVertexBufferLayout
 };
 
 enum GPUIndexFormat {
diff --git a/third_party/blink/renderer/modules/webgpu/idls.gni b/third_party/blink/renderer/modules/webgpu/idls.gni
index 9e713df..887fcc23 100644
--- a/third_party/blink/renderer/modules/webgpu/idls.gni
+++ b/third_party/blink/renderer/modules/webgpu/idls.gni
@@ -43,16 +43,19 @@
   "gpu_bind_group_entry.idl",
   "gpu_bind_group_layout_descriptor.idl",
   "gpu_bind_group_layout_entry.idl",
+  "gpu_blend_component.idl",
   "gpu_blend_state.idl",
   "gpu_buffer_binding.idl",
   "gpu_buffer_binding_layout.idl",
   "gpu_buffer_descriptor.idl",
   "gpu_color_dict.idl",
+  "gpu_color_state_descriptor.idl",
   "gpu_color_target_state.idl",
   "gpu_command_buffer_descriptor.idl",
   "gpu_command_encoder_descriptor.idl",
   "gpu_compute_pass_descriptor.idl",
   "gpu_compute_pipeline_descriptor.idl",
+  "gpu_depth_stencil_state_descriptor.idl",
   "gpu_depth_stencil_state.idl",
   "gpu_device_descriptor.idl",
   "gpu_extent_3d_dict.idl",
@@ -87,8 +90,8 @@
   "gpu_texture_descriptor.idl",
   "gpu_texture_view_descriptor.idl",
   "gpu_uncaptured_error_event_init.idl",
-  "gpu_vertex_attribute_descriptor.idl",
-  "gpu_vertex_buffer_layout_descriptor.idl",
+  "gpu_vertex_attribute.idl",
+  "gpu_vertex_buffer_layout.idl",
   "gpu_vertex_state_descriptor.idl",
 ]
 
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index f794fae4..e5e24b4 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1051,7 +1051,7 @@
     },
     {
       name: "IgnoreCrossOriginWindowWhenNamedAccessOnWindow",
-      status: "experimental",
+      status: "stable",
     },
     {
       name: "ImplicitRootScroller",
diff --git a/third_party/blink/renderer/platform/wtf/linked_hash_set.h b/third_party/blink/renderer/platform/wtf/linked_hash_set.h
index 2c6ad3c..3a1a4abd 100644
--- a/third_party/blink/renderer/platform/wtf/linked_hash_set.h
+++ b/third_party/blink/renderer/platform/wtf/linked_hash_set.h
@@ -41,6 +41,8 @@
 //
 // Unlike ListHashSet, this container supports WeakMember<T>.
 //
+// LinkedHashSet iterators are invalidated by mutation of the collection.
+//
 // Note: empty/deleted values as defined in HashTraits are not allowed.
 template <typename ValueArg,
           typename TraitsArg = HashTraits<ValueArg>,
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index c847cac..423c24a 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -234,11 +234,6 @@
 crbug.com/1126305 wpt_internal/prerender/* [ Skip ]
 crbug.com/1126305 virtual/prerender/wpt_internal/prerender/* [ Pass ]
 
-# This test currently fails since prerendering activation isn't fully plumbed
-# into the renderer yet.
-crbug.com/1183320 virtual/prerender/wpt_internal/prerender/state_and_event.html [ Timeout ]
-
-
 crbug.com/1185506 external/wpt/css/css-backgrounds/background-margin-iframe-root.html [ Pass Failure ]
 crbug.com/1185506 external/wpt/css/css-backgrounds/background-margin-root.html [ Pass Failure ]
 crbug.com/1185506 external/wpt/css/css-backgrounds/background-margin-transformed-root.html [ Pass Failure ]
@@ -5761,3 +5756,7 @@
 # Sheriff 2021-03-09
 crbug.com/1185121 fast/scroll-snap/animate-fling-to-snap-points-1.html [ Pass Failure ]
 crbug.com/1184157 http/tests/serviceworker/window-close-during-registration.html [ Pass Failure ]
+
+# Sheriff 2021-03-11
+crbug.com/1184773 [ Mac ] virtual/synchronous_html_parser/svg/dynamic-updates/SVGFEComponentTransferElement-svgdom-intercept-prop.html [ Pass Failure ]
+crbug.com/1186901 [ Linux ] http/tests/devtools/elements/styles-3/style-autocomplete.js [ Pass Failure ]
diff --git a/third_party/blink/web_tests/WebGPUExpectations b/third_party/blink/web_tests/WebGPUExpectations
index 363f4a67..7513a751 100644
--- a/third_party/blink/web_tests/WebGPUExpectations
+++ b/third_party/blink/web_tests/WebGPUExpectations
@@ -137,6 +137,7 @@
 
 # Test is outdated relative to spec; need to fix the test first.
 wpt_internal/webgpu/cts.html?q=webgpu:api,validation,createBindGroupLayout:bindingTypeSpecific_optional_members,* [ Skip ]
+crbug.com/dawn/130 wpt_internal/webgpu/cts.html?q=webgpu:api,validation,vertex_state:check_multiple_of_4_bytes_constraint_on_offset,* [ Failure ]
 
 # Deprecations that need to be updated in the tests
 wpt_internal/webgpu/cts.html?q=webgpu:idl,constants,flags:* [ Failure ]
diff --git a/third_party/blink/web_tests/editing/deleting/pruning_after_merge.html b/third_party/blink/web_tests/editing/deleting/pruning_after_merge.html
index 77d17ae..217a060b 100644
--- a/third_party/blink/web_tests/editing/deleting/pruning_after_merge.html
+++ b/third_party/blink/web_tests/editing/deleting/pruning_after_merge.html
@@ -12,7 +12,7 @@
         'delete',
         [
             '<div contenteditable>',
-                'b|<b></b>',
+                'b|',
                 '<span style="font-weight: bold;">ar</span>',
                 '<b><div>baz</div></b>',
             '</div>',
diff --git a/third_party/blink/web_tests/external/wpt/common/window-name-setter.html b/third_party/blink/web_tests/external/wpt/common/window-name-setter.html
new file mode 100644
index 0000000..c0603aa
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/common/window-name-setter.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>A page that sets window.name</title>
+
+<script>
+"use strict";
+
+window.onload = () => {
+  window.name = location.hash.slice(1);  // Drop the first '#' character.
+  window.name = "spices";
+};
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/frame-ancestors/frame-ancestors-none-block.html b/third_party/blink/web_tests/external/wpt/content-security-policy/frame-ancestors/frame-ancestors-none-block.html
index 596d3e7..f494468 100644
--- a/third_party/blink/web_tests/external/wpt/content-security-policy/frame-ancestors/frame-ancestors-none-block.html
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/frame-ancestors/frame-ancestors-none-block.html
@@ -6,11 +6,18 @@
     <script src="support/frame-ancestors-test.sub.js"></script>
 </head>
 <body>
-    <script>
-        test = async_test("A 'frame-ancestors' CSP directive with a value 'none' should block rendering.");
+  <script>
+    async_test(t => {
+      window.addEventListener('securitypolicyviolation', t.step_func(function(e) {
+        if (e.violatedDirective === 'frame-ancestors')
+          assert_unreached('No securitypolicyviolation event shoud be raised in the parent.');
+      }));
+      t.step_timeout(function() { t.done(); }, 2000);
+    });
 
-        sameOriginFrameShouldBeBlocked("'none'");
-    </script>
+    test = async_test("A 'frame-ancestors' CSP directive with a value 'none' should block rendering.");
+
+    sameOriginFrameShouldBeBlocked("'none'");
+  </script>
 </body>
 </html>
-
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/inheritance/location-reload.html b/third_party/blink/web_tests/external/wpt/content-security-policy/inheritance/location-reload.html
new file mode 100644
index 0000000..5d68e381
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/inheritance/location-reload.html
@@ -0,0 +1,120 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<meta http-equiv="Content-Security-Policy" content="img-src 'none'">
+<body>
+<script>
+  let message_from = (w, starts_with) => {
+    return new Promise(resolve => {
+      window.addEventListener('message', msg => {
+        if (msg.source == w) {
+          if (!starts_with || msg.data.startsWith(starts_with))
+            resolve(msg.data);
+        }
+      });
+    });
+  };
+
+  const img_url = window.origin + "/content-security-policy/support/fail.png";
+  const img_tag_string = `
+      <img src="${img_url}"
+           onload="top.postMessage('img loaded', '*');"
+           onerror="top.postMessage('img blocked', '*');"
+      >
+   `;
+
+  const html_test_payload = `
+        <!doctype html>
+        <div>${img_tag_string}</div>
+  `;
+  let blob_url = URL.createObjectURL(
+    new Blob([html_test_payload], { type: 'text/html' }));
+
+  let write_img_to_iframe = (iframe) => {
+    let div = iframe.contentDocument.createElement('div');
+    div.innerHTML = img_tag_string;
+    iframe.contentDocument.body.appendChild(div);
+  };
+
+
+  // Test location.reload() for "about:blank".
+  promise_test(async t => {
+    // Create an empty iframe.
+    window.iframe = document.createElement('iframe');
+    document.body.appendChild(iframe);
+
+    // Add an img.
+    let message = message_from(iframe.contentWindow);
+    write_img_to_iframe(iframe);
+
+    // Check that the empty document inherits CSP from the initiator.
+    assert_equals(await message, "img blocked",
+                  "Image should be blocked by CSP inherited from the parent.");
+
+    // Now perform a reload.
+    let message_2 = message_from(iframe.contentWindow);
+    let loaded = new Promise(resolve => iframe.onload = resolve);
+    iframe.contentWindow.location.reload();
+    await loaded;
+
+    // Add an img.
+    write_img_to_iframe(iframe);
+
+    // Check that the empty document still has the right CSP after reload.
+    assert_equals(await message_2, "img blocked",
+                  "Image should be blocked by CSP after reload.");
+  }, "location.reload() of empty iframe.");
+
+
+  // Test location.reload() for a blob URL.
+  promise_test(async t => {
+    // Create an iframe.
+    window.iframe = document.createElement('iframe');
+    document.body.appendChild(iframe);
+
+    // Navigate to the blob URL.
+    let message = message_from(iframe.contentWindow);
+    iframe.contentWindow.location = blob_url;
+
+    // Check that the blob URL inherits CSP from the initiator.
+    assert_equals(await message, "img blocked",
+                  "Image should be blocked by CSP inherited from navigation initiator.");
+
+    // Now perform a reload.
+    let message_2 = message_from(iframe.contentWindow);
+    let loaded = new Promise(resolve => iframe.onload = resolve);
+      iframe.contentWindow.location.reload();
+    await loaded;
+
+    // Check that the blob URL document still has the right CSP after reload.
+    assert_equals(await message_2, "img blocked",
+                  "Image should be blocked by CSP after reload.");
+  }, "location.reload() of blob URL iframe.");
+
+
+  // Test location.reload() for a srcdoc iframe.
+  promise_test(async t => {
+    // Create a srcdoc iframe.
+    window.iframe = document.createElement('iframe');
+    document.body.appendChild(iframe);
+
+    let message = message_from(iframe.contentWindow);
+    iframe.srcdoc = `${html_test_payload}`;
+
+    // Check that the srcdoc iframe inherits from the parent.
+    assert_equals(await message, "img blocked",
+                  "Image should be blocked by CSP inherited from navigation initiator.");
+
+    // Now perform a reload.
+    let message_2 = message_from(iframe.contentWindow);
+    let loaded = new Promise(resolve => iframe.onload = resolve);
+      iframe.contentWindow.location.reload();
+    await loaded;
+
+    // Check that the srcdoc iframe still has the right CSP after reload.
+    assert_equals(await message_2, "img blocked",
+                  "Image should be blocked by CSP after reload.");
+  }, "location.reload() of srcdoc iframe.");
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/custom-elements/state/tentative/ElementInternals-states.html b/third_party/blink/web_tests/external/wpt/custom-elements/state/tentative/ElementInternals-states.html
index 22c95a7..96dcb84 100644
--- a/third_party/blink/web_tests/external/wpt/custom-elements/state/tentative/ElementInternals-states.html
+++ b/third_party/blink/web_tests/external/wpt/custom-elements/state/tentative/ElementInternals-states.html
@@ -48,5 +48,35 @@
   i.states.add('--baz');
   assert_array_equals([...i.states], ['--foo', '--baz']);
 }, 'CustomStateSet behavior of ElementInternals.states: Modifications');
+
+test(() => {
+  let i = (new TestElement()).internals;
+  i.states.add('--one');
+  i.states.add('--two');
+  i.states.add('--three');
+  let iter = i.states.values();
+
+  // Delete the next item.
+  i.states.delete('--one');
+  let item = iter.next();
+  assert_false(item.done);
+  assert_equals(item.value, '--two');
+
+  // Clear the set.
+  i.states.clear();
+  item = iter.next();
+  assert_true(item.done);
+
+  // Delete the previous item.
+  i.states.add('--one');
+  i.states.add('--two');
+  i.states.add('--three');
+  iter = i.states.values();
+  item = iter.next();
+  assert_equals(item.value, '--one');
+  i.states.delete('--one');
+  item = iter.next();
+  assert_equals(item.value, '--two');
+}, 'Updating a CustomStateSet while iterating it should work');
 </script>
 
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/the-windowproxy-exotic-object/document-tree-child-browsing-context-name-property-set.sub.html b/third_party/blink/web_tests/external/wpt/html/browsers/the-windowproxy-exotic-object/document-tree-child-browsing-context-name-property-set.sub.html
new file mode 100644
index 0000000..171aa0199
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/the-windowproxy-exotic-object/document-tree-child-browsing-context-name-property-set.sub.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>document-tree child browsing context name property set</title>
+<link rel="help" href="https://html.spec.whatwg.org/C/#document-tree-child-browsing-context-name-property-set">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<iframe src="//{{domains[www]}}:{{ports[http][1]}}/common/window-name-setter.html#spices"></iframe>
+<iframe name="spices"></iframe>
+<iframe name="fruits"></iframe>
+
+<script>
+"use strict";
+setup({ explicit_done: true });
+
+window.onload = () => {
+  test(() => {
+    assert_equals(window.spices, undefined);
+    assert_not_equals(window.fruits, undefined);
+    assert_equals(window.fruits, window[2]);
+  }, "Cross origin child window's name shadows the second candidate of a same origin iframe");
+
+  done();
+};
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/elements/global-attributes/dir-slots-directionality.tentative.html b/third_party/blink/web_tests/external/wpt/html/dom/elements/global-attributes/dir-slots-directionality.tentative.html
new file mode 100644
index 0000000..851fd2edb
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/dom/elements/global-attributes/dir-slots-directionality.tentative.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<title>HTML Test: dir=auto|rtl with slots, and direction should be RTL</title>
+<meta charset="UTF-8">
+<meta name="author" title="Miyoung Shin" href="mailto:myid.shin@igalia.com">
+<meta name="assert" content="When dir='auto', the direction is set according to
+  slot's assigned node. And the direction should be propagated to shadow" />
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#the-dir-attribute"/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="host1"><span></span></div>
+<div id="host2" dir="rtl"></div>
+<span id="host3" dir="auto"></span>
+<div id="host4">اختبر</div>
+<div id="host5"></div>
+<script>
+let root1 = host1.attachShadow({mode:"open"});
+root1.innerHTML = '<slot dir="rtl"></slot>';
+
+let root2 = host2.attachShadow({mode:"open"});
+root2.innerHTML = '<span></span>';
+
+let root3 = host3.attachShadow({mode:"open"});
+root3.innerHTML = `اختبر`;
+
+let root4 = host4.attachShadow({mode:"open"});
+root4.innerHTML = '<span dir="auto"><slot></slot></span>';
+
+let root5 = host5.attachShadow({mode:"open"});
+  root5.innerHTML = '<span dir="auto"><slot>اختبر</slot></span>';
+
+test(() => {
+  assert_equals(getComputedStyle(host1.firstChild).direction, "rtl");
+  assert_equals(getComputedStyle(root2.querySelector("span")).direction, "rtl");
+  assert_equals(getComputedStyle(host3).direction, "rtl");
+  assert_equals(getComputedStyle(root4.querySelector("span")).direction, "rtl");
+  assert_equals(getComputedStyle(root5.querySelector("span")).direction, "rtl");
+}, 'Slots: Directionality');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/webcodecs/video-track-reader.html b/third_party/blink/web_tests/external/wpt/webcodecs/video-track-reader.html
deleted file mode 100644
index 925e837..0000000
--- a/third_party/blink/web_tests/external/wpt/webcodecs/video-track-reader.html
+++ /dev/null
@@ -1,112 +0,0 @@
-<!DOCTYPE html>
-<html>
-<title>Test the VideoTrackReader API.</title>
-<body></body>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/common/media.js"></script>
-<script>
-
-var testVideo = {
-  url: getVideoURI('/media/movie_5'),
-  height: 240,
-  width: 320,
-}
-
-async function getMediaStream() {
-  let video = document.createElement('video');
-  document.body.appendChild(video);
-  video.src = testVideo.url;
-  await video.play();
-
-  return video.captureStream();
-}
-
-promise_test(async function(t) {
-  let stream = await getMediaStream();
-  let vtr = new VideoTrackReader(stream.getVideoTracks()[0]);
-}, 'Test we can construct a VideoTrackReader.');
-
-promise_test(async function(t) {
-  let stream = await getMediaStream();
-  let vtr = new VideoTrackReader(stream.getVideoTracks()[0]);
-
-  let numberFrames = 0;
-
-  return new Promise(resolve => {
-    vtr.start(t.step_func(frame => {
-      assert_equals(frame.codedWidth, testVideo.width);
-      assert_equals(frame.codedHeight, testVideo.height);
-      assert_not_equals(frame.timestamp, null);
-      frame.close();
-
-      if (++numberFrames == 5) {
-        vtr.stop();
-        resolve();
-      }
-    }));
-  });
-}, 'Test we can start and stop a VideoTrackReader.');
-
-promise_test(async function(t) {
-  let stream = await getMediaStream();
-  let vtr = new VideoTrackReader(stream.getVideoTracks()[0]);
-
-  let stopped = false;
-  return new Promise(resolve => {
-    vtr.start(t.step_func(() => {
-      assert_false(stopped, "A stopped callback should never be called again");
-      vtr.stop();
-      vtr.start(resolve);
-      stopped = true;
-    }));
-  });
-}, 'Test we can restart a stopped VideoTrackReader.');
-
-promise_test(async function(t) {
-  let stream = await getMediaStream();
-  let track = stream.getVideoTracks()[0];
-
-  let vtr_a = new VideoTrackReader(track);
-  let vtr_b = new VideoTrackReader(track);
-
-  let receivedFrame_a = false;
-  let receivedFrame_b = false;
-
-  return Promise.all([
-    new Promise(resolve => { vtr_a.start(resolve); }),
-    new Promise(resolve => { vtr_b.start(resolve); }),
-  ]);
-}, 'Test we can create multiple VideoTrackReaders from the same track.');
-
-promise_test(async function(t) {
-  let stream = await getMediaStream();
-  let audioTrack = stream.getAudioTracks()[0];
-
-  assert_throws_js(TypeError, () => {
-    let vtr = new VideoTrackReader(audioTrack);
-  })
-}, 'Test creating a VideoTrackReaders from an audio track throws.');
-
-promise_test(async function(t) {
-  let stream = await getMediaStream();
-  let vtr = new VideoTrackReader(stream.getVideoTracks()[0]);
-
-  assert_throws_dom("InvalidStateError", () => {
-    vtr.stop();
-  })
-}, 'Test stopping a stopped VideoTrackReader throws.');
-
-promise_test(async function(t) {
-  let stream = await getMediaStream();
-  let vtr = new VideoTrackReader(stream.getVideoTracks()[0]);
-
-  vtr.start(() => {});
-
-  assert_throws_dom("InvalidStateError", () => {
-    vtr.start(() => {});
-  })
-}, 'Test starting a started VideoTrackReader throws.');
-
-</script>
-</html>
diff --git a/third_party/blink/web_tests/http/tests/devtools/localization/basic-l10n-test-expected.txt b/third_party/blink/web_tests/http/tests/devtools/localization/basic-l10n-test-expected.txt
deleted file mode 100644
index 7678158..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/localization/basic-l10n-test-expected.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-Tests that the the localization functions work as expected.
-
-
-Test string is returned as is
-Test string with a placeholder %s is returned as is
-Test %s string with multiple placeholders %s is returned as is
-Test unicode character  %
-
-Test string is returned as is
-Test string with a placeholder is returned with a substitution
-Test string with multiple placeholders is returned with substitutions
-Test numeric placeholder: -99
-Test numeric formatted placeholder and unicode character: 88.15 %
-
-Test string is returned as is
-Test string with a placeholder is returned with a substitution.
-Test string with placeholders is returned with substitutions.
-Test numeric placeholder: -99
-Test numeric placeholder and unicode character 88.149 %
-Test calling ls as a function
-
diff --git a/third_party/blink/web_tests/http/tests/devtools/localization/basic-l10n-test.js b/third_party/blink/web_tests/http/tests/devtools/localization/basic-l10n-test.js
deleted file mode 100644
index b60422f2..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/localization/basic-l10n-test.js
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-(async function() {
-  TestRunner.addResult(`Tests that the the localization functions work as expected.\n`);
-
-  // Verify localize returns an empty string.
-  TestRunner.addResult(Common.localize(''));
-  TestRunner.addResult(Common.localize('Test string is returned as is'));
-  TestRunner.addResult(Common.localize('Test string with a placeholder %s is returned as is'));
-  TestRunner.addResult(Common.localize('Test %s string with multiple placeholders %s is returned as is'));
-  TestRunner.addResult(Common.localize('Test unicode character \xa0%'));
-
-  // Verify UIString returns an empty string.
-  TestRunner.addResult(Common.UIString(''));
-  TestRunner.addResult(Common.UIString('Test string is returned as is'));
-  TestRunner.addResult(Common.UIString('Test string with a %s is returned with a substitution', 'placeholder'));
-  TestRunner.addResult(Common.UIString('%s string with multiple %s is returned with substitutions', 'Test', 'placeholders'));
-  TestRunner.addResult(Common.UIString('Test numeric placeholder: %d', -99));
-  TestRunner.addResult(Common.UIString('Test numeric formatted placeholder and unicode character: %.2f\xa0%%', 88.149));
-
-  // Verify ls returns an empty string.
-  TestRunner.addResult(ls``);
-  TestRunner.addResult(ls`Test string is returned as is`);
-  TestRunner.addResult(ls`Test string with a ${'placeholder'} is returned with a substitution.`);
-  TestRunner.addResult(ls`${'Test'} string with ${'placeholders'} is returned with substitutions.`);
-  TestRunner.addResult(ls`Test numeric placeholder: ${-99}`);
-  TestRunner.addResult(ls`Test numeric placeholder and unicode character ${88.149}\xa0%`);
-  TestRunner.addResult(ls('Test calling ls as a function'));
-
-  TestRunner.completeTest();
-})();
\ No newline at end of file
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/background-services/background-services-events-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/background-services/background-services-events-expected.txt
index 698d7a5e..145f986 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/background-services/background-services-events-expected.txt
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/background-services/background-services-events-expected.txt
@@ -161,7 +161,7 @@
             }
             [1] : {
                 key : Failure Reason
-                value : BackgroundFetchFailureReason::BAD_STATUS
+                value : BAD_STATUS
             }
         ]
         eventName : Background Fetch completed
diff --git a/third_party/blink/web_tests/http/tests/security/promise-access-control-allow-expected.txt b/third_party/blink/web_tests/http/tests/security/promise-access-control-allow-expected.txt
index 081ffb2..e2bed60 100644
--- a/third_party/blink/web_tests/http/tests/security/promise-access-control-allow-expected.txt
+++ b/third_party/blink/web_tests/http/tests/security/promise-access-control-allow-expected.txt
@@ -1,3 +1,4 @@
-CONSOLE MESSAGE: line 11: PASS: received unhandledrejection event
-CONSOLE MESSAGE: line 13: PASS: received expected reason
+CONSOLE ERROR: line 1: Uncaught (in promise) 42
+CONSOLE MESSAGE: line 22: PASS: received unhandledrejection event
+CONSOLE MESSAGE: line 25: PASS: received expected reason
 Tests that promise rejection events are received for cross origin CORS scripts
diff --git a/third_party/blink/web_tests/http/tests/security/promise-access-control-allow.html b/third_party/blink/web_tests/http/tests/security/promise-access-control-allow.html
index ac68a50..c309618 100644
--- a/third_party/blink/web_tests/http/tests/security/promise-access-control-allow.html
+++ b/third_party/blink/web_tests/http/tests/security/promise-access-control-allow.html
@@ -7,9 +7,21 @@
     testRunner.waitUntilDone();
 }
 
-addEventListener('unhandledrejection', function(e) {
+addEventListener('unhandledrejection', async exception => {
+    // Ordering in between:
+    // 1. dispatching the console.error
+    // 2. dispatching 'unhandledrejection'
+    // is not guaranteed.
+    //
+    // This caused this test to be flaky. See https://crbug.com/1185119
+    //
+    // (1) is not observable from here, but part of the expectations. The only
+    // ways to ensure it will happen consistently before (2) is to use
+    // setTimeout, unfortunately.
+    await new Promise(resolve => setTimeout(resolve, 250));
     console.log('PASS: received unhandledrejection event');
-    if (e.reason == 42)
+
+    if (exception.reason == 42)
         console.log('PASS: received expected reason');
     else
         console.log('FAIL: received unexpected reason: ' + e.reason);
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
index 93bf8d456..1ee8b41 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -11516,11 +11516,6 @@
     setter onaddtrack
     setter onchange
     setter onremovetrack
-interface VideoTrackReader
-    attribute @@toStringTag
-    method constructor
-    method start
-    method stop
 interface VirtualKeyboard : EventTarget
     attribute @@toStringTag
     getter boundingRect
diff --git a/third_party/blink/web_tests/wpt_internal/prerender/resources/prerender-state.html b/third_party/blink/web_tests/wpt_internal/prerender/resources/prerender-state.html
index 732f8b5..ab05c47 100644
--- a/third_party/blink/web_tests/wpt_internal/prerender/resources/prerender-state.html
+++ b/third_party/blink/web_tests/wpt_internal/prerender/resources/prerender-state.html
@@ -63,7 +63,7 @@
     writeValueToServer(activate_key, 'did_load');
   });
 
-  addEventListener('prerenderingchange', (e) => {
+  document.addEventListener('prerenderingchange', (e) => {
     result.eventBubbles = e.bubbles;
     result.eventCancelable = e.cancelable;
 
diff --git a/tools/grit/repack.gni b/tools/grit/repack.gni
index 01544acb..df4d8d0 100644
--- a/tools/grit/repack.gni
+++ b/tools/grit/repack.gni
@@ -53,7 +53,13 @@
 
     script = "//tools/grit/pak_util.py"
 
-    inputs = invoker.sources
+    inputs = []
+    foreach(source, invoker.sources) {
+      inputs += [
+        source,
+        "${source}.info",
+      ]
+    }
     outputs = [
       invoker.output,
       "${invoker.output}.info",
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 84172c12..cc04060b 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -16745,6 +16745,9 @@
 </action>
 
 <action name="Notifications.WebPlatform.ActionButton.Click">
+  <obsolete>
+    From 2021-03 use Notifications.WebPlatformV2 instead; it's equivalent.
+  </obsolete>
   <owner>peconn@chromium.org</owner>
   <owner>peter@chromium.org</owner>
   <description>
@@ -16754,6 +16757,9 @@
 </action>
 
 <action name="Notifications.WebPlatform.ActionButton.Close">
+  <obsolete>
+    From 2021-03 use Notifications.WebPlatformV2 instead; it's equivalent.
+  </obsolete>
   <owner>peconn@chromium.org</owner>
   <owner>beverloo@chromium.org</owner>
   <description>
@@ -16763,6 +16769,9 @@
 </action>
 
 <action name="Notifications.WebPlatform.ActionButton.FocusActivity">
+  <obsolete>
+    From 2021-03 use Notifications.WebPlatformV2 instead; it's equivalent.
+  </obsolete>
   <owner>peconn@chromium.org</owner>
   <owner>beverloo@chromium.org</owner>
   <description>
@@ -16772,6 +16781,9 @@
 </action>
 
 <action name="Notifications.WebPlatform.ActionButton.NewActivity">
+  <obsolete>
+    From 2021-03 use Notifications.WebPlatformV2 instead; it's equivalent.
+  </obsolete>
   <owner>peconn@chromium.org</owner>
   <owner>beverloo@chromium.org</owner>
   <description>
@@ -16781,14 +16793,18 @@
 </action>
 
 <action name="Notifications.WebPlatform.Body.Click">
+  <obsolete>From 2021-03 use Notifications.WebPlatformV2 instead.</obsolete>
   <owner>peconn@chromium.org</owner>
   <owner>beverloo@chromium.org</owner>
   <description>
     Recorded when the user clicks on the body of a web platform notification.
+    This metric had a bug where it also counted cases where the user dismissed
+    the notification, invalidating this and related actions.
   </description>
 </action>
 
 <action name="Notifications.WebPlatform.Body.Close">
+  <obsolete>From 2021-03 use Notifications.WebPlatformV2 instead.</obsolete>
   <owner>peconn@chromium.org</owner>
   <owner>beverloo@chromium.org</owner>
   <description>
@@ -16798,6 +16814,7 @@
 </action>
 
 <action name="Notifications.WebPlatform.Body.FocusActivity">
+  <obsolete>From 2021-03 use Notifications.WebPlatformV2 instead.</obsolete>
   <owner>peconn@chromium.org</owner>
   <owner>beverloo@chromium.org</owner>
   <description>
@@ -16807,6 +16824,78 @@
 </action>
 
 <action name="Notifications.WebPlatform.Body.NewActivity">
+  <obsolete>From 2021-03 use Notifications.WebPlatformV2 instead.</obsolete>
+  <owner>peconn@chromium.org</owner>
+  <owner>beverloo@chromium.org</owner>
+  <description>
+    Recorded when the user clicks on the body of a web platform notification,
+    and the notification opens a new Activity.
+  </description>
+</action>
+
+<action name="Notifications.WebPlatformV2.ActionButton.Click">
+  <owner>peconn@chromium.org</owner>
+  <owner>peter@chromium.org</owner>
+  <description>
+    Recorded when the user clicks on the action button of a web platform
+    notification.
+  </description>
+</action>
+
+<action name="Notifications.WebPlatformV2.ActionButton.Close">
+  <owner>peconn@chromium.org</owner>
+  <owner>beverloo@chromium.org</owner>
+  <description>
+    Recorded when the user clicks on the action button of a web platform
+    notification, and the notification closes.
+  </description>
+</action>
+
+<action name="Notifications.WebPlatformV2.ActionButton.FocusActivity">
+  <owner>peconn@chromium.org</owner>
+  <owner>beverloo@chromium.org</owner>
+  <description>
+    Recorded when the user clicks on the action button of a web platform
+    notification, and the notification focuses an Activity.
+  </description>
+</action>
+
+<action name="Notifications.WebPlatformV2.ActionButton.NewActivity">
+  <owner>peconn@chromium.org</owner>
+  <owner>beverloo@chromium.org</owner>
+  <description>
+    Recorded when the user clicks on the action button of a web platform
+    notification, and the notification opens a new Activity.
+  </description>
+</action>
+
+<action name="Notifications.WebPlatformV2.Body.Click">
+  <owner>peconn@chromium.org</owner>
+  <owner>beverloo@chromium.org</owner>
+  <description>
+    Recorded when the user clicks on the body of a web platform notification.
+  </description>
+</action>
+
+<action name="Notifications.WebPlatformV2.Body.Close">
+  <owner>peconn@chromium.org</owner>
+  <owner>beverloo@chromium.org</owner>
+  <description>
+    Recorded when the user clicks on the body of a web platform notification,
+    and the notification closes.
+  </description>
+</action>
+
+<action name="Notifications.WebPlatformV2.Body.FocusActivity">
+  <owner>peconn@chromium.org</owner>
+  <owner>beverloo@chromium.org</owner>
+  <description>
+    Recorded when the user clicks on the body of a web platform notification,
+    and the notification focuses an Activity.
+  </description>
+</action>
+
+<action name="Notifications.WebPlatformV2.Body.NewActivity">
   <owner>peconn@chromium.org</owner>
   <owner>beverloo@chromium.org</owner>
   <description>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 340a3d5..42443b69 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -9237,6 +9237,9 @@
 </enum>
 
 <enum name="BooleanValidKeyExists">
+  <obsolete>
+    Removed in M91 since the data is not monitored
+  </obsolete>
   <int value="0" label="No Valid Cached Key Found"/>
   <int value="1" label="Valid Cached Key Found"/>
 </enum>
@@ -23870,6 +23873,9 @@
 </enum>
 
 <enum name="EnterprisePolicyKeyVerification">
+  <obsolete>
+    Removed in M91 since the data is not monitored
+  </obsolete>
   <summary>
     Defined as MetricPolicyKeyVerification in
     components/policy/core/common/cloud/cloud_policy_validator.cc.
@@ -31881,6 +31887,16 @@
   <int value="3" label="WebPAnimationFormat"/>
 </enum>
 
+<enum name="FeatureUsageEvent">
+  <int value="0"
+      label="Device is eligible for this feature. Recorded once per day."/>
+  <int value="1" label="Feature is enabled by user. Recorded once per day."/>
+  <int value="2"
+      label="Successful attempt to use the feature. Recorded on each event."/>
+  <int value="3"
+      label="Failed attempt to use the feature. Recorded on each event."/>
+</enum>
+
 <enum name="FeedbackSource">
   <int value="0" label="Arc App"/>
   <int value="1" label="Ash"/>
@@ -43147,6 +43163,15 @@
   <int value="5" label="Load failed - Checksum not found in prefs"/>
 </enum>
 
+<enum name="LoadSodaResult">
+  <int value="0" label="Unknown"/>
+  <int value="1" label="Success"/>
+  <int value="2" label="Binary invalid"/>
+  <int value="3"
+      label="Binary successfully loaded but one or more function pointers are
+             null."/>
+</enum>
+
 <enum name="LoadType">
   <int value="0" label="UNDEFINED_LOAD">Not yet initialized</int>
   <int value="1" label="RELOAD">User pressed reload</int>
@@ -80046,6 +80071,13 @@
   <int value="6" label="Success"/>
 </enum>
 
+<enum name="WebAppOriginAssociationFetchResult">
+  <summary>Result of web app origin association file fetch.</summary>
+  <int value="0" label="FetchSucceed"/>
+  <int value="1" label="FailedNoResponseBody"/>
+  <int value="2" label="FetchFailedInvalidUrl"/>
+</enum>
+
 <enum name="WebappUninstallDialogAction">
   <int value="0" label="Uninstall only"/>
   <int value="1" label="Uninstall and remove data"/>
diff --git a/tools/metrics/histograms/histograms_xml/accessibility/histograms.xml b/tools/metrics/histograms/histograms_xml/accessibility/histograms.xml
index f0bf8f21..905696c 100644
--- a/tools/metrics/histograms/histograms_xml/accessibility/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/accessibility/histograms.xml
@@ -671,7 +671,7 @@
 </histogram>
 
 <histogram name="Accessibility.LiveCaption.AudioPropertyChanged"
-    enum="BooleanEnabled" expires_after="2021-04-30">
+    enum="BooleanEnabled" expires_after="2021-09-05">
   <owner>katie@chromium.org</owner>
   <owner>abigailbklein@google.com</owner>
   <owner>evliu@google.com</owner>
@@ -683,30 +683,26 @@
   </summary>
 </histogram>
 
-<histogram name="Accessibility.LiveCaption.Duration.CaptionBubbleHidden"
-    units="ms" expires_after="2021-07-11">
-  <owner>abigailbklein@google.com</owner>
-  <owner>evliu@google.com</owner>
-  <owner>chrome-a11y-core@google.com</owner>
-  <summary>
-    Measures the duration of an audio stream with the caption bubble hidden.
-    Logged once on the destruction of the SpeechRecognitionRecognizerImpl.
-  </summary>
-</histogram>
-
-<histogram name="Accessibility.LiveCaption.Duration.CaptionBubbleVisible"
+<histogram name="Accessibility.LiveCaption.Duration.CaptionBubble{Visibility}"
     units="ms" expires_after="2021-09-05">
   <owner>abigailbklein@google.com</owner>
   <owner>evliu@google.com</owner>
   <owner>chrome-a11y-core@google.com</owner>
   <summary>
-    Measures the duration of an audio stream with the caption bubble visible.
-    Logged once on the destruction of the SpeechRecognitionRecognizerImpl.
+    Measures how long SODA was running while the Live Caption UI was
+    {Visibility}. Logged once on the destruction of the
+    SpeechRecognitionRecognizerImpl.
   </summary>
+  <token key="Visibility">
+    <variant name="Hidden"
+        summary="hidden. This might be because it was closed by user or
+                 because there was an error passing transcriptions to the UI"/>
+    <variant name="Visible" summary="visible and showing transcriptions"/>
+  </token>
 </histogram>
 
 <histogram name="Accessibility.LiveCaption.EnableFrom{Entrypoint}"
-    enum="BooleanEnabled" expires_after="2021-04-30">
+    enum="BooleanEnabled" expires_after="2021-09-05">
   <owner>katie@chromium.org</owner>
   <owner>abigailbklein@google.com</owner>
   <owner>evliu@google.com</owner>
@@ -723,7 +719,7 @@
 </histogram>
 
 <histogram name="Accessibility.LiveCaption.ExpandBubble"
-    enum="LiveCaptionExpandBubbleEvent" expires_after="2021-04-30">
+    enum="LiveCaptionExpandBubbleEvent" expires_after="2021-09-05">
   <owner>katie@chromium.org</owner>
   <owner>abigailbklein@google.com</owner>
   <owner>evliu@google.com</owner>
@@ -745,22 +741,35 @@
   </summary>
 </histogram>
 
+<histogram name="Accessibility.LiveCaption.LoadSodaResult"
+    enum="LoadSodaResult" expires_after="2021-07-18">
+  <owner>abigailbklein@google.com</owner>
+  <owner>evliu@google.com</owner>
+  <owner>chrome-a11y-core@google.com</owner>
+  <summary>
+    The result of an attempt to load the Speech On-Device API (SODA) binary.
+    This is logged once for each media stream when the SODA binary is loaded.
+  </summary>
+</histogram>
+
 <histogram name="Accessibility.LiveCaption.Session"
-    enum="LiveCaptionSessionEvent" expires_after="2021-08-22">
+    enum="LiveCaptionSessionEvent" expires_after="2021-09-05">
   <owner>katie@chromium.org</owner>
   <owner>abigailbklein@google.com</owner>
   <owner>evliu@google.com</owner>
   <owner>chrome-a11y-core@google.com</owner>
   <summary>
-    Logged when there's a change in the lifetime of a Live Caption audio stream:
-    When a session started and captions began arriving from the service, when a
-    session ended because the audio stream finished, or when the session ended
-    because a user clicked the close button on the caption bubble.
+    Logged when the Live Caption bubble appears and disappears. Stream start
+    indicates when the bubble appears due to an audio session starting. Stream
+    end indicates when the bubble disappears due to a tab change, a navigation,
+    or the audio session ending and the bubble fading out due to inactivity.
+    Close button clicked indicates when the bubble disappears due to a user
+    clicking the close button on the caption bubble.
   </summary>
 </histogram>
 
 <histogram name="Accessibility.LiveCaption.UseSodaForLiveCaption"
-    enum="BooleanEnabled" expires_after="2021-07-18">
+    enum="BooleanEnabled" expires_after="2021-09-05">
   <owner>abigailbklein@google.com</owner>
   <owner>evliu@google.com</owner>
   <owner>chrome-a11y-core@google.com</owner>
diff --git a/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml b/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml
index 2906f55..d1d28dbc 100644
--- a/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml
@@ -22,6 +22,19 @@
 
 <histograms>
 
+<variants name="FeaturesLoggingUsageEvents">
+<!-- The variants are names of Chrome OS features. These are used for the
+  ChromeOS.FeatureUsage.* histograms to record different events related to the
+  feature -->
+
+  <variant name="Fingerprint" summary="fingerprint">
+    <owner>rsorokin@chromium.org</owner>
+    <owner>tomhughes@chromium.org</owner>
+    <owner>cros-oac@google.com</owner>
+    <owner>chromeos-fingerprint@google.com</owner>
+  </variant>
+</variants>
+
 <histogram name="ChromeOS.Apps.ExternalProtocolDialog"
     enum="ArcIntentHandlerAction" expires_after="2021-08-22">
   <owner>dominickn@chromium.org</owner>
@@ -470,6 +483,18 @@
   </summary>
 </histogram>
 
+<histogram name="ChromeOS.FeatureUsage.{FeatureName}" enum="FeatureUsageEvent"
+    expires_after="2022-01-01">
+  <owner>rsorokin@chromium.org</owner>
+  <owner>cros-oac@google.com</owner>
+  <summary>
+    Records device eligibility, enabled status, and success rate for the
+    {FeatureName} feature. Different events are recorded at different times, as
+    described in the enum labels.
+  </summary>
+  <token key="FeatureName" variants="FeaturesLoggingUsageEvents"/>
+</histogram>
+
 <histogram name="ChromeOS.GAIA.AuthenticatorContentWindowNull" enum="Boolean"
     expires_after="M85">
   <obsolete>
diff --git a/tools/metrics/histograms/histograms_xml/enterprise/histograms.xml b/tools/metrics/histograms/histograms_xml/enterprise/histograms.xml
index 00c27676..04ebe44 100644
--- a/tools/metrics/histograms/histograms_xml/enterprise/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/enterprise/histograms.xml
@@ -397,6 +397,9 @@
 
 <histogram base="true" name="Enterprise.DevicePolicyDeviceIdValidity"
     enum="EnterprisePolicyDeviceIdValidity" expires_after="M85">
+  <obsolete>
+    Removed in M91 since the data is no longer required.
+  </obsolete>
 <!-- Name completed by histogram_suffixes name="EnterpriseDevicePolicyDeviceIdValidity" -->
 
   <owner>emaxx@chromium.org</owner>
@@ -996,6 +999,9 @@
 
 <histogram name="Enterprise.HeartbeatSignalSuccess" enum="BooleanSuccess"
     expires_after="2020-08-01">
+  <obsolete>
+    Removed in M91 since the data is not monitored.
+  </obsolete>
   <owner>igorcov@chromium.org</owner>
   <owner>poromov@chromium.org</owner>
   <summary>
@@ -1167,6 +1173,9 @@
 
 <histogram name="Enterprise.PolicyHasVerifiedCachedKey"
     enum="BooleanValidKeyExists" expires_after="M77">
+  <obsolete>
+    Removed in M91 since the data is not monitored
+  </obsolete>
   <owner>atwilson@chromium.org</owner>
   <summary>
     Boolean tracking whether there is a valid policy signing key on disk.
@@ -1207,6 +1216,9 @@
 
 <histogram name="Enterprise.PolicyKeyVerification"
     enum="EnterprisePolicyKeyVerification" expires_after="M77">
+  <obsolete>
+    Removed in M91 since the data is not monitored
+  </obsolete>
   <owner>atwilson@chromium.org</owner>
   <summary>Tracking the results of policy key verification.</summary>
 </histogram>
diff --git a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
index 761aa33..36ce73a 100644
--- a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
+++ b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
@@ -4814,6 +4814,8 @@
   <suffix name="FromOtherApp" label="From another app."/>
   <suffix name="FromSharesheet" label="From sharesheet."/>
   <suffix name="FromShelf" label="From shelf."/>
+  <suffix name="FromSmartTextContextMenu"
+      label="From Smart text selection context menu."/>
   <affected-histogram name="Apps.DefaultAppLaunch"/>
 </histogram_suffixes>
 
@@ -5951,6 +5953,9 @@
 </histogram_suffixes>
 
 <histogram_suffixes name="EnterpriseDevicePolicyDeviceIdValidity" separator=".">
+  <obsolete>
+    Removed in M91 since the data is no longer required.
+  </obsolete>
   <suffix name="InitialStore"
       label="the initial device policy stored during enrollment"/>
   <suffix name="Update"
diff --git a/tools/metrics/histograms/histograms_xml/navigation/histograms.xml b/tools/metrics/histograms/histograms_xml/navigation/histograms.xml
index db48ec8e..e55e586cc 100644
--- a/tools/metrics/histograms/histograms_xml/navigation/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/navigation/histograms.xml
@@ -974,6 +974,17 @@
   </summary>
 </histogram>
 
+<histogram name="Navigation.RequestBeginMainFrameNotExpectedCrash"
+    enum="BooleanPresent" expires_after="2021-08-22">
+  <owner>rakina@chromium.org</owner>
+  <owner>dcheng@chromium.org</owner>
+  <summary>
+    Logs cases where ChromeClientImpl::RequestBeginMainFrameNotExpected() is
+    about to crash, which will trigger crbug.com/838348. This is used to trigger
+    traces to be uploaded to analyze what happened in these traces.
+  </summary>
+</histogram>
+
 <histogram name="Navigation.RequiresDedicatedProcess"
     enum="NavigationRequiresDedicatedProcess" expires_after="2021-12-21">
   <owner>alexmos@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/notifications/histograms.xml b/tools/metrics/histograms/histograms_xml/notifications/histograms.xml
index 60cf475..2085382a697 100644
--- a/tools/metrics/histograms/histograms_xml/notifications/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/notifications/histograms.xml
@@ -881,6 +881,9 @@
 
 <histogram name="Notifications.WebPlatform.{Action}.TimeToActivity" units="ms"
     expires_after="M96">
+  <obsolete>
+    From 2021-03 use Notifications.WebPlatform2 instead.
+  </obsolete>
   <owner>peconn@chromium.org</owner>
   <owner>peter@chromium.org</owner>
   <summary>
@@ -896,6 +899,9 @@
 
 <histogram name="Notifications.WebPlatform.{Action}.TimeToClose" units="ms"
     expires_after="M96">
+  <obsolete>
+    From 2021-03 use Notifications.WebPlatform2 instead.
+  </obsolete>
   <owner>peconn@chromium.org</owner>
   <owner>peter@chromium.org</owner>
   <summary>
@@ -909,6 +915,36 @@
   </token>
 </histogram>
 
+<histogram name="Notifications.WebPlatformV2.{Action}.TimeToActivity"
+    units="ms" expires_after="M96">
+  <owner>peconn@chromium.org</owner>
+  <owner>peter@chromium.org</owner>
+  <summary>
+    Records the delay between the user clicking on the {Action} of a web
+    platform notification, and an Activity being launched. Only records if the
+    duration is less than 10 seconds.
+  </summary>
+  <token key="Action">
+    <variant name="ActionButton" summary="action button"/>
+    <variant name="Body" summary="body"/>
+  </token>
+</histogram>
+
+<histogram name="Notifications.WebPlatformV2.{Action}.TimeToClose" units="ms"
+    expires_after="M96">
+  <owner>peconn@chromium.org</owner>
+  <owner>peter@chromium.org</owner>
+  <summary>
+    Records the delay between the user clicking on the {Action} of a web
+    platform notification, and the notification being closed. Only records if
+    the duration is less than 10 seconds.
+  </summary>
+  <token key="Action">
+    <variant name="ActionButton" summary="action button"/>
+    <variant name="Body" summary="body"/>
+  </token>
+</histogram>
+
 <histogram name="Notifications.Windows.ActivationStatus"
     enum="WindowsNotificationActivationStatus" expires_after="M94">
   <owner>finnur@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/others/histograms.xml b/tools/metrics/histograms/histograms_xml/others/histograms.xml
index 6b79928..c79bc846 100644
--- a/tools/metrics/histograms/histograms_xml/others/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/others/histograms.xml
@@ -17742,6 +17742,16 @@
   </summary>
 </histogram>
 
+<histogram name="Webapp.WebAppOriginAssociationFetchResult"
+    enum="WebAppOriginAssociationFetchResult" expires_after="2022-03-05">
+  <owner>mek@chromium.org</owner>
+  <owner>desktop-pwas-team@google.com</owner>
+  <summary>
+    Records the result of web app origin association file fetch when url
+    handlers are present. Happens when PWA is installed or updated.
+  </summary>
+</histogram>
+
 <histogram name="Webapp.WebAppUrlLoaderPrepareForLoadResult"
     enum="WebAppUrlLoaderResult" expires_after="2021-09-05">
   <owner>qjw@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/profile/histograms.xml b/tools/metrics/histograms/histograms_xml/profile/histograms.xml
index b9f34a2..9dec95c4 100644
--- a/tools/metrics/histograms/histograms_xml/profile/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/profile/histograms.xml
@@ -276,23 +276,26 @@
 </histogram>
 
 <histogram name="Profile.Incognito.Lifetime" units="minutes"
-    expires_after="2021-08-01">
+    expires_after="2022-02-02">
   <owner>rhalavati@chromium.org</owner>
-  <owner>chrome-privacy-core@google.com</owner>
+  <owner>chrome-incognito@google.com</owner>
   <summary>
     This histogram records the lifetime duration of incognito profiles. It is
     recorded once an off the record profile for an incognito session is closed.
+    From M91, this metric is not recorded for ChromeOS non user-triggered
+    Incognito profiles.
   </summary>
 </histogram>
 
 <histogram name="Profile.Incognito.MainFrameNavigationsPerSession"
-    units="navigations" expires_after="2021-08-01">
+    units="navigations" expires_after="2022-02-02">
   <owner>rhalavati@chromium.org</owner>
-  <owner>chrome-privacy-core@google.com</owner>
+  <owner>chrome-incognito@google.com</owner>
   <summary>
     This histogram records the number of mainframe navigations that have been
     done during one Incognito session. It is recorded once an off the record
-    profile for an incognito session is closed.
+    profile for an incognito session is closed. From M91, this metric is not
+    recorded for ChromeOS non user-triggered Incognito profiles.
   </summary>
 </histogram>
 
diff --git a/ui/android/java/src/org/chromium/ui/base/EventForwarder.java b/ui/android/java/src/org/chromium/ui/base/EventForwarder.java
index 5cf0319e..c536ac6d 100644
--- a/ui/android/java/src/org/chromium/ui/base/EventForwarder.java
+++ b/ui/android/java/src/org/chromium/ui/base/EventForwarder.java
@@ -20,6 +20,8 @@
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.annotations.NativeMethods;
+import org.chromium.base.compat.ApiHelperForM;
+import org.chromium.base.compat.ApiHelperForQ;
 
 /**
  * Class used to forward view, input events down to native.
@@ -145,7 +147,7 @@
 
             int gestureClassification = 0;
             if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
-                gestureClassification = event.getClassification();
+                gestureClassification = ApiHelperForQ.getClassification(event);
             }
 
             final boolean consumed = EventForwarderJni.get().onTouchEvent(mNativeEventForwarder,
@@ -314,7 +316,9 @@
 
     @TargetApi(Build.VERSION_CODES.M)
     public static int getMouseEventActionButton(MotionEvent event) {
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) return event.getActionButton();
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            return ApiHelperForM.getActionButton(event);
+        }
 
         // On <M, the only mice events sent are hover events, which cannot have a button.
         return 0;
diff --git a/ui/android/java/src/org/chromium/ui/display/PhysicalDisplayAndroid.java b/ui/android/java/src/org/chromium/ui/display/PhysicalDisplayAndroid.java
index 6f6f72c..b6ee8055 100644
--- a/ui/android/java/src/org/chromium/ui/display/PhysicalDisplayAndroid.java
+++ b/ui/android/java/src/org/chromium/ui/display/PhysicalDisplayAndroid.java
@@ -13,6 +13,7 @@
 
 import org.chromium.base.CommandLine;
 import org.chromium.base.Log;
+import org.chromium.base.compat.ApiHelperForM;
 import org.chromium.base.compat.ApiHelperForO;
 
 import java.util.Arrays;
@@ -153,8 +154,8 @@
         Display.Mode currentMode = null;
         List<Display.Mode> supportedModes = null;
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
-            currentMode = display.getMode();
-            supportedModes = Arrays.asList(display.getSupportedModes());
+            currentMode = ApiHelperForM.getDisplayMode(display);
+            supportedModes = Arrays.asList(ApiHelperForM.getDisplaySupportedModes(display));
             assert currentMode != null;
             assert supportedModes != null;
             assert supportedModes.size() > 0;
diff --git a/ui/android/java/src/org/chromium/ui/drawable/AnimationLooper.java b/ui/android/java/src/org/chromium/ui/drawable/AnimationLooper.java
index 9b40599..07b79a9 100644
--- a/ui/android/java/src/org/chromium/ui/drawable/AnimationLooper.java
+++ b/ui/android/java/src/org/chromium/ui/drawable/AnimationLooper.java
@@ -4,7 +4,6 @@
 
 package org.chromium.ui.drawable;
 
-import android.animation.ValueAnimator;
 import android.graphics.drawable.Animatable;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
@@ -17,6 +16,7 @@
 import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat;
 
 import org.chromium.base.ContextUtils;
+import org.chromium.base.compat.ApiHelperForO;
 
 /**
  * Encapsulates the logic to loop animated drawables from both Android Framework.
@@ -70,7 +70,7 @@
         if (sAreAnimatorsEnabledForTests != null) return sAreAnimatorsEnabledForTests;
 
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-            return ValueAnimator.areAnimatorsEnabled();
+            return ApiHelperForO.areAnimatorsEnabled();
         } else {
             return Settings.Global.getFloat(
                            ContextUtils.getApplicationContext().getContentResolver(),
diff --git a/ui/gfx/geometry/mojom/geometry.mojom b/ui/gfx/geometry/mojom/geometry.mojom
index 7ed95f6..30c1992 100644
--- a/ui/gfx/geometry/mojom/geometry.mojom
+++ b/ui/gfx/geometry/mojom/geometry.mojom
@@ -33,6 +33,7 @@
   float height;
 };
 
+[Stable]
 struct Rect {
   int32 x;
   int32 y;
diff --git a/ui/gfx/mojom/native_handle_types.mojom b/ui/gfx/mojom/native_handle_types.mojom
index f16015b..5b7be0a 100644
--- a/ui/gfx/mojom/native_handle_types.mojom
+++ b/ui/gfx/mojom/native_handle_types.mojom
@@ -8,7 +8,7 @@
 import "mojo/public/mojom/base/unguessable_token.mojom";
 
 // gfx::NativePixmapPlane
-[EnableIf=supports_native_pixmap]
+[EnableIf=supports_native_pixmap, Stable]
 struct NativePixmapPlane {
   uint32 stride;
   uint64 offset;
diff --git a/ui/message_center/views/padded_button.cc b/ui/message_center/views/padded_button.cc
index 0972f1c..531992e43 100644
--- a/ui/message_center/views/padded_button.cc
+++ b/ui/message_center/views/padded_button.cc
@@ -8,6 +8,7 @@
 
 #include "build/chromeos_buildflags.h"
 #include "ui/gfx/canvas.h"
+#include "ui/gfx/color_utils.h"
 #include "ui/message_center/public/cpp/message_center_constants.h"
 #include "ui/native_theme/native_theme.h"
 #include "ui/views/animation/ink_drop.h"
@@ -41,11 +42,14 @@
   ImageButton::OnThemeChanged();
   auto* theme = GetNativeTheme();
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  SetBackground(views::CreateSolidBackground(theme->GetSystemColor(
-      ui::NativeTheme::kColorId_NotificationButtonBackground)));
+  SkColor background_color = theme->GetSystemColor(
+      ui::NativeTheme::kColorId_NotificationButtonBackground);
+  SetBackground(views::CreateSolidBackground(background_color));
+#else
+  SkColor background_color =
+      theme->GetSystemColor(ui::NativeTheme::kColorId_WindowBackground);
 #endif
-  SetInkDropBaseColor(theme->GetSystemColor(
-      ui::NativeTheme::kColorId_PaddedButtonInkDropColor));
+  SetInkDropBaseColor(color_utils::GetColorWithMaxContrast(background_color));
 }
 
 BEGIN_METADATA(PaddedButton, views::ImageButton)
diff --git a/ui/native_theme/common_theme.cc b/ui/native_theme/common_theme.cc
index 9b1b01b..082e12f 100644
--- a/ui/native_theme/common_theme.cc
+++ b/ui/native_theme/common_theme.cc
@@ -180,10 +180,6 @@
     case NativeTheme::kColorId_ButtonUncheckedColor:
       return base_theme->GetUnprocessedSystemColor(
           NativeTheme::kColorId_LabelSecondaryColor, color_scheme);
-    case NativeTheme::kColorId_PaddedButtonInkDropColor:
-      return color_utils::GetColorWithMaxContrast(
-          base_theme->GetUnprocessedSystemColor(
-              NativeTheme::kColorId_WindowBackground, color_scheme));
     case NativeTheme::kColorId_ProminentButtonFocusedColor: {
       const SkColor bg = base_theme->GetUnprocessedSystemColor(
           NativeTheme::kColorId_ProminentButtonColor, color_scheme);
@@ -458,7 +454,9 @@
 
     // Throbber
     case NativeTheme::kColorId_ThrobberWaitingColor:
-      return SkColorSetRGB(0xA6, 0xA6, 0xA6);
+      return base_theme->GetUnprocessedSystemColor(
+          NativeTheme::kColorId_LabelTextSelectionBackgroundFocused,
+          color_scheme);
     case NativeTheme::kColorId_ThrobberSpinningColor:
       return base_theme->GetUnprocessedSystemColor(
           NativeTheme::kColorId_ProminentButtonColor, color_scheme);
diff --git a/ui/native_theme/native_theme_color_id.h b/ui/native_theme/native_theme_color_id.h
index da45543..efb0f865 100644
--- a/ui/native_theme/native_theme_color_id.h
+++ b/ui/native_theme/native_theme_color_id.h
@@ -36,7 +36,6 @@
   OP(kColorId_ProminentButtonDisabledColor),                                   \
   OP(kColorId_ProminentButtonFocusedColor),                                    \
   OP(kColorId_TextOnProminentButtonColor),                                     \
-  OP(kColorId_PaddedButtonInkDropColor),                                       \
   /* ToggleButton */                                                           \
   OP(kColorId_ToggleButtonShadowColor),                                        \
   OP(kColorId_ToggleButtonTrackColorOff),                                      \
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_config.html b/ui/webui/resources/cr_components/chromeos/network/network_config.html
index 839b46ce..519b1e21 100644
--- a/ui/webui/resources/cr_components/chromeos/network/network_config.html
+++ b/ui/webui/resources/cr_components/chromeos/network/network_config.html
@@ -58,6 +58,7 @@
       <!-- Passphrase (WiFi) -->
       <template is="dom-if" restamp if="[[configRequiresPassphrase_]]">
         <network-password-input id="wifi-passphrase"
+            on-keypress="onWifiPasswordInputKeypress_"
             label="[[i18n('OncWiFi-Passphrase')]]"
             value="{{configProperties_.typeConfig.wifi.passphrase}}"
             property="[[managedProperties_.typeProperties.wifi.passphrase]]">
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_config.js b/ui/webui/resources/cr_components/chromeos/network/network_config.js
index 0f09dc9..59dbbd4 100644
--- a/ui/webui/resources/cr_components/chromeos/network/network_config.js
+++ b/ui/webui/resources/cr_components/chromeos/network/network_config.js
@@ -1763,4 +1763,13 @@
     assertNotReached();
     return undefined;
   },
+
+  /** @private */
+  onWifiPasswordInputKeypress_() {
+    // bad-passphrase corresponds to kErrorBadPassphrase in shill
+    if (this.error === 'bad-passphrase') {
+      // Reset error if user starts typing new password.
+      this.setError_('');
+    }
+  }
 });
diff --git a/ui/webui/resources/cr_elements/cr_icon_button/cr_icon_button.html b/ui/webui/resources/cr_elements/cr_icon_button/cr_icon_button.html
index 026c48b..efb1d0d 100644
--- a/ui/webui/resources/cr_elements/cr_icon_button/cr_icon_button.html
+++ b/ui/webui/resources/cr_elements/cr_icon_button/cr_icon_button.html
@@ -45,7 +45,7 @@
 
       :host(:active) {
         background-color: var(--cr-icon-button-active-background-color,
-            var(--cr-focus-outline-color));
+            var(--cr-active-background-color));
       }
 
       :host([disabled]) {
diff --git a/url/url_util.cc b/url/url_util.cc
index bd00ed9..d2612417 100644
--- a/url/url_util.cc
+++ b/url/url_util.cc
@@ -469,10 +469,10 @@
   // the SchemeRegistry has been used.
   //
   // This normally means you're trying to set up a new scheme too late or using
-  // the SchemeRegistry too early in your application's init process. Make sure
-  // that you haven't added any static GURL initializers in tests.
+  // the SchemeRegistry too early in your application's init process.
   DCHECK(!g_scheme_registries_used.load())
-      << "Trying to add a scheme after the lists have been used.";
+      << "Trying to add a scheme after the lists have been used. "
+         "Make sure that you haven't added any static GURL initializers in tests.";
 
   // If this assert triggers, it means you've called Add*Scheme after
   // LockSchemeRegistries has been called (see the header file for