diff --git a/DEPS b/DEPS
index bb73731..cbad80f0 100644
--- a/DEPS
+++ b/DEPS
@@ -195,7 +195,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'ea70694da8b162acac5bedfa1e3239e3fac892fa',
+  'skia_revision': '3b08f35fd150a16440d8c9737a3fe4244217e3d6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -207,7 +207,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '3831ac2043e4670eeb51b1167093351e88dfe23c',
+  'angle_revision': 'fb03de53854802fabc7363c00e863922e7bdb393',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -266,7 +266,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': 'e163bc1825767ac17236915ad2b47d5150e339d5',
+  'devtools_frontend_revision': '69a10924bc979146d9e4482f0c3e893ff41050a5',
   # 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.
@@ -302,7 +302,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'spv_tools_revision': '5fd92a7e0c849229e042676d183cada18b006f01',
+  'spv_tools_revision': '7b2dd11dda7a44ecf0d3ef2a2e2205fba3f0f949',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -1248,7 +1248,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'e69d5b2de9433980adaa09301bae62b8d467b390',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '56f14dabfe991afdf09f35a56418657dbcb81791',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1465,7 +1465,7 @@
   },
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '7e30909bf44a224f7dbb49fc6bac6f2fdd4fd822',
+    Var('webrtc_git') + '/src.git' + '@' + '5184219b6ff46b8bdb432c9fe307ec762ec2119b',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1537,7 +1537,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@ff9cb9b4ed1baf703508c97f64946b3f112ee660',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@005aa46e0e2da51737b933782f7db4382bc96378',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/expectations/system_webview_bundle.AndroidManifest.expected b/android_webview/expectations/system_webview_bundle.AndroidManifest.expected
index a58488f4..95fc5bd8 100644
--- a/android_webview/expectations/system_webview_bundle.AndroidManifest.expected
+++ b/android_webview/expectations/system_webview_bundle.AndroidManifest.expected
@@ -12,18 +12,19 @@
   <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
   <uses-feature android:name="android.software.leanback" android:required="false"/>
   <uses-feature android:name="android.hardware.touchscreen" android:required="false"/>
-  <application  # DIFF-ANCHOR: d9433e23
+  <application
       android:extractNativeLibs="True"
       android:icon="@$PACKAGE:drawable/icon_webview"
       android:label="Android System WebView"
       android:multiArch="true"
       android:name="org.chromium.android_webview.nonembedded.WebViewApkApplication"
       android:use32bitAbi="true">
-    <activity  # DIFF-ANCHOR: 8488739d
+    <activity  # DIFF-ANCHOR: ea1a94af
         android:exported="false"
         android:name="com.google.android.gms.common.api.GoogleApiActivity"
-        android:theme="@android:style/Theme.Translucent.NoTitleBar"/>
-    <activity  # DIFF-ANCHOR: c5a36874
+        android:theme="@android:style/Theme.Translucent.NoTitleBar">
+    </activity>  # DIFF-ANCHOR: ea1a94af
+    <activity  # DIFF-ANCHOR: a4438884
         android:icon="@drawable/icon_webview"
         android:label="WebView DevTools"
         android:launchMode="singleTask"
@@ -33,388 +34,437 @@
         android:theme="@style/Theme.DevUi.DayNight"
         android:visibleToInstantApps="true"
         android:windowSoftInputMode="adjustPan">
-      <intent-filter>  # DIFF-ANCHOR: 76367aac
+      <intent-filter>  # DIFF-ANCHOR: b80aa336
         <action android:name="$PACKAGE.SHOW_DEV_UI"/>
         <category android:name="android.intent.category.DEFAULT"/>
-      </intent-filter>  # DIFF-ANCHOR: 76367aac
-    </activity>  # DIFF-ANCHOR: c5a36874
-    <activity  # DIFF-ANCHOR: a003fb0a
+      </intent-filter>  # DIFF-ANCHOR: b80aa336
+    </activity>  # DIFF-ANCHOR: a4438884
+    <activity  # DIFF-ANCHOR: aeabab17
         android:label="@string/license_activity_title"
         android:name="org.chromium.android_webview.nonembedded.LicenseActivity"
         android:process=":webview_apk">
-      <intent-filter>  # DIFF-ANCHOR: 7071b59d
+      <intent-filter>  # DIFF-ANCHOR: 23298d3b
         <action android:name="android.settings.WEBVIEW_LICENSE"/>
         <category android:name="android.intent.category.DEFAULT"/>
-      </intent-filter>  # DIFF-ANCHOR: 7071b59d
+      </intent-filter>  # DIFF-ANCHOR: 23298d3b
       <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED" android:value="true"/>
-    </activity>  # DIFF-ANCHOR: a003fb0a
-    <activity-alias  # DIFF-ANCHOR: 6c354539
+    </activity>  # DIFF-ANCHOR: aeabab17
+    <activity-alias  # DIFF-ANCHOR: b7cc06e9
         android:enabled="false"
         android:name="org.chromium.android_webview.devui.DeveloperModeState"
         android:process=":webview_apk"
         android:targetActivity="org.chromium.android_webview.devui.MainActivity"
-        android:visibleToInstantApps="true"/>
+        android:visibleToInstantApps="true">
+    </activity-alias>  # DIFF-ANCHOR: b7cc06e9
     <meta-data android:name="$PACKAGE.WebViewLibrary" android:value="libwebviewchromium.so"/>
     <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version"/>
     <meta-data android:name="org.chromium.content.browser.NUM_PRIVILEGED_SERVICES" android:value="0"/>
     <meta-data android:name="org.chromium.content.browser.NUM_SANDBOXED_SERVICES" android:value="40"/>
-    <provider  # DIFF-ANCHOR: 25126d98
+    <provider  # DIFF-ANCHOR: bfe37944
         android:authorities="$PACKAGE.DeveloperModeContentProvider"
         android:exported="true"
         android:name="org.chromium.android_webview.services.DeveloperModeContentProvider"
         android:process=":webview_service"
-        android:visibleToInstantApps="true"/>
-    <provider  # DIFF-ANCHOR: 71947426
+        android:visibleToInstantApps="true">
+    </provider>  # DIFF-ANCHOR: bfe37944
+    <provider  # DIFF-ANCHOR: a5e78e63
         android:authorities="$PACKAGE.LicenseContentProvider"
         android:exported="true"
         android:name="org.chromium.android_webview.nonembedded.LicenseContentProvider"
-        android:process=":webview_apk"/>
-    <service  # DIFF-ANCHOR: 60aeec85
+        android:process=":webview_apk">
+    </provider>  # DIFF-ANCHOR: a5e78e63
+    <service  # DIFF-ANCHOR: 65cddb26
         android:exported="false"
         android:name="org.chromium.android_webview.services.AwVariationsSeedFetcher"
         android:permission="android.permission.BIND_JOB_SERVICE"
-        android:process=":webview_service"/>
-    <service  # DIFF-ANCHOR: 72b33f0f
+        android:process=":webview_service">
+    </service>  # DIFF-ANCHOR: 65cddb26
+    <service  # DIFF-ANCHOR: adce9ea1
         android:exported="false"
         android:name="org.chromium.android_webview.services.DeveloperUiService"
-        android:process=":webview_service"/>
-    <service  # DIFF-ANCHOR: 4eb5ab8c
+        android:process=":webview_service">
+    </service>  # DIFF-ANCHOR: adce9ea1
+    <service  # DIFF-ANCHOR: 3cd6d713
         android:exported="true"
         android:name="org.chromium.android_webview.services.AwMinidumpUploadJobService"
         android:permission="android.permission.BIND_JOB_SERVICE"
-        android:process=":webview_service"/>
-    <service  # DIFF-ANCHOR: 7968f7fd
+        android:process=":webview_service">
+    </service>  # DIFF-ANCHOR: 3cd6d713
+    <service  # DIFF-ANCHOR: 5cda9608
         android:exported="true"
         android:name="org.chromium.android_webview.services.CrashReceiverService"
-        android:process=":webview_service"/>
-    <service  # DIFF-ANCHOR: 4e4e6b4
+        android:process=":webview_service">
+    </service>  # DIFF-ANCHOR: 5cda9608
+    <service  # DIFF-ANCHOR: eecf2fee
         android:exported="true"
         android:name="org.chromium.android_webview.services.MetricsBridgeService"
         android:process=":webview_service"
-        android:visibleToInstantApps="true"/>
-    <service  # DIFF-ANCHOR: 55d21b90
+        android:visibleToInstantApps="true">
+    </service>  # DIFF-ANCHOR: eecf2fee
+    <service  # DIFF-ANCHOR: dc926e35
         android:exported="true"
         android:name="org.chromium.android_webview.services.VariationsSeedServer"
-        android:process=":webview_service"/>
-    <service  # DIFF-ANCHOR: 1324609f
+        android:process=":webview_service">
+    </service>  # DIFF-ANCHOR: dc926e35
+    <service  # DIFF-ANCHOR: b1e3e8bd
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService0"
         android:process=":sandboxed_process0"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 1f3ac9d9
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: b1e3e8bd
+    <service  # DIFF-ANCHOR: 76d1ccf8
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService1"
         android:process=":sandboxed_process1"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 530592d1
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 76d1ccf8
+    <service  # DIFF-ANCHOR: 38b95266
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService10"
         android:process=":sandboxed_process10"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 28125eb3
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 38b95266
+    <service  # DIFF-ANCHOR: e4a2e4a2
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService11"
         android:process=":sandboxed_process11"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 5a5339c5
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: e4a2e4a2
+    <service  # DIFF-ANCHOR: d9b2ffba
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService12"
         android:process=":sandboxed_process12"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 69b3c593
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: d9b2ffba
+    <service  # DIFF-ANCHOR: b41bb17d
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService13"
         android:process=":sandboxed_process13"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 98ecbda1
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: b41bb17d
+    <service  # DIFF-ANCHOR: aec0ea21
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService14"
         android:process=":sandboxed_process14"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 4e8c7ee3
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: aec0ea21
+    <service  # DIFF-ANCHOR: cf88a5e5
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService15"
         android:process=":sandboxed_process15"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 1b290ccd
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: cf88a5e5
+    <service  # DIFF-ANCHOR: 7d85889d
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService16"
         android:process=":sandboxed_process16"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 2f60cbe3
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 7d85889d
+    <service  # DIFF-ANCHOR: dae26ed4
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService17"
         android:process=":sandboxed_process17"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: a8a4dc41
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: dae26ed4
+    <service  # DIFF-ANCHOR: 2c6cf029
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService18"
         android:process=":sandboxed_process18"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: e1747923
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 2c6cf029
+    <service  # DIFF-ANCHOR: 1d2f0988
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService19"
         android:process=":sandboxed_process19"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: da26a34b
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 1d2f0988
+    <service  # DIFF-ANCHOR: 4a39041b
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService2"
         android:process=":sandboxed_process2"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 46aced3
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 4a39041b
+    <service  # DIFF-ANCHOR: 073533bf
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService20"
         android:process=":sandboxed_process20"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 81b12211
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 073533bf
+    <service  # DIFF-ANCHOR: d24da41d
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService21"
         android:process=":sandboxed_process21"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 514bacf3
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: d24da41d
+    <service  # DIFF-ANCHOR: 594d8b32
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService22"
         android:process=":sandboxed_process22"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 582624d5
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 594d8b32
+    <service  # DIFF-ANCHOR: 5528c0c3
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService23"
         android:process=":sandboxed_process23"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 580b883
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 5528c0c3
+    <service  # DIFF-ANCHOR: b7ab2ba3
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService24"
         android:process=":sandboxed_process24"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 43aea9c1
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: b7ab2ba3
+    <service  # DIFF-ANCHOR: cec6cb64
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService25"
         android:process=":sandboxed_process25"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 2d9f04a3
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: cec6cb64
+    <service  # DIFF-ANCHOR: 5b4a00fe
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService26"
         android:process=":sandboxed_process26"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 43d9360d
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 5b4a00fe
+    <service  # DIFF-ANCHOR: ad49d203
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService27"
         android:process=":sandboxed_process27"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: a1246283
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: ad49d203
+    <service  # DIFF-ANCHOR: 573298e9
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService28"
         android:process=":sandboxed_process28"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 172c9b01
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 573298e9
+    <service  # DIFF-ANCHOR: 79897b32
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService29"
         android:process=":sandboxed_process29"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: a63cbab1
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 79897b32
+    <service  # DIFF-ANCHOR: 84335864
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService3"
         android:process=":sandboxed_process3"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: b79d985
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 84335864
+    <service  # DIFF-ANCHOR: c4bd371e
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService30"
         android:process=":sandboxed_process30"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 8b0e224b
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: c4bd371e
+    <service  # DIFF-ANCHOR: 394a9fd0
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService31"
         android:process=":sandboxed_process31"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 5ccb4759
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 394a9fd0
+    <service  # DIFF-ANCHOR: b811afb8
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService32"
         android:process=":sandboxed_process32"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 8784437b
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: b811afb8
+    <service  # DIFF-ANCHOR: 2811ddd3
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService33"
         android:process=":sandboxed_process33"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 6b4b480d
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 2811ddd3
+    <service  # DIFF-ANCHOR: 73ae1688
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService34"
         android:process=":sandboxed_process34"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 4964406b
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 73ae1688
+    <service  # DIFF-ANCHOR: c476f324
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService35"
         android:process=":sandboxed_process35"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 7204b619
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: c476f324
+    <service  # DIFF-ANCHOR: 75d5304b
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService36"
         android:process=":sandboxed_process36"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 8e7e4dbb
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 75d5304b
+    <service  # DIFF-ANCHOR: dc6d0617
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService37"
         android:process=":sandboxed_process37"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: dff1dd95
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: dc6d0617
+    <service  # DIFF-ANCHOR: e31efe49
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService38"
         android:process=":sandboxed_process38"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: fcc5211b
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: e31efe49
+    <service  # DIFF-ANCHOR: 5736507e
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService39"
         android:process=":sandboxed_process39"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: dcb0777
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 5736507e
+    <service  # DIFF-ANCHOR: a161be24
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService4"
         android:process=":sandboxed_process4"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: ee03da19
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: a161be24
+    <service  # DIFF-ANCHOR: 8e591688
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService5"
         android:process=":sandboxed_process5"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: b081112b
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 8e591688
+    <service  # DIFF-ANCHOR: 705141d0
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService6"
         android:process=":sandboxed_process6"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 58f16331
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 705141d0
+    <service  # DIFF-ANCHOR: 38ed2189
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService7"
         android:process=":sandboxed_process7"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 305efabf
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 38ed2189
+    <service  # DIFF-ANCHOR: aa417956
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService8"
         android:process=":sandboxed_process8"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: ee4db6a9
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: aa417956
+    <service  # DIFF-ANCHOR: e2f3bbbd
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService9"
         android:process=":sandboxed_process9"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-  </application>  # DIFF-ANCHOR: d9433e23
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: e2f3bbbd
+  </application>
 </manifest>
diff --git a/android_webview/expectations/trichrome_webview_bundle.AndroidManifest.expected b/android_webview/expectations/trichrome_webview_bundle.AndroidManifest.expected
index 7887fd1..cb90773a 100644
--- a/android_webview/expectations/trichrome_webview_bundle.AndroidManifest.expected
+++ b/android_webview/expectations/trichrome_webview_bundle.AndroidManifest.expected
@@ -12,18 +12,19 @@
   <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
   <uses-feature android:name="android.software.leanback" android:required="false"/>
   <uses-feature android:name="android.hardware.touchscreen" android:required="false"/>
-  <application  # DIFF-ANCHOR: 9f4fb3d2
+  <application
       android:extractNativeLibs="False"
       android:icon="@$PACKAGE:drawable/icon_webview"
       android:label="Android System WebView"
       android:multiArch="true"
       android:name="org.chromium.android_webview.nonembedded.WebViewApkApplication"
       android:use32bitAbi="true">
-    <activity  # DIFF-ANCHOR: 8488739d
+    <activity  # DIFF-ANCHOR: ea1a94af
         android:exported="false"
         android:name="com.google.android.gms.common.api.GoogleApiActivity"
-        android:theme="@android:style/Theme.Translucent.NoTitleBar"/>
-    <activity  # DIFF-ANCHOR: c5a36874
+        android:theme="@android:style/Theme.Translucent.NoTitleBar">
+    </activity>  # DIFF-ANCHOR: ea1a94af
+    <activity  # DIFF-ANCHOR: a4438884
         android:icon="@drawable/icon_webview"
         android:label="WebView DevTools"
         android:launchMode="singleTask"
@@ -33,389 +34,438 @@
         android:theme="@style/Theme.DevUi.DayNight"
         android:visibleToInstantApps="true"
         android:windowSoftInputMode="adjustPan">
-      <intent-filter>  # DIFF-ANCHOR: 76367aac
+      <intent-filter>  # DIFF-ANCHOR: b80aa336
         <action android:name="$PACKAGE.SHOW_DEV_UI"/>
         <category android:name="android.intent.category.DEFAULT"/>
-      </intent-filter>  # DIFF-ANCHOR: 76367aac
-    </activity>  # DIFF-ANCHOR: c5a36874
-    <activity  # DIFF-ANCHOR: a003fb0a
+      </intent-filter>  # DIFF-ANCHOR: b80aa336
+    </activity>  # DIFF-ANCHOR: a4438884
+    <activity  # DIFF-ANCHOR: aeabab17
         android:label="@string/license_activity_title"
         android:name="org.chromium.android_webview.nonembedded.LicenseActivity"
         android:process=":webview_apk">
-      <intent-filter>  # DIFF-ANCHOR: 7071b59d
+      <intent-filter>  # DIFF-ANCHOR: 23298d3b
         <action android:name="android.settings.WEBVIEW_LICENSE"/>
         <category android:name="android.intent.category.DEFAULT"/>
-      </intent-filter>  # DIFF-ANCHOR: 7071b59d
+      </intent-filter>  # DIFF-ANCHOR: 23298d3b
       <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED" android:value="true"/>
-    </activity>  # DIFF-ANCHOR: a003fb0a
-    <activity-alias  # DIFF-ANCHOR: 6c354539
+    </activity>  # DIFF-ANCHOR: aeabab17
+    <activity-alias  # DIFF-ANCHOR: b7cc06e9
         android:enabled="false"
         android:name="org.chromium.android_webview.devui.DeveloperModeState"
         android:process=":webview_apk"
         android:targetActivity="org.chromium.android_webview.devui.MainActivity"
-        android:visibleToInstantApps="true"/>
+        android:visibleToInstantApps="true">
+    </activity-alias>  # DIFF-ANCHOR: b7cc06e9
     <meta-data android:name="$PACKAGE.WebViewLibrary" android:value="libmonochrome.so"/>
     <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version"/>
     <meta-data android:name="org.chromium.content.browser.NUM_PRIVILEGED_SERVICES" android:value="0"/>
     <meta-data android:name="org.chromium.content.browser.NUM_SANDBOXED_SERVICES" android:value="40"/>
-    <provider  # DIFF-ANCHOR: 25126d98
+    <provider  # DIFF-ANCHOR: bfe37944
         android:authorities="$PACKAGE.DeveloperModeContentProvider"
         android:exported="true"
         android:name="org.chromium.android_webview.services.DeveloperModeContentProvider"
         android:process=":webview_service"
-        android:visibleToInstantApps="true"/>
-    <provider  # DIFF-ANCHOR: 71947426
+        android:visibleToInstantApps="true">
+    </provider>  # DIFF-ANCHOR: bfe37944
+    <provider  # DIFF-ANCHOR: a5e78e63
         android:authorities="$PACKAGE.LicenseContentProvider"
         android:exported="true"
         android:name="org.chromium.android_webview.nonembedded.LicenseContentProvider"
-        android:process=":webview_apk"/>
-    <service  # DIFF-ANCHOR: 60aeec85
+        android:process=":webview_apk">
+    </provider>  # DIFF-ANCHOR: a5e78e63
+    <service  # DIFF-ANCHOR: 65cddb26
         android:exported="false"
         android:name="org.chromium.android_webview.services.AwVariationsSeedFetcher"
         android:permission="android.permission.BIND_JOB_SERVICE"
-        android:process=":webview_service"/>
-    <service  # DIFF-ANCHOR: 72b33f0f
+        android:process=":webview_service">
+    </service>  # DIFF-ANCHOR: 65cddb26
+    <service  # DIFF-ANCHOR: adce9ea1
         android:exported="false"
         android:name="org.chromium.android_webview.services.DeveloperUiService"
-        android:process=":webview_service"/>
-    <service  # DIFF-ANCHOR: 4eb5ab8c
+        android:process=":webview_service">
+    </service>  # DIFF-ANCHOR: adce9ea1
+    <service  # DIFF-ANCHOR: 3cd6d713
         android:exported="true"
         android:name="org.chromium.android_webview.services.AwMinidumpUploadJobService"
         android:permission="android.permission.BIND_JOB_SERVICE"
-        android:process=":webview_service"/>
-    <service  # DIFF-ANCHOR: 7968f7fd
+        android:process=":webview_service">
+    </service>  # DIFF-ANCHOR: 3cd6d713
+    <service  # DIFF-ANCHOR: 5cda9608
         android:exported="true"
         android:name="org.chromium.android_webview.services.CrashReceiverService"
-        android:process=":webview_service"/>
-    <service  # DIFF-ANCHOR: 4e4e6b4
+        android:process=":webview_service">
+    </service>  # DIFF-ANCHOR: 5cda9608
+    <service  # DIFF-ANCHOR: eecf2fee
         android:exported="true"
         android:name="org.chromium.android_webview.services.MetricsBridgeService"
         android:process=":webview_service"
-        android:visibleToInstantApps="true"/>
-    <service  # DIFF-ANCHOR: 55d21b90
+        android:visibleToInstantApps="true">
+    </service>  # DIFF-ANCHOR: eecf2fee
+    <service  # DIFF-ANCHOR: dc926e35
         android:exported="true"
         android:name="org.chromium.android_webview.services.VariationsSeedServer"
-        android:process=":webview_service"/>
-    <service  # DIFF-ANCHOR: 1324609f
+        android:process=":webview_service">
+    </service>  # DIFF-ANCHOR: dc926e35
+    <service  # DIFF-ANCHOR: b1e3e8bd
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService0"
         android:process=":sandboxed_process0"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 1f3ac9d9
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: b1e3e8bd
+    <service  # DIFF-ANCHOR: 76d1ccf8
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService1"
         android:process=":sandboxed_process1"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 530592d1
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 76d1ccf8
+    <service  # DIFF-ANCHOR: 38b95266
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService10"
         android:process=":sandboxed_process10"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 28125eb3
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 38b95266
+    <service  # DIFF-ANCHOR: e4a2e4a2
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService11"
         android:process=":sandboxed_process11"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 5a5339c5
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: e4a2e4a2
+    <service  # DIFF-ANCHOR: d9b2ffba
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService12"
         android:process=":sandboxed_process12"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 69b3c593
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: d9b2ffba
+    <service  # DIFF-ANCHOR: b41bb17d
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService13"
         android:process=":sandboxed_process13"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 98ecbda1
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: b41bb17d
+    <service  # DIFF-ANCHOR: aec0ea21
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService14"
         android:process=":sandboxed_process14"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 4e8c7ee3
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: aec0ea21
+    <service  # DIFF-ANCHOR: cf88a5e5
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService15"
         android:process=":sandboxed_process15"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 1b290ccd
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: cf88a5e5
+    <service  # DIFF-ANCHOR: 7d85889d
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService16"
         android:process=":sandboxed_process16"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 2f60cbe3
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 7d85889d
+    <service  # DIFF-ANCHOR: dae26ed4
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService17"
         android:process=":sandboxed_process17"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: a8a4dc41
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: dae26ed4
+    <service  # DIFF-ANCHOR: 2c6cf029
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService18"
         android:process=":sandboxed_process18"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: e1747923
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 2c6cf029
+    <service  # DIFF-ANCHOR: 1d2f0988
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService19"
         android:process=":sandboxed_process19"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: da26a34b
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 1d2f0988
+    <service  # DIFF-ANCHOR: 4a39041b
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService2"
         android:process=":sandboxed_process2"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 46aced3
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 4a39041b
+    <service  # DIFF-ANCHOR: 073533bf
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService20"
         android:process=":sandboxed_process20"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 81b12211
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 073533bf
+    <service  # DIFF-ANCHOR: d24da41d
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService21"
         android:process=":sandboxed_process21"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 514bacf3
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: d24da41d
+    <service  # DIFF-ANCHOR: 594d8b32
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService22"
         android:process=":sandboxed_process22"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 582624d5
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 594d8b32
+    <service  # DIFF-ANCHOR: 5528c0c3
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService23"
         android:process=":sandboxed_process23"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 580b883
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 5528c0c3
+    <service  # DIFF-ANCHOR: b7ab2ba3
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService24"
         android:process=":sandboxed_process24"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 43aea9c1
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: b7ab2ba3
+    <service  # DIFF-ANCHOR: cec6cb64
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService25"
         android:process=":sandboxed_process25"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 2d9f04a3
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: cec6cb64
+    <service  # DIFF-ANCHOR: 5b4a00fe
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService26"
         android:process=":sandboxed_process26"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 43d9360d
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 5b4a00fe
+    <service  # DIFF-ANCHOR: ad49d203
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService27"
         android:process=":sandboxed_process27"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: a1246283
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: ad49d203
+    <service  # DIFF-ANCHOR: 573298e9
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService28"
         android:process=":sandboxed_process28"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 172c9b01
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 573298e9
+    <service  # DIFF-ANCHOR: 79897b32
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService29"
         android:process=":sandboxed_process29"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: a63cbab1
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 79897b32
+    <service  # DIFF-ANCHOR: 84335864
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService3"
         android:process=":sandboxed_process3"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: b79d985
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 84335864
+    <service  # DIFF-ANCHOR: c4bd371e
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService30"
         android:process=":sandboxed_process30"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 8b0e224b
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: c4bd371e
+    <service  # DIFF-ANCHOR: 394a9fd0
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService31"
         android:process=":sandboxed_process31"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 5ccb4759
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 394a9fd0
+    <service  # DIFF-ANCHOR: b811afb8
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService32"
         android:process=":sandboxed_process32"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 8784437b
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: b811afb8
+    <service  # DIFF-ANCHOR: 2811ddd3
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService33"
         android:process=":sandboxed_process33"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 6b4b480d
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 2811ddd3
+    <service  # DIFF-ANCHOR: 73ae1688
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService34"
         android:process=":sandboxed_process34"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 4964406b
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 73ae1688
+    <service  # DIFF-ANCHOR: c476f324
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService35"
         android:process=":sandboxed_process35"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 7204b619
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: c476f324
+    <service  # DIFF-ANCHOR: 75d5304b
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService36"
         android:process=":sandboxed_process36"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 8e7e4dbb
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 75d5304b
+    <service  # DIFF-ANCHOR: dc6d0617
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService37"
         android:process=":sandboxed_process37"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: dff1dd95
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: dc6d0617
+    <service  # DIFF-ANCHOR: e31efe49
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService38"
         android:process=":sandboxed_process38"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: fcc5211b
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: e31efe49
+    <service  # DIFF-ANCHOR: 5736507e
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService39"
         android:process=":sandboxed_process39"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: dcb0777
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 5736507e
+    <service  # DIFF-ANCHOR: a161be24
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService4"
         android:process=":sandboxed_process4"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: ee03da19
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: a161be24
+    <service  # DIFF-ANCHOR: 8e591688
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService5"
         android:process=":sandboxed_process5"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: b081112b
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 8e591688
+    <service  # DIFF-ANCHOR: 705141d0
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService6"
         android:process=":sandboxed_process6"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 58f16331
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 705141d0
+    <service  # DIFF-ANCHOR: 38ed2189
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService7"
         android:process=":sandboxed_process7"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 305efabf
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 38ed2189
+    <service  # DIFF-ANCHOR: aa417956
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService8"
         android:process=":sandboxed_process8"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: ee4db6a9
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: aa417956
+    <service  # DIFF-ANCHOR: e2f3bbbd
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService9"
         android:process=":sandboxed_process9"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: e2f3bbbd
     <uses-static-library android:certDigest="32a2fc74d731105859e5a85df16d95f102d85b22099b8064c5d8915c61dad1e0" android:name="org.chromium.trichromelibrary" android:version="$VERSION_NUMBER"/>
-  </application>  # DIFF-ANCHOR: 9f4fb3d2
+  </application>
 </manifest>
diff --git a/base/cpu_affinity_posix_unittest.cc b/base/cpu_affinity_posix_unittest.cc
index 4f934cb..406ccae8 100644
--- a/base/cpu_affinity_posix_unittest.cc
+++ b/base/cpu_affinity_posix_unittest.cc
@@ -73,14 +73,14 @@
 }  // namespace
 
 #if defined(OS_ANDROID)
-#define MAYBE_SetThreadCpuAffinityMode SetThreadCpuAffinityMode
+// Flaky on Android. crbug.com/1113964
+#define MAYBE_SetThreadCpuAffinityMode DISABLED_SetThreadCpuAffinityMode
 #else
 // The test only considers Android device hardware models at the moment. Some
 // CrOS devices on the waterfall have asymmetric CPUs that aren't covered. The
 // linux-trusty-rel bot also fails to sched_setaffinity().
 #define MAYBE_SetThreadCpuAffinityMode DISABLED_SetThreadCpuAffinityMode
 #endif
-
 TEST(CpuAffinityTest, MAYBE_SetThreadCpuAffinityMode) {
   // This test currently only supports Nexus 5x and Pixel devices as big.LITTLE
   // devices. For other devices, we assume that the cores are symmetric. This is
diff --git a/base/util/memory_pressure/system_memory_pressure_evaluator.cc b/base/util/memory_pressure/system_memory_pressure_evaluator.cc
index 3c748b8..7a84598 100644
--- a/base/util/memory_pressure/system_memory_pressure_evaluator.cc
+++ b/base/util/memory_pressure/system_memory_pressure_evaluator.cc
@@ -4,6 +4,7 @@
 
 #include "base/util/memory_pressure/system_memory_pressure_evaluator.h"
 
+#include "base/feature_list.h"
 #include "build/build_config.h"
 
 #if defined(OS_CHROMEOS)
@@ -16,10 +17,16 @@
 #include "base/util/memory_pressure/system_memory_pressure_evaluator_mac.h"
 #elif defined(OS_WIN)
 #include "base/util/memory_pressure/system_memory_pressure_evaluator_win.h"
+#include "base/win/windows_version.h"
 #endif
 
 namespace util {
 
+#if defined(OS_WIN)
+constexpr base::Feature kUseWinOSMemoryPressureSignals{
+    "UseWinOSMemoryPressureSignals", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+
 // static
 std::unique_ptr<SystemMemoryPressureEvaluator>
 SystemMemoryPressureEvaluator::CreateDefaultSystemEvaluator(
@@ -40,8 +47,15 @@
   return std::make_unique<util::mac::SystemMemoryPressureEvaluator>(
       monitor->CreateVoter());
 #elif defined(OS_WIN)
-  return std::make_unique<util::win::SystemMemoryPressureEvaluator>(
+  auto evaluator = std::make_unique<util::win::SystemMemoryPressureEvaluator>(
       monitor->CreateVoter());
+  // Also subscribe to the OS signals if they're available and the feature is
+  // enabled.
+  if (base::FeatureList::IsEnabled(kUseWinOSMemoryPressureSignals) &&
+      base::win::GetVersion() >= base::win::Version::WIN8_1) {
+    evaluator->CreateOSSignalPressureEvaluator(monitor->CreateVoter());
+  }
+  return evaluator;
 #endif
   return nullptr;
 }
diff --git a/base/util/memory_pressure/system_memory_pressure_evaluator_win.cc b/base/util/memory_pressure/system_memory_pressure_evaluator_win.cc
index 4aa36ac..ae22b971 100644
--- a/base/util/memory_pressure/system_memory_pressure_evaluator_win.cc
+++ b/base/util/memory_pressure/system_memory_pressure_evaluator_win.cc
@@ -5,12 +5,14 @@
 #include "base/util/memory_pressure/system_memory_pressure_evaluator_win.h"
 
 #include <windows.h>
+#include <memory>
 
 #include "base/bind.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/time/time.h"
 #include "base/util/memory_pressure/multi_source_memory_pressure_monitor.h"
+#include "base/win/object_watcher.h"
 
 namespace util {
 namespace win {
@@ -19,6 +21,58 @@
 
 static const DWORDLONG kMBBytes = 1024 * 1024;
 
+// Implements ObjectWatcher::Delegate by forwarding to a provided callback.
+class MemoryPressureWatcherDelegate
+    : public base::win::ObjectWatcher::Delegate {
+ public:
+  MemoryPressureWatcherDelegate(base::win::ScopedHandle handle,
+                                base::OnceClosure callback);
+  ~MemoryPressureWatcherDelegate() override;
+  MemoryPressureWatcherDelegate(const MemoryPressureWatcherDelegate& other) =
+      delete;
+  MemoryPressureWatcherDelegate& operator=(
+      const MemoryPressureWatcherDelegate&) = delete;
+
+  void ReplaceWatchedHandleForTesting(base::win::ScopedHandle handle);
+  void SetCallbackForTesting(base::OnceClosure callback) {
+    callback_ = std::move(callback);
+  }
+
+ private:
+  void OnObjectSignaled(HANDLE handle) override;
+
+  base::win::ScopedHandle handle_;
+  base::win::ObjectWatcher watcher_;
+  base::OnceClosure callback_;
+};
+
+MemoryPressureWatcherDelegate::MemoryPressureWatcherDelegate(
+    base::win::ScopedHandle handle,
+    base::OnceClosure callback)
+    : handle_(std::move(handle)), callback_(std::move(callback)) {
+  DCHECK(handle_.IsValid());
+  CHECK(watcher_.StartWatchingOnce(handle_.Get(), this));
+}
+
+MemoryPressureWatcherDelegate::~MemoryPressureWatcherDelegate() {
+  if (watcher_.IsWatching())
+    watcher_.StopWatching();
+  handle_.Close();
+}
+
+void MemoryPressureWatcherDelegate::ReplaceWatchedHandleForTesting(
+    base::win::ScopedHandle handle) {
+  if (watcher_.IsWatching())
+    watcher_.StopWatching();
+  handle_.Close();
+  handle_ = std::move(handle);
+  CHECK(watcher_.StartWatchingOnce(handle_.Get(), this));
+}
+
+void MemoryPressureWatcherDelegate::OnObjectSignaled(HANDLE object) {
+  std::move(callback_).Run();
+}
+
 }  // namespace
 
 // The following constants have been lifted from similar values in the ChromeOS
@@ -53,6 +107,54 @@
 const int
     SystemMemoryPressureEvaluator::kLargeMemoryDefaultCriticalThresholdMb = 400;
 
+// A memory pressure evaluator that receives memory pressure notifications from
+// the OS and forwards them to the memory pressure monitor.
+class SystemMemoryPressureEvaluator::OSSignalsMemoryPressureEvaluator {
+ public:
+  using MemoryPressureLevel = base::MemoryPressureListener::MemoryPressureLevel;
+
+  explicit OSSignalsMemoryPressureEvaluator(
+      std::unique_ptr<MemoryPressureVoter> voter);
+  ~OSSignalsMemoryPressureEvaluator();
+  OSSignalsMemoryPressureEvaluator(
+      const OSSignalsMemoryPressureEvaluator& other) = delete;
+  OSSignalsMemoryPressureEvaluator& operator=(
+      const OSSignalsMemoryPressureEvaluator&) = delete;
+
+  // Creates the watcher used to receive the low and high memory notifications.
+  void Start();
+
+  MemoryPressureWatcherDelegate* GetWatcherForTesting() const {
+    return memory_notification_watcher_.get();
+  }
+  void WaitForHighMemoryNotificationForTesting(base::OnceClosure closure);
+
+ private:
+  // Called when receiving a low/high memory notification.
+  void OnLowMemoryNotification();
+  void OnHighMemoryNotification();
+
+  void StartLowMemoryNotificationWatcher();
+  void StartHighMemoryNotificationWatcher();
+
+  // The period of the critical pressure notification timer.
+  static constexpr base::TimeDelta kHighPressureNotificationInterval =
+      base::TimeDelta::FromSeconds(2);
+
+  // The voter used to cast the votes.
+  std::unique_ptr<MemoryPressureVoter> voter_;
+
+  // The memory notification watcher.
+  std::unique_ptr<MemoryPressureWatcherDelegate> memory_notification_watcher_;
+
+  // Timer that will re-emit the critical memory pressure signal until the
+  // memory gets high again.
+  base::RepeatingTimer critical_pressure_notification_timer_;
+
+  // Ensures that this object is used from a single sequence.
+  SEQUENCE_CHECKER(sequence_checker_);
+};
+
 SystemMemoryPressureEvaluator::SystemMemoryPressureEvaluator(
     std::unique_ptr<MemoryPressureVoter> voter)
     : util::SystemMemoryPressureEvaluator(std::move(voter)),
@@ -88,6 +190,25 @@
                           weak_ptr_factory_.GetWeakPtr()));
 }
 
+void SystemMemoryPressureEvaluator::CreateOSSignalPressureEvaluator(
+    std::unique_ptr<MemoryPressureVoter> voter) {
+  os_signals_evaluator_ =
+      std::make_unique<OSSignalsMemoryPressureEvaluator>(std::move(voter));
+  os_signals_evaluator_->Start();
+}
+
+void SystemMemoryPressureEvaluator::ReplaceWatchedHandleForTesting(
+    base::win::ScopedHandle handle) {
+  os_signals_evaluator_->GetWatcherForTesting()->ReplaceWatchedHandleForTesting(
+      std::move(handle));
+}
+
+void SystemMemoryPressureEvaluator::WaitForHighMemoryNotificationForTesting(
+    base::OnceClosure closure) {
+  os_signals_evaluator_->WaitForHighMemoryNotificationForTesting(
+      std::move(closure));
+}
+
 void SystemMemoryPressureEvaluator::InferThresholds() {
   // Default to a 'high' memory situation, which uses more conservative
   // thresholds.
@@ -199,12 +320,102 @@
 
 bool SystemMemoryPressureEvaluator::GetSystemMemoryStatus(
     MEMORYSTATUSEX* mem_status) {
-  DCHECK(mem_status != nullptr);
+  DCHECK(mem_status);
   mem_status->dwLength = sizeof(*mem_status);
   if (!::GlobalMemoryStatusEx(mem_status))
     return false;
   return true;
 }
 
+SystemMemoryPressureEvaluator::OSSignalsMemoryPressureEvaluator::
+    OSSignalsMemoryPressureEvaluator(std::unique_ptr<MemoryPressureVoter> voter)
+    : voter_(std::move(voter)) {}
+
+SystemMemoryPressureEvaluator::OSSignalsMemoryPressureEvaluator::
+    ~OSSignalsMemoryPressureEvaluator() = default;
+
+void SystemMemoryPressureEvaluator::OSSignalsMemoryPressureEvaluator::Start() {
+  // Start by observing the low memory notifications. If the system is already
+  // under pressure this will run the |OnLowMemoryNotification| callback and
+  // automatically switch to waiting for the high memory notification/
+  StartLowMemoryNotificationWatcher();
+}
+
+void SystemMemoryPressureEvaluator::OSSignalsMemoryPressureEvaluator::
+    OnLowMemoryNotification() {
+  // TODO(sebmarchand): Emit some histogram that compares the level detected by
+  // the default evaluator to this one.
+  voter_->SetVote(base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+                  /* notify = */ true);
+
+  // Start a timer to repeat the notification at regular interval until
+  // OnHighMemoryNotification gets called.
+  critical_pressure_notification_timer_.Start(
+      FROM_HERE, kHighPressureNotificationInterval,
+      base::BindRepeating(
+          &MemoryPressureVoter::SetVote, base::Unretained(voter_.get()),
+          base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+          /* notify = */ true));
+
+  // Start the high memory notification watcher to be notified when the system
+  // exits memory pressure.
+  StartHighMemoryNotificationWatcher();
+}
+
+void SystemMemoryPressureEvaluator::OSSignalsMemoryPressureEvaluator::
+    OnHighMemoryNotification() {
+  critical_pressure_notification_timer_.Stop();
+  voter_->SetVote(base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+                  /* notify = */ false);
+
+  // Start the low memory notification watcher to be notified the next time the
+  // system hits memory pressure.
+  StartLowMemoryNotificationWatcher();
+}
+
+void SystemMemoryPressureEvaluator::OSSignalsMemoryPressureEvaluator::
+    StartLowMemoryNotificationWatcher() {
+  DCHECK(base::SequencedTaskRunnerHandle::IsSet());
+  memory_notification_watcher_ =
+      std::make_unique<MemoryPressureWatcherDelegate>(
+          base::win::ScopedHandle(::CreateMemoryResourceNotification(
+              ::LowMemoryResourceNotification)),
+          base::BindOnce(
+              &SystemMemoryPressureEvaluator::OSSignalsMemoryPressureEvaluator::
+                  OnLowMemoryNotification,
+              base::Unretained(this)));
+}
+
+void SystemMemoryPressureEvaluator::OSSignalsMemoryPressureEvaluator::
+    StartHighMemoryNotificationWatcher() {
+  memory_notification_watcher_ =
+      std::make_unique<MemoryPressureWatcherDelegate>(
+          base::win::ScopedHandle(::CreateMemoryResourceNotification(
+              ::HighMemoryResourceNotification)),
+          base::BindOnce(
+              &SystemMemoryPressureEvaluator::OSSignalsMemoryPressureEvaluator::
+                  OnHighMemoryNotification,
+              base::Unretained(this)));
+}
+
+void SystemMemoryPressureEvaluator::OSSignalsMemoryPressureEvaluator::
+    WaitForHighMemoryNotificationForTesting(base::OnceClosure closure) {
+  // If the timer isn't running then it means that the high memory notification
+  // has already been received.
+  if (!critical_pressure_notification_timer_.IsRunning()) {
+    std::move(closure).Run();
+    return;
+  }
+
+  memory_notification_watcher_->SetCallbackForTesting(base::BindOnce(
+      [](SystemMemoryPressureEvaluator::OSSignalsMemoryPressureEvaluator*
+             evaluator,
+         base::OnceClosure closure) {
+        evaluator->OnHighMemoryNotification();
+        std::move(closure).Run();
+      },
+      base::Unretained(this), std::move(closure)));
+}
+
 }  // namespace win
 }  // namespace util
diff --git a/base/util/memory_pressure/system_memory_pressure_evaluator_win.h b/base/util/memory_pressure/system_memory_pressure_evaluator_win.h
index 877d87a..a079225 100644
--- a/base/util/memory_pressure/system_memory_pressure_evaluator_win.h
+++ b/base/util/memory_pressure/system_memory_pressure_evaluator_win.h
@@ -6,13 +6,16 @@
 #define BASE_UTIL_MEMORY_PRESSURE_SYSTEM_MEMORY_PRESSURE_EVALUATOR_WIN_H_
 
 #include "base/base_export.h"
+#include "base/callback_forward.h"
 #include "base/macros.h"
 #include "base/memory/memory_pressure_listener.h"
 #include "base/memory/weak_ptr.h"
 #include "base/sequence_checker.h"
+#include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "base/util/memory_pressure/memory_pressure_voter.h"
 #include "base/util/memory_pressure/system_memory_pressure_evaluator.h"
+#include "base/win/scoped_handle.h"
 
 // To not pull in windows.h.
 typedef struct _MEMORYSTATUSEX MEMORYSTATUSEX;
@@ -20,8 +23,8 @@
 namespace util {
 namespace win {
 
-// Windows memory pressure voter. Because there is no OS provided signal this
-// polls at a low frequency, and applies internal hysteresis.
+// Windows memory pressure voter that checks the amount of RAM left at a low
+// frequency and applies internal hysteresis.
 class SystemMemoryPressureEvaluator
     : public util::SystemMemoryPressureEvaluator {
  public:
@@ -68,6 +71,26 @@
   // Returns the critical pressure level free memory threshold, in MB.
   int critical_threshold_mb() const { return critical_threshold_mb_; }
 
+  // Create a nested evaluator that will use the signals provided by the OS to
+  // detect memory pressure. This evaluator will take ownership of |voter| and
+  // use it to cast its vote to the monitor.
+  //
+  // This evaluator will subscribe to the OS signals via a call to
+  // CreateMemoryResourceNotification and will use the following mapping:
+  //   - MEMORY_PRESSURE_LEVEL_CRITICAL: LowMemoryResourceNotification.
+  //   - MEMORY_PRESSURE_LEVEL_MODERATE: Not measured by this evaluator.
+  //   - MEMORY_PRESSURE_LEVEL_NONE: HighMemoryResourceNotification.
+  //
+  // MEMORY_PRESSURE_LEVEL_CRITICAL signals will be emitted as soon as the low
+  // memory notification is received and at regular interval until receiving a
+  // HighMemoryResourceNotification.
+  void CreateOSSignalPressureEvaluator(
+      std::unique_ptr<MemoryPressureVoter> voter);
+
+  // Testing seams for the OSSignalPressureEvaluator.
+  void ReplaceWatchedHandleForTesting(base::win::ScopedHandle handle);
+  void WaitForHighMemoryNotificationForTesting(base::OnceClosure closure);
+
  protected:
   // Internals are exposed for unittests.
 
@@ -102,6 +125,8 @@
   virtual bool GetSystemMemoryStatus(MEMORYSTATUSEX* mem_status);
 
  private:
+  class OSSignalsMemoryPressureEvaluator;
+
   // Threshold amounts of available memory that trigger pressure levels. See
   // memory_pressure_monitor.cc for a discussion of reasonable values for these.
   int moderate_threshold_mb_;
@@ -116,6 +141,10 @@
   // |CalculateCurrentPressureLevel|.
   int moderate_pressure_repeat_count_;
 
+  // Optional companion evaluator that will receive the OS memory pressure
+  // notifications, created by |CreateOSSignalPressureEvaluator|.
+  std::unique_ptr<OSSignalsMemoryPressureEvaluator> os_signals_evaluator_;
+
   // Ensures that this object is used from a single sequence.
   SEQUENCE_CHECKER(sequence_checker_);
 
diff --git a/base/util/memory_pressure/system_memory_pressure_evaluator_win_unittest.cc b/base/util/memory_pressure/system_memory_pressure_evaluator_win_unittest.cc
index 4fc55913..683acd3 100644
--- a/base/util/memory_pressure/system_memory_pressure_evaluator_win_unittest.cc
+++ b/base/util/memory_pressure/system_memory_pressure_evaluator_win_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
+#include "base/test/bind_test_util.h"
 #include "base/test/task_environment.h"
 #include "base/util/memory_pressure/multi_source_memory_pressure_monitor.h"
 #include "build/build_config.h"
@@ -318,5 +319,75 @@
   testing::Mock::VerifyAndClearExpectations(&evaluator);
 }
 
+TEST_F(WinSystemMemoryPressureEvaluatorTest, OSSignalsMemoryPressureEvaluator) {
+  MultiSourceMemoryPressureMonitor monitor;
+  monitor.ResetSystemEvaluatorForTesting();
+  testing::StrictMock<TestSystemMemoryPressureEvaluator> evaluator(
+      true, monitor.CreateVoter());
+  evaluator.CreateOSSignalPressureEvaluator(monitor.CreateVoter());
+
+  // Mock function used to ensure that the proper memory pressure signals are
+  // emitted.
+  testing::MockFunction<void(base::MemoryPressureListener::MemoryPressureLevel)>
+      mock_listener_function;
+  base::MemoryPressureListener listener(
+      FROM_HERE,
+      base::BindLambdaForTesting(
+          [&](base::MemoryPressureListener::MemoryPressureLevel level) {
+            mock_listener_function.Call(level);
+          }));
+
+  {
+    base::RunLoop run_loop;
+    auto quit_closure = run_loop.QuitClosure();
+    EXPECT_CALL(
+        mock_listener_function,
+        Call(base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL))
+        .WillOnce(::testing::Invoke([&]() { std::move(quit_closure).Run(); }));
+    // A manual-reset event that is not yet signaled.
+    base::win::ScopedHandle event_low_memory(
+        CreateEvent(nullptr, TRUE, FALSE, nullptr));
+    auto* handle = event_low_memory.Get();
+    // Replace the handle watched by the evaluator to be able to simulate a low
+    // pressure OS notification.
+    evaluator.ReplaceWatchedHandleForTesting(std::move(event_low_memory));
+    ::SetEvent(handle);
+    run_loop.Run();
+    testing::Mock::VerifyAndClearExpectations(&mock_listener_function);
+
+    // |event_low_memory| will be automatically closed by the pressure
+    // evaluator, no need to call CloseEvent on it.
+  }
+
+  {
+    base::RunLoop run_loop;
+    // The evaluator will automatically start watching for a high memory
+    // notification after receiving the previous low memory notification, wait
+    // for it to arrive.
+    evaluator.WaitForHighMemoryNotificationForTesting(run_loop.QuitClosure());
+    run_loop.Run();
+    // There should be no MEMORY_PRESSURE_LEVEL_NONE notification emitted.
+    testing::Mock::VerifyAndClearExpectations(&mock_listener_function);
+  }
+
+  // Do another low memory notification test to make sure that the evaluator
+  // can detect several critical pressure sessions.
+  {
+    base::RunLoop run_loop;
+    auto quit_closure = run_loop.QuitClosure();
+    EXPECT_CALL(
+        mock_listener_function,
+        Call(base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL))
+        .WillOnce(::testing::Invoke([&]() { std::move(quit_closure).Run(); }));
+    base::win::ScopedHandle event_low_memory(
+        CreateEvent(nullptr, TRUE, FALSE, nullptr));
+    auto* handle = event_low_memory.Get();
+    evaluator.ReplaceWatchedHandleForTesting(std::move(event_low_memory));
+    ::SetEvent(handle);
+    run_loop.Run();
+    testing::Mock::VerifyAndClearExpectations(&mock_listener_function);
+  }
+}
+
 }  // namespace win
 }  // namespace util
diff --git a/build/android/PRESUBMIT.py b/build/android/PRESUBMIT.py
index 5fd845d..19571ee 100644
--- a/build/android/PRESUBMIT.py
+++ b/build/android/PRESUBMIT.py
@@ -75,6 +75,7 @@
               J('.', 'emma_coverage_stats_test.py'),
               J('.', 'list_class_verification_failures_test.py'),
               J('gyp', 'util', 'build_utils_test.py'),
+              J('gyp', 'util', 'manifest_utils_test.py'),
               J('gyp', 'util', 'md5_check_test.py'),
               J('gyp', 'util', 'resource_utils_test.py'),
               J('pylib', 'constants', 'host_paths_unittest.py'),
diff --git a/build/android/gyp/compile_resources.py b/build/android/gyp/compile_resources.py
index ae3daba..fe64ca9 100755
--- a/build/android/gyp/compile_resources.py
+++ b/build/android/gyp/compile_resources.py
@@ -992,7 +992,8 @@
 def _CreateNormalizedManifest(options):
   with build_utils.TempDir() as tempdir:
     fixed_manifest, _ = _FixManifest(options, tempdir)
-    return manifest_utils.NormalizeManifest(fixed_manifest)
+    with open(fixed_manifest) as f:
+      return manifest_utils.NormalizeManifest(f.read())
 
 
 def _OnStaleMd5(options):
diff --git a/build/android/gyp/util/diff_utils.py b/build/android/gyp/util/diff_utils.py
index 6ac1aca1..674de31b 100755
--- a/build/android/gyp/util/diff_utils.py
+++ b/build/android/gyp/util/diff_utils.py
@@ -92,7 +92,7 @@
 
   fail_msg = """
 Expectations need updating:
-https://chromium.googlesource.com/chromium/src/+/HEAD/chrome/android/expecations/README.md
+https://chromium.googlesource.com/chromium/src/+/HEAD/chrome/android/expectations/README.md
 
 LogDog tip: Use "Raw log" or "Switch to lite mode" before copying:
 https://bugs.chromium.org/p/chromium/issues/detail?id=984616
diff --git a/build/android/gyp/util/manifest_utils.py b/build/android/gyp/util/manifest_utils.py
index c52a5f95b0..b6fb498 100644
--- a/build/android/gyp/util/manifest_utils.py
+++ b/build/android/gyp/util/manifest_utils.py
@@ -4,6 +4,7 @@
 
 """Contains common helpers for working with Android manifests."""
 
+import hashlib
 import os
 import shlex
 import xml.dom.minidom as minidom
@@ -151,7 +152,7 @@
 
 
 def _CreateNodeHash(lines):
-  """Computes a hash for the first XML node found in |lines|.
+  """Computes a hash (md5) for the first XML node found in |lines|.
 
   Args:
     lines: List of strings containing pretty-printed XML.
@@ -160,12 +161,23 @@
     Positive 32-bit integer hash of the node (including children).
   """
   target_indent = lines[0].find('<')
+  tag_closed = False
   for i, l in enumerate(lines[1:]):
     cur_indent = l.find('<')
     if cur_indent != -1 and cur_indent <= target_indent:
       tag_lines = lines[:i + 1]
-      return hash(tuple(tag_lines)) % 0x100000000  # Make 32-bit non-negative.
-  assert False, 'Did not find end of node:\n' + '\n'.join(lines)
+      break
+    elif not tag_closed and 'android:name="' in l:
+      # To reduce noise of node tags changing, use android:name as the
+      # basis the hash since they usually unique.
+      tag_lines = [l]
+      break
+    tag_closed = tag_closed or '>' in l
+  else:
+    assert False, 'Did not find end of node:\n' + '\n'.join(lines)
+
+  # Insecure and truncated hash as it only needs to be unique vs. its neighbors.
+  return hashlib.md5('\n'.join(tag_lines)).hexdigest()[:8]
 
 
 def _IsSelfClosing(lines):
@@ -190,23 +202,32 @@
   hash_stack = []
   for i, l in enumerate(lines):
     stripped = l.lstrip()
-    # If it's an indented tag that is not self-closing (unless wrapped):
-    if l[0] == ' ' and stripped[0] == '<' and l[-2:] != '/>':
-      if stripped[1] != '/':
-        cur_hash = _CreateNodeHash(lines[i:])
-        if not _IsSelfClosing(lines[i:]):
-          hash_stack.append(cur_hash)
-      else:
-        cur_hash = hash_stack.pop()
-      lines[i] += '  # DIFF-ANCHOR: {:x}'.format(cur_hash)
+    # Ignore non-indented tags and lines that are not the start/end of a node.
+    if l[0] != ' ' or stripped[0] != '<':
+      continue
+    # Ignore self-closing nodes that fit on one line.
+    if l[-2:] == '/>':
+      continue
+    # Ignore <application> since diff tag changes with basically any change.
+    if stripped.lstrip('</').startswith('application'):
+      continue
+
+    # Check for the closing tag (</foo>).
+    if stripped[1] != '/':
+      cur_hash = _CreateNodeHash(lines[i:])
+      if not _IsSelfClosing(lines[i:]):
+        hash_stack.append(cur_hash)
+    else:
+      cur_hash = hash_stack.pop()
+    lines[i] += '  # DIFF-ANCHOR: {}'.format(cur_hash)
   assert not hash_stack, 'hash_stack was not empty:\n' + '\n'.join(hash_stack)
 
 
-def NormalizeManifest(path):
-  with open(path) as f:
-    # This also strips comments and sorts node attributes alphabetically.
-    root = ElementTree.fromstring(f.read())
-    package = GetPackage(root)
+def NormalizeManifest(manifest_contents):
+  _RegisterElementTreeNamespaces()
+  # This also strips comments and sorts node attributes alphabetically.
+  root = ElementTree.fromstring(manifest_contents)
+  package = GetPackage(root)
 
   # Trichrome's static library version number is updated daily. To avoid
   # frequent manifest check failures, we remove the exact version number
@@ -242,16 +263,23 @@
   dom = minidom.parseString(ElementTree.tostring(root))
   out_lines = []
   for l in dom.toprettyxml(indent='  ').splitlines():
-    if l.strip():
-      if len(l) > _WRAP_LINE_LENGTH and any(x in l for x in _WRAP_CANDIDATES):
-        indent = ' ' * l.find('<')
-        start_tag, attrs, end_tag = _SplitElement(l)
-        out_lines.append('{}{}'.format(indent, start_tag))
-        for attribute in attrs:
-          out_lines.append('{}    {}'.format(indent, attribute))
-        out_lines[-1] += end_tag
-      else:
-        out_lines.append(l)
+    if not l or l.isspace():
+      continue
+    if len(l) > _WRAP_LINE_LENGTH and any(x in l for x in _WRAP_CANDIDATES):
+      indent = ' ' * l.find('<')
+      start_tag, attrs, end_tag = _SplitElement(l)
+      out_lines.append('{}{}'.format(indent, start_tag))
+      for attribute in attrs:
+        out_lines.append('{}    {}'.format(indent, attribute))
+      out_lines[-1] += '>'
+      # Heuristic: Do not allow multi-line tags to be self-closing since these
+      # can generally be allowed to have nested elements. When diffing, it adds
+      # noise if the base file is self-closing and the non-base file is not
+      # self-closing.
+      if end_tag == '/>':
+        out_lines.append('{}{}>'.format(indent, start_tag.replace('<', '</')))
+    else:
+      out_lines.append(l)
 
   # Make output more diff-friendly.
   _AddDiffTags(out_lines)
diff --git a/build/android/gyp/util/manifest_utils_test.py b/build/android/gyp/util/manifest_utils_test.py
new file mode 100755
index 0000000..78c2172
--- /dev/null
+++ b/build/android/gyp/util/manifest_utils_test.py
@@ -0,0 +1,128 @@
+#!/usr/bin/env python
+# 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.
+
+import collections
+import os
+import sys
+import unittest
+
+sys.path.insert(1, os.path.join(os.path.dirname(__file__), '..'))
+from util import manifest_utils
+
+_TEST_MANIFEST = """\
+<?xml version="1.0" ?>
+<manifest package="test.pkg"
+    tools:ignore="MissingVersion"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools">
+  <!-- Should be one line. -->
+  <uses-sdk android:minSdkVersion="24"
+      android:targetSdkVersion="30"/>
+  <!-- Should have attrs sorted-->
+  <uses-feature android:required="false" android:version="1"
+    android:name="android.hardware.vr.headtracking" />
+  <!-- Should not be wrapped since < 100 chars. -->
+  <application
+      android:name="testname">
+    <activity
+        {extra_activity_attr}
+        android:icon="@drawable/ic_devices_48dp"
+        android:label="label with spaces"
+        android:name="to be hashed"
+        android:theme="@style/Theme.Chromium.Activity.TranslucentNoAnimations">
+      <intent-filter>
+        {extra_intent_filter_elem}
+        <action android:name="android.intent.action.SEND"/>
+        <category android:name="android.intent.category.DEFAULT"/>
+        <data android:mimeType="text/plain"/>
+      </intent-filter>
+    </activity>
+    <!-- Should be made non-self-closing. -->
+    <receiver android:exported="false" android:name="\
+org.chromium.chrome.browser.announcement.AnnouncementNotificationManager$Rcvr"/>
+  </application>
+</manifest>
+"""
+
+_TEST_MANIFEST_NORMALIZED = """\
+<?xml version="1.0" ?>
+<manifest
+    package="test.pkg"
+    tools:ignore="MissingVersion"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools">
+  <uses-sdk android:minSdkVersion="24" android:targetSdkVersion="30"/>
+  <uses-feature android:name="android.hardware.vr.headtracking" \
+android:required="false" android:version="1"/>
+  <application android:name="testname">
+    <activity  # DIFF-ANCHOR: {activity_diff_anchor}
+        {extra_activity_attr}android:icon="@drawable/ic_devices_48dp"
+        android:label="label with spaces"
+        android:name="to be hashed"
+        android:theme="@style/Theme.Chromium.Activity.TranslucentNoAnimations">
+      <intent-filter>  # DIFF-ANCHOR: {intent_filter_diff_anchor}
+        {extra_intent_filter_elem}\
+<action android:name="android.intent.action.SEND"/>
+        <category android:name="android.intent.category.DEFAULT"/>
+        <data android:mimeType="text/plain"/>
+      </intent-filter>  # DIFF-ANCHOR: {intent_filter_diff_anchor}
+    </activity>  # DIFF-ANCHOR: {activity_diff_anchor}
+    <receiver  # DIFF-ANCHOR: 355000d2
+        android:exported="false"
+        android:name=\
+"org.chromium.chrome.browser.announcement.AnnouncementNotificationManager$Rcvr">
+    </receiver>  # DIFF-ANCHOR: 355000d2
+  </application>
+</manifest>
+"""
+
+_ACTIVITY_DIFF_ANCHOR = '32b3a641'
+_INTENT_FILTER_DIFF_ANCHOR = '4ee601b7'
+
+
+def _CreateTestData(intent_filter_diff_anchor=_INTENT_FILTER_DIFF_ANCHOR,
+                    extra_activity_attr='',
+                    extra_intent_filter_elem=''):
+  if extra_activity_attr:
+    extra_activity_attr += '\n        '
+  if extra_intent_filter_elem:
+    extra_intent_filter_elem += '\n        '
+  test_manifest = _TEST_MANIFEST.format(
+      extra_activity_attr=extra_activity_attr,
+      extra_intent_filter_elem=extra_intent_filter_elem)
+  expected = _TEST_MANIFEST_NORMALIZED.format(
+      activity_diff_anchor=_ACTIVITY_DIFF_ANCHOR,
+      intent_filter_diff_anchor=intent_filter_diff_anchor,
+      extra_activity_attr=extra_activity_attr,
+      extra_intent_filter_elem=extra_intent_filter_elem)
+  return test_manifest, expected
+
+
+class ManifestUtilsTest(unittest.TestCase):
+  # Enable diff output.
+  maxDiff = None
+
+  def testNormalizeManifest_golden(self):
+    test_manifest, expected = _CreateTestData()
+    actual = manifest_utils.NormalizeManifest(test_manifest)
+    self.assertMultiLineEqual(expected, actual)
+
+  def testNormalizeManifest_nameUsedForActivity(self):
+    test_manifest, expected = _CreateTestData(extra_activity_attr='a="b"')
+    actual = manifest_utils.NormalizeManifest(test_manifest)
+    # Checks that the DIFF-ANCHOR does not change with the added attribute.
+    self.assertMultiLineEqual(expected, actual)
+
+  def testNormalizeManifest_nameNotUsedForIntentFilter(self):
+    test_manifest, expected = _CreateTestData(
+        extra_intent_filter_elem='<a/>', intent_filter_diff_anchor='5f5c8a70')
+    actual = manifest_utils.NormalizeManifest(test_manifest)
+    # Checks that the DIFF-ANCHOR does change with the added element despite
+    # having a nested element with an android:name set.
+    self.assertMultiLineEqual(expected, actual)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/chrome/android/expectations/monochrome_public_bundle.AndroidManifest.expected b/chrome/android/expectations/monochrome_public_bundle.AndroidManifest.expected
index fad50474..8e5197f 100644
--- a/chrome/android/expectations/monochrome_public_bundle.AndroidManifest.expected
+++ b/chrome/android/expectations/monochrome_public_bundle.AndroidManifest.expected
@@ -61,7 +61,7 @@
   <permission android:name="$PACKAGE.permission.C2D_MESSAGE" android:protectionLevel="signature"/>
   <permission android:name="$PACKAGE.TOS_ACKED" android:protectionLevel="signatureOrSystem"/>
   <permission android:label="Debug web pages" android:name="$PACKAGE.permission.DEBUG" android:permissionGroup="android.permission-group.DEVELOPMENT_TOOLS" android:protectionLevel="signature"/>
-  <application  # DIFF-ANCHOR: c9a6872
+  <application
       android:allowBackup="false"
       android:extractNativeLibs="false"
       android:icon="@drawable/ic_launcher"
@@ -75,7 +75,7 @@
       android:supportsRtl="true"
       android:use32bitAbi="true"
       android:zygotePreloadName="org.chromium.content.app.ZygotePreload">
-    <activity  # DIFF-ANCHOR: ee659b1a
+    <activity  # DIFF-ANCHOR: 2121eb0d
         android:autoRemoveFromRecents="true"
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:excludeFromRecents="true"
@@ -83,8 +83,9 @@
         android:launchMode="singleInstance"
         android:name="org.chromium.chrome.browser.firstrun.FirstRunActivity"
         android:theme="@style/Theme.Chromium.DialogWhenLarge"
-        android:windowSoftInputMode="stateHidden|adjustPan"/>
-    <activity  # DIFF-ANCHOR: 4f86360c
+        android:windowSoftInputMode="stateHidden|adjustPan">
+    </activity>  # DIFF-ANCHOR: 2121eb0d
+    <activity  # DIFF-ANCHOR: 67932092
         android:autoRemoveFromRecents="true"
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:excludeFromRecents="true"
@@ -92,8 +93,9 @@
         android:launchMode="singleInstance"
         android:name="org.chromium.chrome.browser.firstrun.LightweightFirstRunActivity"
         android:theme="@style/Theme.Chromium.AlertDialog.NoActionBar"
-        android:windowSoftInputMode="stateHidden|adjustPan"/>
-    <activity  # DIFF-ANCHOR: a707c56a
+        android:windowSoftInputMode="stateHidden|adjustPan">
+    </activity>  # DIFF-ANCHOR: 67932092
+    <activity  # DIFF-ANCHOR: bb612a34
         android:autoRemoveFromRecents="true"
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:excludeFromRecents="true"
@@ -101,12 +103,14 @@
         android:launchMode="singleInstance"
         android:name="org.chromium.chrome.browser.firstrun.TabbedModeFirstRunActivity"
         android:theme="@style/Theme.Chromium.TabbedMode"
-        android:windowSoftInputMode="stateHidden|adjustPan"/>
-    <activity  # DIFF-ANCHOR: be0a95a0
+        android:windowSoftInputMode="stateHidden|adjustPan">
+    </activity>  # DIFF-ANCHOR: bb612a34
+    <activity  # DIFF-ANCHOR: 8492e3fd
         android:autoRemoveFromRecents="true"
         android:name="org.chromium.chrome.browser.sync.ui.PassphraseActivity"
-        android:theme="@style/Theme.Chromium.Activity"/>
-    <activity  # DIFF-ANCHOR: 78e0b102
+        android:theme="@style/Theme.Chromium.Activity">
+    </activity>  # DIFF-ANCHOR: 8492e3fd
+    <activity  # DIFF-ANCHOR: 7468a722
         android:clearTaskOnLaunch="true"
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:excludeFromRecents="true"
@@ -117,15 +121,17 @@
         android:name="org.chromium.chrome.browser.searchwidget.SearchActivity"
         android:taskAffinity=""
         android:theme="@style/Theme.Chromium.SearchActivity"
-        android:windowSoftInputMode="adjustResize"/>
-    <activity  # DIFF-ANCHOR: cfaf0e7a
+        android:windowSoftInputMode="adjustResize">
+    </activity>  # DIFF-ANCHOR: 7468a722
+    <activity  # DIFF-ANCHOR: 28dc9019
         android:configChanges="keyboardHidden|orientation|screenSize"
         android:excludeFromRecents="true"
         android:exported="false"
         android:launchMode="singleTop"
         android:name="com.google.ar.core.InstallActivity"
-        android:theme="@android:style/Theme.Material.Light.Dialog.Alert"/>
-    <activity  # DIFF-ANCHOR: 37132267
+        android:theme="@android:style/Theme.Material.Light.Dialog.Alert">
+    </activity>  # DIFF-ANCHOR: 28dc9019
+    <activity  # DIFF-ANCHOR: 44158f9b
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:enabled="false"
         android:excludeFromRecents="true"
@@ -135,13 +141,13 @@
         android:name="org.chromium.chrome.browser.sharing.shared_clipboard.SharedClipboardShareActivity"
         android:noHistory="true"
         android:theme="@style/Theme.Chromium.Activity.TranslucentNoAnimations">
-      <intent-filter>  # DIFF-ANCHOR: 5860c6b5
+      <intent-filter>  # DIFF-ANCHOR: 4ee601b7
         <action android:name="android.intent.action.SEND"/>
         <category android:name="android.intent.category.DEFAULT"/>
         <data android:mimeType="text/plain"/>
-      </intent-filter>  # DIFF-ANCHOR: 5860c6b5
-    </activity>  # DIFF-ANCHOR: 37132267
-    <activity  # DIFF-ANCHOR: 334ee6dc
+      </intent-filter>  # DIFF-ANCHOR: 4ee601b7
+    </activity>  # DIFF-ANCHOR: 44158f9b
+    <activity  # DIFF-ANCHOR: dc9ccfb7
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:enabled="false"
         android:excludeFromRecents="true"
@@ -151,13 +157,13 @@
         android:name="org.chromium.chrome.browser.share.qrcode.QrCodeShareActivity"
         android:noHistory="true"
         android:theme="@android:style/Theme.NoDisplay">
-      <intent-filter>  # DIFF-ANCHOR: 5860c6b5
+      <intent-filter>  # DIFF-ANCHOR: 4ee601b7
         <action android:name="android.intent.action.SEND"/>
         <category android:name="android.intent.category.DEFAULT"/>
         <data android:mimeType="text/plain"/>
-      </intent-filter>  # DIFF-ANCHOR: 5860c6b5
-    </activity>  # DIFF-ANCHOR: 334ee6dc
-    <activity  # DIFF-ANCHOR: 8e3d60cc
+      </intent-filter>  # DIFF-ANCHOR: 4ee601b7
+    </activity>  # DIFF-ANCHOR: dc9ccfb7
+    <activity  # DIFF-ANCHOR: f1aedff1
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:enabled="false"
         android:excludeFromRecents="true"
@@ -167,13 +173,13 @@
         android:name="org.chromium.chrome.browser.send_tab_to_self.SendTabToSelfShareActivity"
         android:noHistory="true"
         android:theme="@android:style/Theme.NoDisplay">
-      <intent-filter>  # DIFF-ANCHOR: 5860c6b5
+      <intent-filter>  # DIFF-ANCHOR: 4ee601b7
         <action android:name="android.intent.action.SEND"/>
         <category android:name="android.intent.category.DEFAULT"/>
         <data android:mimeType="text/plain"/>
-      </intent-filter>  # DIFF-ANCHOR: 5860c6b5
-    </activity>  # DIFF-ANCHOR: 8e3d60cc
-    <activity  # DIFF-ANCHOR: 5715816d
+      </intent-filter>  # DIFF-ANCHOR: 4ee601b7
+    </activity>  # DIFF-ANCHOR: f1aedff1
+    <activity  # DIFF-ANCHOR: bec48e1f
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:enabled="false"
         android:excludeFromRecents="true"
@@ -183,22 +189,23 @@
         android:name="org.chromium.chrome.browser.printing.PrintShareActivity"
         android:noHistory="true"
         android:theme="@android:style/Theme.NoDisplay">
-      <intent-filter>  # DIFF-ANCHOR: 805331e9
+      <intent-filter>  # DIFF-ANCHOR: 4ee601b7
         <action android:name="android.intent.action.SEND"/>
         <category android:name="android.intent.category.DEFAULT"/>
         <data android:mimeType="message/rfc822"/>
         <data android:mimeType="multipart/related"/>
         <data android:mimeType="text/plain"/>
-      </intent-filter>  # DIFF-ANCHOR: 805331e9
-    </activity>  # DIFF-ANCHOR: 5715816d
-    <activity  # DIFF-ANCHOR: 12aa4b5a
+      </intent-filter>  # DIFF-ANCHOR: 4ee601b7
+    </activity>  # DIFF-ANCHOR: bec48e1f
+    <activity  # DIFF-ANCHOR: 43bfa5de
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:excludeFromRecents="true"
         android:exported="true"
         android:name="org.chromium.chrome.browser.test_dummy.TestDummyActivity"
         android:noHistory="true"
-        android:theme="@style/Theme.AppCompat"/>
-    <activity  # DIFF-ANCHOR: f42af6de
+        android:theme="@style/Theme.AppCompat">
+    </activity>  # DIFF-ANCHOR: 43bfa5de
+    <activity  # DIFF-ANCHOR: 8d26d599
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:excludeFromRecents="true"
         android:hardwareAccelerated="true"
@@ -206,73 +213,83 @@
         android:launchMode="singleTask"
         android:name="org.chromium.chrome.browser.media.router.caf.remoting.CafExpandedControllerActivity"
         android:noHistory="true"
-        android:theme="@style/Theme.Chromium.Activity"/>
-    <activity  # DIFF-ANCHOR: b97b5c81
+        android:theme="@style/Theme.Chromium.Activity">
+    </activity>  # DIFF-ANCHOR: 8d26d599
+    <activity  # DIFF-ANCHOR: a208e726
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:excludeFromRecents="true"
         android:name="org.chromium.chrome.browser.bookmarks.BookmarkAddActivity"
         android:theme="@android:style/Theme.NoDisplay"
         android:windowSoftInputMode="stateHidden">
-      <intent-filter>  # DIFF-ANCHOR: c1ed7137
+      <intent-filter>  # DIFF-ANCHOR: 47a8059b
         <action android:name="$PACKAGE.ADDBOOKMARK"/>
         <category android:name="android.intent.category.DEFAULT"/>
-      </intent-filter>  # DIFF-ANCHOR: c1ed7137
-    </activity>  # DIFF-ANCHOR: b97b5c81
-    <activity  # DIFF-ANCHOR: 6d34bd76
+      </intent-filter>  # DIFF-ANCHOR: 47a8059b
+    </activity>  # DIFF-ANCHOR: a208e726
+    <activity  # DIFF-ANCHOR: 0a21ad35
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:exported="false"
         android:label="@string/bookmark_choose_folder"
         android:name="org.chromium.chrome.browser.bookmarks.BookmarkFolderSelectActivity"
         android:theme="@style/Theme.Chromium.DialogWhenLarge"
-        android:windowSoftInputMode="stateAlwaysHidden"/>
-    <activity  # DIFF-ANCHOR: f5269d8e
+        android:windowSoftInputMode="stateAlwaysHidden">
+    </activity>  # DIFF-ANCHOR: 0a21ad35
+    <activity  # DIFF-ANCHOR: b66ce3f2
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:exported="false"
         android:label="@string/edit_bookmark"
         android:name="org.chromium.chrome.browser.bookmarks.BookmarkEditActivity"
         android:theme="@style/Theme.Chromium.DialogWhenLarge"
-        android:windowSoftInputMode="stateHidden"/>
-    <activity  # DIFF-ANCHOR: 2b35e1d5
+        android:windowSoftInputMode="stateHidden">
+    </activity>  # DIFF-ANCHOR: b66ce3f2
+    <activity  # DIFF-ANCHOR: d32b85df
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:exported="false"
         android:label="@string/settings"
         android:name="org.chromium.chrome.browser.settings.SettingsActivity"
-        android:theme="@style/Theme.Chromium.Settings"/>
-    <activity  # DIFF-ANCHOR: 10056d20
+        android:theme="@style/Theme.Chromium.Settings">
+    </activity>  # DIFF-ANCHOR: d32b85df
+    <activity  # DIFF-ANCHOR: d2967c86
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:exported="false"
         android:label="@string/storage_management_activity_label"
         android:name="org.chromium.chrome.browser.site_settings.ManageSpaceActivity"
-        android:theme="@style/Theme.Chromium.Settings.ManageSpace"/>
-    <activity  # DIFF-ANCHOR: 45c62b10
+        android:theme="@style/Theme.Chromium.Settings.ManageSpace">
+    </activity>  # DIFF-ANCHOR: d2967c86
+    <activity  # DIFF-ANCHOR: da2eedc8
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:exported="false"
         android:name="org.chromium.chrome.browser.bookmarks.BookmarkActivity"
         android:theme="@style/Theme.Chromium.Activity.Fullscreen"
-        android:windowSoftInputMode="stateAlwaysHidden|adjustResize"/>
-    <activity  # DIFF-ANCHOR: e3a84ff9
+        android:windowSoftInputMode="stateAlwaysHidden|adjustResize">
+    </activity>  # DIFF-ANCHOR: da2eedc8
+    <activity  # DIFF-ANCHOR: e0427380
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:exported="false"
         android:name="org.chromium.chrome.browser.bookmarks.BookmarkAddEditFolderActivity"
-        android:theme="@style/Theme.Chromium.DialogWhenLarge"/>
-    <activity  # DIFF-ANCHOR: 125092bc
+        android:theme="@style/Theme.Chromium.DialogWhenLarge">
+    </activity>  # DIFF-ANCHOR: e0427380
+    <activity  # DIFF-ANCHOR: 5c83a464
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:exported="false"
         android:name="org.chromium.chrome.browser.download.DownloadActivity"
         android:theme="@style/Theme.Chromium.Activity.Fullscreen"
-        android:windowSoftInputMode="stateAlwaysHidden|adjustResize"/>
-    <activity  # DIFF-ANCHOR: 2650f0aa
+        android:windowSoftInputMode="stateAlwaysHidden|adjustResize">
+    </activity>  # DIFF-ANCHOR: 5c83a464
+    <activity  # DIFF-ANCHOR: 05911131
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:exported="false"
         android:name="org.chromium.chrome.browser.history.HistoryActivity"
         android:theme="@style/Theme.Chromium.Activity.Fullscreen"
-        android:windowSoftInputMode="stateAlwaysHidden|adjustResize"/>
-    <activity  # DIFF-ANCHOR: 56341b41
+        android:windowSoftInputMode="stateAlwaysHidden|adjustResize">
+    </activity>  # DIFF-ANCHOR: 05911131
+    <activity  # DIFF-ANCHOR: f2fee469
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:exported="false"
         android:name="org.chromium.chrome.browser.signin.SigninActivity"
-        android:theme="@style/Theme.Chromium.DialogWhenLarge"/>
-    <activity  # DIFF-ANCHOR: 15f8c0d9
+        android:theme="@style/Theme.Chromium.DialogWhenLarge">
+    </activity>  # DIFF-ANCHOR: f2fee469
+    <activity  # DIFF-ANCHOR: 5e628a6c
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode"
         android:enableVrMode="@string/gvr_vr_mode_component"
         android:excludeFromRecents="true"
@@ -280,13 +297,13 @@
         android:launchMode="singleInstance"
         android:name="org.chromium.chrome.browser.vr.VrFirstRunActivity"
         android:theme="@style/VrActivityTheme">
-      <intent-filter>  # DIFF-ANCHOR: ad124986
+      <intent-filter>  # DIFF-ANCHOR: dea53031
         <action android:name="org.chromium.chrome.browser.dummy.action"/>
         <category android:name="com.google.intent.category.CARDBOARD"/>
         <category android:name="com.google.intent.category.DAYDREAM"/>
-      </intent-filter>  # DIFF-ANCHOR: ad124986
-    </activity>  # DIFF-ANCHOR: 15f8c0d9
-    <activity  # DIFF-ANCHOR: 35467a36
+      </intent-filter>  # DIFF-ANCHOR: dea53031
+    </activity>  # DIFF-ANCHOR: 5e628a6c
+    <activity  # DIFF-ANCHOR: 5e467d8a
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density"
         android:documentLaunchMode="intoExisting"
         android:exported="false"
@@ -299,20 +316,21 @@
         android:supportsPictureInPicture="true"
         android:theme="@style/Theme.Chromium.Webapp"
         android:windowSoftInputMode="adjustResize">
-      <intent-filter>  # DIFF-ANCHOR: ad124986
+      <intent-filter>  # DIFF-ANCHOR: dea53031
         <action android:name="org.chromium.chrome.browser.dummy.action"/>
         <category android:name="com.google.intent.category.CARDBOARD"/>
         <category android:name="com.google.intent.category.DAYDREAM"/>
-      </intent-filter>  # DIFF-ANCHOR: ad124986
-    </activity>  # DIFF-ANCHOR: 35467a36
-    <activity  # DIFF-ANCHOR: 10649477
+      </intent-filter>  # DIFF-ANCHOR: dea53031
+    </activity>  # DIFF-ANCHOR: 5e467d8a
+    <activity  # DIFF-ANCHOR: 1acdfd19
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density"
         android:excludeFromRecents="true"
         android:name="org.chromium.chrome.browser.document.ChromeLauncherActivity"
         android:relinquishTaskIdentity="true"
         android:taskAffinity=""
-        android:theme="@style/LauncherTheme"/>
-    <activity  # DIFF-ANCHOR: b4386459
+        android:theme="@style/LauncherTheme">
+    </activity>  # DIFF-ANCHOR: 1acdfd19
+    <activity  # DIFF-ANCHOR: f1dc024a
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density"
         android:exported="false"
         android:hardwareAccelerated="false"
@@ -323,13 +341,13 @@
         android:supportsPictureInPicture="true"
         android:theme="@style/Theme.Chromium.Webapp.Translucent"
         android:windowSoftInputMode="adjustResize">
-      <intent-filter>  # DIFF-ANCHOR: ad124986
+      <intent-filter>  # DIFF-ANCHOR: dea53031
         <action android:name="org.chromium.chrome.browser.dummy.action"/>
         <category android:name="com.google.intent.category.CARDBOARD"/>
         <category android:name="com.google.intent.category.DAYDREAM"/>
-      </intent-filter>  # DIFF-ANCHOR: ad124986
-    </activity>  # DIFF-ANCHOR: b4386459
-    <activity  # DIFF-ANCHOR: c5947e69
+      </intent-filter>  # DIFF-ANCHOR: dea53031
+    </activity>  # DIFF-ANCHOR: f1dc024a
+    <activity  # DIFF-ANCHOR: 610e8ccf
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density"
         android:exported="false"
         android:hardwareAccelerated="false"
@@ -340,13 +358,13 @@
         android:taskAffinity="$PACKAGE.ChromeTabbedActivity2"
         android:theme="@style/Theme.Chromium.TabbedMode"
         android:windowSoftInputMode="adjustResize">
-      <intent-filter>  # DIFF-ANCHOR: ad124986
+      <intent-filter>  # DIFF-ANCHOR: dea53031
         <action android:name="org.chromium.chrome.browser.dummy.action"/>
         <category android:name="com.google.intent.category.CARDBOARD"/>
         <category android:name="com.google.intent.category.DAYDREAM"/>
-      </intent-filter>  # DIFF-ANCHOR: ad124986
-    </activity>  # DIFF-ANCHOR: c5947e69
-    <activity  # DIFF-ANCHOR: 66124c66
+      </intent-filter>  # DIFF-ANCHOR: dea53031
+    </activity>  # DIFF-ANCHOR: 610e8ccf
+    <activity  # DIFF-ANCHOR: 44266a6a
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density"
         android:exported="false"
         android:hardwareAccelerated="false"
@@ -355,13 +373,13 @@
         android:supportsPictureInPicture="true"
         android:theme="@style/Theme.Chromium.Activity"
         android:windowSoftInputMode="adjustResize">
-      <intent-filter>  # DIFF-ANCHOR: ad124986
+      <intent-filter>  # DIFF-ANCHOR: dea53031
         <action android:name="org.chromium.chrome.browser.dummy.action"/>
         <category android:name="com.google.intent.category.CARDBOARD"/>
         <category android:name="com.google.intent.category.DAYDREAM"/>
-      </intent-filter>  # DIFF-ANCHOR: ad124986
-    </activity>  # DIFF-ANCHOR: 66124c66
-    <activity  # DIFF-ANCHOR: 749aca16
+      </intent-filter>  # DIFF-ANCHOR: dea53031
+    </activity>  # DIFF-ANCHOR: 44266a6a
+    <activity  # DIFF-ANCHOR: 70dc8b5c
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density"
         android:exported="false"
         android:hardwareAccelerated="false"
@@ -370,13 +388,13 @@
         android:supportsPictureInPicture="true"
         android:theme="@style/Theme.Chromium.Activity.Translucent"
         android:windowSoftInputMode="adjustResize">
-      <intent-filter>  # DIFF-ANCHOR: ad124986
+      <intent-filter>  # DIFF-ANCHOR: dea53031
         <action android:name="org.chromium.chrome.browser.dummy.action"/>
         <category android:name="com.google.intent.category.CARDBOARD"/>
         <category android:name="com.google.intent.category.DAYDREAM"/>
-      </intent-filter>  # DIFF-ANCHOR: ad124986
-    </activity>  # DIFF-ANCHOR: 749aca16
-    <activity  # DIFF-ANCHOR: 5466134
+      </intent-filter>  # DIFF-ANCHOR: dea53031
+    </activity>  # DIFF-ANCHOR: 70dc8b5c
+    <activity  # DIFF-ANCHOR: 4d923622
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density"
         android:exported="false"
         android:hardwareAccelerated="false"
@@ -385,20 +403,21 @@
         android:supportsPictureInPicture="true"
         android:theme="@style/Theme.Chromium.Activity.FakeTranslucent"
         android:windowSoftInputMode="adjustResize">
-      <intent-filter>  # DIFF-ANCHOR: ad124986
+      <intent-filter>  # DIFF-ANCHOR: dea53031
         <action android:name="org.chromium.chrome.browser.dummy.action"/>
         <category android:name="com.google.intent.category.CARDBOARD"/>
         <category android:name="com.google.intent.category.DAYDREAM"/>
-      </intent-filter>  # DIFF-ANCHOR: ad124986
-    </activity>  # DIFF-ANCHOR: 5466134
-    <activity  # DIFF-ANCHOR: f5d77a0a
+      </intent-filter>  # DIFF-ANCHOR: dea53031
+    </activity>  # DIFF-ANCHOR: 4d923622
+    <activity  # DIFF-ANCHOR: 9023f153
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density"
         android:exported="false"
         android:hardwareAccelerated="false"
         android:name="org.chromium.chrome.browser.multiwindow.MultiInstanceChromeTabbedActivity"
         android:theme="@style/Theme.Chromium.TabbedMode"
-        android:windowSoftInputMode="adjustResize"/>
-    <activity  # DIFF-ANCHOR: a8bef873
+        android:windowSoftInputMode="adjustResize">
+    </activity>  # DIFF-ANCHOR: 9023f153
+    <activity  # DIFF-ANCHOR: 61b2c776
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density"
         android:exported="true"
         android:hardwareAccelerated="false"
@@ -408,13 +427,13 @@
         android:supportsPictureInPicture="true"
         android:theme="@style/Theme.Chromium.TabbedMode"
         android:windowSoftInputMode="adjustResize">
-      <intent-filter>  # DIFF-ANCHOR: ad124986
+      <intent-filter>  # DIFF-ANCHOR: dea53031
         <action android:name="org.chromium.chrome.browser.dummy.action"/>
         <category android:name="com.google.intent.category.CARDBOARD"/>
         <category android:name="com.google.intent.category.DAYDREAM"/>
-      </intent-filter>  # DIFF-ANCHOR: ad124986
-    </activity>  # DIFF-ANCHOR: a8bef873
-    <activity  # DIFF-ANCHOR: 85b76e7f
+      </intent-filter>  # DIFF-ANCHOR: dea53031
+    </activity>  # DIFF-ANCHOR: 61b2c776
+    <activity  # DIFF-ANCHOR: d706d96e
         android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
         android:excludeFromRecents="true"
         android:exported="false"
@@ -422,122 +441,132 @@
         android:noHistory="true"
         android:resizeableActivity="true"
         android:supportsPictureInPicture="true"
-        android:theme="@style/Theme.Chromium.Activity"/>
-    <activity  # DIFF-ANCHOR: 453e37aa
+        android:theme="@style/Theme.Chromium.Activity">
+    </activity>  # DIFF-ANCHOR: d706d96e
+    <activity  # DIFF-ANCHOR: b007dcaa
         android:enableVrMode="@string/gvr_vr_mode_component"
         android:excludeFromRecents="true"
         android:exported="false"
         android:name="org.chromium.chrome.browser.vr.VrCancelAnimationActivity"
         android:noHistory="true"
         android:theme="@android:style/Theme.NoDisplay">
-      <intent-filter>  # DIFF-ANCHOR: ad124986
+      <intent-filter>  # DIFF-ANCHOR: dea53031
         <action android:name="org.chromium.chrome.browser.dummy.action"/>
         <category android:name="com.google.intent.category.CARDBOARD"/>
         <category android:name="com.google.intent.category.DAYDREAM"/>
-      </intent-filter>  # DIFF-ANCHOR: ad124986
-    </activity>  # DIFF-ANCHOR: 453e37aa
-    <activity  # DIFF-ANCHOR: c4993004
+      </intent-filter>  # DIFF-ANCHOR: dea53031
+    </activity>  # DIFF-ANCHOR: b007dcaa
+    <activity  # DIFF-ANCHOR: b98302dc
         android:enabled="false"
         android:excludeFromRecents="true"
         android:exported="true"
         android:name="org.chromium.chrome.browser.incognito.IncognitoTabLauncher"
         android:taskAffinity=""
         android:theme="@android:style/Theme.NoDisplay">
-      <intent-filter>  # DIFF-ANCHOR: 1541ef4c
+      <intent-filter>  # DIFF-ANCHOR: 8f811d02
         <action android:name="org.chromium.chrome.browser.incognito.OPEN_PRIVATE_TAB"/>
         <category android:name="android.intent.category.DEFAULT"/>
-      </intent-filter>  # DIFF-ANCHOR: 1541ef4c
-    </activity>  # DIFF-ANCHOR: c4993004
-    <activity  # DIFF-ANCHOR: 14e3cdad
+      </intent-filter>  # DIFF-ANCHOR: 8f811d02
+    </activity>  # DIFF-ANCHOR: b98302dc
+    <activity  # DIFF-ANCHOR: 53a4871f
         android:enabled="false"
         android:exported="false"
         android:launchMode="singleInstance"
         android:name="com.google.android.play.core.missingsplits.PlayCoreMissingSplitsActivity"
         android:process=":playcore_missing_splits_activity"
-        android:stateNotNeeded="true"/>
-    <activity  # DIFF-ANCHOR: cb1f1a5e
+        android:stateNotNeeded="true">
+    </activity>  # DIFF-ANCHOR: 53a4871f
+    <activity  # DIFF-ANCHOR: a2bae37c
         android:enabled="false"
         android:exported="false"
         android:name="com.google.android.play.core.common.PlayCoreDialogWrapperActivity"
         android:process=":playcore_dialog_wrapper_activity"
         android:stateNotNeeded="true"
-        android:theme="@style/Theme.PlayCore.Transparent"/>
-    <activity  # DIFF-ANCHOR: 16204651
+        android:theme="@style/Theme.PlayCore.Transparent">
+    </activity>  # DIFF-ANCHOR: a2bae37c
+    <activity  # DIFF-ANCHOR: 93d41352
         android:excludeFromRecents="true"
         android:exported="false"
         android:launchMode="singleInstance"
         android:name="org.chromium.chrome.browser.BrowserRestartActivity"
         android:process=":browser_restart_process"
-        android:theme="@android:style/Theme.Translucent.NoTitleBar"/>
-    <activity  # DIFF-ANCHOR: 172d9b32
+        android:theme="@android:style/Theme.Translucent.NoTitleBar">
+    </activity>  # DIFF-ANCHOR: 93d41352
+    <activity  # DIFF-ANCHOR: 76686af9
         android:excludeFromRecents="true"
         android:exported="false"
         android:name="org.chromium.chrome.browser.LauncherShortcutActivity"
         android:taskAffinity=""
-        android:theme="@android:style/Theme.NoDisplay"/>
-    <activity  # DIFF-ANCHOR: f490b994
+        android:theme="@android:style/Theme.NoDisplay">
+    </activity>  # DIFF-ANCHOR: 76686af9
+    <activity  # DIFF-ANCHOR: 50c7105b
         android:excludeFromRecents="true"
         android:exported="false"
         android:name="org.chromium.chrome.browser.app.reengagement.ReengagementActivity"
         android:taskAffinity=""
-        android:theme="@android:style/Theme.Translucent"/>
-    <activity  # DIFF-ANCHOR: 9ad44b6b
+        android:theme="@android:style/Theme.Translucent">
+    </activity>  # DIFF-ANCHOR: 50c7105b
+    <activity  # DIFF-ANCHOR: 349d8ca5
         android:excludeFromRecents="true"
         android:exported="false"
         android:name="org.chromium.chrome.browser.instantapps.AuthenticatedProxyActivity"
         android:noHistory="true"
-        android:theme="@android:style/Theme.NoDisplay"/>
-    <activity  # DIFF-ANCHOR: 3722f0d9
+        android:theme="@android:style/Theme.NoDisplay">
+    </activity>  # DIFF-ANCHOR: 349d8ca5
+    <activity  # DIFF-ANCHOR: 76b60c10
         android:excludeFromRecents="true"
         android:exported="false"
         android:name="org.chromium.chrome.browser.sync.ui.TrustedVaultKeyRetrievalProxyActivity"
-        android:theme="@style/Theme.AppCompat"/>
-    <activity  # DIFF-ANCHOR: 6dcb7a35
+        android:theme="@style/Theme.AppCompat">
+    </activity>  # DIFF-ANCHOR: 76b60c10
+    <activity  # DIFF-ANCHOR: aea75380
         android:excludeFromRecents="true"
         android:name="org.chromium.chrome.browser.webapps.WebappLauncherActivity"
         android:taskAffinity=""
         android:theme="@android:style/Theme.NoDisplay">
-      <intent-filter>  # DIFF-ANCHOR: 4a61c500
+      <intent-filter>  # DIFF-ANCHOR: faf519ad
         <action android:name="com.google.android.apps.chrome.webapps.WebappManager.ACTION_START_WEBAPP"/>
         <category android:name="android.intent.category.DEFAULT"/>
-      </intent-filter>  # DIFF-ANCHOR: 4a61c500
-      <intent-filter>  # DIFF-ANCHOR: 189026bc
+      </intent-filter>  # DIFF-ANCHOR: faf519ad
+      <intent-filter>  # DIFF-ANCHOR: 9c5197e9
         <action android:name="org.webapk.ACTION_START_WEBAPK"/>
         <category android:name="android.intent.category.DEFAULT"/>
-      </intent-filter>  # DIFF-ANCHOR: 189026bc
-    </activity>  # DIFF-ANCHOR: 6dcb7a35
-    <activity  # DIFF-ANCHOR: 8488739d
+      </intent-filter>  # DIFF-ANCHOR: 9c5197e9
+    </activity>  # DIFF-ANCHOR: aea75380
+    <activity  # DIFF-ANCHOR: ea1a94af
         android:exported="false"
         android:name="com.google.android.gms.common.api.GoogleApiActivity"
-        android:theme="@android:style/Theme.Translucent.NoTitleBar"/>
-    <activity  # DIFF-ANCHOR: 3e94da48
+        android:theme="@android:style/Theme.Translucent.NoTitleBar">
+    </activity>  # DIFF-ANCHOR: ea1a94af
+    <activity  # DIFF-ANCHOR: 209b5ded
         android:exported="false"
         android:name="org.chromium.chrome.browser.browserservices.ClearDataDialogActivity"
-        android:theme="@style/Theme.Chromium.ClearDataDialogActivity"/>
-    <activity  # DIFF-ANCHOR: e89d9458
+        android:theme="@style/Theme.Chromium.ClearDataDialogActivity">
+    </activity>  # DIFF-ANCHOR: 209b5ded
+    <activity  # DIFF-ANCHOR: 2b0ee4cd
         android:exported="true"
         android:name="org.chromium.chrome.browser.browserservices.ManageTrustedWebActivityDataActivity"
         android:theme="@style/Theme.Chromium.Activity.Fullscreen.Transparent">
-      <intent-filter>  # DIFF-ANCHOR: 705f3d0f
+      <intent-filter>  # DIFF-ANCHOR: 38d9d906
         <action android:name="android.support.customtabs.action.ACTION_MANAGE_TRUSTED_WEB_ACTIVITY_DATA"/>
         <category android:name="android.intent.category.DEFAULT"/>
         <data android:scheme="https"/>
-      </intent-filter>  # DIFF-ANCHOR: 705f3d0f
-      <intent-filter>  # DIFF-ANCHOR: ac78e0e4
+      </intent-filter>  # DIFF-ANCHOR: 38d9d906
+      <intent-filter>  # DIFF-ANCHOR: 38d9d906
         <action android:name="android.support.customtabs.action.ACTION_MANAGE_TRUSTED_WEB_ACTIVITY_DATA"/>
         <category android:name="android.intent.category.DEFAULT"/>
-      </intent-filter>  # DIFF-ANCHOR: ac78e0e4
-    </activity>  # DIFF-ANCHOR: e89d9458
-    <activity  # DIFF-ANCHOR: ecad59fd
+      </intent-filter>  # DIFF-ANCHOR: 38d9d906
+    </activity>  # DIFF-ANCHOR: 2b0ee4cd
+    <activity  # DIFF-ANCHOR: 9bb1f409
         android:exported="true"
         android:name="org.chromium.chrome.browser.webapps.ActivateWebApkActivity"
         android:theme="@android:style/Theme.NoDisplay">
-      <intent-filter>  # DIFF-ANCHOR: b3c76e56
+      <intent-filter>  # DIFF-ANCHOR: 0d72b7f0
         <action android:name="org.chromium.chrome.browser.webapps.ActivateWebApkActivity.ACTIVATE"/>
         <category android:name="android.intent.category.DEFAULT"/>
-      </intent-filter>  # DIFF-ANCHOR: b3c76e56
-    </activity>  # DIFF-ANCHOR: ecad59fd
-    <activity  # DIFF-ANCHOR: 1d9e26ca
+      </intent-filter>  # DIFF-ANCHOR: 0d72b7f0
+    </activity>  # DIFF-ANCHOR: 9bb1f409
+    <activity  # DIFF-ANCHOR: a4438884
         android:icon="@drawable/icon_webview"
         android:label="WebView DevTools"
         android:launchMode="singleTask"
@@ -547,78 +576,79 @@
         android:theme="@style/Theme.DevUi.DayNight"
         android:visibleToInstantApps="true"
         android:windowSoftInputMode="adjustPan">
-      <intent-filter>  # DIFF-ANCHOR: 36c368a2
+      <intent-filter>  # DIFF-ANCHOR: a167e73d
         <action android:name="com.android.webview.SHOW_DEV_UI"/>
         <category android:name="android.intent.category.DEFAULT"/>
-      </intent-filter>  # DIFF-ANCHOR: 36c368a2
-    </activity>  # DIFF-ANCHOR: 1d9e26ca
-    <activity  # DIFF-ANCHOR: a003fb0a
+      </intent-filter>  # DIFF-ANCHOR: a167e73d
+    </activity>  # DIFF-ANCHOR: a4438884
+    <activity  # DIFF-ANCHOR: aeabab17
         android:label="@string/license_activity_title"
         android:name="org.chromium.android_webview.nonembedded.LicenseActivity"
         android:process=":webview_apk">
-      <intent-filter>  # DIFF-ANCHOR: 7071b59d
+      <intent-filter>  # DIFF-ANCHOR: 23298d3b
         <action android:name="android.settings.WEBVIEW_LICENSE"/>
         <category android:name="android.intent.category.DEFAULT"/>
-      </intent-filter>  # DIFF-ANCHOR: 7071b59d
+      </intent-filter>  # DIFF-ANCHOR: 23298d3b
       <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED" android:value="true"/>
-    </activity>  # DIFF-ANCHOR: a003fb0a
-    <activity  # DIFF-ANCHOR: 7cb1f2d6
+    </activity>  # DIFF-ANCHOR: aeabab17
+    <activity  # DIFF-ANCHOR: ecd48344
         android:enabled="false"
         android:excludeFromRecents="true"
         android:exported="true"
         android:name="org.chromium.chrome.browser.media.MediaLauncherActivity"
         android:theme="@android:style/Theme.NoDisplay">
-      <intent-filter tools:ignore="AppLinkUrlError">  # DIFF-ANCHOR: 2a7b9cc9
+      <intent-filter tools:ignore="AppLinkUrlError">  # DIFF-ANCHOR: 13c9b0a8
         <action android:name="android.intent.action.VIEW"/>
         <category android:name="android.intent.category.DEFAULT"/>
         <data android:mimeType="image/*"/>
         <data android:mimeType="video/*"/>
         <data android:scheme="content"/>
         <data android:scheme="file"/>
-      </intent-filter>  # DIFF-ANCHOR: 2a7b9cc9
-    </activity>  # DIFF-ANCHOR: 7cb1f2d6
-    <activity-alias  # DIFF-ANCHOR: 7331027
+      </intent-filter>  # DIFF-ANCHOR: 13c9b0a8
+    </activity>  # DIFF-ANCHOR: ecd48344
+    <activity-alias  # DIFF-ANCHOR: 32e34aba
         android:enabled="false"
         android:exported="true"
         android:label="WebView DevTools"
         android:name="org.chromium.android_webview.devui.MonochromeLauncherActivity"
         android:targetActivity="org.chromium.android_webview.devui.MainActivity">
-      <intent-filter>  # DIFF-ANCHOR: c7769f5e
+      <intent-filter>  # DIFF-ANCHOR: a5330430
         <action android:name="android.intent.action.MAIN"/>
         <category android:name="android.intent.category.LAUNCHER"/>
-      </intent-filter>  # DIFF-ANCHOR: c7769f5e
-    </activity-alias>  # DIFF-ANCHOR: 7331027
-    <activity-alias  # DIFF-ANCHOR: 6c354539
+      </intent-filter>  # DIFF-ANCHOR: a5330430
+    </activity-alias>  # DIFF-ANCHOR: 32e34aba
+    <activity-alias  # DIFF-ANCHOR: b7cc06e9
         android:enabled="false"
         android:name="org.chromium.android_webview.devui.DeveloperModeState"
         android:process=":webview_apk"
         android:targetActivity="org.chromium.android_webview.devui.MainActivity"
-        android:visibleToInstantApps="true"/>
-    <activity-alias  # DIFF-ANCHOR: d540bcba
+        android:visibleToInstantApps="true">
+    </activity-alias>  # DIFF-ANCHOR: b7cc06e9
+    <activity-alias  # DIFF-ANCHOR: 7c349c4f
         android:exported="false"
         android:name="org.chromium.chrome.browser.webapps.SecureWebAppLauncher"
         android:targetActivity="org.chromium.chrome.browser.webapps.WebappLauncherActivity">
-      <intent-filter>  # DIFF-ANCHOR: eca516cd
+      <intent-filter>  # DIFF-ANCHOR: 9fe4b527
         <action android:name="org.chromium.chrome.browser.webapps.WebappManager.ACTION_START_SECURE_WEBAPP"/>
         <category android:name="android.intent.category.DEFAULT"/>
-      </intent-filter>  # DIFF-ANCHOR: eca516cd
-    </activity-alias>  # DIFF-ANCHOR: d540bcba
-    <activity-alias  # DIFF-ANCHOR: d9b4f740
+      </intent-filter>  # DIFF-ANCHOR: 9fe4b527
+    </activity-alias>  # DIFF-ANCHOR: 7c349c4f
+    <activity-alias  # DIFF-ANCHOR: 9da0e5b6
         android:exported="true"
         android:name="com.google.android.apps.chrome.IntentDispatcher"
         android:targetActivity="org.chromium.chrome.browser.document.ChromeLauncherActivity">
-      <intent-filter>  # DIFF-ANCHOR: 81efad64
+      <intent-filter>  # DIFF-ANCHOR: a5330430
         <action android:name="android.intent.action.MAIN"/>
         <category android:name="android.intent.category.NOTIFICATION_PREFERENCES"/>
-      </intent-filter>  # DIFF-ANCHOR: 81efad64
-      <intent-filter>  # DIFF-ANCHOR: d4767742
+      </intent-filter>  # DIFF-ANCHOR: a5330430
+      <intent-filter>  # DIFF-ANCHOR: 436dfef3
         <action android:name="android.intent.action.MEDIA_SEARCH"/>
         <category android:name="android.intent.category.DEFAULT"/>
-      </intent-filter>  # DIFF-ANCHOR: d4767742
-      <intent-filter>  # DIFF-ANCHOR: a63fd491
+      </intent-filter>  # DIFF-ANCHOR: 436dfef3
+      <intent-filter>  # DIFF-ANCHOR: 8f70c92f
         <action android:name="android.intent.action.SEARCH"/>
-      </intent-filter>  # DIFF-ANCHOR: a63fd491
-      <intent-filter>  # DIFF-ANCHOR: 19322362
+      </intent-filter>  # DIFF-ANCHOR: 8f70c92f
+      <intent-filter>  # DIFF-ANCHOR: 13c9b0a8
         <action android:name="android.intent.action.VIEW"/>
         <category android:name="android.intent.category.BROWSABLE"/>
         <category android:name="android.intent.category.DEFAULT"/>
@@ -628,8 +658,8 @@
         <data android:pathPattern="/.*\\.mhtml"/>
         <data android:scheme="content"/>
         <data android:scheme="file"/>
-      </intent-filter>  # DIFF-ANCHOR: 19322362
-      <intent-filter>  # DIFF-ANCHOR: dcb86ef4
+      </intent-filter>  # DIFF-ANCHOR: 13c9b0a8
+      <intent-filter>  # DIFF-ANCHOR: 13c9b0a8
         <action android:name="android.intent.action.VIEW"/>
         <category android:name="android.intent.category.BROWSABLE"/>
         <category android:name="android.intent.category.DEFAULT"/>
@@ -638,8 +668,8 @@
         <data android:pathPattern="/.*\\.mhtml"/>
         <data android:scheme="content"/>
         <data android:scheme="file"/>
-      </intent-filter>  # DIFF-ANCHOR: dcb86ef4
-      <intent-filter>  # DIFF-ANCHOR: 17b2c901
+      </intent-filter>  # DIFF-ANCHOR: 13c9b0a8
+      <intent-filter>  # DIFF-ANCHOR: 13c9b0a8
         <action android:name="android.intent.action.VIEW"/>
         <category android:name="android.intent.category.BROWSABLE"/>
         <category android:name="android.intent.category.DEFAULT"/>
@@ -652,8 +682,8 @@
         <data android:scheme="http"/>
         <data android:scheme="https"/>
         <data android:scheme="javascript"/>
-      </intent-filter>  # DIFF-ANCHOR: 17b2c901
-      <intent-filter>  # DIFF-ANCHOR: f8cc82d7
+      </intent-filter>  # DIFF-ANCHOR: 13c9b0a8
+      <intent-filter>  # DIFF-ANCHOR: 13c9b0a8
         <action android:name="android.intent.action.VIEW"/>
         <category android:name="android.intent.category.BROWSABLE"/>
         <category android:name="android.intent.category.DEFAULT"/>
@@ -662,78 +692,80 @@
         <data android:scheme="http"/>
         <data android:scheme="https"/>
         <data android:scheme="javascript"/>
-      </intent-filter>  # DIFF-ANCHOR: f8cc82d7
-      <intent-filter>  # DIFF-ANCHOR: aa31a443
+      </intent-filter>  # DIFF-ANCHOR: 13c9b0a8
+      <intent-filter>  # DIFF-ANCHOR: 13c9b0a8
         <action android:name="android.intent.action.VIEW"/>
         <category android:name="android.intent.category.DEFAULT"/>
         <data android:mimeType="message/rfc822"/>
         <data android:scheme="content"/>
         <data android:scheme="file"/>
-      </intent-filter>  # DIFF-ANCHOR: aa31a443
-      <intent-filter>  # DIFF-ANCHOR: f40b1f1d
+      </intent-filter>  # DIFF-ANCHOR: 13c9b0a8
+      <intent-filter>  # DIFF-ANCHOR: 13c9b0a8
         <action android:name="android.intent.action.VIEW"/>
         <category android:name="android.intent.category.DEFAULT"/>
         <data android:mimeType="multipart/related"/>
         <data android:scheme="content"/>
         <data android:scheme="file"/>
-      </intent-filter>  # DIFF-ANCHOR: f40b1f1d
-      <intent-filter>  # DIFF-ANCHOR: cc547f0c
+      </intent-filter>  # DIFF-ANCHOR: 13c9b0a8
+      <intent-filter>  # DIFF-ANCHOR: 7a3b3be8
         <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
         <category android:name="android.intent.category.DEFAULT"/>
         <data android:scheme="http"/>
         <data android:scheme="https"/>
-      </intent-filter>  # DIFF-ANCHOR: cc547f0c
-      <intent-filter>  # DIFF-ANCHOR: 16d15225
+      </intent-filter>  # DIFF-ANCHOR: 7a3b3be8
+      <intent-filter>  # DIFF-ANCHOR: 2a3a3c3d
         <action android:name="android.speech.action.VOICE_SEARCH_RESULTS"/>
         <category android:name="android.intent.category.DEFAULT"/>
-      </intent-filter>  # DIFF-ANCHOR: 16d15225
-      <intent-filter>  # DIFF-ANCHOR: b59119d3
+      </intent-filter>  # DIFF-ANCHOR: 2a3a3c3d
+      <intent-filter>  # DIFF-ANCHOR: 83919a44
         <action android:name="com.sec.android.airview.HOVER"/>
-      </intent-filter>  # DIFF-ANCHOR: b59119d3
+      </intent-filter>  # DIFF-ANCHOR: 83919a44
       <meta-data android:name="android.app.searchable" android:resource="@xml/searchable"/>
-    </activity-alias>  # DIFF-ANCHOR: d9b4f740
-    <activity-alias  # DIFF-ANCHOR: 67e6b59a
+    </activity-alias>  # DIFF-ANCHOR: 9da0e5b6
+    <activity-alias  # DIFF-ANCHOR: 5042984f
         android:exported="true"
         android:name="com.google.android.apps.chrome.Main"
         android:targetActivity="org.chromium.chrome.browser.ChromeTabbedActivity">
-      <intent-filter>  # DIFF-ANCHOR: 8697c9d3
+      <intent-filter>  # DIFF-ANCHOR: a5330430
         <action android:name="android.intent.action.MAIN"/>
         <category android:name="android.intent.category.APP_BROWSER"/>
         <category android:name="android.intent.category.BROWSABLE"/>
         <category android:name="android.intent.category.DEFAULT"/>
         <category android:name="android.intent.category.LAUNCHER"/>
-      </intent-filter>  # DIFF-ANCHOR: 8697c9d3
-      <intent-filter>  # DIFF-ANCHOR: ad124986
+      </intent-filter>  # DIFF-ANCHOR: a5330430
+      <intent-filter>  # DIFF-ANCHOR: dea53031
         <action android:name="org.chromium.chrome.browser.dummy.action"/>
         <category android:name="com.google.intent.category.CARDBOARD"/>
         <category android:name="com.google.intent.category.DAYDREAM"/>
-      </intent-filter>  # DIFF-ANCHOR: ad124986
+      </intent-filter>  # DIFF-ANCHOR: dea53031
       <meta-data android:name="android.app.shortcuts" android:resource="@xml/launchershortcuts"/>
-    </activity-alias>  # DIFF-ANCHOR: 67e6b59a
-    <activity-alias  # DIFF-ANCHOR: d79b0a5d
+    </activity-alias>  # DIFF-ANCHOR: 5042984f
+    <activity-alias  # DIFF-ANCHOR: dcfe2999
         android:label="@string/webapp_activity_title"
         android:name="com.google.android.apps.chrome.webapps.WebappActivity"
         android:resizeableActivity="true"
         android:supportsPictureInPicture="true"
-        android:targetActivity="org.chromium.chrome.browser.webapps.WebappActivity"/>
-    <activity-alias  # DIFF-ANCHOR: 437bfb37
+        android:targetActivity="org.chromium.chrome.browser.webapps.WebappActivity">
+    </activity-alias>  # DIFF-ANCHOR: dcfe2999
+    <activity-alias  # DIFF-ANCHOR: 8e23336d
         android:name="com.google.android.apps.chrome.webapps.WebappManager"
-        android:targetActivity="org.chromium.chrome.browser.webapps.WebappLauncherActivity"/>
-    <activity-alias  # DIFF-ANCHOR: 193687ae
+        android:targetActivity="org.chromium.chrome.browser.webapps.WebappLauncherActivity">
+    </activity-alias>  # DIFF-ANCHOR: 8e23336d
+    <activity-alias  # DIFF-ANCHOR: b4a6221b
         android:enabled="false"
         android:excludeFromRecents="true"
         android:exported="true"
         android:name="org.chromium.chrome.browser.media.AudioLauncherActivity"
         android:targetActivity="org.chromium.chrome.browser.media.MediaLauncherActivity"
         android:theme="@android:style/Theme.NoDisplay">
-      <intent-filter tools:ignore="AppLinkUrlError">  # DIFF-ANCHOR: c8fe3827
+      <intent-filter tools:ignore="AppLinkUrlError">  # DIFF-ANCHOR: 13c9b0a8
         <action android:name="android.intent.action.VIEW"/>
         <category android:name="android.intent.category.DEFAULT"/>
         <data android:mimeType="audio/*"/>
         <data android:scheme="content"/>
         <data android:scheme="file"/>
-      </intent-filter>  # DIFF-ANCHOR: c8fe3827
-    </activity-alias>  # DIFF-ANCHOR: 193687ae
+      </intent-filter>  # DIFF-ANCHOR: 13c9b0a8
+    </activity-alias>  # DIFF-ANCHOR: b4a6221b
     <meta-data android:name="android.allow_multiple_resumed_activities" android:value="true"/>
     <meta-data android:name="android.content.APP_RESTRICTIONS" android:resource="@xml/app_restrictions"/>
     <meta-data android:name="com.android.webview.WebViewLibrary" android:value="libmonochrome.so"/>
@@ -747,342 +779,388 @@
     <meta-data android:name="org.chromium.content.browser.NUM_SANDBOXED_SERVICES" android:value="40"/>
     <meta-data android:name="org.chromium.content.browser.REMOTE_MEDIA_PLAYERS" android:value="org.chromium.chrome.browser.media.remote.DefaultMediaRouteController"/>
     <meta-data android:name="org.chromium.content.browser.SMART_CLIP_PROVIDER" android:value="org.chromium.content_public.browser.SmartClipProvider"/>
-    <provider  # DIFF-ANCHOR: 7b04a994
+    <provider  # DIFF-ANCHOR: 2215b9cd
         android:authorities="$PACKAGE.ChromeBrowserProvider;$PACKAGE.browser;$PACKAGE"
         android:exported="true"
         android:name="org.chromium.chrome.browser.provider.ChromeBrowserProvider">
       <path-permission android:path="/bookmarks/search_suggest_query" android:readPermission="android.permission.GLOBAL_SEARCH"/>
-    </provider>  # DIFF-ANCHOR: 7b04a994
-    <provider  # DIFF-ANCHOR: 25126d98
+    </provider>  # DIFF-ANCHOR: 2215b9cd
+    <provider  # DIFF-ANCHOR: bfe37944
         android:authorities="$PACKAGE.DeveloperModeContentProvider"
         android:exported="true"
         android:name="org.chromium.android_webview.services.DeveloperModeContentProvider"
         android:process=":webview_service"
-        android:visibleToInstantApps="true"/>
-    <provider  # DIFF-ANCHOR: 5bca08b9
+        android:visibleToInstantApps="true">
+    </provider>  # DIFF-ANCHOR: bfe37944
+    <provider  # DIFF-ANCHOR: 97e158a1
         android:authorities="$PACKAGE.DownloadFileProvider"
         android:exported="false"
         android:grantUriPermissions="true"
         android:name="org.chromium.chrome.browser.download.DownloadFileProvider">
       <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"/>
-    </provider>  # DIFF-ANCHOR: 5bca08b9
-    <provider  # DIFF-ANCHOR: 8bf77a49
+    </provider>  # DIFF-ANCHOR: 97e158a1
+    <provider  # DIFF-ANCHOR: 6e306896
         android:authorities="$PACKAGE.FileProvider"
         android:exported="false"
         android:grantUriPermissions="true"
         android:name="org.chromium.chrome.browser.util.ChromeFileProvider">
       <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"/>
-    </provider>  # DIFF-ANCHOR: 8bf77a49
-    <provider  # DIFF-ANCHOR: 71947426
+    </provider>  # DIFF-ANCHOR: 6e306896
+    <provider  # DIFF-ANCHOR: a5e78e63
         android:authorities="$PACKAGE.LicenseContentProvider"
         android:exported="true"
         android:name="org.chromium.android_webview.nonembedded.LicenseContentProvider"
-        android:process=":webview_apk"/>
-    <receiver  # DIFF-ANCHOR: 69cbb2bd
+        android:process=":webview_apk">
+    </provider>  # DIFF-ANCHOR: a5e78e63
+    <receiver  # DIFF-ANCHOR: 1091f66b
         android:exported="false"
-        android:name="com.google.android.gms.cast.framework.media.MediaIntentReceiver"/>
-    <receiver  # DIFF-ANCHOR: 6c526882
+        android:name="com.google.android.gms.cast.framework.media.MediaIntentReceiver">
+    </receiver>  # DIFF-ANCHOR: 1091f66b
+    <receiver  # DIFF-ANCHOR: 9ef4cd0a
         android:exported="false"
-        android:name="org.chromium.chrome.browser.announcement.AnnouncementNotificationManager$Receiver"/>
-    <receiver  # DIFF-ANCHOR: 90a77f4a
+        android:name="org.chromium.chrome.browser.announcement.AnnouncementNotificationManager$Receiver">
+    </receiver>  # DIFF-ANCHOR: 9ef4cd0a
+    <receiver  # DIFF-ANCHOR: 9a0a00e8
         android:exported="false"
-        android:name="org.chromium.chrome.browser.app.send_tab_to_self.SendTabToSelfNotificationReceiver"/>
-    <receiver  # DIFF-ANCHOR: 1bf83908
+        android:name="org.chromium.chrome.browser.app.send_tab_to_self.SendTabToSelfNotificationReceiver">
+    </receiver>  # DIFF-ANCHOR: 9a0a00e8
+    <receiver  # DIFF-ANCHOR: b93ab7db
         android:exported="false"
-        android:name="org.chromium.chrome.browser.bookmarkswidget.BookmarkWidgetProxy"/>
-    <receiver  # DIFF-ANCHOR: 26e8340e
+        android:name="org.chromium.chrome.browser.bookmarkswidget.BookmarkWidgetProxy">
+    </receiver>  # DIFF-ANCHOR: b93ab7db
+    <receiver  # DIFF-ANCHOR: 3a086f97
         android:exported="false"
-        android:name="org.chromium.chrome.browser.browserservices.trustedwebactivityui.DisclosureAcceptanceBroadcastReceiver"/>
-    <receiver  # DIFF-ANCHOR: eba37b00
+        android:name="org.chromium.chrome.browser.browserservices.trustedwebactivityui.DisclosureAcceptanceBroadcastReceiver">
+    </receiver>  # DIFF-ANCHOR: 3a086f97
+    <receiver  # DIFF-ANCHOR: bccc7d87
         android:exported="false"
         android:name="org.chromium.chrome.browser.locale.LocaleChangedBroadcastReceiver">
-      <intent-filter>  # DIFF-ANCHOR: fa875e92
+      <intent-filter>  # DIFF-ANCHOR: 5458f2a2
         <action android:name="android.intent.action.LOCALE_CHANGED"/>
-      </intent-filter>  # DIFF-ANCHOR: fa875e92
-    </receiver>  # DIFF-ANCHOR: eba37b00
-    <receiver  # DIFF-ANCHOR: 93ba598d
+      </intent-filter>  # DIFF-ANCHOR: 5458f2a2
+    </receiver>  # DIFF-ANCHOR: bccc7d87
+    <receiver  # DIFF-ANCHOR: 17866e9d
         android:exported="false"
-        android:name="org.chromium.chrome.browser.notifications.NotificationIntentInterceptor$Receiver"/>
-    <receiver  # DIFF-ANCHOR: bf69fd0b
+        android:name="org.chromium.chrome.browser.notifications.NotificationIntentInterceptor$Receiver">
+    </receiver>  # DIFF-ANCHOR: 17866e9d
+    <receiver  # DIFF-ANCHOR: de24469c
         android:exported="false"
         android:name="org.chromium.chrome.browser.notifications.NotificationService$Receiver">
-      <intent-filter>  # DIFF-ANCHOR: 996a6219
+      <intent-filter>  # DIFF-ANCHOR: 1c1c5ed8
         <action android:name="org.chromium.chrome.browser.notifications.CLICK_NOTIFICATION"/>
         <action android:name="org.chromium.chrome.browser.notifications.CLOSE_NOTIFICATION"/>
-      </intent-filter>  # DIFF-ANCHOR: 996a6219
-    </receiver>  # DIFF-ANCHOR: bf69fd0b
-    <receiver  # DIFF-ANCHOR: 1935e7c
+      </intent-filter>  # DIFF-ANCHOR: 1c1c5ed8
+    </receiver>  # DIFF-ANCHOR: de24469c
+    <receiver  # DIFF-ANCHOR: e1c4d394
         android:exported="false"
-        android:name="org.chromium.chrome.browser.notifications.scheduler.DisplayAgent$Receiver"/>
-    <receiver  # DIFF-ANCHOR: 83b4a7de
+        android:name="org.chromium.chrome.browser.notifications.scheduler.DisplayAgent$Receiver">
+    </receiver>  # DIFF-ANCHOR: e1c4d394
+    <receiver  # DIFF-ANCHOR: de47f306
         android:exported="false"
-        android:name="org.chromium.chrome.browser.offlinepages.AutoFetchNotifier$CompleteNotificationReceiver"/>
-    <receiver  # DIFF-ANCHOR: a675c918
+        android:name="org.chromium.chrome.browser.offlinepages.AutoFetchNotifier$CompleteNotificationReceiver">
+    </receiver>  # DIFF-ANCHOR: de47f306
+    <receiver  # DIFF-ANCHOR: 98349cb3
         android:exported="false"
-        android:name="org.chromium.chrome.browser.offlinepages.AutoFetchNotifier$InProgressCancelReceiver"/>
-    <receiver  # DIFF-ANCHOR: 8ca151ce
+        android:name="org.chromium.chrome.browser.offlinepages.AutoFetchNotifier$InProgressCancelReceiver">
+    </receiver>  # DIFF-ANCHOR: 98349cb3
+    <receiver  # DIFF-ANCHOR: cfa3bb7f
         android:exported="false"
-        android:name="org.chromium.chrome.browser.offlinepages.prefetch.PrefetchedPagesNotifier$ClickReceiver"/>
-    <receiver  # DIFF-ANCHOR: eaa424f2
+        android:name="org.chromium.chrome.browser.offlinepages.prefetch.PrefetchedPagesNotifier$ClickReceiver">
+    </receiver>  # DIFF-ANCHOR: cfa3bb7f
+    <receiver  # DIFF-ANCHOR: 1f02dc2f
         android:exported="false"
-        android:name="org.chromium.chrome.browser.offlinepages.prefetch.PrefetchedPagesNotifier$SettingsReceiver"/>
-    <receiver  # DIFF-ANCHOR: 6438cd32
+        android:name="org.chromium.chrome.browser.offlinepages.prefetch.PrefetchedPagesNotifier$SettingsReceiver">
+    </receiver>  # DIFF-ANCHOR: 1f02dc2f
+    <receiver  # DIFF-ANCHOR: 40a69297
         android:exported="false"
-        android:name="org.chromium.chrome.browser.omaha.UpdateNotificationController$UpdateNotificationReceiver"/>
-    <receiver  # DIFF-ANCHOR: 81df5876
+        android:name="org.chromium.chrome.browser.omaha.UpdateNotificationController$UpdateNotificationReceiver">
+    </receiver>  # DIFF-ANCHOR: 40a69297
+    <receiver  # DIFF-ANCHOR: 956432e8
         android:exported="false"
-        android:name="org.chromium.chrome.browser.sharing.click_to_call.ClickToCallMessageHandler$TapReceiver"/>
-    <receiver  # DIFF-ANCHOR: f0f8380e
+        android:name="org.chromium.chrome.browser.sharing.click_to_call.ClickToCallMessageHandler$TapReceiver">
+    </receiver>  # DIFF-ANCHOR: 956432e8
+    <receiver  # DIFF-ANCHOR: cbb425dc
         android:exported="false"
-        android:name="org.chromium.chrome.browser.sharing.shared_clipboard.SharedClipboardMessageHandler$TapReceiver"/>
-    <receiver  # DIFF-ANCHOR: 2c01f887
+        android:name="org.chromium.chrome.browser.sharing.shared_clipboard.SharedClipboardMessageHandler$TapReceiver">
+    </receiver>  # DIFF-ANCHOR: cbb425dc
+    <receiver  # DIFF-ANCHOR: 729144c9
         android:exported="false"
-        android:name="org.chromium.chrome.browser.sharing.shared_clipboard.SharedClipboardMessageHandler$TryAgainReceiver"/>
-    <receiver  # DIFF-ANCHOR: c188afe9
+        android:name="org.chromium.chrome.browser.sharing.shared_clipboard.SharedClipboardMessageHandler$TryAgainReceiver">
+    </receiver>  # DIFF-ANCHOR: 729144c9
+    <receiver  # DIFF-ANCHOR: aa6748fc
         android:exported="false"
         android:name="org.chromium.chrome.browser.upgrade.PackageReplacedBroadcastReceiver">
-      <intent-filter>  # DIFF-ANCHOR: d4b9350a
+      <intent-filter>  # DIFF-ANCHOR: e8cce90c
         <action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>
-      </intent-filter>  # DIFF-ANCHOR: d4b9350a
-    </receiver>  # DIFF-ANCHOR: c188afe9
-    <receiver  # DIFF-ANCHOR: 3fa7b55c
+      </intent-filter>  # DIFF-ANCHOR: e8cce90c
+    </receiver>  # DIFF-ANCHOR: aa6748fc
+    <receiver  # DIFF-ANCHOR: 3e5f56cb
         android:exported="false"
-        android:name="org.chromium.components.background_task_scheduler.internal.BackgroundTaskBroadcastReceiver"/>
-    <receiver  # DIFF-ANCHOR: 5150dcbe
+        android:name="org.chromium.components.background_task_scheduler.internal.BackgroundTaskBroadcastReceiver">
+    </receiver>  # DIFF-ANCHOR: 3e5f56cb
+    <receiver  # DIFF-ANCHOR: 0ea504ef
         android:exported="true"
         android:name="com.google.android.gms.gcm.GcmReceiver"
         android:permission="com.google.android.c2dm.permission.SEND">
-      <intent-filter>  # DIFF-ANCHOR: 8c951239
+      <intent-filter>  # DIFF-ANCHOR: aae22013
         <action android:name="com.google.android.c2dm.intent.RECEIVE"/>
         <action android:name="com.google.android.c2dm.intent.REGISTRATION"/>
         <category android:name="$PACKAGE"/>
-      </intent-filter>  # DIFF-ANCHOR: 8c951239
-    </receiver>  # DIFF-ANCHOR: 5150dcbe
-    <receiver  # DIFF-ANCHOR: cd683ecb
+      </intent-filter>  # DIFF-ANCHOR: aae22013
+    </receiver>  # DIFF-ANCHOR: 0ea504ef
+    <receiver  # DIFF-ANCHOR: 3e596004
         android:exported="true"
         android:name="org.chromium.chrome.browser.browserservices.ClientAppBroadcastReceiver">
-      <intent-filter>  # DIFF-ANCHOR: 2441713a
+      <intent-filter>  # DIFF-ANCHOR: e5bb6a36
         <action android:name="android.intent.action.PACKAGE_DATA_CLEARED"/>
         <action android:name="android.intent.action.PACKAGE_FULLY_REMOVED"/>
         <data android:scheme="package"/>
-      </intent-filter>  # DIFF-ANCHOR: 2441713a
-    </receiver>  # DIFF-ANCHOR: cd683ecb
-    <receiver  # DIFF-ANCHOR: 21a02c7f
+      </intent-filter>  # DIFF-ANCHOR: e5bb6a36
+    </receiver>  # DIFF-ANCHOR: 3e596004
+    <receiver  # DIFF-ANCHOR: 93e73992
         android:exported="true"
         android:name="org.chromium.chrome.browser.sharing.click_to_call.ClickToCallMessageHandler$PhoneUnlockedReceiver">
-      <intent-filter>  # DIFF-ANCHOR: 3376741e
+      <intent-filter>  # DIFF-ANCHOR: 4b5ec7a9
         <action android:name="android.intent.action.USER_PRESENT"/>
-      </intent-filter>  # DIFF-ANCHOR: 3376741e
-    </receiver>  # DIFF-ANCHOR: 21a02c7f
-    <receiver  # DIFF-ANCHOR: 2adb81c1
+      </intent-filter>  # DIFF-ANCHOR: 4b5ec7a9
+    </receiver>  # DIFF-ANCHOR: 93e73992
+    <receiver  # DIFF-ANCHOR: 7d221226
         android:label="@string/bookmark_widget_title"
         android:name="com.google.android.apps.chrome.appwidget.bookmarks.BookmarkThumbnailWidgetProvider">
-      <intent-filter>  # DIFF-ANCHOR: 5d4f51d1
+      <intent-filter>  # DIFF-ANCHOR: 1ebe78e9
         <action android:name=".BOOKMARK_APPWIDGET_UPDATE"/>
         <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
-      </intent-filter>  # DIFF-ANCHOR: 5d4f51d1
+      </intent-filter>  # DIFF-ANCHOR: 1ebe78e9
       <meta-data android:name="android.appwidget.provider" android:resource="@xml/bookmark_widget_info"/>
-    </receiver>  # DIFF-ANCHOR: 2adb81c1
-    <receiver  # DIFF-ANCHOR: e42bcf7f
+    </receiver>  # DIFF-ANCHOR: 7d221226
+    <receiver  # DIFF-ANCHOR: 3664f7eb
         android:label="@string/search_widget_title"
         android:name="org.chromium.chrome.browser.searchwidget.SearchWidgetProvider">
-      <intent-filter>  # DIFF-ANCHOR: 7ec97164
+      <intent-filter>  # DIFF-ANCHOR: 4ed161a4
         <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
-      </intent-filter>  # DIFF-ANCHOR: 7ec97164
-      <intent-filter>  # DIFF-ANCHOR: bb85582a
+      </intent-filter>  # DIFF-ANCHOR: 4ed161a4
+      <intent-filter>  # DIFF-ANCHOR: 92485a5d
         <action android:name="org.chromium.chrome.browser.searchwidget.START_TEXT_QUERY"/>
-      </intent-filter>  # DIFF-ANCHOR: bb85582a
-      <intent-filter>  # DIFF-ANCHOR: 18b2f9b2
+      </intent-filter>  # DIFF-ANCHOR: 92485a5d
+      <intent-filter>  # DIFF-ANCHOR: 444cf2a4
         <action android:name="org.chromium.chrome.browser.searchwidget.START_VOICE_QUERY"/>
-      </intent-filter>  # DIFF-ANCHOR: 18b2f9b2
-      <intent-filter>  # DIFF-ANCHOR: 68d261de
+      </intent-filter>  # DIFF-ANCHOR: 444cf2a4
+      <intent-filter>  # DIFF-ANCHOR: fc048873
         <action android:name="org.chromium.chrome.browser.searchwidget.UPDATE_ALL_WIDGETS"/>
-      </intent-filter>  # DIFF-ANCHOR: 68d261de
+      </intent-filter>  # DIFF-ANCHOR: fc048873
       <meta-data android:name="android.appwidget.provider" android:resource="@xml/search_widget_info"/>
-    </receiver>  # DIFF-ANCHOR: e42bcf7f
-    <receiver android:name="org.chromium.chrome.browser.services.AccountsChangedReceiver">  # DIFF-ANCHOR: 2f954a4e
-      <intent-filter>  # DIFF-ANCHOR: dda0015b
+    </receiver>  # DIFF-ANCHOR: 3664f7eb
+    <receiver android:name="org.chromium.chrome.browser.services.AccountsChangedReceiver">  # DIFF-ANCHOR: 4de2a279
+      <intent-filter>  # DIFF-ANCHOR: 6a188b57
         <action android:name="android.accounts.LOGIN_ACCOUNTS_CHANGED"/>
-      </intent-filter>  # DIFF-ANCHOR: dda0015b
-    </receiver>  # DIFF-ANCHOR: 2f954a4e
-    <service  # DIFF-ANCHOR: cb679965
+      </intent-filter>  # DIFF-ANCHOR: 6a188b57
+    </receiver>  # DIFF-ANCHOR: 4de2a279
+    <service  # DIFF-ANCHOR: 53256720
         android:description="@string/decoder_description"
         android:exported="false"
         android:isolatedProcess="true"
         android:name="org.chromium.chrome.browser.photo_picker.DecoderService"
-        android:process=":decoder_service"/>
-    <service  # DIFF-ANCHOR: e8b1a590
+        android:process=":decoder_service">
+    </service>  # DIFF-ANCHOR: 53256720
+    <service  # DIFF-ANCHOR: 0c6c4fd9
         android:exported="false"
         android:isolatedProcess="false"
         android:name="org.chromium.content.app.PrivilegedProcessService0"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":privileged_process0"/>
-    <service  # DIFF-ANCHOR: 4a4a6a58
+        android:process=":privileged_process0">
+    </service>  # DIFF-ANCHOR: 0c6c4fd9
+    <service  # DIFF-ANCHOR: 6f89af32
         android:exported="false"
         android:isolatedProcess="false"
         android:name="org.chromium.content.app.PrivilegedProcessService1"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":privileged_process1"/>
-    <service  # DIFF-ANCHOR: 95fccd84
+        android:process=":privileged_process1">
+    </service>  # DIFF-ANCHOR: 6f89af32
+    <service  # DIFF-ANCHOR: 40e0d738
         android:exported="false"
         android:isolatedProcess="false"
         android:name="org.chromium.content.app.PrivilegedProcessService2"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":privileged_process2"/>
-    <service  # DIFF-ANCHOR: 28107274
+        android:process=":privileged_process2">
+    </service>  # DIFF-ANCHOR: 40e0d738
+    <service  # DIFF-ANCHOR: b197517d
         android:exported="false"
         android:isolatedProcess="false"
         android:name="org.chromium.content.app.PrivilegedProcessService3"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":privileged_process3"/>
-    <service  # DIFF-ANCHOR: fef3fab8
+        android:process=":privileged_process3">
+    </service>  # DIFF-ANCHOR: b197517d
+    <service  # DIFF-ANCHOR: 52303702
         android:exported="false"
         android:isolatedProcess="false"
         android:name="org.chromium.content.app.PrivilegedProcessService4"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":privileged_process4"/>
-    <service  # DIFF-ANCHOR: 3993e711
+        android:process=":privileged_process4">
+    </service>  # DIFF-ANCHOR: 52303702
+    <service  # DIFF-ANCHOR: 41539e3c
         android:exported="false"
-        android:name="com.google.android.gms.cast.framework.ReconnectionService"/>
-    <service  # DIFF-ANCHOR: 3833fcec
+        android:name="com.google.android.gms.cast.framework.ReconnectionService">
+    </service>  # DIFF-ANCHOR: 41539e3c
+    <service  # DIFF-ANCHOR: 7dad1ec5
         android:exported="false"
-        android:name="com.google.android.gms.cast.framework.media.MediaNotificationService"/>
-    <service  # DIFF-ANCHOR: 60aeec85
+        android:name="com.google.android.gms.cast.framework.media.MediaNotificationService">
+    </service>  # DIFF-ANCHOR: 7dad1ec5
+    <service  # DIFF-ANCHOR: 65cddb26
         android:exported="false"
         android:name="org.chromium.android_webview.services.AwVariationsSeedFetcher"
         android:permission="android.permission.BIND_JOB_SERVICE"
-        android:process=":webview_service"/>
-    <service  # DIFF-ANCHOR: 72b33f0f
+        android:process=":webview_service">
+    </service>  # DIFF-ANCHOR: 65cddb26
+    <service  # DIFF-ANCHOR: adce9ea1
         android:exported="false"
         android:name="org.chromium.android_webview.services.DeveloperUiService"
-        android:process=":webview_service"/>
-    <service  # DIFF-ANCHOR: 3f857fa7
+        android:process=":webview_service">
+    </service>  # DIFF-ANCHOR: adce9ea1
+    <service  # DIFF-ANCHOR: ac44dbad
         android:exported="false"
         android:name="org.chromium.chrome.browser.bookmarkswidget.BookmarkWidgetService"
-        android:permission="android.permission.BIND_REMOTEVIEWS"/>
-    <service  # DIFF-ANCHOR: 2189666a
+        android:permission="android.permission.BIND_REMOTEVIEWS">
+    </service>  # DIFF-ANCHOR: ac44dbad
+    <service  # DIFF-ANCHOR: 90d2ec9b
         android:exported="false"
         android:name="org.chromium.chrome.browser.crash.ChromeMinidumpUploadJobService"
-        android:permission="android.permission.BIND_JOB_SERVICE"/>
-    <service  # DIFF-ANCHOR: c90e4a72
+        android:permission="android.permission.BIND_JOB_SERVICE">
+    </service>  # DIFF-ANCHOR: 90d2ec9b
+    <service  # DIFF-ANCHOR: 2ce0b6a4
         android:exported="false"
-        android:name="org.chromium.chrome.browser.crash.MinidumpUploadService"/>
-    <service  # DIFF-ANCHOR: 23f4e84e
+        android:name="org.chromium.chrome.browser.crash.MinidumpUploadService">
+    </service>  # DIFF-ANCHOR: 2ce0b6a4
+    <service  # DIFF-ANCHOR: 555432db
         android:exported="false"
-        android:name="org.chromium.chrome.browser.download.DownloadBroadcastManager"/>
-    <service  # DIFF-ANCHOR: 96e7f1c5
+        android:name="org.chromium.chrome.browser.download.DownloadBroadcastManager">
+    </service>  # DIFF-ANCHOR: 555432db
+    <service  # DIFF-ANCHOR: 4cf14268
         android:exported="false"
-        android:name="org.chromium.chrome.browser.download.DownloadForegroundService"/>
-    <service  # DIFF-ANCHOR: de7eeb6f
+        android:name="org.chromium.chrome.browser.download.DownloadForegroundService">
+    </service>  # DIFF-ANCHOR: 4cf14268
+    <service  # DIFF-ANCHOR: a651602a
         android:exported="false"
-        android:name="org.chromium.chrome.browser.incognito.IncognitoNotificationService"/>
-    <service  # DIFF-ANCHOR: 755973a5
+        android:name="org.chromium.chrome.browser.incognito.IncognitoNotificationService">
+    </service>  # DIFF-ANCHOR: a651602a
+    <service  # DIFF-ANCHOR: bd027029
         android:exported="false"
         android:name="org.chromium.chrome.browser.invalidation.ChromeBrowserSyncAdapterService">
-      <intent-filter>  # DIFF-ANCHOR: 6c973a7d
+      <intent-filter>  # DIFF-ANCHOR: 3e31084a
         <action android:name="android.content.SyncAdapter"/>
-      </intent-filter>  # DIFF-ANCHOR: 6c973a7d
+      </intent-filter>  # DIFF-ANCHOR: 3e31084a
       <meta-data android:name="android.content.SyncAdapter" android:resource="@xml/syncadapter"/>
-    </service>  # DIFF-ANCHOR: 755973a5
-    <service  # DIFF-ANCHOR: d5a051d0
+    </service>  # DIFF-ANCHOR: bd027029
+    <service  # DIFF-ANCHOR: 4f8e62ea
         android:exported="false"
-        android:name="org.chromium.chrome.browser.media.MediaCaptureNotificationService"/>
-    <service  # DIFF-ANCHOR: 5a2c1348
+        android:name="org.chromium.chrome.browser.media.MediaCaptureNotificationService">
+    </service>  # DIFF-ANCHOR: 4f8e62ea
+    <service  # DIFF-ANCHOR: 63d24cf5
         android:exported="false"
         android:name="org.chromium.chrome.browser.media.ui.ChromeMediaNotificationControllerDelegate$CastListenerService">
-      <intent-filter>  # DIFF-ANCHOR: c11fb724
+      <intent-filter>  # DIFF-ANCHOR: f401157d
         <action android:name="android.intent.action.MEDIA_BUTTON"/>
-      </intent-filter>  # DIFF-ANCHOR: c11fb724
-    </service>  # DIFF-ANCHOR: 5a2c1348
-    <service  # DIFF-ANCHOR: 42ed3896
+      </intent-filter>  # DIFF-ANCHOR: f401157d
+    </service>  # DIFF-ANCHOR: 63d24cf5
+    <service  # DIFF-ANCHOR: a4f153af
         android:exported="false"
         android:name="org.chromium.chrome.browser.media.ui.ChromeMediaNotificationControllerDelegate$PlaybackListenerService">
-      <intent-filter>  # DIFF-ANCHOR: c11fb724
+      <intent-filter>  # DIFF-ANCHOR: f401157d
         <action android:name="android.intent.action.MEDIA_BUTTON"/>
-      </intent-filter>  # DIFF-ANCHOR: c11fb724
-    </service>  # DIFF-ANCHOR: 42ed3896
-    <service  # DIFF-ANCHOR: d8c248a9
+      </intent-filter>  # DIFF-ANCHOR: f401157d
+    </service>  # DIFF-ANCHOR: a4f153af
+    <service  # DIFF-ANCHOR: 365e9d83
         android:exported="false"
         android:name="org.chromium.chrome.browser.media.ui.ChromeMediaNotificationControllerDelegate$PresentationListenerService">
-      <intent-filter>  # DIFF-ANCHOR: c11fb724
+      <intent-filter>  # DIFF-ANCHOR: f401157d
         <action android:name="android.intent.action.MEDIA_BUTTON"/>
-      </intent-filter>  # DIFF-ANCHOR: c11fb724
-    </service>  # DIFF-ANCHOR: d8c248a9
-    <service  # DIFF-ANCHOR: fd141652
+      </intent-filter>  # DIFF-ANCHOR: f401157d
+    </service>  # DIFF-ANCHOR: 365e9d83
+    <service  # DIFF-ANCHOR: 4b2220c4
         android:exported="false"
         android:name="org.chromium.chrome.browser.notifications.NotificationJobService"
-        android:permission="android.permission.BIND_JOB_SERVICE"/>
-    <service  # DIFF-ANCHOR: c31b12ea
+        android:permission="android.permission.BIND_JOB_SERVICE">
+    </service>  # DIFF-ANCHOR: 4b2220c4
+    <service  # DIFF-ANCHOR: 3224d309
         android:exported="false"
-        android:name="org.chromium.chrome.browser.notifications.NotificationService"/>
+        android:name="org.chromium.chrome.browser.notifications.NotificationService">
+    </service>  # DIFF-ANCHOR: 3224d309
     <service android:exported="false" android:name="org.chromium.chrome.browser.omaha.OmahaClient"/>
-    <service  # DIFF-ANCHOR: e276993e
+    <service  # DIFF-ANCHOR: d930289b
         android:exported="false"
         android:name="org.chromium.chrome.browser.services.gcm.ChromeGcmListenerService">
-      <intent-filter>  # DIFF-ANCHOR: 84d0a85e
+      <intent-filter>  # DIFF-ANCHOR: aae22013
         <action android:name="com.google.android.c2dm.intent.RECEIVE"/>
-      </intent-filter>  # DIFF-ANCHOR: 84d0a85e
-    </service>  # DIFF-ANCHOR: e276993e
-    <service  # DIFF-ANCHOR: c616f3cb
+      </intent-filter>  # DIFF-ANCHOR: aae22013
+    </service>  # DIFF-ANCHOR: d930289b
+    <service  # DIFF-ANCHOR: 682abdc1
         android:exported="false"
-        android:name="org.chromium.chrome.browser.services.gcm.GCMBackgroundService"/>
-    <service  # DIFF-ANCHOR: b0c6ffa3
+        android:name="org.chromium.chrome.browser.services.gcm.GCMBackgroundService">
+    </service>  # DIFF-ANCHOR: 682abdc1
+    <service  # DIFF-ANCHOR: dfb5da84
         android:exported="false"
-        android:name="org.chromium.chrome.browser.services.gcm.InvalidationGcmUpstreamSender"/>
-    <service  # DIFF-ANCHOR: 302f517b
+        android:name="org.chromium.chrome.browser.services.gcm.InvalidationGcmUpstreamSender">
+    </service>  # DIFF-ANCHOR: dfb5da84
+    <service  # DIFF-ANCHOR: 80f6a8e5
         android:exported="false"
-        android:name="org.chromium.chrome.browser.tracing.TracingNotificationService"/>
-    <service  # DIFF-ANCHOR: c97b9e14
+        android:name="org.chromium.chrome.browser.tracing.TracingNotificationService">
+    </service>  # DIFF-ANCHOR: 80f6a8e5
+    <service  # DIFF-ANCHOR: a550decc
         android:exported="false"
         android:name="org.chromium.components.background_task_scheduler.internal.BackgroundTaskJobService"
-        android:permission="android.permission.BIND_JOB_SERVICE"/>
-    <service  # DIFF-ANCHOR: a927ca85
+        android:permission="android.permission.BIND_JOB_SERVICE">
+    </service>  # DIFF-ANCHOR: a550decc
+    <service  # DIFF-ANCHOR: 4c2196d9
         android:exported="true"
         android:name="com.google.ipc.invalidation.ticl.android2.channel.GcmRegistrationTaskService"
         android:permission="com.google.android.gms.permission.BIND_NETWORK_TASK_SERVICE">
-      <intent-filter>  # DIFF-ANCHOR: bfec5949
+      <intent-filter>  # DIFF-ANCHOR: 99686c45
         <action android:name="com.google.android.gms.gcm.ACTION_TASK_READY"/>
-      </intent-filter>  # DIFF-ANCHOR: bfec5949
-    </service>  # DIFF-ANCHOR: a927ca85
-    <service  # DIFF-ANCHOR: 4eb5ab8c
+      </intent-filter>  # DIFF-ANCHOR: 99686c45
+    </service>  # DIFF-ANCHOR: 4c2196d9
+    <service  # DIFF-ANCHOR: 3cd6d713
         android:exported="true"
         android:name="org.chromium.android_webview.services.AwMinidumpUploadJobService"
         android:permission="android.permission.BIND_JOB_SERVICE"
-        android:process=":webview_service"/>
-    <service  # DIFF-ANCHOR: 7968f7fd
+        android:process=":webview_service">
+    </service>  # DIFF-ANCHOR: 3cd6d713
+    <service  # DIFF-ANCHOR: 5cda9608
         android:exported="true"
         android:name="org.chromium.android_webview.services.CrashReceiverService"
-        android:process=":webview_service"/>
-    <service  # DIFF-ANCHOR: 4e4e6b4
+        android:process=":webview_service">
+    </service>  # DIFF-ANCHOR: 5cda9608
+    <service  # DIFF-ANCHOR: eecf2fee
         android:exported="true"
         android:name="org.chromium.android_webview.services.MetricsBridgeService"
         android:process=":webview_service"
-        android:visibleToInstantApps="true"/>
-    <service  # DIFF-ANCHOR: 55d21b90
+        android:visibleToInstantApps="true">
+    </service>  # DIFF-ANCHOR: eecf2fee
+    <service  # DIFF-ANCHOR: dc926e35
         android:exported="true"
         android:name="org.chromium.android_webview.services.VariationsSeedServer"
-        android:process=":webview_service"/>
-    <service  # DIFF-ANCHOR: 964f81d7
+        android:process=":webview_service">
+    </service>  # DIFF-ANCHOR: dc926e35
+    <service  # DIFF-ANCHOR: c34d99ad
         android:exported="true"
         android:name="org.chromium.chrome.browser.ChromeBackgroundService"
         android:permission="com.google.android.gms.permission.BIND_NETWORK_TASK_SERVICE">
-      <intent-filter>  # DIFF-ANCHOR: bfec5949
+      <intent-filter>  # DIFF-ANCHOR: 99686c45
         <action android:name="com.google.android.gms.gcm.ACTION_TASK_READY"/>
-      </intent-filter>  # DIFF-ANCHOR: bfec5949
-    </service>  # DIFF-ANCHOR: 964f81d7
-    <service  # DIFF-ANCHOR: b702e25d
+      </intent-filter>  # DIFF-ANCHOR: 99686c45
+    </service>  # DIFF-ANCHOR: c34d99ad
+    <service  # DIFF-ANCHOR: 8fc286d0
         android:exported="true"
         android:name="org.chromium.components.background_task_scheduler.internal.BackgroundTaskGcmTaskService"
         android:permission="com.google.android.gms.permission.BIND_NETWORK_TASK_SERVICE">
-      <intent-filter>  # DIFF-ANCHOR: bfec5949
+      <intent-filter>  # DIFF-ANCHOR: 99686c45
         <action android:name="com.google.android.gms.gcm.ACTION_TASK_READY"/>
-      </intent-filter>  # DIFF-ANCHOR: bfec5949
-    </service>  # DIFF-ANCHOR: b702e25d
-    <service  # DIFF-ANCHOR: 44246b4
+      </intent-filter>  # DIFF-ANCHOR: 99686c45
+    </service>  # DIFF-ANCHOR: 8fc286d0
+    <service  # DIFF-ANCHOR: 2ce68981
         android:exported="true"
-        android:name="org.chromium.components.payments.PaymentDetailsUpdateService"/>
+        android:name="org.chromium.components.payments.PaymentDetailsUpdateService">
+    </service>  # DIFF-ANCHOR: 2ce68981
     <service android:name="androidx.browser.customtabs.PostMessageService"/>
-    <service  # DIFF-ANCHOR: 943b94
+    <service  # DIFF-ANCHOR: b1e3e8bd
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1091,8 +1169,9 @@
         android:process=":sandboxed_process0"
         android:useAppZygote="true"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 35a912af
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: b1e3e8bd
+    <service  # DIFF-ANCHOR: 76d1ccf8
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1100,8 +1179,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process1"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 67829235
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 76d1ccf8
+    <service  # DIFF-ANCHOR: 38b95266
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1109,8 +1189,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process10"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 73684155
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 38b95266
+    <service  # DIFF-ANCHOR: e4a2e4a2
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1118,8 +1199,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process11"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 2e2852f5
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: e4a2e4a2
+    <service  # DIFF-ANCHOR: d9b2ffba
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1127,8 +1209,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process12"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: d5e55e95
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: d9b2ffba
+    <service  # DIFF-ANCHOR: b41bb17d
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1136,8 +1219,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process13"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: b81ee5c5
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: b41bb17d
+    <service  # DIFF-ANCHOR: aec0ea21
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1145,8 +1229,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process14"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 391153e5
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: aec0ea21
+    <service  # DIFF-ANCHOR: cf88a5e5
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1154,8 +1239,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process15"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 4e6b6575
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: cf88a5e5
+    <service  # DIFF-ANCHOR: 7d85889d
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1163,8 +1249,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process16"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 1de0ed25
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 7d85889d
+    <service  # DIFF-ANCHOR: dae26ed4
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1172,8 +1259,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process17"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 98cf7da5
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: dae26ed4
+    <service  # DIFF-ANCHOR: 2c6cf029
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1181,8 +1269,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process18"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 66b09905
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 2c6cf029
+    <service  # DIFF-ANCHOR: 1d2f0988
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1190,8 +1279,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process19"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: b2a19bdf
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 1d2f0988
+    <service  # DIFF-ANCHOR: 4a39041b
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1199,8 +1289,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process2"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 927feb95
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 4a39041b
+    <service  # DIFF-ANCHOR: 073533bf
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1208,8 +1299,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process20"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 7b063f35
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 073533bf
+    <service  # DIFF-ANCHOR: d24da41d
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1217,8 +1309,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process21"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: b5081035
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: d24da41d
+    <service  # DIFF-ANCHOR: 594d8b32
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1226,8 +1319,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process22"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 1cd38c35
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 594d8b32
+    <service  # DIFF-ANCHOR: 5528c0c3
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1235,8 +1329,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process23"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 1b147f85
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 5528c0c3
+    <service  # DIFF-ANCHOR: b7ab2ba3
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1244,8 +1339,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process24"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 960d0425
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: b7ab2ba3
+    <service  # DIFF-ANCHOR: cec6cb64
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1253,8 +1349,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process25"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 27ac8d45
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: cec6cb64
+    <service  # DIFF-ANCHOR: 5b4a00fe
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1262,8 +1359,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process26"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 47d33035
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 5b4a00fe
+    <service  # DIFF-ANCHOR: ad49d203
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1271,8 +1369,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process27"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 28eaa0c5
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: ad49d203
+    <service  # DIFF-ANCHOR: 573298e9
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1280,8 +1379,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process28"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 1f8e17a5
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 573298e9
+    <service  # DIFF-ANCHOR: 79897b32
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1289,8 +1389,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process29"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 48ca2e47
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 79897b32
+    <service  # DIFF-ANCHOR: 84335864
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1298,8 +1399,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process3"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 5c70a30d
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 84335864
+    <service  # DIFF-ANCHOR: c4bd371e
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1307,8 +1409,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process30"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 53066d
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: c4bd371e
+    <service  # DIFF-ANCHOR: 394a9fd0
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1316,8 +1419,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process31"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: b4f1725d
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 394a9fd0
+    <service  # DIFF-ANCHOR: b811afb8
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1325,8 +1429,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process32"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 5df0ea7d
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: b811afb8
+    <service  # DIFF-ANCHOR: 2811ddd3
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1334,8 +1439,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process33"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 6eb3150d
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 2811ddd3
+    <service  # DIFF-ANCHOR: 73ae1688
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1343,8 +1449,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process34"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 148c14ad
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 73ae1688
+    <service  # DIFF-ANCHOR: c476f324
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1352,8 +1459,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process35"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 547bf5dd
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: c476f324
+    <service  # DIFF-ANCHOR: 75d5304b
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1361,8 +1469,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process36"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 4ceb5e3d
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 75d5304b
+    <service  # DIFF-ANCHOR: dc6d0617
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1370,8 +1479,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process37"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: f74269d
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: dc6d0617
+    <service  # DIFF-ANCHOR: e31efe49
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1379,8 +1489,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process38"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 6bbc94bd
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: e31efe49
+    <service  # DIFF-ANCHOR: 5736507e
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1388,8 +1499,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process39"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: f09ca567
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 5736507e
+    <service  # DIFF-ANCHOR: a161be24
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1397,8 +1509,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process4"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: d982666f
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: a161be24
+    <service  # DIFF-ANCHOR: 8e591688
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1406,8 +1519,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process5"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: f755947f
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 8e591688
+    <service  # DIFF-ANCHOR: 705141d0
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1415,8 +1529,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process6"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 30afda27
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 705141d0
+    <service  # DIFF-ANCHOR: 38ed2189
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1424,8 +1539,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process7"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 36c519b7
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 38ed2189
+    <service  # DIFF-ANCHOR: aa417956
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1433,8 +1549,9 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process8"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 3f67adbf
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: aa417956
+    <service  # DIFF-ANCHOR: e2f3bbbd
         android:exported="true"
         android:externalService="true"
         android:isolatedProcess="true"
@@ -1442,12 +1559,13 @@
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process9"
         android:visibleToInstantApps="true"
-        tools:ignore="ExportedService"/>
-    <service  # DIFF-ANCHOR: 794db76d
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: e2f3bbbd
+    <service  # DIFF-ANCHOR: ee1c39a8
         android:exported="true"
         android:name="org.chromium.chrome.browser.customtabs.CustomTabsConnectionService"
         tools:ignore="ExportedService">
-      <intent-filter>  # DIFF-ANCHOR: b3ec9de2
+      <intent-filter>  # DIFF-ANCHOR: d46bf795
         <action android:name="android.support.customtabs.action.CustomTabsService"/>
         <category android:name="androidx.browser.customtabs.category.ColorSchemeCustomization"/>
         <category android:name="androidx.browser.customtabs.category.NavBarColorCustomization"/>
@@ -1455,11 +1573,12 @@
         <category android:name="androidx.browser.trusted.category.TrustedWebActivities"/>
         <category android:name="androidx.browser.trusted.category.TrustedWebActivitySplashScreensV1"/>
         <category android:name="androidx.browser.trusted.category.WebShareTargetV2"/>
-      </intent-filter>  # DIFF-ANCHOR: b3ec9de2
-    </service>  # DIFF-ANCHOR: 794db76d
-    <service  # DIFF-ANCHOR: d22e975a
+      </intent-filter>  # DIFF-ANCHOR: d46bf795
+    </service>  # DIFF-ANCHOR: ee1c39a8
+    <service  # DIFF-ANCHOR: 064aae37
         android:exported="true"
         android:name="org.chromium.chrome.browser.prerender.ChromePrerenderService"
-        tools:ignore="ExportedService"/>
-  </application>  # DIFF-ANCHOR: c9a6872
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 064aae37
+  </application>
 </manifest>
diff --git a/chrome/android/expectations/trichrome_chrome_bundle.AndroidManifest.expected b/chrome/android/expectations/trichrome_chrome_bundle.AndroidManifest.expected
index 9d790cbf..06e44d1 100644
--- a/chrome/android/expectations/trichrome_chrome_bundle.AndroidManifest.expected
+++ b/chrome/android/expectations/trichrome_chrome_bundle.AndroidManifest.expected
@@ -61,7 +61,7 @@
   <permission android:name="$PACKAGE.permission.C2D_MESSAGE" android:protectionLevel="signature"/>
   <permission android:name="$PACKAGE.TOS_ACKED" android:protectionLevel="signatureOrSystem"/>
   <permission android:label="Debug web pages" android:name="$PACKAGE.permission.DEBUG" android:permissionGroup="android.permission-group.DEVELOPMENT_TOOLS" android:protectionLevel="signature"/>
-  <application  # DIFF-ANCHOR: 1b98dacf
+  <application
       android:allowBackup="false"
       android:extractNativeLibs="false"
       android:icon="@drawable/ic_launcher"
@@ -75,7 +75,7 @@
       android:supportsRtl="true"
       android:use32bitAbi="true"
       android:zygotePreloadName="org.chromium.content.app.ZygotePreload">
-    <activity  # DIFF-ANCHOR: ee659b1a
+    <activity  # DIFF-ANCHOR: 2121eb0d
         android:autoRemoveFromRecents="true"
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:excludeFromRecents="true"
@@ -83,8 +83,9 @@
         android:launchMode="singleInstance"
         android:name="org.chromium.chrome.browser.firstrun.FirstRunActivity"
         android:theme="@style/Theme.Chromium.DialogWhenLarge"
-        android:windowSoftInputMode="stateHidden|adjustPan"/>
-    <activity  # DIFF-ANCHOR: 4f86360c
+        android:windowSoftInputMode="stateHidden|adjustPan">
+    </activity>  # DIFF-ANCHOR: 2121eb0d
+    <activity  # DIFF-ANCHOR: 67932092
         android:autoRemoveFromRecents="true"
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:excludeFromRecents="true"
@@ -92,8 +93,9 @@
         android:launchMode="singleInstance"
         android:name="org.chromium.chrome.browser.firstrun.LightweightFirstRunActivity"
         android:theme="@style/Theme.Chromium.AlertDialog.NoActionBar"
-        android:windowSoftInputMode="stateHidden|adjustPan"/>
-    <activity  # DIFF-ANCHOR: a707c56a
+        android:windowSoftInputMode="stateHidden|adjustPan">
+    </activity>  # DIFF-ANCHOR: 67932092
+    <activity  # DIFF-ANCHOR: bb612a34
         android:autoRemoveFromRecents="true"
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:excludeFromRecents="true"
@@ -101,12 +103,14 @@
         android:launchMode="singleInstance"
         android:name="org.chromium.chrome.browser.firstrun.TabbedModeFirstRunActivity"
         android:theme="@style/Theme.Chromium.TabbedMode"
-        android:windowSoftInputMode="stateHidden|adjustPan"/>
-    <activity  # DIFF-ANCHOR: be0a95a0
+        android:windowSoftInputMode="stateHidden|adjustPan">
+    </activity>  # DIFF-ANCHOR: bb612a34
+    <activity  # DIFF-ANCHOR: 8492e3fd
         android:autoRemoveFromRecents="true"
         android:name="org.chromium.chrome.browser.sync.ui.PassphraseActivity"
-        android:theme="@style/Theme.Chromium.Activity"/>
-    <activity  # DIFF-ANCHOR: 78e0b102
+        android:theme="@style/Theme.Chromium.Activity">
+    </activity>  # DIFF-ANCHOR: 8492e3fd
+    <activity  # DIFF-ANCHOR: 7468a722
         android:clearTaskOnLaunch="true"
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:excludeFromRecents="true"
@@ -117,15 +121,17 @@
         android:name="org.chromium.chrome.browser.searchwidget.SearchActivity"
         android:taskAffinity=""
         android:theme="@style/Theme.Chromium.SearchActivity"
-        android:windowSoftInputMode="adjustResize"/>
-    <activity  # DIFF-ANCHOR: cfaf0e7a
+        android:windowSoftInputMode="adjustResize">
+    </activity>  # DIFF-ANCHOR: 7468a722
+    <activity  # DIFF-ANCHOR: 28dc9019
         android:configChanges="keyboardHidden|orientation|screenSize"
         android:excludeFromRecents="true"
         android:exported="false"
         android:launchMode="singleTop"
         android:name="com.google.ar.core.InstallActivity"
-        android:theme="@android:style/Theme.Material.Light.Dialog.Alert"/>
-    <activity  # DIFF-ANCHOR: 37132267
+        android:theme="@android:style/Theme.Material.Light.Dialog.Alert">
+    </activity>  # DIFF-ANCHOR: 28dc9019
+    <activity  # DIFF-ANCHOR: 44158f9b
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:enabled="false"
         android:excludeFromRecents="true"
@@ -135,13 +141,13 @@
         android:name="org.chromium.chrome.browser.sharing.shared_clipboard.SharedClipboardShareActivity"
         android:noHistory="true"
         android:theme="@style/Theme.Chromium.Activity.TranslucentNoAnimations">
-      <intent-filter>  # DIFF-ANCHOR: 5860c6b5
+      <intent-filter>  # DIFF-ANCHOR: 4ee601b7
         <action android:name="android.intent.action.SEND"/>
         <category android:name="android.intent.category.DEFAULT"/>
         <data android:mimeType="text/plain"/>
-      </intent-filter>  # DIFF-ANCHOR: 5860c6b5
-    </activity>  # DIFF-ANCHOR: 37132267
-    <activity  # DIFF-ANCHOR: 334ee6dc
+      </intent-filter>  # DIFF-ANCHOR: 4ee601b7
+    </activity>  # DIFF-ANCHOR: 44158f9b
+    <activity  # DIFF-ANCHOR: dc9ccfb7
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:enabled="false"
         android:excludeFromRecents="true"
@@ -151,13 +157,13 @@
         android:name="org.chromium.chrome.browser.share.qrcode.QrCodeShareActivity"
         android:noHistory="true"
         android:theme="@android:style/Theme.NoDisplay">
-      <intent-filter>  # DIFF-ANCHOR: 5860c6b5
+      <intent-filter>  # DIFF-ANCHOR: 4ee601b7
         <action android:name="android.intent.action.SEND"/>
         <category android:name="android.intent.category.DEFAULT"/>
         <data android:mimeType="text/plain"/>
-      </intent-filter>  # DIFF-ANCHOR: 5860c6b5
-    </activity>  # DIFF-ANCHOR: 334ee6dc
-    <activity  # DIFF-ANCHOR: 8e3d60cc
+      </intent-filter>  # DIFF-ANCHOR: 4ee601b7
+    </activity>  # DIFF-ANCHOR: dc9ccfb7
+    <activity  # DIFF-ANCHOR: f1aedff1
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:enabled="false"
         android:excludeFromRecents="true"
@@ -167,13 +173,13 @@
         android:name="org.chromium.chrome.browser.send_tab_to_self.SendTabToSelfShareActivity"
         android:noHistory="true"
         android:theme="@android:style/Theme.NoDisplay">
-      <intent-filter>  # DIFF-ANCHOR: 5860c6b5
+      <intent-filter>  # DIFF-ANCHOR: 4ee601b7
         <action android:name="android.intent.action.SEND"/>
         <category android:name="android.intent.category.DEFAULT"/>
         <data android:mimeType="text/plain"/>
-      </intent-filter>  # DIFF-ANCHOR: 5860c6b5
-    </activity>  # DIFF-ANCHOR: 8e3d60cc
-    <activity  # DIFF-ANCHOR: 5715816d
+      </intent-filter>  # DIFF-ANCHOR: 4ee601b7
+    </activity>  # DIFF-ANCHOR: f1aedff1
+    <activity  # DIFF-ANCHOR: bec48e1f
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:enabled="false"
         android:excludeFromRecents="true"
@@ -183,22 +189,23 @@
         android:name="org.chromium.chrome.browser.printing.PrintShareActivity"
         android:noHistory="true"
         android:theme="@android:style/Theme.NoDisplay">
-      <intent-filter>  # DIFF-ANCHOR: 805331e9
+      <intent-filter>  # DIFF-ANCHOR: 4ee601b7
         <action android:name="android.intent.action.SEND"/>
         <category android:name="android.intent.category.DEFAULT"/>
         <data android:mimeType="message/rfc822"/>
         <data android:mimeType="multipart/related"/>
         <data android:mimeType="text/plain"/>
-      </intent-filter>  # DIFF-ANCHOR: 805331e9
-    </activity>  # DIFF-ANCHOR: 5715816d
-    <activity  # DIFF-ANCHOR: 12aa4b5a
+      </intent-filter>  # DIFF-ANCHOR: 4ee601b7
+    </activity>  # DIFF-ANCHOR: bec48e1f
+    <activity  # DIFF-ANCHOR: 43bfa5de
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:excludeFromRecents="true"
         android:exported="true"
         android:name="org.chromium.chrome.browser.test_dummy.TestDummyActivity"
         android:noHistory="true"
-        android:theme="@style/Theme.AppCompat"/>
-    <activity  # DIFF-ANCHOR: f42af6de
+        android:theme="@style/Theme.AppCompat">
+    </activity>  # DIFF-ANCHOR: 43bfa5de
+    <activity  # DIFF-ANCHOR: 8d26d599
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:excludeFromRecents="true"
         android:hardwareAccelerated="true"
@@ -206,73 +213,83 @@
         android:launchMode="singleTask"
         android:name="org.chromium.chrome.browser.media.router.caf.remoting.CafExpandedControllerActivity"
         android:noHistory="true"
-        android:theme="@style/Theme.Chromium.Activity"/>
-    <activity  # DIFF-ANCHOR: b97b5c81
+        android:theme="@style/Theme.Chromium.Activity">
+    </activity>  # DIFF-ANCHOR: 8d26d599
+    <activity  # DIFF-ANCHOR: a208e726
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:excludeFromRecents="true"
         android:name="org.chromium.chrome.browser.bookmarks.BookmarkAddActivity"
         android:theme="@android:style/Theme.NoDisplay"
         android:windowSoftInputMode="stateHidden">
-      <intent-filter>  # DIFF-ANCHOR: c1ed7137
+      <intent-filter>  # DIFF-ANCHOR: 47a8059b
         <action android:name="$PACKAGE.ADDBOOKMARK"/>
         <category android:name="android.intent.category.DEFAULT"/>
-      </intent-filter>  # DIFF-ANCHOR: c1ed7137
-    </activity>  # DIFF-ANCHOR: b97b5c81
-    <activity  # DIFF-ANCHOR: 6d34bd76
+      </intent-filter>  # DIFF-ANCHOR: 47a8059b
+    </activity>  # DIFF-ANCHOR: a208e726
+    <activity  # DIFF-ANCHOR: 0a21ad35
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:exported="false"
         android:label="@string/bookmark_choose_folder"
         android:name="org.chromium.chrome.browser.bookmarks.BookmarkFolderSelectActivity"
         android:theme="@style/Theme.Chromium.DialogWhenLarge"
-        android:windowSoftInputMode="stateAlwaysHidden"/>
-    <activity  # DIFF-ANCHOR: f5269d8e
+        android:windowSoftInputMode="stateAlwaysHidden">
+    </activity>  # DIFF-ANCHOR: 0a21ad35
+    <activity  # DIFF-ANCHOR: b66ce3f2
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:exported="false"
         android:label="@string/edit_bookmark"
         android:name="org.chromium.chrome.browser.bookmarks.BookmarkEditActivity"
         android:theme="@style/Theme.Chromium.DialogWhenLarge"
-        android:windowSoftInputMode="stateHidden"/>
-    <activity  # DIFF-ANCHOR: 2b35e1d5
+        android:windowSoftInputMode="stateHidden">
+    </activity>  # DIFF-ANCHOR: b66ce3f2
+    <activity  # DIFF-ANCHOR: d32b85df
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:exported="false"
         android:label="@string/settings"
         android:name="org.chromium.chrome.browser.settings.SettingsActivity"
-        android:theme="@style/Theme.Chromium.Settings"/>
-    <activity  # DIFF-ANCHOR: 10056d20
+        android:theme="@style/Theme.Chromium.Settings">
+    </activity>  # DIFF-ANCHOR: d32b85df
+    <activity  # DIFF-ANCHOR: d2967c86
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:exported="false"
         android:label="@string/storage_management_activity_label"
         android:name="org.chromium.chrome.browser.site_settings.ManageSpaceActivity"
-        android:theme="@style/Theme.Chromium.Settings.ManageSpace"/>
-    <activity  # DIFF-ANCHOR: 45c62b10
+        android:theme="@style/Theme.Chromium.Settings.ManageSpace">
+    </activity>  # DIFF-ANCHOR: d2967c86
+    <activity  # DIFF-ANCHOR: da2eedc8
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:exported="false"
         android:name="org.chromium.chrome.browser.bookmarks.BookmarkActivity"
         android:theme="@style/Theme.Chromium.Activity.Fullscreen"
-        android:windowSoftInputMode="stateAlwaysHidden|adjustResize"/>
-    <activity  # DIFF-ANCHOR: e3a84ff9
+        android:windowSoftInputMode="stateAlwaysHidden|adjustResize">
+    </activity>  # DIFF-ANCHOR: da2eedc8
+    <activity  # DIFF-ANCHOR: e0427380
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:exported="false"
         android:name="org.chromium.chrome.browser.bookmarks.BookmarkAddEditFolderActivity"
-        android:theme="@style/Theme.Chromium.DialogWhenLarge"/>
-    <activity  # DIFF-ANCHOR: 125092bc
+        android:theme="@style/Theme.Chromium.DialogWhenLarge">
+    </activity>  # DIFF-ANCHOR: e0427380
+    <activity  # DIFF-ANCHOR: 5c83a464
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:exported="false"
         android:name="org.chromium.chrome.browser.download.DownloadActivity"
         android:theme="@style/Theme.Chromium.Activity.Fullscreen"
-        android:windowSoftInputMode="stateAlwaysHidden|adjustResize"/>
-    <activity  # DIFF-ANCHOR: 2650f0aa
+        android:windowSoftInputMode="stateAlwaysHidden|adjustResize">
+    </activity>  # DIFF-ANCHOR: 5c83a464
+    <activity  # DIFF-ANCHOR: 05911131
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:exported="false"
         android:name="org.chromium.chrome.browser.history.HistoryActivity"
         android:theme="@style/Theme.Chromium.Activity.Fullscreen"
-        android:windowSoftInputMode="stateAlwaysHidden|adjustResize"/>
-    <activity  # DIFF-ANCHOR: 56341b41
+        android:windowSoftInputMode="stateAlwaysHidden|adjustResize">
+    </activity>  # DIFF-ANCHOR: 05911131
+    <activity  # DIFF-ANCHOR: f2fee469
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
         android:exported="false"
         android:name="org.chromium.chrome.browser.signin.SigninActivity"
-        android:theme="@style/Theme.Chromium.DialogWhenLarge"/>
-    <activity  # DIFF-ANCHOR: 15f8c0d9
+        android:theme="@style/Theme.Chromium.DialogWhenLarge">
+    </activity>  # DIFF-ANCHOR: f2fee469
+    <activity  # DIFF-ANCHOR: 5e628a6c
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode"
         android:enableVrMode="@string/gvr_vr_mode_component"
         android:excludeFromRecents="true"
@@ -280,13 +297,13 @@
         android:launchMode="singleInstance"
         android:name="org.chromium.chrome.browser.vr.VrFirstRunActivity"
         android:theme="@style/VrActivityTheme">
-      <intent-filter>  # DIFF-ANCHOR: ad124986
+      <intent-filter>  # DIFF-ANCHOR: dea53031
         <action android:name="org.chromium.chrome.browser.dummy.action"/>
         <category android:name="com.google.intent.category.CARDBOARD"/>
         <category android:name="com.google.intent.category.DAYDREAM"/>
-      </intent-filter>  # DIFF-ANCHOR: ad124986
-    </activity>  # DIFF-ANCHOR: 15f8c0d9
-    <activity  # DIFF-ANCHOR: 35467a36
+      </intent-filter>  # DIFF-ANCHOR: dea53031
+    </activity>  # DIFF-ANCHOR: 5e628a6c
+    <activity  # DIFF-ANCHOR: 5e467d8a
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density"
         android:documentLaunchMode="intoExisting"
         android:exported="false"
@@ -299,20 +316,21 @@
         android:supportsPictureInPicture="true"
         android:theme="@style/Theme.Chromium.Webapp"
         android:windowSoftInputMode="adjustResize">
-      <intent-filter>  # DIFF-ANCHOR: ad124986
+      <intent-filter>  # DIFF-ANCHOR: dea53031
         <action android:name="org.chromium.chrome.browser.dummy.action"/>
         <category android:name="com.google.intent.category.CARDBOARD"/>
         <category android:name="com.google.intent.category.DAYDREAM"/>
-      </intent-filter>  # DIFF-ANCHOR: ad124986
-    </activity>  # DIFF-ANCHOR: 35467a36
-    <activity  # DIFF-ANCHOR: 10649477
+      </intent-filter>  # DIFF-ANCHOR: dea53031
+    </activity>  # DIFF-ANCHOR: 5e467d8a
+    <activity  # DIFF-ANCHOR: 1acdfd19
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density"
         android:excludeFromRecents="true"
         android:name="org.chromium.chrome.browser.document.ChromeLauncherActivity"
         android:relinquishTaskIdentity="true"
         android:taskAffinity=""
-        android:theme="@style/LauncherTheme"/>
-    <activity  # DIFF-ANCHOR: b4386459
+        android:theme="@style/LauncherTheme">
+    </activity>  # DIFF-ANCHOR: 1acdfd19
+    <activity  # DIFF-ANCHOR: f1dc024a
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density"
         android:exported="false"
         android:hardwareAccelerated="false"
@@ -323,13 +341,13 @@
         android:supportsPictureInPicture="true"
         android:theme="@style/Theme.Chromium.Webapp.Translucent"
         android:windowSoftInputMode="adjustResize">
-      <intent-filter>  # DIFF-ANCHOR: ad124986
+      <intent-filter>  # DIFF-ANCHOR: dea53031
         <action android:name="org.chromium.chrome.browser.dummy.action"/>
         <category android:name="com.google.intent.category.CARDBOARD"/>
         <category android:name="com.google.intent.category.DAYDREAM"/>
-      </intent-filter>  # DIFF-ANCHOR: ad124986
-    </activity>  # DIFF-ANCHOR: b4386459
-    <activity  # DIFF-ANCHOR: c5947e69
+      </intent-filter>  # DIFF-ANCHOR: dea53031
+    </activity>  # DIFF-ANCHOR: f1dc024a
+    <activity  # DIFF-ANCHOR: 610e8ccf
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density"
         android:exported="false"
         android:hardwareAccelerated="false"
@@ -340,13 +358,13 @@
         android:taskAffinity="$PACKAGE.ChromeTabbedActivity2"
         android:theme="@style/Theme.Chromium.TabbedMode"
         android:windowSoftInputMode="adjustResize">
-      <intent-filter>  # DIFF-ANCHOR: ad124986
+      <intent-filter>  # DIFF-ANCHOR: dea53031
         <action android:name="org.chromium.chrome.browser.dummy.action"/>
         <category android:name="com.google.intent.category.CARDBOARD"/>
         <category android:name="com.google.intent.category.DAYDREAM"/>
-      </intent-filter>  # DIFF-ANCHOR: ad124986
-    </activity>  # DIFF-ANCHOR: c5947e69
-    <activity  # DIFF-ANCHOR: 66124c66
+      </intent-filter>  # DIFF-ANCHOR: dea53031
+    </activity>  # DIFF-ANCHOR: 610e8ccf
+    <activity  # DIFF-ANCHOR: 44266a6a
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density"
         android:exported="false"
         android:hardwareAccelerated="false"
@@ -355,13 +373,13 @@
         android:supportsPictureInPicture="true"
         android:theme="@style/Theme.Chromium.Activity"
         android:windowSoftInputMode="adjustResize">
-      <intent-filter>  # DIFF-ANCHOR: ad124986
+      <intent-filter>  # DIFF-ANCHOR: dea53031
         <action android:name="org.chromium.chrome.browser.dummy.action"/>
         <category android:name="com.google.intent.category.CARDBOARD"/>
         <category android:name="com.google.intent.category.DAYDREAM"/>
-      </intent-filter>  # DIFF-ANCHOR: ad124986
-    </activity>  # DIFF-ANCHOR: 66124c66
-    <activity  # DIFF-ANCHOR: 749aca16
+      </intent-filter>  # DIFF-ANCHOR: dea53031
+    </activity>  # DIFF-ANCHOR: 44266a6a
+    <activity  # DIFF-ANCHOR: 70dc8b5c
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density"
         android:exported="false"
         android:hardwareAccelerated="false"
@@ -370,13 +388,13 @@
         android:supportsPictureInPicture="true"
         android:theme="@style/Theme.Chromium.Activity.Translucent"
         android:windowSoftInputMode="adjustResize">
-      <intent-filter>  # DIFF-ANCHOR: ad124986
+      <intent-filter>  # DIFF-ANCHOR: dea53031
         <action android:name="org.chromium.chrome.browser.dummy.action"/>
         <category android:name="com.google.intent.category.CARDBOARD"/>
         <category android:name="com.google.intent.category.DAYDREAM"/>
-      </intent-filter>  # DIFF-ANCHOR: ad124986
-    </activity>  # DIFF-ANCHOR: 749aca16
-    <activity  # DIFF-ANCHOR: 5466134
+      </intent-filter>  # DIFF-ANCHOR: dea53031
+    </activity>  # DIFF-ANCHOR: 70dc8b5c
+    <activity  # DIFF-ANCHOR: 4d923622
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density"
         android:exported="false"
         android:hardwareAccelerated="false"
@@ -385,20 +403,21 @@
         android:supportsPictureInPicture="true"
         android:theme="@style/Theme.Chromium.Activity.FakeTranslucent"
         android:windowSoftInputMode="adjustResize">
-      <intent-filter>  # DIFF-ANCHOR: ad124986
+      <intent-filter>  # DIFF-ANCHOR: dea53031
         <action android:name="org.chromium.chrome.browser.dummy.action"/>
         <category android:name="com.google.intent.category.CARDBOARD"/>
         <category android:name="com.google.intent.category.DAYDREAM"/>
-      </intent-filter>  # DIFF-ANCHOR: ad124986
-    </activity>  # DIFF-ANCHOR: 5466134
-    <activity  # DIFF-ANCHOR: f5d77a0a
+      </intent-filter>  # DIFF-ANCHOR: dea53031
+    </activity>  # DIFF-ANCHOR: 4d923622
+    <activity  # DIFF-ANCHOR: 9023f153
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density"
         android:exported="false"
         android:hardwareAccelerated="false"
         android:name="org.chromium.chrome.browser.multiwindow.MultiInstanceChromeTabbedActivity"
         android:theme="@style/Theme.Chromium.TabbedMode"
-        android:windowSoftInputMode="adjustResize"/>
-    <activity  # DIFF-ANCHOR: a8bef873
+        android:windowSoftInputMode="adjustResize">
+    </activity>  # DIFF-ANCHOR: 9023f153
+    <activity  # DIFF-ANCHOR: 61b2c776
         android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize|uiMode|density"
         android:exported="true"
         android:hardwareAccelerated="false"
@@ -408,13 +427,13 @@
         android:supportsPictureInPicture="true"
         android:theme="@style/Theme.Chromium.TabbedMode"
         android:windowSoftInputMode="adjustResize">
-      <intent-filter>  # DIFF-ANCHOR: ad124986
+      <intent-filter>  # DIFF-ANCHOR: dea53031
         <action android:name="org.chromium.chrome.browser.dummy.action"/>
         <category android:name="com.google.intent.category.CARDBOARD"/>
         <category android:name="com.google.intent.category.DAYDREAM"/>
-      </intent-filter>  # DIFF-ANCHOR: ad124986
-    </activity>  # DIFF-ANCHOR: a8bef873
-    <activity  # DIFF-ANCHOR: 85b76e7f
+      </intent-filter>  # DIFF-ANCHOR: dea53031
+    </activity>  # DIFF-ANCHOR: 61b2c776
+    <activity  # DIFF-ANCHOR: d706d96e
         android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
         android:excludeFromRecents="true"
         android:exported="false"
@@ -422,161 +441,171 @@
         android:noHistory="true"
         android:resizeableActivity="true"
         android:supportsPictureInPicture="true"
-        android:theme="@style/Theme.Chromium.Activity"/>
-    <activity  # DIFF-ANCHOR: 453e37aa
+        android:theme="@style/Theme.Chromium.Activity">
+    </activity>  # DIFF-ANCHOR: d706d96e
+    <activity  # DIFF-ANCHOR: b007dcaa
         android:enableVrMode="@string/gvr_vr_mode_component"
         android:excludeFromRecents="true"
         android:exported="false"
         android:name="org.chromium.chrome.browser.vr.VrCancelAnimationActivity"
         android:noHistory="true"
         android:theme="@android:style/Theme.NoDisplay">
-      <intent-filter>  # DIFF-ANCHOR: ad124986
+      <intent-filter>  # DIFF-ANCHOR: dea53031
         <action android:name="org.chromium.chrome.browser.dummy.action"/>
         <category android:name="com.google.intent.category.CARDBOARD"/>
         <category android:name="com.google.intent.category.DAYDREAM"/>
-      </intent-filter>  # DIFF-ANCHOR: ad124986
-    </activity>  # DIFF-ANCHOR: 453e37aa
-    <activity  # DIFF-ANCHOR: c4993004
+      </intent-filter>  # DIFF-ANCHOR: dea53031
+    </activity>  # DIFF-ANCHOR: b007dcaa
+    <activity  # DIFF-ANCHOR: b98302dc
         android:enabled="false"
         android:excludeFromRecents="true"
         android:exported="true"
         android:name="org.chromium.chrome.browser.incognito.IncognitoTabLauncher"
         android:taskAffinity=""
         android:theme="@android:style/Theme.NoDisplay">
-      <intent-filter>  # DIFF-ANCHOR: 1541ef4c
+      <intent-filter>  # DIFF-ANCHOR: 8f811d02
         <action android:name="org.chromium.chrome.browser.incognito.OPEN_PRIVATE_TAB"/>
         <category android:name="android.intent.category.DEFAULT"/>
-      </intent-filter>  # DIFF-ANCHOR: 1541ef4c
-    </activity>  # DIFF-ANCHOR: c4993004
-    <activity  # DIFF-ANCHOR: 14e3cdad
+      </intent-filter>  # DIFF-ANCHOR: 8f811d02
+    </activity>  # DIFF-ANCHOR: b98302dc
+    <activity  # DIFF-ANCHOR: 53a4871f
         android:enabled="false"
         android:exported="false"
         android:launchMode="singleInstance"
         android:name="com.google.android.play.core.missingsplits.PlayCoreMissingSplitsActivity"
         android:process=":playcore_missing_splits_activity"
-        android:stateNotNeeded="true"/>
-    <activity  # DIFF-ANCHOR: cb1f1a5e
+        android:stateNotNeeded="true">
+    </activity>  # DIFF-ANCHOR: 53a4871f
+    <activity  # DIFF-ANCHOR: a2bae37c
         android:enabled="false"
         android:exported="false"
         android:name="com.google.android.play.core.common.PlayCoreDialogWrapperActivity"
         android:process=":playcore_dialog_wrapper_activity"
         android:stateNotNeeded="true"
-        android:theme="@style/Theme.PlayCore.Transparent"/>
-    <activity  # DIFF-ANCHOR: 16204651
+        android:theme="@style/Theme.PlayCore.Transparent">
+    </activity>  # DIFF-ANCHOR: a2bae37c
+    <activity  # DIFF-ANCHOR: 93d41352
         android:excludeFromRecents="true"
         android:exported="false"
         android:launchMode="singleInstance"
         android:name="org.chromium.chrome.browser.BrowserRestartActivity"
         android:process=":browser_restart_process"
-        android:theme="@android:style/Theme.Translucent.NoTitleBar"/>
-    <activity  # DIFF-ANCHOR: 172d9b32
+        android:theme="@android:style/Theme.Translucent.NoTitleBar">
+    </activity>  # DIFF-ANCHOR: 93d41352
+    <activity  # DIFF-ANCHOR: 76686af9
         android:excludeFromRecents="true"
         android:exported="false"
         android:name="org.chromium.chrome.browser.LauncherShortcutActivity"
         android:taskAffinity=""
-        android:theme="@android:style/Theme.NoDisplay"/>
-    <activity  # DIFF-ANCHOR: f490b994
+        android:theme="@android:style/Theme.NoDisplay">
+    </activity>  # DIFF-ANCHOR: 76686af9
+    <activity  # DIFF-ANCHOR: 50c7105b
         android:excludeFromRecents="true"
         android:exported="false"
         android:name="org.chromium.chrome.browser.app.reengagement.ReengagementActivity"
         android:taskAffinity=""
-        android:theme="@android:style/Theme.Translucent"/>
-    <activity  # DIFF-ANCHOR: 9ad44b6b
+        android:theme="@android:style/Theme.Translucent">
+    </activity>  # DIFF-ANCHOR: 50c7105b
+    <activity  # DIFF-ANCHOR: 349d8ca5
         android:excludeFromRecents="true"
         android:exported="false"
         android:name="org.chromium.chrome.browser.instantapps.AuthenticatedProxyActivity"
         android:noHistory="true"
-        android:theme="@android:style/Theme.NoDisplay"/>
-    <activity  # DIFF-ANCHOR: 3722f0d9
+        android:theme="@android:style/Theme.NoDisplay">
+    </activity>  # DIFF-ANCHOR: 349d8ca5
+    <activity  # DIFF-ANCHOR: 76b60c10
         android:excludeFromRecents="true"
         android:exported="false"
         android:name="org.chromium.chrome.browser.sync.ui.TrustedVaultKeyRetrievalProxyActivity"
-        android:theme="@style/Theme.AppCompat"/>
-    <activity  # DIFF-ANCHOR: 6dcb7a35
+        android:theme="@style/Theme.AppCompat">
+    </activity>  # DIFF-ANCHOR: 76b60c10
+    <activity  # DIFF-ANCHOR: aea75380
         android:excludeFromRecents="true"
         android:name="org.chromium.chrome.browser.webapps.WebappLauncherActivity"
         android:taskAffinity=""
         android:theme="@android:style/Theme.NoDisplay">
-      <intent-filter>  # DIFF-ANCHOR: 4a61c500
+      <intent-filter>  # DIFF-ANCHOR: faf519ad
         <action android:name="com.google.android.apps.chrome.webapps.WebappManager.ACTION_START_WEBAPP"/>
         <category android:name="android.intent.category.DEFAULT"/>
-      </intent-filter>  # DIFF-ANCHOR: 4a61c500
-      <intent-filter>  # DIFF-ANCHOR: 189026bc
+      </intent-filter>  # DIFF-ANCHOR: faf519ad
+      <intent-filter>  # DIFF-ANCHOR: 9c5197e9
         <action android:name="org.webapk.ACTION_START_WEBAPK"/>
         <category android:name="android.intent.category.DEFAULT"/>
-      </intent-filter>  # DIFF-ANCHOR: 189026bc
-    </activity>  # DIFF-ANCHOR: 6dcb7a35
-    <activity  # DIFF-ANCHOR: 8488739d
+      </intent-filter>  # DIFF-ANCHOR: 9c5197e9
+    </activity>  # DIFF-ANCHOR: aea75380
+    <activity  # DIFF-ANCHOR: ea1a94af
         android:exported="false"
         android:name="com.google.android.gms.common.api.GoogleApiActivity"
-        android:theme="@android:style/Theme.Translucent.NoTitleBar"/>
-    <activity  # DIFF-ANCHOR: 3e94da48
+        android:theme="@android:style/Theme.Translucent.NoTitleBar">
+    </activity>  # DIFF-ANCHOR: ea1a94af
+    <activity  # DIFF-ANCHOR: 209b5ded
         android:exported="false"
         android:name="org.chromium.chrome.browser.browserservices.ClearDataDialogActivity"
-        android:theme="@style/Theme.Chromium.ClearDataDialogActivity"/>
-    <activity  # DIFF-ANCHOR: e89d9458
+        android:theme="@style/Theme.Chromium.ClearDataDialogActivity">
+    </activity>  # DIFF-ANCHOR: 209b5ded
+    <activity  # DIFF-ANCHOR: 2b0ee4cd
         android:exported="true"
         android:name="org.chromium.chrome.browser.browserservices.ManageTrustedWebActivityDataActivity"
         android:theme="@style/Theme.Chromium.Activity.Fullscreen.Transparent">
-      <intent-filter>  # DIFF-ANCHOR: 705f3d0f
+      <intent-filter>  # DIFF-ANCHOR: 38d9d906
         <action android:name="android.support.customtabs.action.ACTION_MANAGE_TRUSTED_WEB_ACTIVITY_DATA"/>
         <category android:name="android.intent.category.DEFAULT"/>
         <data android:scheme="https"/>
-      </intent-filter>  # DIFF-ANCHOR: 705f3d0f
-      <intent-filter>  # DIFF-ANCHOR: ac78e0e4
+      </intent-filter>  # DIFF-ANCHOR: 38d9d906
+      <intent-filter>  # DIFF-ANCHOR: 38d9d906
         <action android:name="android.support.customtabs.action.ACTION_MANAGE_TRUSTED_WEB_ACTIVITY_DATA"/>
         <category android:name="android.intent.category.DEFAULT"/>
-      </intent-filter>  # DIFF-ANCHOR: ac78e0e4
-    </activity>  # DIFF-ANCHOR: e89d9458
-    <activity  # DIFF-ANCHOR: ecad59fd
+      </intent-filter>  # DIFF-ANCHOR: 38d9d906
+    </activity>  # DIFF-ANCHOR: 2b0ee4cd
+    <activity  # DIFF-ANCHOR: 9bb1f409
         android:exported="true"
         android:name="org.chromium.chrome.browser.webapps.ActivateWebApkActivity"
         android:theme="@android:style/Theme.NoDisplay">
-      <intent-filter>  # DIFF-ANCHOR: b3c76e56
+      <intent-filter>  # DIFF-ANCHOR: 0d72b7f0
         <action android:name="org.chromium.chrome.browser.webapps.ActivateWebApkActivity.ACTIVATE"/>
         <category android:name="android.intent.category.DEFAULT"/>
-      </intent-filter>  # DIFF-ANCHOR: b3c76e56
-    </activity>  # DIFF-ANCHOR: ecad59fd
-    <activity  # DIFF-ANCHOR: 7cb1f2d6
+      </intent-filter>  # DIFF-ANCHOR: 0d72b7f0
+    </activity>  # DIFF-ANCHOR: 9bb1f409
+    <activity  # DIFF-ANCHOR: ecd48344
         android:enabled="false"
         android:excludeFromRecents="true"
         android:exported="true"
         android:name="org.chromium.chrome.browser.media.MediaLauncherActivity"
         android:theme="@android:style/Theme.NoDisplay">
-      <intent-filter tools:ignore="AppLinkUrlError">  # DIFF-ANCHOR: 2a7b9cc9
+      <intent-filter tools:ignore="AppLinkUrlError">  # DIFF-ANCHOR: 13c9b0a8
         <action android:name="android.intent.action.VIEW"/>
         <category android:name="android.intent.category.DEFAULT"/>
         <data android:mimeType="image/*"/>
         <data android:mimeType="video/*"/>
         <data android:scheme="content"/>
         <data android:scheme="file"/>
-      </intent-filter>  # DIFF-ANCHOR: 2a7b9cc9
-    </activity>  # DIFF-ANCHOR: 7cb1f2d6
-    <activity-alias  # DIFF-ANCHOR: d540bcba
+      </intent-filter>  # DIFF-ANCHOR: 13c9b0a8
+    </activity>  # DIFF-ANCHOR: ecd48344
+    <activity-alias  # DIFF-ANCHOR: 7c349c4f
         android:exported="false"
         android:name="org.chromium.chrome.browser.webapps.SecureWebAppLauncher"
         android:targetActivity="org.chromium.chrome.browser.webapps.WebappLauncherActivity">
-      <intent-filter>  # DIFF-ANCHOR: eca516cd
+      <intent-filter>  # DIFF-ANCHOR: 9fe4b527
         <action android:name="org.chromium.chrome.browser.webapps.WebappManager.ACTION_START_SECURE_WEBAPP"/>
         <category android:name="android.intent.category.DEFAULT"/>
-      </intent-filter>  # DIFF-ANCHOR: eca516cd
-    </activity-alias>  # DIFF-ANCHOR: d540bcba
-    <activity-alias  # DIFF-ANCHOR: d9b4f740
+      </intent-filter>  # DIFF-ANCHOR: 9fe4b527
+    </activity-alias>  # DIFF-ANCHOR: 7c349c4f
+    <activity-alias  # DIFF-ANCHOR: 9da0e5b6
         android:exported="true"
         android:name="com.google.android.apps.chrome.IntentDispatcher"
         android:targetActivity="org.chromium.chrome.browser.document.ChromeLauncherActivity">
-      <intent-filter>  # DIFF-ANCHOR: 81efad64
+      <intent-filter>  # DIFF-ANCHOR: a5330430
         <action android:name="android.intent.action.MAIN"/>
         <category android:name="android.intent.category.NOTIFICATION_PREFERENCES"/>
-      </intent-filter>  # DIFF-ANCHOR: 81efad64
-      <intent-filter>  # DIFF-ANCHOR: d4767742
+      </intent-filter>  # DIFF-ANCHOR: a5330430
+      <intent-filter>  # DIFF-ANCHOR: 436dfef3
         <action android:name="android.intent.action.MEDIA_SEARCH"/>
         <category android:name="android.intent.category.DEFAULT"/>
-      </intent-filter>  # DIFF-ANCHOR: d4767742
-      <intent-filter>  # DIFF-ANCHOR: a63fd491
+      </intent-filter>  # DIFF-ANCHOR: 436dfef3
+      <intent-filter>  # DIFF-ANCHOR: 8f70c92f
         <action android:name="android.intent.action.SEARCH"/>
-      </intent-filter>  # DIFF-ANCHOR: a63fd491
-      <intent-filter>  # DIFF-ANCHOR: 19322362
+      </intent-filter>  # DIFF-ANCHOR: 8f70c92f
+      <intent-filter>  # DIFF-ANCHOR: 13c9b0a8
         <action android:name="android.intent.action.VIEW"/>
         <category android:name="android.intent.category.BROWSABLE"/>
         <category android:name="android.intent.category.DEFAULT"/>
@@ -586,8 +615,8 @@
         <data android:pathPattern="/.*\\.mhtml"/>
         <data android:scheme="content"/>
         <data android:scheme="file"/>
-      </intent-filter>  # DIFF-ANCHOR: 19322362
-      <intent-filter>  # DIFF-ANCHOR: dcb86ef4
+      </intent-filter>  # DIFF-ANCHOR: 13c9b0a8
+      <intent-filter>  # DIFF-ANCHOR: 13c9b0a8
         <action android:name="android.intent.action.VIEW"/>
         <category android:name="android.intent.category.BROWSABLE"/>
         <category android:name="android.intent.category.DEFAULT"/>
@@ -596,8 +625,8 @@
         <data android:pathPattern="/.*\\.mhtml"/>
         <data android:scheme="content"/>
         <data android:scheme="file"/>
-      </intent-filter>  # DIFF-ANCHOR: dcb86ef4
-      <intent-filter>  # DIFF-ANCHOR: 17b2c901
+      </intent-filter>  # DIFF-ANCHOR: 13c9b0a8
+      <intent-filter>  # DIFF-ANCHOR: 13c9b0a8
         <action android:name="android.intent.action.VIEW"/>
         <category android:name="android.intent.category.BROWSABLE"/>
         <category android:name="android.intent.category.DEFAULT"/>
@@ -610,8 +639,8 @@
         <data android:scheme="http"/>
         <data android:scheme="https"/>
         <data android:scheme="javascript"/>
-      </intent-filter>  # DIFF-ANCHOR: 17b2c901
-      <intent-filter>  # DIFF-ANCHOR: f8cc82d7
+      </intent-filter>  # DIFF-ANCHOR: 13c9b0a8
+      <intent-filter>  # DIFF-ANCHOR: 13c9b0a8
         <action android:name="android.intent.action.VIEW"/>
         <category android:name="android.intent.category.BROWSABLE"/>
         <category android:name="android.intent.category.DEFAULT"/>
@@ -620,78 +649,80 @@
         <data android:scheme="http"/>
         <data android:scheme="https"/>
         <data android:scheme="javascript"/>
-      </intent-filter>  # DIFF-ANCHOR: f8cc82d7
-      <intent-filter>  # DIFF-ANCHOR: aa31a443
+      </intent-filter>  # DIFF-ANCHOR: 13c9b0a8
+      <intent-filter>  # DIFF-ANCHOR: 13c9b0a8
         <action android:name="android.intent.action.VIEW"/>
         <category android:name="android.intent.category.DEFAULT"/>
         <data android:mimeType="message/rfc822"/>
         <data android:scheme="content"/>
         <data android:scheme="file"/>
-      </intent-filter>  # DIFF-ANCHOR: aa31a443
-      <intent-filter>  # DIFF-ANCHOR: f40b1f1d
+      </intent-filter>  # DIFF-ANCHOR: 13c9b0a8
+      <intent-filter>  # DIFF-ANCHOR: 13c9b0a8
         <action android:name="android.intent.action.VIEW"/>
         <category android:name="android.intent.category.DEFAULT"/>
         <data android:mimeType="multipart/related"/>
         <data android:scheme="content"/>
         <data android:scheme="file"/>
-      </intent-filter>  # DIFF-ANCHOR: f40b1f1d
-      <intent-filter>  # DIFF-ANCHOR: cc547f0c
+      </intent-filter>  # DIFF-ANCHOR: 13c9b0a8
+      <intent-filter>  # DIFF-ANCHOR: 7a3b3be8
         <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
         <category android:name="android.intent.category.DEFAULT"/>
         <data android:scheme="http"/>
         <data android:scheme="https"/>
-      </intent-filter>  # DIFF-ANCHOR: cc547f0c
-      <intent-filter>  # DIFF-ANCHOR: 16d15225
+      </intent-filter>  # DIFF-ANCHOR: 7a3b3be8
+      <intent-filter>  # DIFF-ANCHOR: 2a3a3c3d
         <action android:name="android.speech.action.VOICE_SEARCH_RESULTS"/>
         <category android:name="android.intent.category.DEFAULT"/>
-      </intent-filter>  # DIFF-ANCHOR: 16d15225
-      <intent-filter>  # DIFF-ANCHOR: b59119d3
+      </intent-filter>  # DIFF-ANCHOR: 2a3a3c3d
+      <intent-filter>  # DIFF-ANCHOR: 83919a44
         <action android:name="com.sec.android.airview.HOVER"/>
-      </intent-filter>  # DIFF-ANCHOR: b59119d3
+      </intent-filter>  # DIFF-ANCHOR: 83919a44
       <meta-data android:name="android.app.searchable" android:resource="@xml/searchable"/>
-    </activity-alias>  # DIFF-ANCHOR: d9b4f740
-    <activity-alias  # DIFF-ANCHOR: 67e6b59a
+    </activity-alias>  # DIFF-ANCHOR: 9da0e5b6
+    <activity-alias  # DIFF-ANCHOR: 5042984f
         android:exported="true"
         android:name="com.google.android.apps.chrome.Main"
         android:targetActivity="org.chromium.chrome.browser.ChromeTabbedActivity">
-      <intent-filter>  # DIFF-ANCHOR: 8697c9d3
+      <intent-filter>  # DIFF-ANCHOR: a5330430
         <action android:name="android.intent.action.MAIN"/>
         <category android:name="android.intent.category.APP_BROWSER"/>
         <category android:name="android.intent.category.BROWSABLE"/>
         <category android:name="android.intent.category.DEFAULT"/>
         <category android:name="android.intent.category.LAUNCHER"/>
-      </intent-filter>  # DIFF-ANCHOR: 8697c9d3
-      <intent-filter>  # DIFF-ANCHOR: ad124986
+      </intent-filter>  # DIFF-ANCHOR: a5330430
+      <intent-filter>  # DIFF-ANCHOR: dea53031
         <action android:name="org.chromium.chrome.browser.dummy.action"/>
         <category android:name="com.google.intent.category.CARDBOARD"/>
         <category android:name="com.google.intent.category.DAYDREAM"/>
-      </intent-filter>  # DIFF-ANCHOR: ad124986
+      </intent-filter>  # DIFF-ANCHOR: dea53031
       <meta-data android:name="android.app.shortcuts" android:resource="@xml/launchershortcuts"/>
-    </activity-alias>  # DIFF-ANCHOR: 67e6b59a
-    <activity-alias  # DIFF-ANCHOR: d79b0a5d
+    </activity-alias>  # DIFF-ANCHOR: 5042984f
+    <activity-alias  # DIFF-ANCHOR: dcfe2999
         android:label="@string/webapp_activity_title"
         android:name="com.google.android.apps.chrome.webapps.WebappActivity"
         android:resizeableActivity="true"
         android:supportsPictureInPicture="true"
-        android:targetActivity="org.chromium.chrome.browser.webapps.WebappActivity"/>
-    <activity-alias  # DIFF-ANCHOR: 437bfb37
+        android:targetActivity="org.chromium.chrome.browser.webapps.WebappActivity">
+    </activity-alias>  # DIFF-ANCHOR: dcfe2999
+    <activity-alias  # DIFF-ANCHOR: 8e23336d
         android:name="com.google.android.apps.chrome.webapps.WebappManager"
-        android:targetActivity="org.chromium.chrome.browser.webapps.WebappLauncherActivity"/>
-    <activity-alias  # DIFF-ANCHOR: 193687ae
+        android:targetActivity="org.chromium.chrome.browser.webapps.WebappLauncherActivity">
+    </activity-alias>  # DIFF-ANCHOR: 8e23336d
+    <activity-alias  # DIFF-ANCHOR: b4a6221b
         android:enabled="false"
         android:excludeFromRecents="true"
         android:exported="true"
         android:name="org.chromium.chrome.browser.media.AudioLauncherActivity"
         android:targetActivity="org.chromium.chrome.browser.media.MediaLauncherActivity"
         android:theme="@android:style/Theme.NoDisplay">
-      <intent-filter tools:ignore="AppLinkUrlError">  # DIFF-ANCHOR: c8fe3827
+      <intent-filter tools:ignore="AppLinkUrlError">  # DIFF-ANCHOR: 13c9b0a8
         <action android:name="android.intent.action.VIEW"/>
         <category android:name="android.intent.category.DEFAULT"/>
         <data android:mimeType="audio/*"/>
         <data android:scheme="content"/>
         <data android:scheme="file"/>
-      </intent-filter>  # DIFF-ANCHOR: c8fe3827
-    </activity-alias>  # DIFF-ANCHOR: 193687ae
+      </intent-filter>  # DIFF-ANCHOR: 13c9b0a8
+    </activity-alias>  # DIFF-ANCHOR: b4a6221b
     <meta-data android:name="android.allow_multiple_resumed_activities" android:value="true"/>
     <meta-data android:name="android.content.APP_RESTRICTIONS" android:resource="@xml/app_restrictions"/>
     <meta-data android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME" android:value="org.chromium.chrome.browser.media.router.caf.CastOptionsProvider"/>
@@ -704,549 +735,627 @@
     <meta-data android:name="org.chromium.content.browser.NUM_SANDBOXED_SERVICES" android:value="40"/>
     <meta-data android:name="org.chromium.content.browser.REMOTE_MEDIA_PLAYERS" android:value="org.chromium.chrome.browser.media.remote.DefaultMediaRouteController"/>
     <meta-data android:name="org.chromium.content.browser.SMART_CLIP_PROVIDER" android:value="org.chromium.content_public.browser.SmartClipProvider"/>
-    <provider  # DIFF-ANCHOR: 7b04a994
+    <provider  # DIFF-ANCHOR: 2215b9cd
         android:authorities="$PACKAGE.ChromeBrowserProvider;$PACKAGE.browser;$PACKAGE"
         android:exported="true"
         android:name="org.chromium.chrome.browser.provider.ChromeBrowserProvider">
       <path-permission android:path="/bookmarks/search_suggest_query" android:readPermission="android.permission.GLOBAL_SEARCH"/>
-    </provider>  # DIFF-ANCHOR: 7b04a994
-    <provider  # DIFF-ANCHOR: 5bca08b9
+    </provider>  # DIFF-ANCHOR: 2215b9cd
+    <provider  # DIFF-ANCHOR: 97e158a1
         android:authorities="$PACKAGE.DownloadFileProvider"
         android:exported="false"
         android:grantUriPermissions="true"
         android:name="org.chromium.chrome.browser.download.DownloadFileProvider">
       <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"/>
-    </provider>  # DIFF-ANCHOR: 5bca08b9
-    <provider  # DIFF-ANCHOR: 8bf77a49
+    </provider>  # DIFF-ANCHOR: 97e158a1
+    <provider  # DIFF-ANCHOR: 6e306896
         android:authorities="$PACKAGE.FileProvider"
         android:exported="false"
         android:grantUriPermissions="true"
         android:name="org.chromium.chrome.browser.util.ChromeFileProvider">
       <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"/>
-    </provider>  # DIFF-ANCHOR: 8bf77a49
-    <receiver  # DIFF-ANCHOR: 69cbb2bd
+    </provider>  # DIFF-ANCHOR: 6e306896
+    <receiver  # DIFF-ANCHOR: 1091f66b
         android:exported="false"
-        android:name="com.google.android.gms.cast.framework.media.MediaIntentReceiver"/>
-    <receiver  # DIFF-ANCHOR: 6c526882
+        android:name="com.google.android.gms.cast.framework.media.MediaIntentReceiver">
+    </receiver>  # DIFF-ANCHOR: 1091f66b
+    <receiver  # DIFF-ANCHOR: 9ef4cd0a
         android:exported="false"
-        android:name="org.chromium.chrome.browser.announcement.AnnouncementNotificationManager$Receiver"/>
-    <receiver  # DIFF-ANCHOR: 90a77f4a
+        android:name="org.chromium.chrome.browser.announcement.AnnouncementNotificationManager$Receiver">
+    </receiver>  # DIFF-ANCHOR: 9ef4cd0a
+    <receiver  # DIFF-ANCHOR: 9a0a00e8
         android:exported="false"
-        android:name="org.chromium.chrome.browser.app.send_tab_to_self.SendTabToSelfNotificationReceiver"/>
-    <receiver  # DIFF-ANCHOR: 1bf83908
+        android:name="org.chromium.chrome.browser.app.send_tab_to_self.SendTabToSelfNotificationReceiver">
+    </receiver>  # DIFF-ANCHOR: 9a0a00e8
+    <receiver  # DIFF-ANCHOR: b93ab7db
         android:exported="false"
-        android:name="org.chromium.chrome.browser.bookmarkswidget.BookmarkWidgetProxy"/>
-    <receiver  # DIFF-ANCHOR: 26e8340e
+        android:name="org.chromium.chrome.browser.bookmarkswidget.BookmarkWidgetProxy">
+    </receiver>  # DIFF-ANCHOR: b93ab7db
+    <receiver  # DIFF-ANCHOR: 3a086f97
         android:exported="false"
-        android:name="org.chromium.chrome.browser.browserservices.trustedwebactivityui.DisclosureAcceptanceBroadcastReceiver"/>
-    <receiver  # DIFF-ANCHOR: eba37b00
+        android:name="org.chromium.chrome.browser.browserservices.trustedwebactivityui.DisclosureAcceptanceBroadcastReceiver">
+    </receiver>  # DIFF-ANCHOR: 3a086f97
+    <receiver  # DIFF-ANCHOR: bccc7d87
         android:exported="false"
         android:name="org.chromium.chrome.browser.locale.LocaleChangedBroadcastReceiver">
-      <intent-filter>  # DIFF-ANCHOR: fa875e92
+      <intent-filter>  # DIFF-ANCHOR: 5458f2a2
         <action android:name="android.intent.action.LOCALE_CHANGED"/>
-      </intent-filter>  # DIFF-ANCHOR: fa875e92
-    </receiver>  # DIFF-ANCHOR: eba37b00
-    <receiver  # DIFF-ANCHOR: 93ba598d
+      </intent-filter>  # DIFF-ANCHOR: 5458f2a2
+    </receiver>  # DIFF-ANCHOR: bccc7d87
+    <receiver  # DIFF-ANCHOR: 17866e9d
         android:exported="false"
-        android:name="org.chromium.chrome.browser.notifications.NotificationIntentInterceptor$Receiver"/>
-    <receiver  # DIFF-ANCHOR: bf69fd0b
+        android:name="org.chromium.chrome.browser.notifications.NotificationIntentInterceptor$Receiver">
+    </receiver>  # DIFF-ANCHOR: 17866e9d
+    <receiver  # DIFF-ANCHOR: de24469c
         android:exported="false"
         android:name="org.chromium.chrome.browser.notifications.NotificationService$Receiver">
-      <intent-filter>  # DIFF-ANCHOR: 996a6219
+      <intent-filter>  # DIFF-ANCHOR: 1c1c5ed8
         <action android:name="org.chromium.chrome.browser.notifications.CLICK_NOTIFICATION"/>
         <action android:name="org.chromium.chrome.browser.notifications.CLOSE_NOTIFICATION"/>
-      </intent-filter>  # DIFF-ANCHOR: 996a6219
-    </receiver>  # DIFF-ANCHOR: bf69fd0b
-    <receiver  # DIFF-ANCHOR: 1935e7c
+      </intent-filter>  # DIFF-ANCHOR: 1c1c5ed8
+    </receiver>  # DIFF-ANCHOR: de24469c
+    <receiver  # DIFF-ANCHOR: e1c4d394
         android:exported="false"
-        android:name="org.chromium.chrome.browser.notifications.scheduler.DisplayAgent$Receiver"/>
-    <receiver  # DIFF-ANCHOR: 83b4a7de
+        android:name="org.chromium.chrome.browser.notifications.scheduler.DisplayAgent$Receiver">
+    </receiver>  # DIFF-ANCHOR: e1c4d394
+    <receiver  # DIFF-ANCHOR: de47f306
         android:exported="false"
-        android:name="org.chromium.chrome.browser.offlinepages.AutoFetchNotifier$CompleteNotificationReceiver"/>
-    <receiver  # DIFF-ANCHOR: a675c918
+        android:name="org.chromium.chrome.browser.offlinepages.AutoFetchNotifier$CompleteNotificationReceiver">
+    </receiver>  # DIFF-ANCHOR: de47f306
+    <receiver  # DIFF-ANCHOR: 98349cb3
         android:exported="false"
-        android:name="org.chromium.chrome.browser.offlinepages.AutoFetchNotifier$InProgressCancelReceiver"/>
-    <receiver  # DIFF-ANCHOR: 8ca151ce
+        android:name="org.chromium.chrome.browser.offlinepages.AutoFetchNotifier$InProgressCancelReceiver">
+    </receiver>  # DIFF-ANCHOR: 98349cb3
+    <receiver  # DIFF-ANCHOR: cfa3bb7f
         android:exported="false"
-        android:name="org.chromium.chrome.browser.offlinepages.prefetch.PrefetchedPagesNotifier$ClickReceiver"/>
-    <receiver  # DIFF-ANCHOR: eaa424f2
+        android:name="org.chromium.chrome.browser.offlinepages.prefetch.PrefetchedPagesNotifier$ClickReceiver">
+    </receiver>  # DIFF-ANCHOR: cfa3bb7f
+    <receiver  # DIFF-ANCHOR: 1f02dc2f
         android:exported="false"
-        android:name="org.chromium.chrome.browser.offlinepages.prefetch.PrefetchedPagesNotifier$SettingsReceiver"/>
-    <receiver  # DIFF-ANCHOR: 6438cd32
+        android:name="org.chromium.chrome.browser.offlinepages.prefetch.PrefetchedPagesNotifier$SettingsReceiver">
+    </receiver>  # DIFF-ANCHOR: 1f02dc2f
+    <receiver  # DIFF-ANCHOR: 40a69297
         android:exported="false"
-        android:name="org.chromium.chrome.browser.omaha.UpdateNotificationController$UpdateNotificationReceiver"/>
-    <receiver  # DIFF-ANCHOR: 81df5876
+        android:name="org.chromium.chrome.browser.omaha.UpdateNotificationController$UpdateNotificationReceiver">
+    </receiver>  # DIFF-ANCHOR: 40a69297
+    <receiver  # DIFF-ANCHOR: 956432e8
         android:exported="false"
-        android:name="org.chromium.chrome.browser.sharing.click_to_call.ClickToCallMessageHandler$TapReceiver"/>
-    <receiver  # DIFF-ANCHOR: f0f8380e
+        android:name="org.chromium.chrome.browser.sharing.click_to_call.ClickToCallMessageHandler$TapReceiver">
+    </receiver>  # DIFF-ANCHOR: 956432e8
+    <receiver  # DIFF-ANCHOR: cbb425dc
         android:exported="false"
-        android:name="org.chromium.chrome.browser.sharing.shared_clipboard.SharedClipboardMessageHandler$TapReceiver"/>
-    <receiver  # DIFF-ANCHOR: 2c01f887
+        android:name="org.chromium.chrome.browser.sharing.shared_clipboard.SharedClipboardMessageHandler$TapReceiver">
+    </receiver>  # DIFF-ANCHOR: cbb425dc
+    <receiver  # DIFF-ANCHOR: 729144c9
         android:exported="false"
-        android:name="org.chromium.chrome.browser.sharing.shared_clipboard.SharedClipboardMessageHandler$TryAgainReceiver"/>
-    <receiver  # DIFF-ANCHOR: c188afe9
+        android:name="org.chromium.chrome.browser.sharing.shared_clipboard.SharedClipboardMessageHandler$TryAgainReceiver">
+    </receiver>  # DIFF-ANCHOR: 729144c9
+    <receiver  # DIFF-ANCHOR: aa6748fc
         android:exported="false"
         android:name="org.chromium.chrome.browser.upgrade.PackageReplacedBroadcastReceiver">
-      <intent-filter>  # DIFF-ANCHOR: d4b9350a
+      <intent-filter>  # DIFF-ANCHOR: e8cce90c
         <action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>
-      </intent-filter>  # DIFF-ANCHOR: d4b9350a
-    </receiver>  # DIFF-ANCHOR: c188afe9
-    <receiver  # DIFF-ANCHOR: 3fa7b55c
+      </intent-filter>  # DIFF-ANCHOR: e8cce90c
+    </receiver>  # DIFF-ANCHOR: aa6748fc
+    <receiver  # DIFF-ANCHOR: 3e5f56cb
         android:exported="false"
-        android:name="org.chromium.components.background_task_scheduler.internal.BackgroundTaskBroadcastReceiver"/>
-    <receiver  # DIFF-ANCHOR: 5150dcbe
+        android:name="org.chromium.components.background_task_scheduler.internal.BackgroundTaskBroadcastReceiver">
+    </receiver>  # DIFF-ANCHOR: 3e5f56cb
+    <receiver  # DIFF-ANCHOR: 0ea504ef
         android:exported="true"
         android:name="com.google.android.gms.gcm.GcmReceiver"
         android:permission="com.google.android.c2dm.permission.SEND">
-      <intent-filter>  # DIFF-ANCHOR: 8c951239
+      <intent-filter>  # DIFF-ANCHOR: aae22013
         <action android:name="com.google.android.c2dm.intent.RECEIVE"/>
         <action android:name="com.google.android.c2dm.intent.REGISTRATION"/>
         <category android:name="$PACKAGE"/>
-      </intent-filter>  # DIFF-ANCHOR: 8c951239
-    </receiver>  # DIFF-ANCHOR: 5150dcbe
-    <receiver  # DIFF-ANCHOR: cd683ecb
+      </intent-filter>  # DIFF-ANCHOR: aae22013
+    </receiver>  # DIFF-ANCHOR: 0ea504ef
+    <receiver  # DIFF-ANCHOR: 3e596004
         android:exported="true"
         android:name="org.chromium.chrome.browser.browserservices.ClientAppBroadcastReceiver">
-      <intent-filter>  # DIFF-ANCHOR: 2441713a
+      <intent-filter>  # DIFF-ANCHOR: e5bb6a36
         <action android:name="android.intent.action.PACKAGE_DATA_CLEARED"/>
         <action android:name="android.intent.action.PACKAGE_FULLY_REMOVED"/>
         <data android:scheme="package"/>
-      </intent-filter>  # DIFF-ANCHOR: 2441713a
-    </receiver>  # DIFF-ANCHOR: cd683ecb
-    <receiver  # DIFF-ANCHOR: 21a02c7f
+      </intent-filter>  # DIFF-ANCHOR: e5bb6a36
+    </receiver>  # DIFF-ANCHOR: 3e596004
+    <receiver  # DIFF-ANCHOR: 93e73992
         android:exported="true"
         android:name="org.chromium.chrome.browser.sharing.click_to_call.ClickToCallMessageHandler$PhoneUnlockedReceiver">
-      <intent-filter>  # DIFF-ANCHOR: 3376741e
+      <intent-filter>  # DIFF-ANCHOR: 4b5ec7a9
         <action android:name="android.intent.action.USER_PRESENT"/>
-      </intent-filter>  # DIFF-ANCHOR: 3376741e
-    </receiver>  # DIFF-ANCHOR: 21a02c7f
-    <receiver  # DIFF-ANCHOR: 2adb81c1
+      </intent-filter>  # DIFF-ANCHOR: 4b5ec7a9
+    </receiver>  # DIFF-ANCHOR: 93e73992
+    <receiver  # DIFF-ANCHOR: 7d221226
         android:label="@string/bookmark_widget_title"
         android:name="com.google.android.apps.chrome.appwidget.bookmarks.BookmarkThumbnailWidgetProvider">
-      <intent-filter>  # DIFF-ANCHOR: 5d4f51d1
+      <intent-filter>  # DIFF-ANCHOR: 1ebe78e9
         <action android:name=".BOOKMARK_APPWIDGET_UPDATE"/>
         <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
-      </intent-filter>  # DIFF-ANCHOR: 5d4f51d1
+      </intent-filter>  # DIFF-ANCHOR: 1ebe78e9
       <meta-data android:name="android.appwidget.provider" android:resource="@xml/bookmark_widget_info"/>
-    </receiver>  # DIFF-ANCHOR: 2adb81c1
-    <receiver  # DIFF-ANCHOR: e42bcf7f
+    </receiver>  # DIFF-ANCHOR: 7d221226
+    <receiver  # DIFF-ANCHOR: 3664f7eb
         android:label="@string/search_widget_title"
         android:name="org.chromium.chrome.browser.searchwidget.SearchWidgetProvider">
-      <intent-filter>  # DIFF-ANCHOR: 7ec97164
+      <intent-filter>  # DIFF-ANCHOR: 4ed161a4
         <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
-      </intent-filter>  # DIFF-ANCHOR: 7ec97164
-      <intent-filter>  # DIFF-ANCHOR: bb85582a
+      </intent-filter>  # DIFF-ANCHOR: 4ed161a4
+      <intent-filter>  # DIFF-ANCHOR: 92485a5d
         <action android:name="org.chromium.chrome.browser.searchwidget.START_TEXT_QUERY"/>
-      </intent-filter>  # DIFF-ANCHOR: bb85582a
-      <intent-filter>  # DIFF-ANCHOR: 18b2f9b2
+      </intent-filter>  # DIFF-ANCHOR: 92485a5d
+      <intent-filter>  # DIFF-ANCHOR: 444cf2a4
         <action android:name="org.chromium.chrome.browser.searchwidget.START_VOICE_QUERY"/>
-      </intent-filter>  # DIFF-ANCHOR: 18b2f9b2
-      <intent-filter>  # DIFF-ANCHOR: 68d261de
+      </intent-filter>  # DIFF-ANCHOR: 444cf2a4
+      <intent-filter>  # DIFF-ANCHOR: fc048873
         <action android:name="org.chromium.chrome.browser.searchwidget.UPDATE_ALL_WIDGETS"/>
-      </intent-filter>  # DIFF-ANCHOR: 68d261de
+      </intent-filter>  # DIFF-ANCHOR: fc048873
       <meta-data android:name="android.appwidget.provider" android:resource="@xml/search_widget_info"/>
-    </receiver>  # DIFF-ANCHOR: e42bcf7f
-    <receiver android:name="org.chromium.chrome.browser.services.AccountsChangedReceiver">  # DIFF-ANCHOR: 2f954a4e
-      <intent-filter>  # DIFF-ANCHOR: dda0015b
+    </receiver>  # DIFF-ANCHOR: 3664f7eb
+    <receiver android:name="org.chromium.chrome.browser.services.AccountsChangedReceiver">  # DIFF-ANCHOR: 4de2a279
+      <intent-filter>  # DIFF-ANCHOR: 6a188b57
         <action android:name="android.accounts.LOGIN_ACCOUNTS_CHANGED"/>
-      </intent-filter>  # DIFF-ANCHOR: dda0015b
-    </receiver>  # DIFF-ANCHOR: 2f954a4e
-    <service  # DIFF-ANCHOR: cb679965
+      </intent-filter>  # DIFF-ANCHOR: 6a188b57
+    </receiver>  # DIFF-ANCHOR: 4de2a279
+    <service  # DIFF-ANCHOR: 53256720
         android:description="@string/decoder_description"
         android:exported="false"
         android:isolatedProcess="true"
         android:name="org.chromium.chrome.browser.photo_picker.DecoderService"
-        android:process=":decoder_service"/>
-    <service  # DIFF-ANCHOR: 7c346007
+        android:process=":decoder_service">
+    </service>  # DIFF-ANCHOR: 53256720
+    <service  # DIFF-ANCHOR: b1e3e8bd
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService0"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
         android:process=":sandboxed_process0"
-        android:useAppZygote="true"/>
-    <service  # DIFF-ANCHOR: a86463c0
+        android:useAppZygote="true">
+    </service>  # DIFF-ANCHOR: b1e3e8bd
+    <service  # DIFF-ANCHOR: 76d1ccf8
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService1"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process1"/>
-    <service  # DIFF-ANCHOR: a6cdbb5a
+        android:process=":sandboxed_process1">
+    </service>  # DIFF-ANCHOR: 76d1ccf8
+    <service  # DIFF-ANCHOR: 38b95266
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService10"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process10"/>
-    <service  # DIFF-ANCHOR: 8b64ff2a
+        android:process=":sandboxed_process10">
+    </service>  # DIFF-ANCHOR: 38b95266
+    <service  # DIFF-ANCHOR: e4a2e4a2
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService11"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process11"/>
-    <service  # DIFF-ANCHOR: d05b76b6
+        android:process=":sandboxed_process11">
+    </service>  # DIFF-ANCHOR: e4a2e4a2
+    <service  # DIFF-ANCHOR: d9b2ffba
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService12"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process12"/>
-    <service  # DIFF-ANCHOR: e51a6816
+        android:process=":sandboxed_process12">
+    </service>  # DIFF-ANCHOR: d9b2ffba
+    <service  # DIFF-ANCHOR: b41bb17d
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService13"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process13"/>
-    <service  # DIFF-ANCHOR: 991c97b2
+        android:process=":sandboxed_process13">
+    </service>  # DIFF-ANCHOR: b41bb17d
+    <service  # DIFF-ANCHOR: aec0ea21
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService14"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process14"/>
-    <service  # DIFF-ANCHOR: 85e6b502
+        android:process=":sandboxed_process14">
+    </service>  # DIFF-ANCHOR: aec0ea21
+    <service  # DIFF-ANCHOR: cf88a5e5
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService15"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process15"/>
-    <service  # DIFF-ANCHOR: be4233a6
+        android:process=":sandboxed_process15">
+    </service>  # DIFF-ANCHOR: cf88a5e5
+    <service  # DIFF-ANCHOR: 7d85889d
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService16"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process16"/>
-    <service  # DIFF-ANCHOR: 83bce056
+        android:process=":sandboxed_process16">
+    </service>  # DIFF-ANCHOR: 7d85889d
+    <service  # DIFF-ANCHOR: dae26ed4
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService17"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process17"/>
-    <service  # DIFF-ANCHOR: 49cdb46a
+        android:process=":sandboxed_process17">
+    </service>  # DIFF-ANCHOR: dae26ed4
+    <service  # DIFF-ANCHOR: 2c6cf029
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService18"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process18"/>
-    <service  # DIFF-ANCHOR: 7d77b39a
+        android:process=":sandboxed_process18">
+    </service>  # DIFF-ANCHOR: 2c6cf029
+    <service  # DIFF-ANCHOR: 1d2f0988
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService19"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process19"/>
-    <service  # DIFF-ANCHOR: 5866feac
+        android:process=":sandboxed_process19">
+    </service>  # DIFF-ANCHOR: 1d2f0988
+    <service  # DIFF-ANCHOR: 4a39041b
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService2"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process2"/>
-    <service  # DIFF-ANCHOR: 95433d6a
+        android:process=":sandboxed_process2">
+    </service>  # DIFF-ANCHOR: 4a39041b
+    <service  # DIFF-ANCHOR: 073533bf
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService20"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process20"/>
-    <service  # DIFF-ANCHOR: 4912ce7a
+        android:process=":sandboxed_process20">
+    </service>  # DIFF-ANCHOR: 073533bf
+    <service  # DIFF-ANCHOR: d24da41d
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService21"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process21"/>
-    <service  # DIFF-ANCHOR: 5dc2c536
+        android:process=":sandboxed_process21">
+    </service>  # DIFF-ANCHOR: d24da41d
+    <service  # DIFF-ANCHOR: 594d8b32
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService22"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process22"/>
-    <service  # DIFF-ANCHOR: 62ced1b6
+        android:process=":sandboxed_process22">
+    </service>  # DIFF-ANCHOR: 594d8b32
+    <service  # DIFF-ANCHOR: 5528c0c3
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService23"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process23"/>
-    <service  # DIFF-ANCHOR: 4dd22712
+        android:process=":sandboxed_process23">
+    </service>  # DIFF-ANCHOR: 5528c0c3
+    <service  # DIFF-ANCHOR: b7ab2ba3
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService24"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process24"/>
-    <service  # DIFF-ANCHOR: c37fd582
+        android:process=":sandboxed_process24">
+    </service>  # DIFF-ANCHOR: b7ab2ba3
+    <service  # DIFF-ANCHOR: cec6cb64
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService25"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process25"/>
-    <service  # DIFF-ANCHOR: 3df79696
+        android:process=":sandboxed_process25">
+    </service>  # DIFF-ANCHOR: cec6cb64
+    <service  # DIFF-ANCHOR: 5b4a00fe
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService26"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process26"/>
-    <service  # DIFF-ANCHOR: cf84a9c6
+        android:process=":sandboxed_process26">
+    </service>  # DIFF-ANCHOR: 5b4a00fe
+    <service  # DIFF-ANCHOR: ad49d203
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService27"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process27"/>
-    <service  # DIFF-ANCHOR: 2fd249ba
+        android:process=":sandboxed_process27">
+    </service>  # DIFF-ANCHOR: ad49d203
+    <service  # DIFF-ANCHOR: 573298e9
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService28"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process28"/>
-    <service  # DIFF-ANCHOR: 8c564c6a
+        android:process=":sandboxed_process28">
+    </service>  # DIFF-ANCHOR: 573298e9
+    <service  # DIFF-ANCHOR: 79897b32
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService29"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process29"/>
-    <service  # DIFF-ANCHOR: ab57e1cc
+        android:process=":sandboxed_process29">
+    </service>  # DIFF-ANCHOR: 79897b32
+    <service  # DIFF-ANCHOR: 84335864
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService3"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process3"/>
-    <service  # DIFF-ANCHOR: 1439b1ee
+        android:process=":sandboxed_process3">
+    </service>  # DIFF-ANCHOR: 84335864
+    <service  # DIFF-ANCHOR: c4bd371e
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService30"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process30"/>
-    <service  # DIFF-ANCHOR: 4a12743e
+        android:process=":sandboxed_process30">
+    </service>  # DIFF-ANCHOR: c4bd371e
+    <service  # DIFF-ANCHOR: 394a9fd0
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService31"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process31"/>
-    <service  # DIFF-ANCHOR: 3930e00a
+        android:process=":sandboxed_process31">
+    </service>  # DIFF-ANCHOR: 394a9fd0
+    <service  # DIFF-ANCHOR: b811afb8
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService32"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process32"/>
-    <service  # DIFF-ANCHOR: 520fcdca
+        android:process=":sandboxed_process32">
+    </service>  # DIFF-ANCHOR: b811afb8
+    <service  # DIFF-ANCHOR: 2811ddd3
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService33"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process33"/>
-    <service  # DIFF-ANCHOR: da55eede
+        android:process=":sandboxed_process33">
+    </service>  # DIFF-ANCHOR: 2811ddd3
+    <service  # DIFF-ANCHOR: 73ae1688
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService34"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process34"/>
-    <service  # DIFF-ANCHOR: b51badfe
+        android:process=":sandboxed_process34">
+    </service>  # DIFF-ANCHOR: 73ae1688
+    <service  # DIFF-ANCHOR: c476f324
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService35"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process35"/>
-    <service  # DIFF-ANCHOR: c04e8de2
+        android:process=":sandboxed_process35">
+    </service>  # DIFF-ANCHOR: c476f324
+    <service  # DIFF-ANCHOR: 75d5304b
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService36"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process36"/>
-    <service  # DIFF-ANCHOR: 697f7f12
+        android:process=":sandboxed_process36">
+    </service>  # DIFF-ANCHOR: 75d5304b
+    <service  # DIFF-ANCHOR: dc6d0617
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService37"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process37"/>
-    <service  # DIFF-ANCHOR: 42e50c7e
+        android:process=":sandboxed_process37">
+    </service>  # DIFF-ANCHOR: dc6d0617
+    <service  # DIFF-ANCHOR: e31efe49
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService38"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process38"/>
-    <service  # DIFF-ANCHOR: ad2f154e
+        android:process=":sandboxed_process38">
+    </service>  # DIFF-ANCHOR: e31efe49
+    <service  # DIFF-ANCHOR: 5736507e
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService39"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process39"/>
-    <service  # DIFF-ANCHOR: 935e1108
+        android:process=":sandboxed_process39">
+    </service>  # DIFF-ANCHOR: 5736507e
+    <service  # DIFF-ANCHOR: a161be24
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService4"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process4"/>
-    <service  # DIFF-ANCHOR: 38e82c20
+        android:process=":sandboxed_process4">
+    </service>  # DIFF-ANCHOR: a161be24
+    <service  # DIFF-ANCHOR: 8e591688
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService5"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process5"/>
-    <service  # DIFF-ANCHOR: bbb6ae84
+        android:process=":sandboxed_process5">
+    </service>  # DIFF-ANCHOR: 8e591688
+    <service  # DIFF-ANCHOR: 705141d0
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService6"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process6"/>
-    <service  # DIFF-ANCHOR: a2fcd454
+        android:process=":sandboxed_process6">
+    </service>  # DIFF-ANCHOR: 705141d0
+    <service  # DIFF-ANCHOR: 38ed2189
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService7"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process7"/>
-    <service  # DIFF-ANCHOR: 62796fa8
+        android:process=":sandboxed_process7">
+    </service>  # DIFF-ANCHOR: 38ed2189
+    <service  # DIFF-ANCHOR: aa417956
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService8"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process8"/>
-    <service  # DIFF-ANCHOR: 7e65b7a0
+        android:process=":sandboxed_process8">
+    </service>  # DIFF-ANCHOR: aa417956
+    <service  # DIFF-ANCHOR: e2f3bbbd
         android:exported="False"
         android:isolatedProcess="true"
         android:name="org.chromium.content.app.SandboxedProcessService9"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":sandboxed_process9"/>
-    <service  # DIFF-ANCHOR: e8b1a590
+        android:process=":sandboxed_process9">
+    </service>  # DIFF-ANCHOR: e2f3bbbd
+    <service  # DIFF-ANCHOR: 0c6c4fd9
         android:exported="false"
         android:isolatedProcess="false"
         android:name="org.chromium.content.app.PrivilegedProcessService0"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":privileged_process0"/>
-    <service  # DIFF-ANCHOR: 4a4a6a58
+        android:process=":privileged_process0">
+    </service>  # DIFF-ANCHOR: 0c6c4fd9
+    <service  # DIFF-ANCHOR: 6f89af32
         android:exported="false"
         android:isolatedProcess="false"
         android:name="org.chromium.content.app.PrivilegedProcessService1"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":privileged_process1"/>
-    <service  # DIFF-ANCHOR: 95fccd84
+        android:process=":privileged_process1">
+    </service>  # DIFF-ANCHOR: 6f89af32
+    <service  # DIFF-ANCHOR: 40e0d738
         android:exported="false"
         android:isolatedProcess="false"
         android:name="org.chromium.content.app.PrivilegedProcessService2"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":privileged_process2"/>
-    <service  # DIFF-ANCHOR: 28107274
+        android:process=":privileged_process2">
+    </service>  # DIFF-ANCHOR: 40e0d738
+    <service  # DIFF-ANCHOR: b197517d
         android:exported="false"
         android:isolatedProcess="false"
         android:name="org.chromium.content.app.PrivilegedProcessService3"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":privileged_process3"/>
-    <service  # DIFF-ANCHOR: fef3fab8
+        android:process=":privileged_process3">
+    </service>  # DIFF-ANCHOR: b197517d
+    <service  # DIFF-ANCHOR: 52303702
         android:exported="false"
         android:isolatedProcess="false"
         android:name="org.chromium.content.app.PrivilegedProcessService4"
         android:permission="$PACKAGE.permission.CHILD_SERVICE"
-        android:process=":privileged_process4"/>
-    <service  # DIFF-ANCHOR: 3993e711
+        android:process=":privileged_process4">
+    </service>  # DIFF-ANCHOR: 52303702
+    <service  # DIFF-ANCHOR: 41539e3c
         android:exported="false"
-        android:name="com.google.android.gms.cast.framework.ReconnectionService"/>
-    <service  # DIFF-ANCHOR: 3833fcec
+        android:name="com.google.android.gms.cast.framework.ReconnectionService">
+    </service>  # DIFF-ANCHOR: 41539e3c
+    <service  # DIFF-ANCHOR: 7dad1ec5
         android:exported="false"
-        android:name="com.google.android.gms.cast.framework.media.MediaNotificationService"/>
-    <service  # DIFF-ANCHOR: 3f857fa7
+        android:name="com.google.android.gms.cast.framework.media.MediaNotificationService">
+    </service>  # DIFF-ANCHOR: 7dad1ec5
+    <service  # DIFF-ANCHOR: ac44dbad
         android:exported="false"
         android:name="org.chromium.chrome.browser.bookmarkswidget.BookmarkWidgetService"
-        android:permission="android.permission.BIND_REMOTEVIEWS"/>
-    <service  # DIFF-ANCHOR: 2189666a
+        android:permission="android.permission.BIND_REMOTEVIEWS">
+    </service>  # DIFF-ANCHOR: ac44dbad
+    <service  # DIFF-ANCHOR: 90d2ec9b
         android:exported="false"
         android:name="org.chromium.chrome.browser.crash.ChromeMinidumpUploadJobService"
-        android:permission="android.permission.BIND_JOB_SERVICE"/>
-    <service  # DIFF-ANCHOR: c90e4a72
+        android:permission="android.permission.BIND_JOB_SERVICE">
+    </service>  # DIFF-ANCHOR: 90d2ec9b
+    <service  # DIFF-ANCHOR: 2ce0b6a4
         android:exported="false"
-        android:name="org.chromium.chrome.browser.crash.MinidumpUploadService"/>
-    <service  # DIFF-ANCHOR: 23f4e84e
+        android:name="org.chromium.chrome.browser.crash.MinidumpUploadService">
+    </service>  # DIFF-ANCHOR: 2ce0b6a4
+    <service  # DIFF-ANCHOR: 555432db
         android:exported="false"
-        android:name="org.chromium.chrome.browser.download.DownloadBroadcastManager"/>
-    <service  # DIFF-ANCHOR: 96e7f1c5
+        android:name="org.chromium.chrome.browser.download.DownloadBroadcastManager">
+    </service>  # DIFF-ANCHOR: 555432db
+    <service  # DIFF-ANCHOR: 4cf14268
         android:exported="false"
-        android:name="org.chromium.chrome.browser.download.DownloadForegroundService"/>
-    <service  # DIFF-ANCHOR: de7eeb6f
+        android:name="org.chromium.chrome.browser.download.DownloadForegroundService">
+    </service>  # DIFF-ANCHOR: 4cf14268
+    <service  # DIFF-ANCHOR: a651602a
         android:exported="false"
-        android:name="org.chromium.chrome.browser.incognito.IncognitoNotificationService"/>
-    <service  # DIFF-ANCHOR: 755973a5
+        android:name="org.chromium.chrome.browser.incognito.IncognitoNotificationService">
+    </service>  # DIFF-ANCHOR: a651602a
+    <service  # DIFF-ANCHOR: bd027029
         android:exported="false"
         android:name="org.chromium.chrome.browser.invalidation.ChromeBrowserSyncAdapterService">
-      <intent-filter>  # DIFF-ANCHOR: 6c973a7d
+      <intent-filter>  # DIFF-ANCHOR: 3e31084a
         <action android:name="android.content.SyncAdapter"/>
-      </intent-filter>  # DIFF-ANCHOR: 6c973a7d
+      </intent-filter>  # DIFF-ANCHOR: 3e31084a
       <meta-data android:name="android.content.SyncAdapter" android:resource="@xml/syncadapter"/>
-    </service>  # DIFF-ANCHOR: 755973a5
-    <service  # DIFF-ANCHOR: d5a051d0
+    </service>  # DIFF-ANCHOR: bd027029
+    <service  # DIFF-ANCHOR: 4f8e62ea
         android:exported="false"
-        android:name="org.chromium.chrome.browser.media.MediaCaptureNotificationService"/>
-    <service  # DIFF-ANCHOR: 5a2c1348
+        android:name="org.chromium.chrome.browser.media.MediaCaptureNotificationService">
+    </service>  # DIFF-ANCHOR: 4f8e62ea
+    <service  # DIFF-ANCHOR: 63d24cf5
         android:exported="false"
         android:name="org.chromium.chrome.browser.media.ui.ChromeMediaNotificationControllerDelegate$CastListenerService">
-      <intent-filter>  # DIFF-ANCHOR: c11fb724
+      <intent-filter>  # DIFF-ANCHOR: f401157d
         <action android:name="android.intent.action.MEDIA_BUTTON"/>
-      </intent-filter>  # DIFF-ANCHOR: c11fb724
-    </service>  # DIFF-ANCHOR: 5a2c1348
-    <service  # DIFF-ANCHOR: 42ed3896
+      </intent-filter>  # DIFF-ANCHOR: f401157d
+    </service>  # DIFF-ANCHOR: 63d24cf5
+    <service  # DIFF-ANCHOR: a4f153af
         android:exported="false"
         android:name="org.chromium.chrome.browser.media.ui.ChromeMediaNotificationControllerDelegate$PlaybackListenerService">
-      <intent-filter>  # DIFF-ANCHOR: c11fb724
+      <intent-filter>  # DIFF-ANCHOR: f401157d
         <action android:name="android.intent.action.MEDIA_BUTTON"/>
-      </intent-filter>  # DIFF-ANCHOR: c11fb724
-    </service>  # DIFF-ANCHOR: 42ed3896
-    <service  # DIFF-ANCHOR: d8c248a9
+      </intent-filter>  # DIFF-ANCHOR: f401157d
+    </service>  # DIFF-ANCHOR: a4f153af
+    <service  # DIFF-ANCHOR: 365e9d83
         android:exported="false"
         android:name="org.chromium.chrome.browser.media.ui.ChromeMediaNotificationControllerDelegate$PresentationListenerService">
-      <intent-filter>  # DIFF-ANCHOR: c11fb724
+      <intent-filter>  # DIFF-ANCHOR: f401157d
         <action android:name="android.intent.action.MEDIA_BUTTON"/>
-      </intent-filter>  # DIFF-ANCHOR: c11fb724
-    </service>  # DIFF-ANCHOR: d8c248a9
-    <service  # DIFF-ANCHOR: fd141652
+      </intent-filter>  # DIFF-ANCHOR: f401157d
+    </service>  # DIFF-ANCHOR: 365e9d83
+    <service  # DIFF-ANCHOR: 4b2220c4
         android:exported="false"
         android:name="org.chromium.chrome.browser.notifications.NotificationJobService"
-        android:permission="android.permission.BIND_JOB_SERVICE"/>
-    <service  # DIFF-ANCHOR: c31b12ea
+        android:permission="android.permission.BIND_JOB_SERVICE">
+    </service>  # DIFF-ANCHOR: 4b2220c4
+    <service  # DIFF-ANCHOR: 3224d309
         android:exported="false"
-        android:name="org.chromium.chrome.browser.notifications.NotificationService"/>
+        android:name="org.chromium.chrome.browser.notifications.NotificationService">
+    </service>  # DIFF-ANCHOR: 3224d309
     <service android:exported="false" android:name="org.chromium.chrome.browser.omaha.OmahaClient"/>
-    <service  # DIFF-ANCHOR: e276993e
+    <service  # DIFF-ANCHOR: d930289b
         android:exported="false"
         android:name="org.chromium.chrome.browser.services.gcm.ChromeGcmListenerService">
-      <intent-filter>  # DIFF-ANCHOR: 84d0a85e
+      <intent-filter>  # DIFF-ANCHOR: aae22013
         <action android:name="com.google.android.c2dm.intent.RECEIVE"/>
-      </intent-filter>  # DIFF-ANCHOR: 84d0a85e
-    </service>  # DIFF-ANCHOR: e276993e
-    <service  # DIFF-ANCHOR: c616f3cb
+      </intent-filter>  # DIFF-ANCHOR: aae22013
+    </service>  # DIFF-ANCHOR: d930289b
+    <service  # DIFF-ANCHOR: 682abdc1
         android:exported="false"
-        android:name="org.chromium.chrome.browser.services.gcm.GCMBackgroundService"/>
-    <service  # DIFF-ANCHOR: b0c6ffa3
+        android:name="org.chromium.chrome.browser.services.gcm.GCMBackgroundService">
+    </service>  # DIFF-ANCHOR: 682abdc1
+    <service  # DIFF-ANCHOR: dfb5da84
         android:exported="false"
-        android:name="org.chromium.chrome.browser.services.gcm.InvalidationGcmUpstreamSender"/>
-    <service  # DIFF-ANCHOR: 302f517b
+        android:name="org.chromium.chrome.browser.services.gcm.InvalidationGcmUpstreamSender">
+    </service>  # DIFF-ANCHOR: dfb5da84
+    <service  # DIFF-ANCHOR: 80f6a8e5
         android:exported="false"
-        android:name="org.chromium.chrome.browser.tracing.TracingNotificationService"/>
-    <service  # DIFF-ANCHOR: c97b9e14
+        android:name="org.chromium.chrome.browser.tracing.TracingNotificationService">
+    </service>  # DIFF-ANCHOR: 80f6a8e5
+    <service  # DIFF-ANCHOR: a550decc
         android:exported="false"
         android:name="org.chromium.components.background_task_scheduler.internal.BackgroundTaskJobService"
-        android:permission="android.permission.BIND_JOB_SERVICE"/>
-    <service  # DIFF-ANCHOR: a927ca85
+        android:permission="android.permission.BIND_JOB_SERVICE">
+    </service>  # DIFF-ANCHOR: a550decc
+    <service  # DIFF-ANCHOR: 4c2196d9
         android:exported="true"
         android:name="com.google.ipc.invalidation.ticl.android2.channel.GcmRegistrationTaskService"
         android:permission="com.google.android.gms.permission.BIND_NETWORK_TASK_SERVICE">
-      <intent-filter>  # DIFF-ANCHOR: bfec5949
+      <intent-filter>  # DIFF-ANCHOR: 99686c45
         <action android:name="com.google.android.gms.gcm.ACTION_TASK_READY"/>
-      </intent-filter>  # DIFF-ANCHOR: bfec5949
-    </service>  # DIFF-ANCHOR: a927ca85
-    <service  # DIFF-ANCHOR: 964f81d7
+      </intent-filter>  # DIFF-ANCHOR: 99686c45
+    </service>  # DIFF-ANCHOR: 4c2196d9
+    <service  # DIFF-ANCHOR: c34d99ad
         android:exported="true"
         android:name="org.chromium.chrome.browser.ChromeBackgroundService"
         android:permission="com.google.android.gms.permission.BIND_NETWORK_TASK_SERVICE">
-      <intent-filter>  # DIFF-ANCHOR: bfec5949
+      <intent-filter>  # DIFF-ANCHOR: 99686c45
         <action android:name="com.google.android.gms.gcm.ACTION_TASK_READY"/>
-      </intent-filter>  # DIFF-ANCHOR: bfec5949
-    </service>  # DIFF-ANCHOR: 964f81d7
-    <service  # DIFF-ANCHOR: b702e25d
+      </intent-filter>  # DIFF-ANCHOR: 99686c45
+    </service>  # DIFF-ANCHOR: c34d99ad
+    <service  # DIFF-ANCHOR: 8fc286d0
         android:exported="true"
         android:name="org.chromium.components.background_task_scheduler.internal.BackgroundTaskGcmTaskService"
         android:permission="com.google.android.gms.permission.BIND_NETWORK_TASK_SERVICE">
-      <intent-filter>  # DIFF-ANCHOR: bfec5949
+      <intent-filter>  # DIFF-ANCHOR: 99686c45
         <action android:name="com.google.android.gms.gcm.ACTION_TASK_READY"/>
-      </intent-filter>  # DIFF-ANCHOR: bfec5949
-    </service>  # DIFF-ANCHOR: b702e25d
-    <service  # DIFF-ANCHOR: 44246b4
+      </intent-filter>  # DIFF-ANCHOR: 99686c45
+    </service>  # DIFF-ANCHOR: 8fc286d0
+    <service  # DIFF-ANCHOR: 2ce68981
         android:exported="true"
-        android:name="org.chromium.components.payments.PaymentDetailsUpdateService"/>
+        android:name="org.chromium.components.payments.PaymentDetailsUpdateService">
+    </service>  # DIFF-ANCHOR: 2ce68981
     <service android:name="androidx.browser.customtabs.PostMessageService"/>
-    <service  # DIFF-ANCHOR: 794db76d
+    <service  # DIFF-ANCHOR: ee1c39a8
         android:exported="true"
         android:name="org.chromium.chrome.browser.customtabs.CustomTabsConnectionService"
         tools:ignore="ExportedService">
-      <intent-filter>  # DIFF-ANCHOR: b3ec9de2
+      <intent-filter>  # DIFF-ANCHOR: d46bf795
         <action android:name="android.support.customtabs.action.CustomTabsService"/>
         <category android:name="androidx.browser.customtabs.category.ColorSchemeCustomization"/>
         <category android:name="androidx.browser.customtabs.category.NavBarColorCustomization"/>
@@ -1254,12 +1363,13 @@
         <category android:name="androidx.browser.trusted.category.TrustedWebActivities"/>
         <category android:name="androidx.browser.trusted.category.TrustedWebActivitySplashScreensV1"/>
         <category android:name="androidx.browser.trusted.category.WebShareTargetV2"/>
-      </intent-filter>  # DIFF-ANCHOR: b3ec9de2
-    </service>  # DIFF-ANCHOR: 794db76d
-    <service  # DIFF-ANCHOR: d22e975a
+      </intent-filter>  # DIFF-ANCHOR: d46bf795
+    </service>  # DIFF-ANCHOR: ee1c39a8
+    <service  # DIFF-ANCHOR: 064aae37
         android:exported="true"
         android:name="org.chromium.chrome.browser.prerender.ChromePrerenderService"
-        tools:ignore="ExportedService"/>
+        tools:ignore="ExportedService">
+    </service>  # DIFF-ANCHOR: 064aae37
     <uses-static-library android:certDigest="32a2fc74d731105859e5a85df16d95f102d85b22099b8064c5d8915c61dad1e0" android:name="org.chromium.trichromelibrary" android:version="$VERSION_NUMBER"/>
-  </application>  # DIFF-ANCHOR: 1b98dacf
+  </application>
 </manifest>
diff --git a/chrome/android/expectations/trichrome_library_apk.AndroidManifest.expected b/chrome/android/expectations/trichrome_library_apk.AndroidManifest.expected
index 5974e3a6..87ae8ae 100644
--- a/chrome/android/expectations/trichrome_library_apk.AndroidManifest.expected
+++ b/chrome/android/expectations/trichrome_library_apk.AndroidManifest.expected
@@ -10,11 +10,11 @@
   <uses-feature android:name="android.software.leanback" android:required="false"/>
   <uses-feature android:name="android.hardware.touchscreen" android:required="false"/>
   <uses-feature android:glEsVersion="0x00020000"/>
-  <application  # DIFF-ANCHOR: 9d5595e9
+  <application
       android:extractNativeLibs="false"
       android:icon="@drawable/icon_webview"
       android:label="Trichrome Library"
       android:multiArch="true">
     <static-library android:name="$PACKAGE" android:version="$VERSION_NUMBER"/>
-  </application>  # DIFF-ANCHOR: 9d5595e9
+  </application>
 </manifest>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/BrowserServicesIntentDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/BrowserServicesIntentDataProvider.java
index 9ab4e32..3801c35 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/BrowserServicesIntentDataProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/BrowserServicesIntentDataProvider.java
@@ -500,4 +500,9 @@
     public int getTwaDisclosureUi() {
         return TwaDisclosureUi.DEFAULT;
     }
+
+    @Nullable
+    public int[] getGsaExperimentIds() {
+        return null;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIncognitoManager.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIncognitoManager.java
index f98133a..46dd2b9e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIncognitoManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIncognitoManager.java
@@ -87,11 +87,6 @@
         }
     }
 
-    // TODO(crbug.com/1023759): Remove this function.
-    public static boolean hasIsolatedProfile() {
-        return true;
-    }
-
     private void initializeIncognito() {
         mIncognitoTabHost = new IncognitoCustomTabHost();
         IncognitoTabHostRegistry.getInstance().register(mIncognitoTabHost);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
index 9a23f6b..b38cf9e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
@@ -157,6 +157,9 @@
             + "To make locally-built Chrome a first-party app, sign with release-test "
             + "signing keys and run on userdebug devices. See use_signing_keys GN arg.";
 
+    private static final String EXPERIMENT_IDS =
+            "org.chromium.chrome.browser.customtabs.AGA_EXPERIMENT_IDS";
+
     private final Intent mIntent;
     private final CustomTabsSessionToken mSession;
     private final boolean mIsTrustedIntent;
@@ -209,6 +212,9 @@
     private final String mTranslateLanguage;
     private final int mDefaultOrientation;
 
+    @Nullable
+    private final int[] mGsaExperimentIds;
+
     /**
      * Add extras to customize menu items for opening payment request UI custom tab from Chrome.
      */
@@ -354,6 +360,8 @@
         mDefaultOrientation = convertOrientationType(IntentUtils.safeGetIntExtra(intent,
                 TrustedWebActivityIntentBuilder.EXTRA_SCREEN_ORIENTATION,
                 ScreenOrientation.DEFAULT));
+
+        mGsaExperimentIds = IntentUtils.safeGetIntArrayExtra(intent, EXPERIMENT_IDS);
     }
 
     /**
@@ -857,4 +865,10 @@
 
         return version;
     }
+
+    @Override
+    @Nullable
+    public int[] getGsaExperimentIds() {
+        return mGsaExperimentIds;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
index 3ce0238f9..245918e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
@@ -1607,6 +1607,11 @@
                 sessionToken, uri, purpose, extras);
     }
 
+    @VisibleForTesting
+    public static void setInstanceForTesting(CustomTabsConnection connection) {
+        sInstance = connection;
+    }
+
     @NativeMethods
     interface Natives {
         void createAndStartDetachedResourceRequest(Profile profile, CustomTabsSessionToken session,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java
index 96fcc464..14e686e4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java
@@ -41,6 +41,7 @@
 import org.chromium.chrome.browser.init.StartupTabPreloader;
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
 import org.chromium.chrome.browser.lifecycle.InflationObserver;
+import org.chromium.chrome.browser.metrics.UmaSessionStats;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
 import org.chromium.chrome.browser.tab.RedirectHandlerTabHelper;
@@ -86,6 +87,8 @@
         int NUM_ENTRIES = 4;
     }
 
+    private static final String GSA_STUDY_NAME = "GsaExperiments";
+
     private final Lazy<CustomTabDelegateFactory> mCustomTabDelegateFactory;
     private final ChromeActivity<?> mActivity;
     private final CustomTabsConnection mConnection;
@@ -383,6 +386,16 @@
     }
 
     private Tab createTab() {
+        // At this point we know native has been loaded, but we haven't kicked off a navigation yet.
+        // Experiment ids for GSA are normally set a bit later in the process, but this resulted in
+        // them being absent for the initial request. We set them here early.
+        int[] experimentIds = mIntentDataProvider.getGsaExperimentIds();
+        if (experimentIds != null) {
+            // When ids are set through the intent, we don't want them to override the existing ids.
+            boolean override = false;
+            UmaSessionStats.registerExternalExperiment(GSA_STUDY_NAME, experimentIds, override);
+        }
+
         WebContents webContents = takeWebContents();
         // clang-format off
         Tab tab = mTabFactory.createTab(webContents, mCustomTabDelegateFactory.get(),
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaSessionStats.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaSessionStats.java
index e098959..c12fe71 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaSessionStats.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaSessionStats.java
@@ -209,8 +209,16 @@
     }
 
     public static void registerExternalExperiment(String fallbackStudyName, int[] experimentIds) {
+        // TODO(https://crbug.com/1111941): Remove this method once all callers have moved onto
+        // the overload below.
+        registerExternalExperiment(fallbackStudyName, experimentIds, true);
+    }
+
+    public static void registerExternalExperiment(
+            String fallbackStudyName, int[] experimentIds, boolean overrideExistingIds) {
         assert isMetricsServiceAvailable();
-        UmaSessionStatsJni.get().registerExternalExperiment(fallbackStudyName, experimentIds);
+        UmaSessionStatsJni.get().registerExternalExperiment(
+                fallbackStudyName, experimentIds, overrideExistingIds);
     }
 
     public static void registerSyntheticFieldTrial(String trialName, String groupName) {
@@ -246,7 +254,8 @@
         void updateMetricsServiceState(boolean mayUpload);
         void umaResumeSession(long nativeUmaSessionStats, UmaSessionStats caller);
         void umaEndSession(long nativeUmaSessionStats, UmaSessionStats caller);
-        void registerExternalExperiment(String studyName, int[] experimentIds);
+        void registerExternalExperiment(
+                String studyName, int[] experimentIds, boolean overrideExistingIds);
         void registerSyntheticFieldTrial(String trialName, String groupName);
         void recordTabCountPerLoad(int numTabsOpen);
         void recordPageLoaded(boolean isDesktopUserAgent);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/RequestGenerator.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/RequestGenerator.java
index 49f45c7..1b9ad62 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omaha/RequestGenerator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/RequestGenerator.java
@@ -22,8 +22,10 @@
 import org.chromium.chrome.browser.identity.UniqueIdentificationGeneratorFactory;
 import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
 import org.chromium.chrome.browser.init.ProcessInitializationHandler;
+import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.signin.IdentityServicesProvider;
 import org.chromium.components.signin.AccountManagerFacadeProvider;
+import org.chromium.components.signin.identitymanager.IdentityManager;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
 import org.chromium.ui.base.DeviceFormFactor;
 
@@ -223,7 +225,9 @@
             // The native needs to be loaded for the usage of IdentityManager.
             ChromeBrowserInitializer.getInstance().handleSynchronousStartup();
             // We only have a single account.
-            return IdentityServicesProvider.get().getIdentityManager().hasPrimaryAccount() ? 1 : 0;
+            IdentityManager identityManager = IdentityServicesProvider.get().getIdentityManager(
+                    Profile.getLastUsedRegularProfile());
+            return identityManager.hasPrimaryAccount() ? 1 : 0;
         });
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/page_info/ChromePageInfoControllerDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/page_info/ChromePageInfoControllerDelegate.java
index b6ecb314..b16d0de 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/page_info/ChromePageInfoControllerDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/page_info/ChromePageInfoControllerDelegate.java
@@ -277,6 +277,8 @@
         SingleWebsiteSettings fragment = (SingleWebsiteSettings) Fragment.instantiate(
                 mContext, SingleWebsiteSettings.class.getName(), fragmentArgs);
         fragment.setSiteSettingsClient(new ChromeSiteSettingsClient(mContext, getBrowserContext()));
+        fragment.setHideNonPermissionPreferences(true);
+        fragment.setRefreshAfterReset(true);
         return fragment;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerLauncher.java b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerLauncher.java
index 92014fa..e604e78 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerLauncher.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerLauncher.java
@@ -17,6 +17,7 @@
 import org.chromium.chrome.browser.settings.SettingsLauncherImpl;
 import org.chromium.chrome.browser.signin.IdentityServicesProvider;
 import org.chromium.chrome.browser.sync.ProfileSyncService;
+import org.chromium.components.signin.identitymanager.IdentityManager;
 import org.chromium.components.sync.ModelType;
 import org.chromium.components.user_prefs.UserPrefs;
 import org.chromium.content_public.browser.WebContents;
@@ -74,7 +75,9 @@
     }
 
     public static boolean isSyncingPasswordsWithoutCustomPassphrase() {
-        if (!IdentityServicesProvider.get().getIdentityManager().hasPrimaryAccount()) return false;
+        IdentityManager identityManager = IdentityServicesProvider.get().getIdentityManager(
+                Profile.getLastUsedRegularProfile());
+        if (!identityManager.hasPrimaryAccount()) return false;
 
         ProfileSyncService profileSyncService = ProfileSyncService.get();
         if (profileSyncService == null
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetMediator.java
index c6a05a4..59fec37f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetMediator.java
@@ -161,6 +161,8 @@
         if (mSelectedAccountName == null) {
             addAccount();
         } else {
+            mModel.set(AccountPickerBottomSheetProperties.ACCOUNT_PICKER_BOTTOM_SHEET_STATE,
+                    AccountPickerBottomSheetState.SIGNIN_IN_PROGRESS);
             mAccountPickerDelegate.signIn(mSelectedAccountName);
         }
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetView.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetView.java
index 6c6812b28..f124108 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetView.java
@@ -109,6 +109,19 @@
         mContinueAsButton.setText(continueAsButtonText);
     }
 
+    /**
+     * Sets up the sign-in in progress view.
+     */
+    void setUpSignInInProgressView() {
+        // TODO(https://crbug.com/1102784):
+        //  - Setup the sign-in string |Signing in...|
+        //  - Add signing in progress spinner
+        mContentView.findViewById(R.id.account_picker_bottom_sheet_subtitle)
+                .setVisibility(View.GONE);
+        mSelectedAccountView.setVisibility(View.GONE);
+        mContinueAsButton.setVisibility(View.GONE);
+    }
+
     @Override
     public View getContentView() {
         return mContentView;
@@ -122,7 +135,7 @@
 
     @Override
     public int getVerticalScrollOffset() {
-        return mAccountListView.computeVerticalScrollOffset();
+        return 0;
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetViewBinder.java
index 37c3d6b..31776a4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetViewBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetViewBinder.java
@@ -54,7 +54,7 @@
                 view.expandAccountList();
                 break;
             case AccountPickerBottomSheetState.SIGNIN_IN_PROGRESS:
-                // TODO(https://crbug.com/1102784): Implement UI update when sign-in in progress
+                view.setUpSignInInProgressView();
                 break;
             default:
                 throw new IllegalArgumentException(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/AccountManagementFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/AccountManagementFragment.java
index 50151165..318c7be9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/AccountManagementFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/AccountManagementFragment.java
@@ -23,6 +23,7 @@
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.ContextUtils;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
 import org.chromium.chrome.browser.preferences.Pref;
 import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
@@ -66,24 +67,23 @@
         implements SignOutDialogListener, SignInStateObserver, ProfileDataCache.Observer {
     private static final String TAG = "AcctManagementPref";
 
-    public static final String SIGN_OUT_DIALOG_TAG = "sign_out_dialog_tag";
+    private static final String SIGN_OUT_DIALOG_TAG = "sign_out_dialog_tag";
     private static final String CLEAR_DATA_PROGRESS_DIALOG_TAG = "clear_data_progress";
 
     /**
      * The key for an integer value in arguments bundle to
      * specify the correct GAIA service that has triggered the dialog.
      * If the argument is not set, GAIA_SERVICE_TYPE_NONE is used as the origin of the dialog.
-     * TODO(https://crbug.com/1038924): Set the TAG variables of this class to private
      */
-    public static final String SHOW_GAIA_SERVICE_TYPE_EXTRA = "ShowGAIAServiceType";
+    private static final String SHOW_GAIA_SERVICE_TYPE_EXTRA = "ShowGAIAServiceType";
 
-    public static final String PREF_ACCOUNTS_CATEGORY = "accounts_category";
-    public static final String PREF_PARENTAL_SETTINGS = "parental_settings";
-    public static final String PREF_PARENT_ACCOUNTS = "parent_accounts";
-    public static final String PREF_CHILD_CONTENT = "child_content";
-    public static final String PREF_CHILD_CONTENT_DIVIDER = "child_content_divider";
-    public static final String PREF_SIGN_OUT = "sign_out";
-    public static final String PREF_SIGN_OUT_DIVIDER = "sign_out_divider";
+    private static final String PREF_ACCOUNTS_CATEGORY = "accounts_category";
+    private static final String PREF_PARENTAL_SETTINGS = "parental_settings";
+    private static final String PREF_PARENT_ACCOUNTS = "parent_accounts";
+    private static final String PREF_CHILD_CONTENT = "child_content";
+    private static final String PREF_CHILD_CONTENT_DIVIDER = "child_content_divider";
+    private static final String PREF_SIGN_OUT = "sign_out";
+    private static final String PREF_SIGN_OUT_DIVIDER = "sign_out_divider";
 
     private @GAIAServiceType int mGaiaServiceType = GAIAServiceType.GAIA_SERVICE_TYPE_NONE;
 
@@ -294,8 +294,12 @@
         ChromeBasePreference addAccountPreference = new ChromeBasePreference(getStyledContext());
         addAccountPreference.setLayoutResource(R.layout.account_management_account_row);
         addAccountPreference.setIcon(
-                AppCompatResources.getDrawable(getActivity(), R.drawable.ic_add_circle_40dp));
-        addAccountPreference.setTitle(R.string.account_management_add_account_title);
+                AppCompatResources.getDrawable(requireContext(), R.drawable.ic_add_circle_40dp));
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.MOBILE_IDENTITY_CONSISTENCY)) {
+            addAccountPreference.setTitle(R.string.signin_add_account_to_device);
+        } else {
+            addAccountPreference.setTitle(R.string.account_management_add_account_title);
+        }
         addAccountPreference.setOnPreferenceClickListener(preference -> {
             if (!isVisible() || !isResumed()) return false;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/SyncSettingsUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/SyncSettingsUtils.java
index fc5963e..5b5ff0e2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/SyncSettingsUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/SyncSettingsUtils.java
@@ -55,7 +55,8 @@
     private static final String TAG = "SyncSettingsUtils";
 
     @IntDef({SyncError.NO_ERROR, SyncError.ANDROID_SYNC_DISABLED, SyncError.AUTH_ERROR,
-            SyncError.PASSPHRASE_REQUIRED, SyncError.CLIENT_OUT_OF_DATE,
+            SyncError.PASSPHRASE_REQUIRED, SyncError.TRUSTED_VAULT_KEY_REQUIRED_FOR_EVERYTHING,
+            SyncError.TRUSTED_VAULT_KEY_REQUIRED_FOR_PASSWORDS, SyncError.CLIENT_OUT_OF_DATE,
             SyncError.SYNC_SETUP_INCOMPLETE, SyncError.OTHER_ERRORS})
     @Retention(RetentionPolicy.SOURCE)
     public @interface SyncError {
@@ -149,6 +150,30 @@
         }
     }
 
+    public static @Nullable String getSyncErrorCardButtonLabel(
+            Context context, @SyncError int error) {
+        switch (error) {
+            case SyncError.ANDROID_SYNC_DISABLED:
+                return context.getString(R.string.android_sync_disabled_error_card_button);
+            case SyncError.AUTH_ERROR:
+                return context.getString(R.string.auth_error_card_button);
+            case SyncError.CLIENT_OUT_OF_DATE:
+                return context.getString(R.string.client_out_of_date_error_card_button,
+                        BuildInfo.getInstance().hostPackageLabel);
+            case SyncError.PASSPHRASE_REQUIRED:
+                return context.getString(R.string.passphrase_required_error_card_button);
+            case SyncError.TRUSTED_VAULT_KEY_REQUIRED_FOR_EVERYTHING:
+            case SyncError.TRUSTED_VAULT_KEY_REQUIRED_FOR_PASSWORDS:
+                return context.getString(R.string.trusted_vault_error_card_button);
+            case SyncError.SYNC_SETUP_INCOMPLETE:
+                return context.getString(R.string.sync_setup_incomplete_error_card_confirm_button);
+            case SyncError.OTHER_ERRORS:
+            case SyncError.NO_ERROR:
+            default:
+                return null;
+        }
+    }
+
     /**
      * Gets the corresponding message id of a given {@link GoogleServiceAuthError.State}.
      */
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoCookieLeakageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoCookieLeakageTest.java
index 4cd0765..0ce5771 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoCookieLeakageTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoCookieLeakageTest.java
@@ -27,7 +27,6 @@
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule;
-import org.chromium.chrome.browser.customtabs.CustomTabIncognitoManager;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.incognito.IncognitoDataTestUtils.ActivityType;
@@ -134,7 +133,7 @@
         Tab getter_tab = incognitoActivity2.launchUrl(
                 mChromeActivityTestRule, mCustomTabActivityTestRule, mCookiesTestPage);
 
-        String expected = CustomTabIncognitoManager.hasIsolatedProfile() ? "\"\"" : "\"Foo=Bar\"";
+        String expected = "\"\"";
 
         assertCookies(getter_tab, expected);
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoPermissionLeakageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoPermissionLeakageTest.java
index 03ee9177..0dd47957 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoPermissionLeakageTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoPermissionLeakageTest.java
@@ -37,7 +37,6 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule;
-import org.chromium.chrome.browser.customtabs.CustomTabIncognitoManager;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.incognito.IncognitoDataTestUtils.ActivityType;
@@ -192,13 +191,9 @@
         // Request permission in incognitoActivity2's tab.
         requestLocationPermission(tab2);
 
-        // Incognito CCTs with isolated profiles should not inherit permissions from other sessions.
-        if (CustomTabIncognitoManager.hasIsolatedProfile()) {
-            // Permission is asked again, therefore the previous permission wasn't inherited.
-            assertDialogIsShown();
-        } else {
-            assertDialogIsNotShown();
-        }
+        // Incognito CCTs should not inherit permissions from other sessions.
+        // If permission is asked again, we can infer that the previous permission wasn't inherited.
+        assertDialogIsShown();
     }
 
     @Test
@@ -223,13 +218,9 @@
         // Request permission now in incognitoActivity2's tab.
         requestLocationPermission(tab2);
 
-        // Incognito CCTs with isolated profiles should not inherit permissions from other sessions.
-        if (CustomTabIncognitoManager.hasIsolatedProfile()) {
-            // Permission is asked again, therefore the previous permission wasn't inherited.
-            assertDialogIsShown();
-        } else {
-            assertDialogIsNotShown();
-        }
+        // Incognito CCTs should not inherit permissions from other sessions.
+        // If permission is asked again, we can infer that the previous permission wasn't inherited.
+        assertDialogIsShown();
     }
 
     @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoStorageLeakageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoStorageLeakageTest.java
index b91b3878..43256301 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoStorageLeakageTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoStorageLeakageTest.java
@@ -26,7 +26,6 @@
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule;
-import org.chromium.chrome.browser.customtabs.CustomTabIncognitoManager;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.incognito.IncognitoDataTestUtils.ActivityType;
@@ -146,13 +145,6 @@
         for (String type : sSiteData) {
             String expected = "false";
 
-            // Both activity types are incognito (one of them being CCT) and they share the storage
-            // only if incognito CCT doesn't have an isolated profile.
-            if (activity1.incognito && activity2.incognito
-                    && !CustomTabIncognitoManager.hasIsolatedProfile()) {
-                expected = "true";
-            }
-
             // Both activity types are regular and they share storages.
             if (!activity1.incognito && !activity2.incognito) {
                 expected = "true";
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omaha/RequestGeneratorTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omaha/RequestGeneratorTest.java
index 591ccb7b..32c09d1 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omaha/RequestGeneratorTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omaha/RequestGeneratorTest.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.omaha;
 
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -183,9 +184,9 @@
         AdvancedMockContext context = new AdvancedMockContext(targetContext);
 
         IdentityServicesProvider.setInstanceForTests(mock(IdentityServicesProvider.class));
-        when(IdentityServicesProvider.get().getIdentityManager())
+        when(IdentityServicesProvider.get().getIdentityManager(any()))
                 .thenReturn(mock(IdentityManager.class));
-        when(IdentityServicesProvider.get().getIdentityManager().hasPrimaryAccount())
+        when(IdentityServicesProvider.get().getIdentityManager(any()).hasPrimaryAccount())
                 .thenReturn(true);
 
         for (Account account : accounts) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java
index b94f78d3..a4c4fc4 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java
@@ -264,7 +264,6 @@
     @Feature({"RenderTest"})
     @Features.EnableFeatures(PageInfoFeatureList.PAGE_INFO_V2)
     public void testShowConnectionInfoSubpage() throws IOException {
-        setThirdPartyCookieBlocking(true);
         loadUrlAndOpenPageInfo(mTestServerRule.getServer().getURL(mPath));
         View dialog = (View) getPageInfoView().getParent();
         onView(withId(R.id.page_info_connection_row)).perform(click());
@@ -272,6 +271,20 @@
     }
 
     /**
+     * Tests the permissions page of the new PageInfo UI.
+     */
+    @Test
+    @MediumTest
+    @Feature({"RenderTest"})
+    @Features.EnableFeatures(PageInfoFeatureList.PAGE_INFO_V2)
+    public void testShowPermissionsSubpage() throws IOException {
+        loadUrlAndOpenPageInfo(mTestServerRule.getServer().getURL(mPath));
+        View dialog = (View) getPageInfoView().getParent();
+        onView(withId(R.id.page_info_permissions_row)).perform(click());
+        mRenderTestRule.render(dialog, "PageInfo_PermissionsSubpage");
+    }
+
+    /**
      * Tests the cookies page of the new PageInfo UI.
      */
     @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetTest.java
index 1cdc464..02c4db65 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetTest.java
@@ -23,6 +23,7 @@
 import static org.mockito.MockitoAnnotations.initMocks;
 
 import android.support.test.InstrumentationRegistry;
+import android.view.View;
 
 import androidx.test.filters.MediumTest;
 
@@ -37,6 +38,7 @@
 import org.mockito.Mock;
 
 import org.chromium.base.Callback;
+import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.R;
@@ -287,10 +289,18 @@
     @MediumTest
     public void testSignInDefaultAccountOnCollapsedSheet() {
         buildAndShowCollapsedBottomSheet();
-        String continueAsText = mActivityTestRule.getActivity().getString(
-                R.string.signin_promo_continue_as, PROFILE_DATA1.getGivenName());
-        onView(withText(continueAsText)).perform(click());
+        View bottomSheetView = mCoordinator.getBottomSheetViewForTesting();
+        ThreadUtils.runOnUiThread(
+                bottomSheetView.findViewById(R.id.account_picker_continue_as_button)::performClick);
+        CriteriaHelper.pollUiThread(() -> {
+            return !bottomSheetView.findViewById(R.id.account_picker_continue_as_button).isShown();
+        });
         verify(mAccountPickerDelegateMock).signIn(PROFILE_DATA1.getAccountName());
+        onView(withId(R.id.account_picker_bottom_sheet_subtitle))
+                .check(matches(not(isDisplayed())));
+        onView(withId(R.id.account_picker_account_list)).check(matches(not(isDisplayed())));
+        onView(withId(R.id.account_picker_selected_account)).check(matches(not(isDisplayed())));
+        onView(withId(R.id.account_picker_continue_as_button)).check(matches(not(isDisplayed())));
     }
 
     @Test
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityContentTestEnvironment.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityContentTestEnvironment.java
index 85bfffe..946ffa9 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityContentTestEnvironment.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityContentTestEnvironment.java
@@ -112,6 +112,10 @@
     protected void starting(Description description) {
         MockitoAnnotations.initMocks(this);
 
+        // There are a number of places that call CustomTabsConnection.getInstance(), which would
+        // otherwise result in a real CustomTabsConnection being created.
+        CustomTabsConnection.setInstanceForTesting(connection);
+
         tabFromFactory = prepareTab();
 
         when(intentDataProvider.getIntent()).thenReturn(intent);
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 4d04667..249014f 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -2870,10 +2870,10 @@
      Update now
   </message>
   <message name="IDS_UPDATE_REQUIRED_SCREEN_EOL_TITLE" desc="The title on login screen to inform the user that policy prevents the device from being used as it has reached its end of life.">
-    Device has been blocked
+    <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> has been blocked
   </message>
   <message name="IDS_UPDATE_REQUIRED_SCREEN_EOL_MESSAGE" desc="The message on login screen to inform the user that policy prevents the device from being used as it has reached its end of life.">
-    The deadline to return this device has passed.
+    The deadline to return this <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> has passed.
   </message>
   <message name="IDS_UPDATE_REQUIRED_SCREEN_METERED_MESSAGE" desc="The message on the dialog shown to the user in Chrome OS before forced update is attempted if the Chrome OS device is connected to a cellular/metered network. The dialog warns the user that procceeding on a metered network can cause overage charges.">
     <ph name="DOMAIN">$1<ex>example.com</ex></ph> requires you to connect to Wi-Fi now and download an update. Or, download from a metered connection (charges may apply).
@@ -2888,7 +2888,7 @@
     Open network settings
   </message>
   <message name="IDS_UPDATE_REQUIRED_UPDATING_MESSAGE" desc="The message of the update required dialog on the login screen to inform the user that the device is updating and will restart after the update is complete.">
-    Device will restart when updates are complete.
+    <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> will restart when updates are complete.
   </message>
   <message name="IDS_UPDATE_REQUIRED_EOL_ADMIN_MESSAGE" desc="The title of the message on the update required dialog on the login screen showing return instructions from the device administrator as the device has reached its end of life.">
     Instructions from your device administrator:
@@ -2896,42 +2896,39 @@
 
   <!-- Update Required Notification Strings-->
   <message name="IDS_UPDATE_REQUIRED_NETWORK_LIMITATION_TITLE_DAYS" desc="The title of the notification dialog informing the user that the device is not connected to a network suitable for downloading updates and an update is required within one or more days.">
-    {0, plural,
-      =1 {Last day to update device}
-      other {Update device within # days}}
+    {NUM_DAYS, plural,
+      =1 {Last day to update <ph name="DEVICE_TYPE">{1}<ex>Chromebook</ex></ph>}
+      other {Update <ph name="DEVICE_TYPE">{1}<ex>Chromebook</ex></ph> within {NUM_DAYS} days}}
   </message>
   <message name="IDS_UPDATE_REQUIRED_NETWORK_LIMITATION_TITLE_WEEKS" desc="The title of the notification dialog informing the user that the device is not connected to a network suitable for downloading updates and an update is required within one or more weeks.">
-    {0, plural,
-      =1 {Update device within 1 week}
-      other {Update device within # weeks}}
+    {NUM_WEEKS, plural,
+      =1 {Update <ph name="DEVICE_TYPE">{1}<ex>Chromebook</ex></ph> within 1 week}
+      other {Update <ph name="DEVICE_TYPE">{1}<ex>Chromebook</ex></ph> within {NUM_WEEKS} weeks}}
   </message>
-  <message name="IDS_UPDATE_REQUIRED_NO_NETWORK_MESSAGE" desc="The body text of the notification dialog informing the user that the device is not connected to the internet and an update is required.">
-    <ph name="DOMAIN">$1<ex>example.com</ex></ph> requires you to download an update before the deadline. The update will download automatically when you connect to the internet.
+  <message name="IDS_UPDATE_REQUIRED_NO_NETWORK_MESSAGE" desc="The body text of the notification dialog informing the user that the device is not connected to the internet and an update is required before the deadline which is within one or more days.">
+    {NUM_DAYS, plural,
+      =1 {<ph name="DOMAIN">{1}<ex>example.com</ex></ph> requires you to download an update today. The update will download automatically when you connect to the internet.}
+      other {<ph name="DOMAIN">{1}<ex>example.com</ex></ph> requires you to download an update before the deadline. The update will download automatically when you connect to the internet.}}
   </message>
-  <message name="IDS_UPDATE_REQUIRED_NO_NETWORK_MESSAGE_IMMEDIATE" desc="The body text of the notification dialog informing the user that the device is not connected to the internet and it is last day to update the device.">
-    <ph name="DOMAIN">$1<ex>example.com</ex></ph> requires you to download an update today. The update will download automatically when you connect to the internet.
-  </message>
-  <message name="IDS_UPDATE_REQUIRED_METERED_NETWORK_MESSAGE" desc="The body text of the notification dialog informing the user that the device is connected to a metered network and an update is required.">
-    <ph name="DOMAIN">$1<ex>example.com</ex></ph> requires you to connect to Wi-Fi and download an update before the deadline. Or, download from a metered connection (charges may apply).
-  </message>
-  <message name="IDS_UPDATE_REQUIRED_METERED_NETWORK_MESSAGE_IMMEDIATE" desc="The body text of the notification dialog informing the user that the device is connected to a metered network and it is last day to update the device.">
-    <ph name="DOMAIN">$1<ex>example.com</ex></ph> requires you to connect to Wi-Fi today to download an update. Or, download from a metered connection (charges may apply).
+  <message name="IDS_UPDATE_REQUIRED_METERED_NETWORK_MESSAGE" desc="The body text of the notification dialog informing the user that the device is connected to a metered network and an update is required before the deadline which is within one or more days.">
+    {NUM_DAYS, plural,
+      =1 {<ph name="DOMAIN">{1}<ex>example.com</ex></ph> requires you to connect to Wi-Fi today to download an update. Or, download from a metered connection (charges may apply).}
+      other {<ph name="DOMAIN">{1}<ex>example.com</ex></ph> requires you to connect to Wi-Fi and download an update before the deadline. Or, download from a metered connection (charges may apply).}}
   </message>
   <message name="IDS_UPDATE_REQUIRED_EOL_TITLE_DAYS" desc="The title of the notification dialog informing the user that the device has reached end of life and should be returned before the deadline.">
-    {0, plural,
+    {NUM_DAYS, plural,
       =1 {Immediate return required}
-      other {Return device within # days}}
+      other {Return <ph name="DEVICE_TYPE">{1}<ex>Chromebook</ex></ph> within {NUM_DAYS} days}}
   </message>
   <message name="IDS_UPDATE_REQUIRED_EOL_TITLE_WEEKS" desc="The title of the notification dialog informing the user that the device has reached end of life and should be returned within one or more weeks.">
-    {0, plural,
-      =1 {Return device within 1 week}
-      other {Return device within # weeks}}
+    {NUM_WEEKS, plural,
+      =1 {Return <ph name="DEVICE_TYPE">{1}<ex>Chromebook</ex></ph> within {NUM_WEEKS} week}
+      other {Return <ph name="DEVICE_TYPE">{1}<ex>Chromebook</ex></ph> within {NUM_WEEKS} weeks}}
   </message>
-  <message name="IDS_UPDATE_REQUIRED_EOL_MESSAGE_IMMEDIATE" desc="The body text of the noti fication dialog informing the user that the device has reached end of life and it is last day to return it.">
-    <ph name="DOMAIN">$1<ex>example.com</ex></ph> requires you to back up your data and return this device today.
-  </message>
-  <message name="IDS_UPDATE_REQUIRED_EOL_MESSAGE" desc="The body text of the notification dialog informing the user that the device has reached end of life and should be returned before the deadline.">
-    <ph name="DOMAIN">$1<ex>example.com</ex></ph> requires you to back up your data and return this device before the deadline.
+  <message name="IDS_UPDATE_REQUIRED_EOL_MESSAGE" desc="The body text of the notification dialog informing the user that the device has reached end of life and should be returned before the deadline which is within one or more days.">
+    {NUM_DAYS, plural,
+      =1 {<ph name="DOMAIN">{1}<ex>example.com</ex></ph> requires you to back up your data and return this <ph name="DEVICE_TYPE">{2}<ex>Chromebook</ex></ph> today.}
+      other {<ph name="DOMAIN">{1}<ex>example.com</ex></ph> requires you to back up your data and return this <ph name="DEVICE_TYPE">{2}<ex>Chromebook</ex></ph> before the deadline.}}
   </message>
   <message name="IDS_UPDATE_REQUIRED_EOL_SEE_DETAILS" desc="The button text of the notification dialog which can be clicked to view return instructions from the admin on the settings page.">
     See Details
diff --git a/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_EOL_MESSAGE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_EOL_MESSAGE.png.sha1
index e626642..85dd1019 100644
--- a/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_EOL_MESSAGE.png.sha1
+++ b/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_EOL_MESSAGE.png.sha1
@@ -1 +1 @@
-ef5ea1960e83040ecd2930f349fa065c7875d03d
\ No newline at end of file
+ae7723c0d9f4365b7cfb5d1a520332c192cdef77
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_EOL_MESSAGE_IMMEDIATE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_EOL_MESSAGE_IMMEDIATE.png.sha1
deleted file mode 100644
index 1f51c74d..0000000
--- a/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_EOL_MESSAGE_IMMEDIATE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-80bc5fa9690ddee420644429152296d4ba2e7153
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_EOL_TITLE_DAYS.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_EOL_TITLE_DAYS.png.sha1
index d3e2e4b..85dd1019 100644
--- a/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_EOL_TITLE_DAYS.png.sha1
+++ b/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_EOL_TITLE_DAYS.png.sha1
@@ -1 +1 @@
-4d497d66d7829e0d8be46d583e5c0f251e6eb1a3
\ No newline at end of file
+ae7723c0d9f4365b7cfb5d1a520332c192cdef77
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_EOL_TITLE_WEEKS.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_EOL_TITLE_WEEKS.png.sha1
index 6269eb01..c6d56be 100644
--- a/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_EOL_TITLE_WEEKS.png.sha1
+++ b/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_EOL_TITLE_WEEKS.png.sha1
@@ -1 +1 @@
-e2ede6057af0666db09f77fc67b2afd0cc52f822
\ No newline at end of file
+4af518e286c030df37f14728ee9a63b73ac991e8
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_METERED_NETWORK_MESSAGE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_METERED_NETWORK_MESSAGE.png.sha1
index 7619d9768..fb9492c 100644
--- a/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_METERED_NETWORK_MESSAGE.png.sha1
+++ b/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_METERED_NETWORK_MESSAGE.png.sha1
@@ -1 +1 @@
-5df42bf902f65d3b396f473a5fe005c7423a7928
\ No newline at end of file
+741358bbb3b2a2ec5dd6b58e7fca1f55aefb2fbe
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_METERED_NETWORK_MESSAGE_IMMEDIATE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_METERED_NETWORK_MESSAGE_IMMEDIATE.png.sha1
deleted file mode 100644
index 62a848a..0000000
--- a/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_METERED_NETWORK_MESSAGE_IMMEDIATE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-3f66b8884699b0543805014357c4d33445f39f9e
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_NETWORK_LIMITATION_TITLE_DAYS.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_NETWORK_LIMITATION_TITLE_DAYS.png.sha1
index 93fdcd7..fb9492c 100644
--- a/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_NETWORK_LIMITATION_TITLE_DAYS.png.sha1
+++ b/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_NETWORK_LIMITATION_TITLE_DAYS.png.sha1
@@ -1 +1 @@
-43c7e98e139718809dc6ccb93f9e43d5d5cfa358
\ No newline at end of file
+741358bbb3b2a2ec5dd6b58e7fca1f55aefb2fbe
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_NETWORK_LIMITATION_TITLE_WEEKS.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_NETWORK_LIMITATION_TITLE_WEEKS.png.sha1
index 03c34e9..a4617f7 100644
--- a/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_NETWORK_LIMITATION_TITLE_WEEKS.png.sha1
+++ b/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_NETWORK_LIMITATION_TITLE_WEEKS.png.sha1
@@ -1 +1 @@
-77b242cfccdcdcf2f244cd4d431b62ddaa835ce3
\ No newline at end of file
+f0d0320c80f648d304962395cbf80697feb4f4df
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_NO_NETWORK_MESSAGE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_NO_NETWORK_MESSAGE.png.sha1
index e38ad6d7..b566299 100644
--- a/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_NO_NETWORK_MESSAGE.png.sha1
+++ b/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_NO_NETWORK_MESSAGE.png.sha1
@@ -1 +1 @@
-9ea4bcaf0a870ea64b4655fc089016241dbb3f35
\ No newline at end of file
+a5711869a95cb93532582f161d1d134a17e6adcc
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_NO_NETWORK_MESSAGE_IMMEDIATE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_NO_NETWORK_MESSAGE_IMMEDIATE.png.sha1
deleted file mode 100644
index 0505ac0..0000000
--- a/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_NO_NETWORK_MESSAGE_IMMEDIATE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-e84e0bdb02c3edb288972353dad9c251c500039a
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_SCREEN_EOL_MESSAGE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_SCREEN_EOL_MESSAGE.png.sha1
new file mode 100644
index 0000000..190a61c
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_SCREEN_EOL_MESSAGE.png.sha1
@@ -0,0 +1 @@
+5886904d98b5759ce02dc108f35ef699d6d35637
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_SCREEN_EOL_TITLE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_SCREEN_EOL_TITLE.png.sha1
new file mode 100644
index 0000000..190a61c
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_SCREEN_EOL_TITLE.png.sha1
@@ -0,0 +1 @@
+5886904d98b5759ce02dc108f35ef699d6d35637
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_UPDATING_MESSAGE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_UPDATING_MESSAGE.png.sha1
new file mode 100644
index 0000000..c7d8b0e0
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_UPDATE_REQUIRED_UPDATING_MESSAGE.png.sha1
@@ -0,0 +1 @@
+6c4c78b0ead106e84942b7afa5626fe467eb089e
\ No newline at end of file
diff --git a/chrome/app/nearby_share_strings.grdp b/chrome/app/nearby_share_strings.grdp
index d36cffee..50ed616 100644
--- a/chrome/app/nearby_share_strings.grdp
+++ b/chrome/app/nearby_share_strings.grdp
@@ -35,7 +35,9 @@
 
   <!-- Notification strings -->
   <message name="IDS_NEARBY_NOTIFICATION_CONNECTION_REQUEST_MESSAGE" desc="Text shown as the message of a notfication when a nearby device requests a connection via Nearby Share.">
-    <ph name="DEVICE_NAME">$1<ex>Ted's Pixel 2</ex></ph> is sharing <ph name="ATTACHMENTS">$2<ex>3 items</ex></ph> with you.
+    {COUNT, plural,
+      =1 {<ph name="DEVICE_NAME">$1<ex>Ted's Pixel 2</ex></ph> is sharing <ph name="ATTACHMENTS">$2<ex>1 item</ex></ph> with you.}
+      other {<ph name="DEVICE_NAME">$1<ex>Ted's Pixel 2</ex></ph> is sharing <ph name="ATTACHMENTS">$2<ex>3 items</ex></ph> with you.}}
   </message>
   <message name="IDS_NEARBY_NOTIFICATION_CONNECTION_REQUEST_TITLE" desc="Text shown as the title of a notfication when a nearby device requests a connection via Nearby Share.">
     Receive with Nearby Share?
@@ -53,22 +55,34 @@
     Receive
   </message>
   <message name="IDS_NEARBY_NOTIFICATION_RECEIVE_FAILURE_TITLE" desc="Text shown as the title of a notfication when receiving data via Nearby Share failed.">
-    Failed to receive <ph name="ATTACHMENTS">$1<ex>3 items</ex></ph> from <ph name="DEVICE_NAME">$2<ex>Ted's Pixel 2</ex></ph>
+    {COUNT, plural,
+      =1 {Failed to receive <ph name="ATTACHMENTS">$1<ex>1 item</ex></ph> from <ph name="DEVICE_NAME">$2<ex>Ted's Pixel 2</ex></ph>}
+      other {Failed to receive <ph name="ATTACHMENTS">$1<ex>3 items</ex></ph> from <ph name="DEVICE_NAME">$2<ex>Ted's Pixel 2</ex></ph>}}
   </message>
   <message name="IDS_NEARBY_NOTIFICATION_RECEIVE_PROGRESS_TITLE" desc="Text shown as the title of a notfication when receiving data via Nearby Share.">
-    Receiving <ph name="ATTACHMENTS">$1<ex>3 items</ex></ph> from <ph name="DEVICE_NAME">$2<ex>Ted's Pixel 2</ex></ph>
+    {COUNT, plural,
+      =1 {Receiving <ph name="ATTACHMENTS">$1<ex>1 item</ex></ph> from <ph name="DEVICE_NAME">$2<ex>Ted's Pixel 2</ex></ph>}
+      other {Receiving <ph name="ATTACHMENTS">$1<ex>3 items</ex></ph> from <ph name="DEVICE_NAME">$2<ex>Ted's Pixel 2</ex></ph>}}
   </message>
   <message name="IDS_NEARBY_NOTIFICATION_RECEIVE_SUCCESS_TITLE" desc="Text shown as the title of a notfication when data was sucessfully received via Nearby Share.">
-    <ph name="ATTACHMENTS">$1<ex>3 items</ex></ph> received from <ph name="DEVICE_NAME">$2<ex>Ted's Pixel 2</ex></ph>
+    {COUNT, plural,
+      =1 {<ph name="ATTACHMENTS">$1<ex>1 item</ex></ph> received from <ph name="DEVICE_NAME">$2<ex>Ted's Pixel 2</ex></ph>}
+      other {<ph name="ATTACHMENTS">$1<ex>3 items</ex></ph> received from <ph name="DEVICE_NAME">$2<ex>Ted's Pixel 2</ex></ph>}}
   </message>
   <message name="IDS_NEARBY_NOTIFICATION_SEND_FAILURE_TITLE" desc="Text shown as the title of a notfication when sending data via Nearby Share failed.">
-    Failed to send <ph name="ATTACHMENTS">$1<ex>3 items</ex></ph> to <ph name="DEVICE_NAME">$2<ex>Ted's Pixel 2</ex></ph>
+    {COUNT, plural,
+      =1 {Failed to send <ph name="ATTACHMENTS">$1<ex>1 item</ex></ph> to <ph name="DEVICE_NAME">$2<ex>Ted's Pixel 2</ex></ph>}
+      other {Failed to send <ph name="ATTACHMENTS">$1<ex>3 items</ex></ph> to <ph name="DEVICE_NAME">$2<ex>Ted's Pixel 2</ex></ph>}}
   </message>
   <message name="IDS_NEARBY_NOTIFICATION_SEND_PROGRESS_TITLE" desc="Text shown as the title of a notfication when sending data via Nearby Share.">
-    Sending <ph name="ATTACHMENTS">$1<ex>3 items</ex></ph> to <ph name="DEVICE_NAME">$2<ex>Ted's Pixel 2</ex></ph>
+    {COUNT, plural,
+      =1 {Sending <ph name="ATTACHMENTS">$1<ex>1 item</ex></ph> to <ph name="DEVICE_NAME">$2<ex>Ted's Pixel 2</ex></ph>}
+      other {Sending <ph name="ATTACHMENTS">$1<ex>3 items</ex></ph> to <ph name="DEVICE_NAME">$2<ex>Ted's Pixel 2</ex></ph>}}
   </message>
   <message name="IDS_NEARBY_NOTIFICATION_SEND_SUCCESS_TITLE" desc="Text shown as the title of a notfication when data was successfully sent via Nearby Share.">
-    <ph name="ATTACHMENTS">$1<ex>3 items</ex></ph> successfully sent to <ph name="DEVICE_NAME">$2<ex>Ted's Pixel 2</ex></ph>
+    {COUNT, plural,
+      =1 {<ph name="ATTACHMENTS">$1<ex>1 item</ex></ph> successfully sent to <ph name="DEVICE_NAME">$2<ex>Ted's Pixel 2</ex></ph>}
+      other {<ph name="ATTACHMENTS">$1<ex>3 items</ex></ph> successfully sent to <ph name="DEVICE_NAME">$2<ex>Ted's Pixel 2</ex></ph>}}
   </message>
   <message name="IDS_NEARBY_NOTIFICATION_SOURCE" desc="Text shown as the source of a Nearby Share notification.">
     Nearby Share
diff --git a/chrome/app/os_settings_strings.grdp b/chrome/app/os_settings_strings.grdp
index 4f2159fa..acf940f 100644
--- a/chrome/app/os_settings_strings.grdp
+++ b/chrome/app/os_settings_strings.grdp
@@ -18,14 +18,13 @@
   <message name="IDS_SETTINGS_SECONDARY_USER_BANNER" desc="Banner displayed in settings page when the user is secondary in a multi-profile session.">
     Some settings belonging to <ph name="PRIMARY_EMAIL">$1<ex>john@google.com</ex></ph> are being shared with you. These settings only affect your account when using multiple sign-in.
   </message>
-  <message name="IDS_SETTINGS_UPDATE_REQUIRED_EOL_BANNER_DAYS" desc="Banner displayed in OS settings page in case update is required by policy but device has reached end-of-life and the days remaining to return the device back to the enterprise is greater than one and less than seven.">
-      <ph name="DOMAIN">$1<ex>example.com</ex></ph> requires you to back up your data and return this device within <ph name="DAYS_COUNT">$2<ex>10</ex></ph> days.<ph name="LINK_BEGIN">&lt;a target="_blank" href="$3<ex>https://google.com/</ex>"&gt;</ph>See details<ph name="LINK_END">&lt;/a&gt;</ph>
-  </message>
-  <message name="IDS_SETTINGS_UPDATE_REQUIRED_EOL_BANNER_LAST_DAY" desc="Banner displayed in OS settings page in case update is required by policy but device has reached end-of-life and it is the last day to return the device back to the enterprise.">
-      <ph name="DOMAIN">$1<ex>example.com</ex></ph> requires you to back up your data and return this device today.<ph name="LINK_BEGIN">&lt;a target="_blank" href="$2<ex>https://google.com/</ex>"&gt;</ph>See details<ph name="LINK_END">&lt;/a&gt;</ph>
+  <message name="IDS_SETTINGS_UPDATE_REQUIRED_EOL_BANNER_DAYS" desc="Banner displayed in OS settings page in case update is required by policy but device has reached end-of-life and the days remaining to return the device back to the enterprise is less than seven.">
+    {NUM_DAYS, plural,
+      =1 {<ph name="DOMAIN">{1}<ex>example.com</ex></ph> requires you to back up your data and return this <ph name="DEVICE_TYPE">{2}<ex>Chromebook</ex></ph> today.<ph name="LINK_BEGIN">&lt;a target="_blank" href="{3}<ex>https://google.com/</ex>"&gt;</ph>See details<ph name="LINK_END">&lt;/a&gt;</ph>}
+      other {<ph name="DOMAIN">{1}<ex>example.com</ex></ph> requires you to back up your data and return this <ph name="DEVICE_TYPE">{2}<ex>Chromebook</ex></ph> within {NUM_DAYS} days.<ph name="LINK_BEGIN">&lt;a target="_blank" href="{3}<ex>https://google.com/</ex>"&gt;</ph>See details<ph name="LINK_END">&lt;/a&gt;</ph>}}
   </message>
   <message name="IDS_SETTINGS_UPDATE_REQUIRED_EOL_BANNER_ONE_WEEK" desc="Banner displayed in OS settings page in case update is required by policy but device has reached end-of-life and the days remaining to return the device back to the enterprise is equal to seven.">
-      <ph name="DOMAIN">$1<ex>example.com</ex></ph> requires you to back up your data and return this device within 1 week.<ph name="LINK_BEGIN">&lt;a target="_blank" href="$2<ex>https://google.com/</ex>"&gt;</ph>See details<ph name="LINK_END">&lt;/a&gt;</ph>
+    <ph name="DOMAIN">$1<ex>example.com</ex></ph> requires you to back up your data and return this <ph name="DEVICE_TYPE">$2<ex>Chromebook</ex></ph> within 1 week.<ph name="LINK_BEGIN">&lt;a target="_blank" href="$3<ex>https://google.com/</ex>"&gt;</ph>See details<ph name="LINK_END">&lt;/a&gt;</ph>
   </message>
 
   <!-- Settings Search Box -->
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_UPDATE_REQUIRED_EOL_BANNER_DAYS.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_UPDATE_REQUIRED_EOL_BANNER_DAYS.png.sha1
index 9e106a1..68897631 100644
--- a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_UPDATE_REQUIRED_EOL_BANNER_DAYS.png.sha1
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_UPDATE_REQUIRED_EOL_BANNER_DAYS.png.sha1
@@ -1 +1 @@
-932a1b84fef78d74fa7802ad184487feaa2e9e5f
\ No newline at end of file
+7fb20039ee560a2011c23caa90be95ad49cb8a2a
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_UPDATE_REQUIRED_EOL_BANNER_LAST_DAY.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_UPDATE_REQUIRED_EOL_BANNER_LAST_DAY.png.sha1
deleted file mode 100644
index e226813..0000000
--- a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_UPDATE_REQUIRED_EOL_BANNER_LAST_DAY.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-836fdeaa65fa654bd342623dd680ee6ff378b295
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_UPDATE_REQUIRED_EOL_BANNER_ONE_WEEK.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_UPDATE_REQUIRED_EOL_BANNER_ONE_WEEK.png.sha1
index 49bf1e6..94e41e2 100644
--- a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_UPDATE_REQUIRED_EOL_BANNER_ONE_WEEK.png.sha1
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_UPDATE_REQUIRED_EOL_BANNER_ONE_WEEK.png.sha1
@@ -1 +1 @@
-6dcd6792924c36dc064038d41aba50c07f105a6f
\ No newline at end of file
+9e08260e0f4b0af62a9b344a5584615126caac3d
\ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 91f07986..b921a5a 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -997,6 +997,8 @@
     "page_load_metrics/observers/https_engagement_metrics/https_engagement_service_factory.h",
     "page_load_metrics/observers/isolated_prerender_page_load_metrics_observer.cc",
     "page_load_metrics/observers/isolated_prerender_page_load_metrics_observer.h",
+    "page_load_metrics/observers/javascript_frameworks_ukm_observer.cc",
+    "page_load_metrics/observers/javascript_frameworks_ukm_observer.h",
     "page_load_metrics/observers/live_tab_count_page_load_metrics_observer.cc",
     "page_load_metrics/observers/live_tab_count_page_load_metrics_observer.h",
     "page_load_metrics/observers/loading_predictor_page_load_metrics_observer.cc",
@@ -4132,8 +4134,6 @@
       "profiles/profile_shortcut_manager_win.h",
       "shell_integration_win.cc",
       "shell_integration_win.h",
-      "sync/roaming_profile_directory_deleter_win.cc",
-      "sync/roaming_profile_directory_deleter_win.h",
       "task_manager/sampling/shared_sampler_win.cc",
       "task_manager/sampling/shared_sampler_win_defines.h",
       "taskbar/taskbar_decorator_win.cc",
diff --git a/chrome/browser/android/autofill_assistant/client_android.cc b/chrome/browser/android/autofill_assistant/client_android.cc
index a964562..2e4d3118 100644
--- a/chrome/browser/android/autofill_assistant/client_android.cc
+++ b/chrome/browser/android/autofill_assistant/client_android.cc
@@ -81,19 +81,6 @@
       base::android::ConvertJavaStringToUTF8(env, jexperiment_ids));
 }
 
-// Notifies Chrome's Password Manager that Autofill Assistant is running or
-// not. No-op if the script is not a password change script.
-void NotifyPasswordManagerIfApplicable(
-    ClientAndroid* client,
-    password_manager::AutofillAssistantMode mode) {
-  auto* password_manager_client = client->GetPasswordManagerClient();
-  if (password_manager_client &&
-      password_manager_client->WasCredentialLeakDialogShown()) {
-    password_manager_client->GetPasswordManager()->SetAutofillAssistantMode(
-        mode);
-  }
-}
-
 }  // namespace
 
 static base::android::ScopedJavaLocalRef<jobject>
@@ -197,9 +184,8 @@
   auto ui_ptr = std::move(ui_controller_android_);
   // From this point on, the UIController, in ui_ptr, is either transferred or
   // deleted.
-
   NotifyPasswordManagerIfApplicable(
-      this, password_manager::AutofillAssistantMode::kNotRunning);
+      password_manager::AutofillAssistantMode::kNotRunning);
 
   if (!jother_web_contents)
     return;
@@ -351,6 +337,18 @@
       env, java_object_, jcallback, controller_ != nullptr);
 }
 
+void ClientAndroid::NotifyPasswordManagerIfApplicable(
+    password_manager::AutofillAssistantMode mode) {
+  if (!controller_->GetTriggerContext()->GetPasswordChangeUsername())
+    return;
+
+  auto* password_manager_client = GetPasswordManagerClient();
+  if (password_manager_client) {
+    password_manager_client->GetPasswordManager()->SetAutofillAssistantMode(
+        mode);
+  }
+}
+
 bool ClientAndroid::PerformDirectAction(
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& jcaller,
@@ -438,7 +436,7 @@
     // Suppress password manager's prompts while running a password change
     // script.
     NotifyPasswordManagerIfApplicable(
-        this, password_manager::AutofillAssistantMode::kRunning);
+        password_manager::AutofillAssistantMode::kRunning);
   }
 }
 
@@ -552,11 +550,12 @@
   if (!controller_)
     return;
 
-  NotifyPasswordManagerIfApplicable(
-      this, password_manager::AutofillAssistantMode::kNotRunning);
-
-  if (ui_controller_android_ && ui_controller_android_->IsAttached())
+  if (ui_controller_android_ && ui_controller_android_->IsAttached()) {
+    // Notify the password manager only if ui is not transferred to another tab.
+    NotifyPasswordManagerIfApplicable(
+        password_manager::AutofillAssistantMode::kNotRunning);
     DestroyUI();
+  }
 
   if (started_)
     Metrics::RecordDropOut(reason);
diff --git a/chrome/browser/android/autofill_assistant/client_android.h b/chrome/browser/android/autofill_assistant/client_android.h
index 81aa35c2..28c0a815 100644
--- a/chrome/browser/android/autofill_assistant/client_android.h
+++ b/chrome/browser/android/autofill_assistant/client_android.h
@@ -22,6 +22,10 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_user_data.h"
 
+namespace password_manager {
+enum class AutofillAssistantMode;
+}
+
 namespace autofill_assistant {
 
 // Creates a Autofill Assistant client associated with a WebContents.
@@ -129,6 +133,10 @@
       const base::android::JavaParamRef<jobject>& jonboarding_coordinator);
   bool NeedsUI();
   void OnFetchWebsiteActions(const base::android::JavaRef<jobject>& jcallback);
+  // Notifies Chrome's Password Manager that Autofill Assistant is running or
+  // not. No-op if the script is not a password change script.
+  void NotifyPasswordManagerIfApplicable(
+      password_manager::AutofillAssistantMode mode);
 
   base::android::ScopedJavaLocalRef<jobjectArray>
   GetDirectActionsAsJavaArrayOfStrings(JNIEnv* env) const;
diff --git a/chrome/browser/android/metrics/uma_session_stats.cc b/chrome/browser/android/metrics/uma_session_stats.cc
index 61d3cc3..c14dbe5 100644
--- a/chrome/browser/android/metrics/uma_session_stats.cc
+++ b/chrome/browser/android/metrics/uma_session_stats.cc
@@ -276,7 +276,8 @@
 static void JNI_UmaSessionStats_RegisterExternalExperiment(
     JNIEnv* env,
     const JavaParamRef<jstring>& jfallback_study_name,
-    const JavaParamRef<jintArray>& jexperiment_ids) {
+    const JavaParamRef<jintArray>& jexperiment_ids,
+    jboolean override_existing_ids) {
   std::string fallback_study_name(
       ConvertJavaStringToUTF8(env, jfallback_study_name));
   std::vector<int> experiment_ids;
@@ -286,11 +287,15 @@
                                            &experiment_ids);
   }
 
+  auto override_mode =
+      override_existing_ids
+          ? variations::SyntheticTrialRegistry::kOverrideExistingIds
+          : variations::SyntheticTrialRegistry::kDoNotOverrideExistingIds;
+
   g_browser_process->metrics_service()
       ->synthetic_trial_registry()
-      ->RegisterExternalExperiments(
-          fallback_study_name, experiment_ids,
-          variations::SyntheticTrialRegistry::kOverrideExistingIds);
+      ->RegisterExternalExperiments(fallback_study_name, experiment_ids,
+                                    override_mode);
 }
 
 static void JNI_UmaSessionStats_RegisterSyntheticFieldTrial(
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 8bb1eac3..7b1eab0 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -1559,6 +1559,12 @@
     "login/saml/in_session_password_sync_manager_factory.h",
     "login/saml/password_expiry_notification.cc",
     "login/saml/password_expiry_notification.h",
+    "login/saml/password_sync_token_fetcher.cc",
+    "login/saml/password_sync_token_fetcher.h",
+    "login/saml/password_sync_token_verifier.cc",
+    "login/saml/password_sync_token_verifier.h",
+    "login/saml/password_sync_token_verifier_factory.cc",
+    "login/saml/password_sync_token_verifier_factory.h",
     "login/saml/public_saml_url_fetcher.cc",
     "login/saml/public_saml_url_fetcher.h",
     "login/saml/saml_metric_utils.cc",
@@ -3221,6 +3227,7 @@
     "login/saml/mock_lock_handler.cc",
     "login/saml/mock_lock_handler.h",
     "login/saml/password_expiry_notification_unittest.cc",
+    "login/saml/password_sync_token_verifier_unittest.cc",
     "login/saml/saml_offline_signin_limiter_unittest.cc",
     "login/screens/network_screen_unittest.cc",
     "login/screens/recommend_apps/recommend_apps_fetcher_impl_unittest.cc",
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index 444bedb..bd396d1 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -900,14 +900,17 @@
   network_pref_state_observer_ = std::make_unique<NetworkPrefStateObserver>();
 
   // Initialize the NetworkHealth aggregator.
-  network_health::NetworkHealthService* network_health_service =
-      network_health::NetworkHealthService::GetInstance();
-  DCHECK(network_health_service);
+  network_health::NetworkHealthService::GetInstance();
 
-  // Create the service connection to cros_healthd.
-  cros_healthd::ServiceConnection* cros_healthd =
-      cros_healthd::ServiceConnection::GetInstance();
-  DCHECK(cros_healthd);
+  // Create the service connection to CrosHealthd platform service instance.
+  auto* cros_healthd = cros_healthd::ServiceConnection::GetInstance();
+
+  // Pass a callback to the CrosHealthd service connection that binds a pending
+  // remote to service.
+  cros_healthd->SetBindNetworkHealthServiceCallback(base::BindRepeating([] {
+    return network_health::NetworkHealthService::GetInstance()
+        ->GetHealthRemoteAndBindReceiver();
+  }));
 
   // Initialize input methods.
   input_method::InputMethodManager* manager =
diff --git a/chrome/browser/chromeos/login/kiosk_browsertest.cc b/chrome/browser/chromeos/login/kiosk_browsertest.cc
index 3be4bf1..2240b88 100644
--- a/chrome/browser/chromeos/login/kiosk_browsertest.cc
+++ b/chrome/browser/chromeos/login/kiosk_browsertest.cc
@@ -2553,7 +2553,8 @@
   DISALLOW_COPY_AND_ASSIGN(KioskVirtualKeyboardTest);
 };
 
-IN_PROC_BROWSER_TEST_F(KioskVirtualKeyboardTest, RestrictFeatures) {
+// Flaky. crbug.com/1094809
+IN_PROC_BROWSER_TEST_F(KioskVirtualKeyboardTest, DISABLED_RestrictFeatures) {
   set_test_app_id(kTestVirtualKeyboardKioskApp);
   set_test_app_version("0.1");
   set_test_crx_file(test_app_id() + ".crx");
diff --git a/chrome/browser/chromeos/login/saml/in_session_password_sync_manager.cc b/chrome/browser/chromeos/login/saml/in_session_password_sync_manager.cc
index 9df0829..4a100e7 100644
--- a/chrome/browser/chromeos/login/saml/in_session_password_sync_manager.cc
+++ b/chrome/browser/chromeos/login/saml/in_session_password_sync_manager.cc
@@ -5,9 +5,8 @@
 #include "chrome/browser/chromeos/login/saml/in_session_password_sync_manager.h"
 
 #include "base/time/default_clock.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/browser_process_platform_part_chromeos.h"
 #include "chrome/browser/chromeos/login/lock/screen_locker.h"
+#include "chrome/browser/chromeos/login/saml/password_sync_token_fetcher.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/components/proximity_auth/screenlock_bridge.h"
@@ -17,6 +16,7 @@
 #include "components/session_manager/core/session_manager_observer.h"
 #include "components/user_manager/known_user.h"
 #include "components/user_manager/user_manager_base.h"
+#include "content/public/browser/storage_partition.h"
 
 namespace chromeos {
 
@@ -50,11 +50,19 @@
   return prefs->GetBoolean(prefs::kSamlLockScreenReauthenticationEnabled);
 }
 
-void InSessionPasswordSyncManager::MaybeForceReauthOnLockScreen() {
-  if (enforce_reauth_on_lock_) {
+void InSessionPasswordSyncManager::MaybeForceReauthOnLockScreen(
+    ReauthenticationReason reauth_reason) {
+  if (lock_screen_reauth_reason_ == ReauthenticationReason::kInvalidToken) {
     // Re-authentication already enforced, no other action is needed.
     return;
   }
+  if (lock_screen_reauth_reason_ == ReauthenticationReason::kPolicy &&
+      reauth_reason == ReauthenticationReason::kInvalidToken) {
+    // Re-authentication already enforced but need to reset it to trigger token
+    // update. No other action is needed.
+    lock_screen_reauth_reason_ = reauth_reason;
+    return;
+  }
   if (!primary_user_->force_online_signin()) {
     // force_online_signin flag is not set - do not update the screen.
     return;
@@ -65,7 +73,7 @@
         primary_user_->GetAccountId(),
         proximity_auth::mojom::AuthType::ONLINE_SIGN_IN, base::string16());
   }
-  enforce_reauth_on_lock_ = true;
+  lock_screen_reauth_reason_ = reauth_reason;
 }
 
 void InSessionPasswordSyncManager::OnAuthSucceeded(
@@ -80,7 +88,11 @@
   }
 
   UpdateOnlineAuth();
-  enforce_reauth_on_lock_ = false;
+  if (lock_screen_reauth_reason_ == ReauthenticationReason::kInvalidToken) {
+    FetchTokenAsync();
+  } else {
+    lock_screen_reauth_reason_ = ReauthenticationReason::kNone;
+  }
   if (screenlock_bridge_->IsLocked()) {
     screenlock_bridge_->lock_handler()->Unlock(user_context.GetAccountId());
   }
@@ -98,7 +110,7 @@
     // We are unlocking the session, no further action required.
     return;
   }
-  if (!enforce_reauth_on_lock_) {
+  if (lock_screen_reauth_reason_ == ReauthenticationReason::kNone) {
     // locking the session but no re-auth flag set - show standard UI.
     return;
   }
@@ -120,4 +132,45 @@
                                                 now);
 }
 
+void InSessionPasswordSyncManager::CreateTokenAsync() {
+  password_sync_token_fetcher_ = std::make_unique<PasswordSyncTokenFetcher>(
+      primary_profile_->GetURLLoaderFactory(), primary_profile_, this);
+  password_sync_token_fetcher_->StartTokenCreate();
+}
+
+void InSessionPasswordSyncManager::OnTokenCreated(const std::string& token) {
+  user_manager::known_user::SetPasswordSyncToken(primary_user_->GetAccountId(),
+                                                 token);
+  lock_screen_reauth_reason_ = ReauthenticationReason::kNone;
+}
+
+void InSessionPasswordSyncManager::FetchTokenAsync() {
+  password_sync_token_fetcher_ = std::make_unique<PasswordSyncTokenFetcher>(
+      primary_profile_->GetURLLoaderFactory(), primary_profile_, this);
+  password_sync_token_fetcher_->StartTokenGet();
+}
+
+void InSessionPasswordSyncManager::OnTokenFetched(const std::string& token) {
+  if (!token.empty()) {
+    // Set token fetched from the endpoint.
+    user_manager::known_user::SetPasswordSyncToken(
+        primary_user_->GetAccountId(), token);
+    lock_screen_reauth_reason_ = ReauthenticationReason::kNone;
+  } else {
+    // This is the first time a sync token is created for the user: we need to
+    // initialize its value by calling the API and store it locally.
+    CreateTokenAsync();
+  }
+}
+
+void InSessionPasswordSyncManager::OnTokenVerified(bool is_valid) {
+  // InSessionPasswordSyncManager does not verify the sync token.
+}
+
+void InSessionPasswordSyncManager::OnApiCallFailed(
+    PasswordSyncTokenFetcher::ErrorType error_type) {
+  // Ignore API errors since they are logged by TokenFetcher and will be
+  // re-tried after the next verify interval.
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/saml/in_session_password_sync_manager.h b/chrome/browser/chromeos/login/saml/in_session_password_sync_manager.h
index 818c9eb..a0e4867 100644
--- a/chrome/browser/chromeos/login/saml/in_session_password_sync_manager.h
+++ b/chrome/browser/chromeos/login/saml/in_session_password_sync_manager.h
@@ -11,6 +11,7 @@
 #include "base/observer_list.h"
 #include "base/time/clock.h"
 #include "base/time/time.h"
+#include "chrome/browser/chromeos/login/saml/password_sync_token_fetcher.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chromeos/components/proximity_auth/screenlock_bridge.h"
 #include "components/account_id/account_id.h"
@@ -34,8 +35,18 @@
 // policy is set.
 class InSessionPasswordSyncManager
     : public KeyedService,
-      public session_manager::SessionManagerObserver {
+      public session_manager::SessionManagerObserver,
+      public PasswordSyncTokenFetcher::Consumer {
  public:
+  enum class ReauthenticationReason {
+    kNone,
+    // Enforced by the timeout set in SAMLOfflineSigninTimeLimit policy.
+    kPolicy,
+    // Enforced by mismatch between sync token API endpoint and the local copy
+    // of the token.
+    kInvalidToken
+  };
+
   explicit InSessionPasswordSyncManager(Profile* primary_profile);
   ~InSessionPasswordSyncManager() override;
 
@@ -53,7 +64,7 @@
 
   // Sets online re-auth on lock flag and changes the UI to online
   // re-auth when called on the lock screen.
-  void MaybeForceReauthOnLockScreen();
+  void MaybeForceReauthOnLockScreen(ReauthenticationReason reauth_reason);
 
   // Set special clock for testing.
   void SetClockForTesting(const base::Clock* clock);
@@ -64,17 +75,30 @@
   // session_manager::SessionManagerObserver::
   void OnSessionStateChanged() override;
 
+  // PasswordSyncTokenFetcher::Consumer
+  void OnTokenCreated(const std::string& sync_token) override;
+  void OnTokenFetched(const std::string& sync_token) override;
+  void OnTokenVerified(bool is_valid) override;
+  void OnApiCallFailed(PasswordSyncTokenFetcher::ErrorType error_type) override;
+
  private:
   void UpdateOnlineAuth();
+  // Password sync token API calls.
+  void CreateTokenAsync();
+  void FetchTokenAsync();
 
   Profile* const primary_profile_;
   const base::Clock* clock_;
   const user_manager::User* const primary_user_;
-  bool enforce_reauth_on_lock_ = false;
+  ReauthenticationReason lock_screen_reauth_reason_ =
+      ReauthenticationReason::kNone;
   proximity_auth::ScreenlockBridge* screenlock_bridge_;
+  std::unique_ptr<PasswordSyncTokenFetcher> password_sync_token_fetcher_;
 
   friend class InSessionPasswordSyncManagerTest;
   friend class InSessionPasswordSyncManagerFactory;
+
+  base::WeakPtrFactory<InSessionPasswordSyncManager> weak_factory_{this};
 };
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/saml/in_session_password_sync_manager_unittest.cc b/chrome/browser/chromeos/login/saml/in_session_password_sync_manager_unittest.cc
index 6f08dca..bf902d4b 100644
--- a/chrome/browser/chromeos/login/saml/in_session_password_sync_manager_unittest.cc
+++ b/chrome/browser/chromeos/login/saml/in_session_password_sync_manager_unittest.cc
@@ -63,7 +63,7 @@
   void CreateInSessionSyncManager();
   void DestroyInSessionSyncManager();
 
-  bool InSessionReauthFlagSet();
+  InSessionPasswordSyncManager::ReauthenticationReason InSessionReauthReason();
   void LockScreen();
   void UnlockScreen();
 
@@ -145,8 +145,9 @@
   proximity_auth::ScreenlockBridge::Get()->SetLockHandler(nullptr);
 }
 
-bool InSessionPasswordSyncManagerTest::InSessionReauthFlagSet() {
-  return manager_->enforce_reauth_on_lock_;
+InSessionPasswordSyncManager::ReauthenticationReason
+InSessionPasswordSyncManagerTest::InSessionReauthReason() {
+  return manager_->lock_screen_reauth_reason_;
 }
 
 TEST_F(InSessionPasswordSyncManagerTest, ReauthenticateSetInSession) {
@@ -155,8 +156,25 @@
   CreateInSessionSyncManager();
   UnlockScreen();
   user_manager_->SaveForceOnlineSignin(saml_login_account_id1_, true);
-  manager_->MaybeForceReauthOnLockScreen();
-  EXPECT_TRUE(InSessionReauthFlagSet());
+  manager_->MaybeForceReauthOnLockScreen(
+      InSessionPasswordSyncManager::ReauthenticationReason::kPolicy);
+  EXPECT_EQ(InSessionReauthReason(),
+            InSessionPasswordSyncManager::ReauthenticationReason::kPolicy);
+}
+
+TEST_F(InSessionPasswordSyncManagerTest, ReauthenticateResetByToken) {
+  primary_profile_->GetPrefs()->SetBoolean(
+      prefs::kSamlLockScreenReauthenticationEnabled, true);
+  CreateInSessionSyncManager();
+  UnlockScreen();
+  user_manager_->SaveForceOnlineSignin(saml_login_account_id1_, true);
+  manager_->MaybeForceReauthOnLockScreen(
+      InSessionPasswordSyncManager::ReauthenticationReason::kPolicy);
+  manager_->MaybeForceReauthOnLockScreen(
+      InSessionPasswordSyncManager::ReauthenticationReason::kInvalidToken);
+  EXPECT_EQ(
+      InSessionReauthReason(),
+      InSessionPasswordSyncManager::ReauthenticationReason::kInvalidToken);
 }
 
 TEST_F(InSessionPasswordSyncManagerTest, ReauthenticateSetOnLock) {
@@ -170,8 +188,10 @@
                           base::string16()))
       .Times(1);
   user_manager_->SaveForceOnlineSignin(saml_login_account_id1_, true);
-  manager_->MaybeForceReauthOnLockScreen();
-  EXPECT_TRUE(InSessionReauthFlagSet());
+  manager_->MaybeForceReauthOnLockScreen(
+      InSessionPasswordSyncManager::ReauthenticationReason::kPolicy);
+  EXPECT_EQ(InSessionReauthReason(),
+            InSessionPasswordSyncManager::ReauthenticationReason::kPolicy);
 }
 
 // User tries to unlock the screen using valid SAML credentials but not for the
@@ -189,12 +209,15 @@
       .Times(1);
   EXPECT_CALL(*lock_handler_, Unlock(saml_login_account_id1_)).Times(0);
   user_manager_->SaveForceOnlineSignin(saml_login_account_id1_, true);
-  manager_->MaybeForceReauthOnLockScreen();
-  EXPECT_TRUE(InSessionReauthFlagSet());
+  manager_->MaybeForceReauthOnLockScreen(
+      InSessionPasswordSyncManager::ReauthenticationReason::kPolicy);
+  EXPECT_EQ(InSessionReauthReason(),
+            InSessionPasswordSyncManager::ReauthenticationReason::kPolicy);
   UserContext user_context(user_manager::USER_TYPE_REGULAR,
                            saml_login_account_id2_);
   manager_->OnAuthSucceeded(user_context);
-  EXPECT_TRUE(InSessionReauthFlagSet());
+  EXPECT_EQ(InSessionReauthReason(),
+            InSessionPasswordSyncManager::ReauthenticationReason::kPolicy);
   EXPECT_TRUE(proximity_auth::ScreenlockBridge::Get()->IsLocked());
 }
 
@@ -217,12 +240,15 @@
   EXPECT_CALL(*lock_handler_, Unlock(saml_login_account_id1_)).Times(1);
   user_manager_->SaveForceOnlineSignin(saml_login_account_id1_, true);
   test_environment_.FastForwardBy(kSamlOnlineShortDelay);
-  manager_->MaybeForceReauthOnLockScreen();
-  EXPECT_TRUE(InSessionReauthFlagSet());
+  manager_->MaybeForceReauthOnLockScreen(
+      InSessionPasswordSyncManager::ReauthenticationReason::kPolicy);
+  EXPECT_EQ(InSessionReauthReason(),
+            InSessionPasswordSyncManager::ReauthenticationReason::kPolicy);
   UserContext user_context(user_manager::USER_TYPE_REGULAR,
                            saml_login_account_id1_);
   manager_->OnAuthSucceeded(user_context);
-  EXPECT_FALSE(InSessionReauthFlagSet());
+  EXPECT_EQ(InSessionReauthReason(),
+            InSessionPasswordSyncManager::ReauthenticationReason::kNone);
   now = user_manager::known_user::GetLastOnlineSignin(saml_login_account_id1_);
   EXPECT_EQ(now, expected_signin_time);
 }
diff --git a/chrome/browser/chromeos/login/saml/password_sync_token_fetcher.cc b/chrome/browser/chromeos/login/saml/password_sync_token_fetcher.cc
new file mode 100644
index 0000000..0a6196e
--- /dev/null
+++ b/chrome/browser/chromeos/login/saml/password_sync_token_fetcher.cc
@@ -0,0 +1,338 @@
+// 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/chromeos/login/saml/password_sync_token_fetcher.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/json/json_string_value_serializer.h"
+#include "base/json/json_writer.h"
+#include "base/logging.h"
+#include "base/values.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
+#include "components/account_id/account_id.h"
+#include "components/signin/public/identity_manager/access_token_fetcher.h"
+#include "components/signin/public/identity_manager/access_token_info.h"
+#include "components/signin/public/identity_manager/identity_manager.h"
+#include "components/signin/public/identity_manager/primary_account_access_token_fetcher.h"
+#include "components/signin/public/identity_manager/scope_set.h"
+#include "components/user_manager/known_user.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/common/url_constants.h"
+#include "google_apis/gaia/gaia_auth_fetcher.h"
+#include "google_apis/gaia/gaia_constants.h"
+#include "google_apis/gaia/google_service_auth_error.h"
+#include "net/base/load_flags.h"
+#include "net/http/http_status_code.h"
+#include "net/url_request/url_request_context_getter.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/simple_url_loader.h"
+
+namespace chromeos {
+
+namespace {
+
+constexpr int kGetAuthCodeNetworkRetry = 1;
+constexpr int kMaxResponseSize = 5 * 1024;
+const char kAccessTokenFetchId[] = "sync_token_fetcher";
+
+const char kErrorKey[] = "error";
+const char kErrorDescription[] = "message";
+const char kToken[] = "name";
+const char kTokenEntry[] = "token";
+const char kTokenStatusKey[] = "tokenStatus";
+const char kTokenStatusValid[] = "VALID";
+const char kAuthorizationHeaderFormat[] = "Bearer %s";
+const char kContentTypeJSON[] = "application/json";
+const char kTokenTypeKey[] = "token_type";
+const char kTokenTypeValue[] = "SAML_PASSWORD";
+const char kAcceptValue[] =
+    "Accept=text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
+
+const char kPasswordSyncTokenCreateEndPoint[] =
+    "https://chromedevicetoken.googleapis.com/v1/tokens";
+
+const char kPasswordSyncTokenGetEndPoint[] =
+    "https://chromedevicetoken.googleapis.com/v1/"
+    "tokens?token_type=SAML_PASSWORD";
+
+const char kPasswordSyncTokenVerifyEndPoint[] =
+    "https://chromedevicetoken.googleapis.com/v1/tokens/"
+    "%s:verify?token_type=SAML_PASSWORD";
+
+GURL sync_token_create_url() {
+  return GURL(kPasswordSyncTokenCreateEndPoint);
+}
+
+GURL sync_token_get_url() {
+  return GURL(kPasswordSyncTokenGetEndPoint);
+}
+
+GURL sync_token_verify_url(const std::string& sync_token) {
+  return GURL(
+      base::StringPrintf(kPasswordSyncTokenVerifyEndPoint, sync_token.c_str()));
+}
+
+}  // namespace
+
+PasswordSyncTokenFetcher::Consumer::Consumer() = default;
+
+PasswordSyncTokenFetcher::Consumer::~Consumer() = default;
+
+PasswordSyncTokenFetcher::PasswordSyncTokenFetcher(
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+    Profile* profile,
+    Consumer* consumer)
+    : url_loader_factory_(std::move(url_loader_factory)),
+      profile_(profile),
+      consumer_(consumer),
+      request_type_(RequestType::kNone) {
+  DCHECK(profile_);
+  DCHECK(consumer_);
+}
+
+PasswordSyncTokenFetcher::~PasswordSyncTokenFetcher() = default;
+
+void PasswordSyncTokenFetcher::StartTokenCreate() {
+  DCHECK_EQ(request_type_, RequestType::kNone);
+  request_type_ = RequestType::kCreateToken;
+  StartAccessTokenFetch();
+}
+
+void PasswordSyncTokenFetcher::StartTokenGet() {
+  DCHECK_EQ(request_type_, RequestType::kNone);
+  request_type_ = RequestType::kGetToken;
+  StartAccessTokenFetch();
+}
+
+void PasswordSyncTokenFetcher::StartTokenVerify(const std::string& sync_token) {
+  DCHECK_EQ(request_type_, RequestType::kNone);
+  request_type_ = RequestType::kVerifyToken;
+  sync_token_ = sync_token;
+  StartAccessTokenFetch();
+}
+
+void PasswordSyncTokenFetcher::StartAccessTokenFetch() {
+  signin::IdentityManager* identity_manager =
+      IdentityManagerFactory::GetForProfile(profile_);
+  DCHECK(identity_manager);
+
+  // Now we can request the token, knowing that it will be immediately requested
+  // if the refresh token is available, or that it will be requested once the
+  // refresh token is available for the primary account.
+  signin::ScopeSet scopes;
+  scopes.insert(GaiaConstants::kOAuthWrapBridgeUserInfoScope);
+  scopes.insert(GaiaConstants::kDeviceManagementServiceOAuth);
+
+  access_token_fetcher_ =
+      std::make_unique<signin::PrimaryAccountAccessTokenFetcher>(
+          kAccessTokenFetchId, identity_manager, scopes,
+          base::BindOnce(&PasswordSyncTokenFetcher::OnAccessTokenFetchComplete,
+                         weak_ptr_factory_.GetWeakPtr()),
+          signin::PrimaryAccountAccessTokenFetcher::Mode::kWaitUntilAvailable,
+          signin::ConsentLevel::kNotRequired);
+}
+
+void PasswordSyncTokenFetcher::OnAccessTokenFetchComplete(
+    GoogleServiceAuthError error,
+    signin::AccessTokenInfo token_info) {
+  access_token_fetcher_.reset();
+
+  if (error.state() != GoogleServiceAuthError::NONE) {
+    LOG(ERROR)
+        << "Could not get access token to authorize sync token operation: "
+        << error.ToString();
+    consumer_->OnApiCallFailed(ErrorType::kMissingAccessToken);
+    return;
+  }
+  FetchSyncToken(token_info.token);
+}
+
+void PasswordSyncTokenFetcher::FetchSyncToken(const std::string& access_token) {
+  base::Value request_data(base::Value::Type::DICTIONARY);
+  request_data.SetStringKey(kTokenTypeKey, kTokenTypeValue);
+  std::string request_string;
+  if (!base::JSONWriter::Write(request_data, &request_string)) {
+    LOG(ERROR) << "Not able to serialize token request body.";
+    consumer_->OnApiCallFailed(ErrorType::kRequestBodyNotSerialized);
+    return;
+  }
+  const net::NetworkTrafficAnnotationTag traffic_annotation =
+      net::DefineNetworkTrafficAnnotation("password_sync_token_fetcher", R"(
+      semantics {
+        sender: "Chrome OS sync token fetcher"
+        description:
+          "Call password sync token API used to synchronize SAML credentials"
+          "between multiple user devices."
+        trigger:
+          "When SAML password is changed in session or device initiates check "
+          "of the local version of password sync token. When the token is "
+          "invalid device requests online re-authentication of the user in "
+          "order to sync user's password and update the token."
+        data: "Access token and token_type."
+        destination: GOOGLE_OWNED_SERVICE
+        }
+  })");
+  auto resource_request = std::make_unique<network::ResourceRequest>();
+  switch (request_type_) {
+    case RequestType::kCreateToken:
+      resource_request->url = sync_token_create_url();
+      break;
+    case RequestType::kGetToken:
+      resource_request->url = sync_token_get_url();
+      break;
+    case RequestType::kVerifyToken:
+      resource_request->url = sync_token_verify_url(sync_token_);
+      break;
+    case RequestType::kNone:
+      // Error: request type needs to be already set.
+      NOTREACHED();
+  }
+  resource_request->load_flags =
+      net::LOAD_DISABLE_CACHE | net::LOAD_BYPASS_CACHE;
+  resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
+  if (request_type_ == RequestType::kCreateToken) {
+    resource_request->method = net::HttpRequestHeaders::kPostMethod;
+  } else {
+    resource_request->method = net::HttpRequestHeaders::kGetMethod;
+  }
+  resource_request->headers.SetHeader(
+      net::HttpRequestHeaders::kAuthorization,
+      base::StringPrintf(kAuthorizationHeaderFormat, access_token.c_str()));
+  resource_request->headers.SetHeader(net::HttpRequestHeaders::kContentType,
+                                      kContentTypeJSON);
+  resource_request->headers.SetHeader(net::HttpRequestHeaders::kAccept,
+                                      kAcceptValue);
+  DCHECK(!simple_url_loader_);
+
+  simple_url_loader_ = network::SimpleURLLoader::Create(
+      std::move(resource_request), traffic_annotation);
+  if (request_type_ == RequestType::kCreateToken) {
+    simple_url_loader_->AttachStringForUpload(request_string, kContentTypeJSON);
+  }
+  simple_url_loader_->SetRetryOptions(
+      kGetAuthCodeNetworkRetry,
+      network::SimpleURLLoader::RETRY_ON_NETWORK_CHANGE);
+  simple_url_loader_->SetAllowHttpErrorResults(true);
+  simple_url_loader_->DownloadToString(
+      url_loader_factory_.get(),
+      base::BindOnce(&PasswordSyncTokenFetcher::OnSimpleLoaderComplete,
+                     weak_ptr_factory_.GetWeakPtr()),
+      kMaxResponseSize);
+}
+
+void PasswordSyncTokenFetcher::OnSimpleLoaderComplete(
+    std::unique_ptr<std::string> response_body) {
+  int response_code = -1;
+  if (simple_url_loader_->ResponseInfo() &&
+      simple_url_loader_->ResponseInfo()->headers) {
+    response_code =
+        simple_url_loader_->ResponseInfo()->headers->response_code();
+  }
+  std::string json_string;
+  if (response_body)
+    json_string = std::move(*response_body);
+  simple_url_loader_.reset();
+
+  JSONStringValueDeserializer deserializer(json_string);
+  std::string error_msg;
+  std::unique_ptr<base::Value> json_value =
+      deserializer.Deserialize(/*error_code=*/nullptr, &error_msg);
+
+  if (!response_body || (response_code != net::HTTP_OK)) {
+    const auto* error_json = json_value && json_value->is_dict()
+                                 ? json_value->FindKeyOfType(
+                                       kErrorKey, base::Value::Type::DICTIONARY)
+                                 : nullptr;
+    const auto* error_value =
+        error_json ? error_json->FindKeyOfType(kErrorDescription,
+                                               base::Value::Type::STRING)
+                   : nullptr;
+
+    LOG(WARNING) << "Server returned wrong response code: " << response_code
+                 << ": " << (error_value ? error_value->GetString() : "Unknown")
+                 << ".";
+    consumer_->OnApiCallFailed(ErrorType::kServerError);
+    return;
+  }
+
+  if (!json_value) {
+    LOG(WARNING) << "Unable to deserialize json data.";
+    consumer_->OnApiCallFailed(ErrorType::kInvalidJson);
+    return;
+  }
+
+  if (!json_value->is_dict()) {
+    LOG(WARNING) << "Response is not a JSON dictionary.";
+    consumer_->OnApiCallFailed(ErrorType::kNotJsonDict);
+    return;
+  }
+
+  ProcessValidTokenResponse(std::move(json_value));
+}
+
+void PasswordSyncTokenFetcher::ProcessValidTokenResponse(
+    std::unique_ptr<base::Value> json_response) {
+  switch (request_type_) {
+    case RequestType::kCreateToken: {
+      const auto* sync_token_value =
+          json_response->FindKeyOfType(kToken, base::Value::Type::STRING);
+      std::string sync_token =
+          sync_token_value ? sync_token_value->GetString() : std::string();
+      if (sync_token.empty()) {
+        LOG(WARNING) << "Response does not contain sync token.";
+        consumer_->OnApiCallFailed(ErrorType::kCreateNoToken);
+        return;
+      }
+      consumer_->OnTokenCreated(sync_token);
+      break;
+    }
+    case RequestType::kGetToken: {
+      std::string sync_token;
+      const auto* token_list_entry = json_response->FindKey(kTokenEntry);
+      if (!token_list_entry || !token_list_entry->is_list()) {
+        LOG(WARNING) << "Response does not contain list of sync tokens.";
+        consumer_->OnApiCallFailed(ErrorType::kGetNoList);
+        return;
+      }
+      base::Value::ConstListView list_of_tokens = token_list_entry->GetList();
+      if (list_of_tokens.size() > 0) {
+        const auto* sync_token_value =
+            list_of_tokens[0].FindKeyOfType(kToken, base::Value::Type::STRING);
+        if (!sync_token_value) {
+          LOG(WARNING) << "Response does not contain sync token.";
+          consumer_->OnApiCallFailed(ErrorType::kGetNoToken);
+          return;
+        }
+        sync_token = sync_token_value->GetString();
+        if (sync_token.empty()) {
+          LOG(WARNING) << "Response does not contain sync token.";
+          consumer_->OnApiCallFailed(ErrorType::kGetNoToken);
+          return;
+        }
+      }
+      // list_of_tokens.size() == 0 is still a valid case here - it means we
+      // have not created any token for this user yet.
+      consumer_->OnTokenFetched(sync_token);
+      break;
+    }
+    case RequestType::kVerifyToken: {
+      const auto* sync_token_status = json_response->FindKeyOfType(
+          kTokenStatusKey, base::Value::Type::STRING);
+      bool is_valid = false;
+      if (sync_token_status &&
+          sync_token_status->GetString() == kTokenStatusValid) {
+        is_valid = true;
+      }
+      consumer_->OnTokenVerified(is_valid);
+      break;
+    }
+    case RequestType::kNone:
+      NOTREACHED();
+  }
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/saml/password_sync_token_fetcher.h b/chrome/browser/chromeos/login/saml/password_sync_token_fetcher.h
new file mode 100644
index 0000000..02204f4
--- /dev/null
+++ b/chrome/browser/chromeos/login/saml/password_sync_token_fetcher.h
@@ -0,0 +1,98 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_SAML_PASSWORD_SYNC_TOKEN_FETCHER_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_SAML_PASSWORD_SYNC_TOKEN_FETCHER_H_
+
+#include <memory>
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/values.h"
+#include "components/signin/public/identity_manager/access_token_info.h"
+#include "google_apis/gaia/google_service_auth_error.h"
+
+class Profile;
+
+namespace network {
+class SimpleURLLoader;
+class SharedURLLoaderFactory;
+}  // namespace network
+
+namespace signin {
+class PrimaryAccountAccessTokenFetcher;
+}  // namespace signin
+
+namespace chromeos {
+
+// A simple fetcher object that interacts with the sync token API in order to
+// create a new token, get one or verify validity of its local copy.
+// The instance is not reusable, so for each StartToken(), the instance must be
+// re-created. Deleting the instance cancels inflight operation.
+class PasswordSyncTokenFetcher final {
+ public:
+  enum class RequestType { kNone, kCreateToken, kGetToken, kVerifyToken };
+
+  // Error types will be tracked by UMA histograms.
+  // TODO(crbug.com/1112896)
+  enum class ErrorType {
+    kMissingAccessToken,
+    kRequestBodyNotSerialized,
+    kServerError,
+    kInvalidJson,
+    kNotJsonDict,
+    kCreateNoToken,
+    kGetNoList,
+    kGetNoToken
+  };
+
+  class Consumer {
+   public:
+    Consumer();
+    virtual ~Consumer();
+
+    virtual void OnTokenCreated(const std::string& sync_token) = 0;
+    virtual void OnTokenFetched(const std::string& sync_token) = 0;
+    virtual void OnTokenVerified(bool is_valid) = 0;
+    virtual void OnApiCallFailed(ErrorType error_type) = 0;
+  };
+
+  PasswordSyncTokenFetcher(
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+      Profile* profile,
+      Consumer* consumer);
+  ~PasswordSyncTokenFetcher();
+
+  void StartTokenCreate();
+  void StartTokenGet();
+  void StartTokenVerify(const std::string& sync_token);
+
+ private:
+  void StartAccessTokenFetch();
+  void OnAccessTokenFetchComplete(GoogleServiceAuthError error,
+                                  signin::AccessTokenInfo token_info);
+  void FetchSyncToken(const std::string& access_token);
+  void OnSimpleLoaderComplete(std::unique_ptr<std::string> response_body);
+  void ProcessValidTokenResponse(std::unique_ptr<base::Value> json_response);
+
+  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
+  Profile* const profile_;
+  // |consumer_| to call back when this request completes.
+  Consumer* const consumer_;
+
+  std::unique_ptr<network::SimpleURLLoader> simple_url_loader_;
+  std::unique_ptr<signin::PrimaryAccountAccessTokenFetcher>
+      access_token_fetcher_;
+  RequestType request_type_;
+  // Sync token for verification request.
+  std::string sync_token_;
+
+  base::WeakPtrFactory<PasswordSyncTokenFetcher> weak_ptr_factory_{this};
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_LOGIN_SAML_PASSWORD_SYNC_TOKEN_FETCHER_H_
diff --git a/chrome/browser/chromeos/login/saml/password_sync_token_verifier.cc b/chrome/browser/chromeos/login/saml/password_sync_token_verifier.cc
new file mode 100644
index 0000000..b69ac18
--- /dev/null
+++ b/chrome/browser/chromeos/login/saml/password_sync_token_verifier.cc
@@ -0,0 +1,111 @@
+// 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/chromeos/login/saml/password_sync_token_verifier.h"
+
+#include "base/task/post_task.h"
+#include "chrome/browser/chromeos/login/saml/in_session_password_sync_manager.h"
+#include "chrome/browser/chromeos/login/saml/in_session_password_sync_manager_factory.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/common/pref_names.h"
+#include "components/prefs/pref_service.h"
+#include "components/user_manager/known_user.h"
+#include "content/public/browser/storage_partition.h"
+
+namespace chromeos {
+
+namespace {
+const char dummy_token[] = "dummy-token";
+}
+
+const net::BackoffEntry::Policy
+    PasswordSyncTokenVerifier::kFetchTokenRetryBackoffPolicy = {
+        0,              // Number of initial errors to ignore.
+        5 * 60 * 1000,  // Initial request delay in ms.
+        2.0,            // Factor by which the waiting time will be multiplied.
+        0.1,            // Fuzzing percentage.
+        6 * 60 * 60 * 1000,  // Maximum request delay in ms.
+        -1,                  // Never discard the entry.
+        true,  // Don't use initial delay unless last request was an error.
+};
+
+PasswordSyncTokenVerifier::PasswordSyncTokenVerifier(Profile* primary_profile)
+    : primary_profile_(primary_profile),
+      primary_user_(ProfileHelper::Get()->GetUserByProfile(primary_profile)),
+      retry_backoff_(&kFetchTokenRetryBackoffPolicy) {
+  DCHECK(primary_profile_);
+  DCHECK(primary_user_);
+}
+
+PasswordSyncTokenVerifier::~PasswordSyncTokenVerifier() = default;
+
+void PasswordSyncTokenVerifier::RecheckAfter(base::TimeDelta delay) {
+  CancelPendingChecks();
+  base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE,
+      base::BindOnce(&PasswordSyncTokenVerifier::CheckForPasswordNotInSync,
+                     weak_ptr_factory_.GetWeakPtr()),
+      delay);
+}
+
+void PasswordSyncTokenVerifier::CheckForPasswordNotInSync() {
+  // In-session password change is as of now the only way to trigger the sync
+  // token update. We do not need to poll if this feature is not enabled.
+  PrefService* prefs = primary_profile_->GetPrefs();
+  if (!prefs->GetBoolean(prefs::kSamlInSessionPasswordChangeEnabled)) {
+    return;
+  }
+  // Get current sync token for primary_user_.
+  std::string sync_token = user_manager::known_user::GetPasswordSyncToken(
+      primary_user_->GetAccountId());
+
+  // No local sync token on the device - create it by sending user through the
+  // online re-auth.
+  if (sync_token.empty())
+    sync_token = dummy_token;
+
+  password_sync_token_fetcher_ = std::make_unique<PasswordSyncTokenFetcher>(
+      primary_profile_->GetURLLoaderFactory(), primary_profile_, this);
+  password_sync_token_fetcher_->StartTokenVerify(sync_token);
+}
+
+void PasswordSyncTokenVerifier::CancelPendingChecks() {
+  // We should not have any active request at this point. DCHECK makes sure it
+  // is really the case for the dev build. In a release build InvalidateWeakPtrs
+  // helps to recover by cancelling potential existing requests.
+  DCHECK(!weak_ptr_factory_.HasWeakPtrs());
+  weak_ptr_factory_.InvalidateWeakPtrs();
+}
+
+void PasswordSyncTokenVerifier::OnTokenCreated(const std::string& sync_token) {}
+
+void PasswordSyncTokenVerifier::OnTokenFetched(const std::string& sync_token) {}
+
+void PasswordSyncTokenVerifier::OnTokenVerified(bool is_valid) {
+  retry_backoff_.InformOfRequest(true);
+  // Schedule next token check after base interval.
+  RecheckAfter(retry_backoff_.GetTimeUntilRelease());
+  if (is_valid)
+    return;
+
+  user_manager::UserManager::Get()->SaveForceOnlineSignin(
+      primary_user_->GetAccountId(), true);
+  // Re-auth on lock.
+  InSessionPasswordSyncManager* password_sync_manager =
+      InSessionPasswordSyncManagerFactory::GetForProfile(primary_profile_);
+  if (password_sync_manager && password_sync_manager->IsLockReauthEnabled()) {
+    password_sync_manager->MaybeForceReauthOnLockScreen(
+        InSessionPasswordSyncManager::ReauthenticationReason::kInvalidToken);
+  }
+}
+
+void PasswordSyncTokenVerifier::OnApiCallFailed(
+    PasswordSyncTokenFetcher::ErrorType error_type) {
+  retry_backoff_.InformOfRequest(false);
+  // Schedule next token check with interval calculated with exponential
+  // backoff.
+  RecheckAfter(retry_backoff_.GetTimeUntilRelease());
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/saml/password_sync_token_verifier.h b/chrome/browser/chromeos/login/saml/password_sync_token_verifier.h
new file mode 100644
index 0000000..b388454
--- /dev/null
+++ b/chrome/browser/chromeos/login/saml/password_sync_token_verifier.h
@@ -0,0 +1,72 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_SAML_PASSWORD_SYNC_TOKEN_VERIFIER_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_SAML_PASSWORD_SYNC_TOKEN_VERIFIER_H_
+
+#include <memory>
+#include <string>
+
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+#include "chrome/browser/chromeos/login/saml/password_sync_token_fetcher.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/account_id/account_id.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "net/base/backoff_entry.h"
+
+class Profile;
+
+namespace user_manager {
+class User;
+}
+
+namespace chromeos {
+
+// Verifies local copy of the password sync token by executing API call. If
+// token is invalid calls InSessionPasswordSyncManager to request online re-auth
+// that will sync the password and update the token.
+class PasswordSyncTokenVerifier : public KeyedService,
+                                  public PasswordSyncTokenFetcher::Consumer {
+ public:
+  // Backoff policy for token fetch retry attempts in case token fetch failed or
+  // returned invalid data.
+  static const net::BackoffEntry::Policy kFetchTokenRetryBackoffPolicy;
+
+  explicit PasswordSyncTokenVerifier(Profile* primary_profile);
+  ~PasswordSyncTokenVerifier() override;
+
+  PasswordSyncTokenVerifier(const PasswordSyncTokenVerifier&) = delete;
+  PasswordSyncTokenVerifier& operator=(const PasswordSyncTokenVerifier&) =
+      delete;
+
+  // Execute verification API call.
+  void CheckForPasswordNotInSync();
+
+  // Cancel all pending check requests.
+  void CancelPendingChecks();
+
+  // PasswordSyncTokenFetcher::Consumer
+  void OnTokenCreated(const std::string& sync_token) override;
+  void OnTokenFetched(const std::string& sync_token) override;
+  void OnTokenVerified(bool is_valid) override;
+  void OnApiCallFailed(PasswordSyncTokenFetcher::ErrorType error_type) override;
+
+ private:
+  // Recheck after given |delay|.
+  void RecheckAfter(base::TimeDelta delay);
+
+  Profile* const primary_profile_;
+  const user_manager::User* const primary_user_;
+  std::unique_ptr<PasswordSyncTokenFetcher> password_sync_token_fetcher_;
+  net::BackoffEntry retry_backoff_;
+
+  base::WeakPtrFactory<PasswordSyncTokenVerifier> weak_ptr_factory_{this};
+
+  friend class PasswordSyncTokenVerifierTest;
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_LOGIN_SAML_PASSWORD_SYNC_TOKEN_VERIFIER_H_
diff --git a/chrome/browser/chromeos/login/saml/password_sync_token_verifier_factory.cc b/chrome/browser/chromeos/login/saml/password_sync_token_verifier_factory.cc
new file mode 100644
index 0000000..709c7a1d
--- /dev/null
+++ b/chrome/browser/chromeos/login/saml/password_sync_token_verifier_factory.cc
@@ -0,0 +1,54 @@
+// 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/chromeos/login/saml/password_sync_token_verifier_factory.h"
+
+#include "chrome/browser/chromeos/login/saml/in_session_password_sync_manager_factory.h"
+#include "chrome/browser/chromeos/login/saml/password_sync_token_verifier.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/user_manager/user.h"
+#include "components/user_manager/user_manager.h"
+#include "content/public/browser/browser_context.h"
+
+namespace chromeos {
+
+// static
+PasswordSyncTokenVerifierFactory*
+PasswordSyncTokenVerifierFactory::GetInstance() {
+  return base::Singleton<PasswordSyncTokenVerifierFactory>::get();
+}
+
+// static
+PasswordSyncTokenVerifier* PasswordSyncTokenVerifierFactory::GetForProfile(
+    Profile* profile) {
+  return static_cast<PasswordSyncTokenVerifier*>(
+      GetInstance()->GetServiceForBrowserContext(profile, true));
+}
+
+PasswordSyncTokenVerifierFactory::PasswordSyncTokenVerifierFactory()
+    : BrowserContextKeyedServiceFactory(
+          "PasswordSyncTokenVerifier",
+          BrowserContextDependencyManager::GetInstance()) {
+  DependsOn(InSessionPasswordSyncManagerFactory::GetInstance());
+}
+
+PasswordSyncTokenVerifierFactory::~PasswordSyncTokenVerifierFactory() = default;
+
+KeyedService* PasswordSyncTokenVerifierFactory::BuildServiceInstanceFor(
+    content::BrowserContext* context) const {
+  Profile* profile = Profile::FromBrowserContext(context);
+  user_manager::User* user = ProfileHelper::Get()->GetUserByProfile(profile);
+
+  // PasswordSyncTokenVerifier should be created for the primary user only.
+  if (!ProfileHelper::IsPrimaryProfile(profile) || !user ||
+      !user->using_saml()) {
+    return nullptr;
+  }
+  return new PasswordSyncTokenVerifier(profile);
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/saml/password_sync_token_verifier_factory.h b/chrome/browser/chromeos/login/saml/password_sync_token_verifier_factory.h
new file mode 100644
index 0000000..c0212b5
--- /dev/null
+++ b/chrome/browser/chromeos/login/saml/password_sync_token_verifier_factory.h
@@ -0,0 +1,39 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_SAML_PASSWORD_SYNC_TOKEN_VERIFIER_FACTORY_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_SAML_PASSWORD_SYNC_TOKEN_VERIFIER_FACTORY_H_
+
+#include "base/memory/singleton.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+class Profile;
+
+namespace chromeos {
+
+class PasswordSyncTokenVerifier;
+
+// Singleton that owns all PasswordSyncTokenVerifiers and associates them
+// with Profiles.
+class PasswordSyncTokenVerifierFactory
+    : public BrowserContextKeyedServiceFactory {
+ public:
+  static PasswordSyncTokenVerifierFactory* GetInstance();
+
+  static PasswordSyncTokenVerifier* GetForProfile(Profile* profile);
+
+ private:
+  friend struct base::DefaultSingletonTraits<PasswordSyncTokenVerifierFactory>;
+
+  PasswordSyncTokenVerifierFactory();
+  ~PasswordSyncTokenVerifierFactory() override;
+
+  // BrowserContextKeyedServiceFactory:
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* context) const override;
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_LOGIN_SAML_PASSWORD_SYNC_TOKEN_VERIFIER_FACTORY_H_
diff --git a/chrome/browser/chromeos/login/saml/password_sync_token_verifier_unittest.cc b/chrome/browser/chromeos/login/saml/password_sync_token_verifier_unittest.cc
new file mode 100644
index 0000000..10ce5cd
--- /dev/null
+++ b/chrome/browser/chromeos/login/saml/password_sync_token_verifier_unittest.cc
@@ -0,0 +1,203 @@
+// 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/chromeos/login/saml/password_sync_token_verifier.h"
+
+#include "base/time/default_clock.h"
+#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
+#include "chrome/browser/chromeos/login/users/mock_user_manager.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/base/testing_browser_process.h"
+#include "chrome/test/base/testing_profile.h"
+#include "chrome/test/base/testing_profile_manager.h"
+#include "chromeos/login/auth/user_context.h"
+#include "components/user_manager/known_user.h"
+#include "components/user_manager/scoped_user_manager.h"
+#include "components/user_manager/user_names.h"
+#include "content/public/test/browser_task_environment.h"
+
+namespace chromeos {
+
+namespace {
+
+const char kSAMLUserId1[] = "12345";
+const char kSAMLUserEmail1[] = "alice@corp.example.com";
+
+const char kSyncToken[] = "sync-token-1";
+
+constexpr base::TimeDelta kSyncTokenCheckInterval =
+    base::TimeDelta::FromMinutes(6);
+
+constexpr base::TimeDelta kSyncTokenCheckBelowInterval =
+    base::TimeDelta::FromMinutes(4);
+
+class FakeUserManagerWithLocalState : public chromeos::FakeChromeUserManager {
+ public:
+  FakeUserManagerWithLocalState()
+      : test_local_state_(std::make_unique<TestingPrefServiceSimple>()) {
+    RegisterPrefs(test_local_state_->registry());
+  }
+  ~FakeUserManagerWithLocalState() override = default;
+
+  PrefService* GetLocalState() const override {
+    return test_local_state_.get();
+  }
+
+ private:
+  std::unique_ptr<TestingPrefServiceSimple> test_local_state_;
+};
+
+}  // namespace
+
+class PasswordSyncTokenVerifierTest : public testing::Test {
+ protected:
+  PasswordSyncTokenVerifierTest();
+  ~PasswordSyncTokenVerifierTest() override;
+
+  // testing::Test:
+  void SetUp() override;
+
+  void CreatePasswordSyncTokenVerifier();
+  void DestroyPasswordSyncTokenVerifier();
+  void OnTokenVerified(bool is_verified);
+  bool PasswordSyncTokenFetcherIsAllocated();
+  void InvalidatePasswordSyncTokenFetcher();
+
+  const AccountId saml_login_account_id_ =
+      AccountId::FromUserEmailGaiaId(kSAMLUserEmail1, kSAMLUserId1);
+
+  content::BrowserTaskEnvironment test_environment_{
+      base::test::TaskEnvironment::MainThreadType::UI,
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+  TestingProfileManager profile_manager_{TestingBrowserProcess::GetGlobal()};
+  TestingProfile* primary_profile_ = nullptr;
+
+  FakeChromeUserManager* user_manager_ = nullptr;
+  std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_;
+  std::unique_ptr<PasswordSyncTokenVerifier> verifier_;
+};
+
+PasswordSyncTokenVerifierTest::PasswordSyncTokenVerifierTest() {
+  std::unique_ptr<FakeChromeUserManager> fake_user_manager =
+      std::make_unique<FakeUserManagerWithLocalState>();
+  scoped_user_manager_ = std::make_unique<user_manager::ScopedUserManager>(
+      std::move(fake_user_manager));
+
+  user_manager_ =
+      static_cast<FakeChromeUserManager*>(user_manager::UserManager::Get());
+}
+
+PasswordSyncTokenVerifierTest::~PasswordSyncTokenVerifierTest() {
+  DestroyPasswordSyncTokenVerifier();
+}
+
+void PasswordSyncTokenVerifierTest::SetUp() {
+  ASSERT_TRUE(profile_manager_.SetUp());
+  primary_profile_ = profile_manager_.CreateTestingProfile("test1");
+
+  user_manager_->AddUserWithAffiliationAndTypeAndProfile(
+      saml_login_account_id_, /* is_afiliated = */ false,
+      user_manager::UserType::USER_TYPE_REGULAR, primary_profile_);
+  user_manager_->LoginUser(saml_login_account_id_);
+  // ActiveUser in FakeChromeUserManager needs to be set explicitly.
+  user_manager_->SwitchActiveUser(saml_login_account_id_);
+  ASSERT_TRUE(user_manager_->GetActiveUser());
+  primary_profile_->GetPrefs()->SetBoolean(
+      prefs::kSamlInSessionPasswordChangeEnabled, true);
+}
+
+void PasswordSyncTokenVerifierTest::CreatePasswordSyncTokenVerifier() {
+  DestroyPasswordSyncTokenVerifier();
+  verifier_ = std::make_unique<PasswordSyncTokenVerifier>(primary_profile_);
+}
+
+void PasswordSyncTokenVerifierTest::DestroyPasswordSyncTokenVerifier() {
+  if (verifier_) {
+    verifier_->Shutdown();
+    verifier_.reset();
+  }
+}
+
+void PasswordSyncTokenVerifierTest::OnTokenVerified(bool is_verified) {
+  verifier_->OnTokenVerified(is_verified);
+}
+
+bool PasswordSyncTokenVerifierTest::PasswordSyncTokenFetcherIsAllocated() {
+  return verifier_->password_sync_token_fetcher_ != nullptr;
+}
+
+void PasswordSyncTokenVerifierTest::InvalidatePasswordSyncTokenFetcher() {
+  verifier_->password_sync_token_fetcher_.reset();
+}
+
+TEST_F(PasswordSyncTokenVerifierTest, EmptySyncToken) {
+  CreatePasswordSyncTokenVerifier();
+  verifier_->CheckForPasswordNotInSync();
+  OnTokenVerified(false);
+  EXPECT_TRUE(PasswordSyncTokenFetcherIsAllocated());
+  EXPECT_TRUE(user_manager_->GetActiveUser()->force_online_signin());
+}
+
+TEST_F(PasswordSyncTokenVerifierTest, SyncTokenValidationPassed) {
+  user_manager::known_user::SetPasswordSyncToken(saml_login_account_id_,
+                                                 kSyncToken);
+  CreatePasswordSyncTokenVerifier();
+  verifier_->CheckForPasswordNotInSync();
+  OnTokenVerified(true);
+  EXPECT_FALSE(user_manager_->GetActiveUser()->force_online_signin());
+}
+
+TEST_F(PasswordSyncTokenVerifierTest, SyncTokenValidationFailed) {
+  user_manager::known_user::SetPasswordSyncToken(saml_login_account_id_,
+                                                 kSyncToken);
+  CreatePasswordSyncTokenVerifier();
+  verifier_->CheckForPasswordNotInSync();
+  OnTokenVerified(false);
+  EXPECT_TRUE(user_manager_->GetActiveUser()->force_online_signin());
+}
+
+TEST_F(PasswordSyncTokenVerifierTest, SyncTokenValidationAfterDelay) {
+  user_manager::known_user::SetPasswordSyncToken(saml_login_account_id_,
+                                                 kSyncToken);
+  CreatePasswordSyncTokenVerifier();
+  verifier_->CheckForPasswordNotInSync();
+  OnTokenVerified(true);
+  EXPECT_FALSE(user_manager_->GetActiveUser()->force_online_signin());
+  InvalidatePasswordSyncTokenFetcher();
+  test_environment_.FastForwardBy(kSyncTokenCheckInterval);
+  EXPECT_TRUE(PasswordSyncTokenFetcherIsAllocated());
+  OnTokenVerified(false);
+  EXPECT_TRUE(user_manager_->GetActiveUser()->force_online_signin());
+}
+
+TEST_F(PasswordSyncTokenVerifierTest, SyncTokenNoRecheckExecuted) {
+  user_manager::known_user::SetPasswordSyncToken(saml_login_account_id_,
+                                                 kSyncToken);
+  CreatePasswordSyncTokenVerifier();
+  verifier_->CheckForPasswordNotInSync();
+  OnTokenVerified(true);
+  EXPECT_FALSE(user_manager_->GetActiveUser()->force_online_signin());
+  user_manager::known_user::SetPasswordSyncToken(saml_login_account_id_,
+                                                 std::string());
+  test_environment_.FastForwardBy(kSyncTokenCheckBelowInterval);
+  EXPECT_FALSE(user_manager_->GetActiveUser()->force_online_signin());
+}
+
+TEST_F(PasswordSyncTokenVerifierTest, PasswordChangePolicyNotSet) {
+  primary_profile_->GetPrefs()->SetBoolean(
+      prefs::kSamlInSessionPasswordChangeEnabled, false);
+  user_manager::known_user::SetPasswordSyncToken(saml_login_account_id_,
+                                                 kSyncToken);
+  CreatePasswordSyncTokenVerifier();
+  verifier_->CheckForPasswordNotInSync();
+  OnTokenVerified(true);
+  user_manager::known_user::SetPasswordSyncToken(saml_login_account_id_,
+                                                 std::string());
+  test_environment_.FastForwardBy(kSyncTokenCheckInterval);
+  EXPECT_FALSE(user_manager_->GetActiveUser()->force_online_signin());
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/saml/saml_offline_signin_limiter.cc b/chrome/browser/chromeos/login/saml/saml_offline_signin_limiter.cc
index 26c3e98c..f75c598 100644
--- a/chrome/browser/chromeos/login/saml/saml_offline_signin_limiter.cc
+++ b/chrome/browser/chromeos/login/saml/saml_offline_signin_limiter.cc
@@ -178,7 +178,8 @@
   InSessionPasswordSyncManager* password_sync_manager =
       InSessionPasswordSyncManagerFactory::GetForProfile(profile_);
   if (password_sync_manager && password_sync_manager->IsLockReauthEnabled()) {
-    password_sync_manager->MaybeForceReauthOnLockScreen();
+    password_sync_manager->MaybeForceReauthOnLockScreen(
+        InSessionPasswordSyncManager::ReauthenticationReason::kPolicy);
   }
   RecordReauthReason(user->GetAccountId(), ReauthReason::SAML_REAUTH_POLICY);
   offline_signin_limit_timer_->Stop();
diff --git a/chrome/browser/chromeos/login/session/user_session_manager.cc b/chrome/browser/chromeos/login/session/user_session_manager.cc
index 4b1748e..30beda3a8 100644
--- a/chrome/browser/chromeos/login/session/user_session_manager.cc
+++ b/chrome/browser/chromeos/login/session/user_session_manager.cc
@@ -56,6 +56,8 @@
 #include "chrome/browser/chromeos/login/login_pref_names.h"
 #include "chrome/browser/chromeos/login/profile_auth_data.h"
 #include "chrome/browser/chromeos/login/quick_unlock/pin_backend.h"
+#include "chrome/browser/chromeos/login/saml/password_sync_token_verifier.h"
+#include "chrome/browser/chromeos/login/saml/password_sync_token_verifier_factory.h"
 #include "chrome/browser/chromeos/login/saml/saml_offline_signin_limiter.h"
 #include "chrome/browser/chromeos/login/saml/saml_offline_signin_limiter_factory.h"
 #include "chrome/browser/chromeos/login/screens/arc_terms_of_service_screen.h"
@@ -1607,6 +1609,11 @@
           user_context_.GetAccountId(),
           user_context_.IsUsingSamlPrincipalsApi());
     }
+    PasswordSyncTokenVerifier* password_sync_token_verifier =
+        PasswordSyncTokenVerifierFactory::GetForProfile(profile);
+    if (password_sync_token_verifier)
+      password_sync_token_verifier->CheckForPasswordNotInSync();
+
     SAMLOfflineSigninLimiter* saml_offline_signin_limiter =
         SAMLOfflineSigninLimiterFactory::GetForProfile(profile);
     if (saml_offline_signin_limiter)
diff --git a/chrome/browser/chromeos/net/network_health/network_health_service.cc b/chrome/browser/chromeos/net/network_health/network_health_service.cc
index e5c31642..27b0b93 100644
--- a/chrome/browser/chromeos/net/network_health/network_health_service.cc
+++ b/chrome/browser/chromeos/net/network_health/network_health_service.cc
@@ -16,6 +16,13 @@
           chromeos::DBusThreadManager::Get()->GetDebugDaemonClient());
 }
 
+mojo::PendingRemote<mojom::NetworkHealthService>
+NetworkHealthService::GetHealthRemoteAndBindReceiver() {
+  mojo::PendingRemote<mojom::NetworkHealthService> remote;
+  BindHealthReceiver(remote.InitWithNewPipeAndPassReceiver());
+  return remote;
+}
+
 void NetworkHealthService::BindHealthReceiver(
     mojo::PendingReceiver<mojom::NetworkHealthService> receiver) {
   network_health_.BindReceiver(std::move(receiver));
diff --git a/chrome/browser/chromeos/net/network_health/network_health_service.h b/chrome/browser/chromeos/net/network_health/network_health_service.h
index 2432a32..22e6713 100644
--- a/chrome/browser/chromeos/net/network_health/network_health_service.h
+++ b/chrome/browser/chromeos/net/network_health/network_health_service.h
@@ -7,6 +7,7 @@
 
 #include "chrome/browser/chromeos/net/network_diagnostics/network_diagnostics_impl.h"
 #include "chrome/browser/chromeos/net/network_health/network_health.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 
 namespace chromeos {
 namespace network_health {
@@ -18,6 +19,9 @@
   NetworkHealthService();
   ~NetworkHealthService() = delete;
 
+  mojo::PendingRemote<mojom::NetworkHealthService>
+  GetHealthRemoteAndBindReceiver();
+
   void BindHealthReceiver(
       mojo::PendingReceiver<mojom::NetworkHealthService> receiver);
   void BindDiagnosticsReceiver(
diff --git a/chrome/browser/chromeos/policy/minimum_version_policy_handler.cc b/chrome/browser/chromeos/policy/minimum_version_policy_handler.cc
index 2ced7a7..8419616f 100644
--- a/chrome/browser/chromeos/policy/minimum_version_policy_handler.cc
+++ b/chrome/browser/chromeos/policy/minimum_version_policy_handler.cc
@@ -10,6 +10,7 @@
 #include "base/bind.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
+#include "base/strings/string16.h"
 #include "base/time/default_clock.h"
 #include "base/time/time.h"
 #include "base/values.h"
@@ -31,6 +32,7 @@
 #include "chromeos/settings/cros_settings_provider.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
+#include "ui/chromeos/devicetype_utils.h"
 
 using MinimumVersionRequirement =
     policy::MinimumVersionPolicyHandler::MinimumVersionRequirement;
@@ -488,6 +490,7 @@
   NotificationType type = NotificationType::kNoConnection;
   base::OnceClosure button_click_callback;
   std::string domain_name = GetEnterpriseDomainName();
+  base::string16 device_type = ui::GetChromeOSDeviceName();
   auto close_callback =
       base::BindOnce(&MinimumVersionPolicyHandler::StopObservingNetwork,
                      weak_factory_.GetWeakPtr());
@@ -508,7 +511,7 @@
     NOTREACHED();
     return;
   }
-  notification_handler_->Show(type, warning, domain_name,
+  notification_handler_->Show(type, warning, domain_name, device_type,
                               std::move(button_click_callback),
                               std::move(close_callback));
 
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 1a48d45..6926db1 100644
--- a/chrome/browser/chromeos/policy/minimum_version_policy_handler_unittest.cc
+++ b/chrome/browser/chromeos/policy/minimum_version_policy_handler_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/system/sys_info.h"
 #include "base/test/bind_test_util.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
@@ -460,7 +461,7 @@
 
   // Check notification is shown for offline devices with the warning time.
   base::string16 expected_title =
-      base::ASCIIToUTF16("Update device within 10 days");
+      base::ASCIIToUTF16("Update Chrome device within 10 days");
   base::string16 expected_message = base::ASCIIToUTF16(
       "managed.com requires you to download an update before the deadline. The "
       "update will download automatically when you connect to the internet.");
@@ -471,7 +472,7 @@
   task_environment.FastForwardBy(warning);
 
   base::string16 expected_title_last_day =
-      base::ASCIIToUTF16("Last day to update device");
+      base::ASCIIToUTF16("Last day to update Chrome device");
   base::string16 expected_message_last_day = base::ASCIIToUTF16(
       "managed.com requires you to download an update today. The "
       "update will download automatically when you connect to the internet.");
@@ -509,7 +510,7 @@
 
   // Check notification is shown for metered network with the warning time.
   base::string16 expected_title =
-      base::ASCIIToUTF16("Update device within 10 days");
+      base::ASCIIToUTF16("Update Chrome device within 10 days");
   base::string16 expected_message = base::ASCIIToUTF16(
       "managed.com requires you to connect to Wi-Fi and download an update "
       "before the deadline. Or, download from a metered connection (charges "
@@ -521,7 +522,7 @@
   task_environment.FastForwardBy(warning);
 
   base::string16 expected_title_last_day =
-      base::ASCIIToUTF16("Last day to update device");
+      base::ASCIIToUTF16("Last day to update Chrome device");
   base::string16 expected_message_last_day = base::ASCIIToUTF16(
       "managed.com requires you to connect to Wi-Fi today to download an "
       "update. Or, download from a metered connection (charges may apply).");
@@ -551,10 +552,10 @@
 
   // Check notification is shown for end of life with the warning time.
   base::string16 expected_title =
-      base::ASCIIToUTF16("Return device within 10 days");
+      base::ASCIIToUTF16("Return Chrome device within 10 days");
   base::string16 expected_message = base::ASCIIToUTF16(
-      "managed.com requires you to back up your data and return this device "
-      "before the deadline.");
+      "managed.com requires you to back up your data and return this Chrome "
+      "device before the deadline.");
   VerifyUpdateRequiredNotification(expected_title, expected_message);
 
   // Expire notification timer to show new notification a week before deadline.
@@ -562,7 +563,7 @@
   task_environment.FastForwardBy(warning);
 
   base::string16 expected_title_one_week =
-      base::ASCIIToUTF16("Return device within 1 week");
+      base::ASCIIToUTF16("Return Chrome device within 1 week");
   VerifyUpdateRequiredNotification(expected_title_one_week, expected_message);
 
   // Expire the notification timer to show new notification on the last day.
@@ -572,8 +573,8 @@
   base::string16 expected_title_last_day =
       base::ASCIIToUTF16("Immediate return required");
   base::string16 expected_message_last_day = base::ASCIIToUTF16(
-      "managed.com requires you to back up your data and return this device "
-      "today.");
+      "managed.com requires you to back up your data and return this Chrome "
+      "device today.");
   VerifyUpdateRequiredNotification(expected_title_last_day,
                                    expected_message_last_day);
 }
@@ -611,10 +612,50 @@
   base::string16 expected_title_last_day =
       base::ASCIIToUTF16("Immediate return required");
   base::string16 expected_message_last_day = base::ASCIIToUTF16(
-      "managed.com requires you to back up your data and return this device "
-      "today.");
+      "managed.com requires you to back up your data and return this Chrome "
+      "device today.");
   VerifyUpdateRequiredNotification(expected_title_last_day,
                                    expected_message_last_day);
 }
 
+TEST_F(MinimumVersionPolicyHandlerTest, ChromeboxNotifications) {
+  base::SysInfo::SetChromeOSVersionInfoForTest("DEVICETYPE=CHROMEBOX",
+                                               base::Time::Now());
+  // Set device state to end of life reached.
+  update_engine()->set_eol_date(base::DefaultClock::GetInstance()->Now() -
+                                base::TimeDelta::FromDays(kLongWarning));
+
+  // This is needed to wait till EOL status is fetched from the update_engine.
+  base::RunLoop run_loop;
+  GetMinimumVersionPolicyHandler()->set_fetch_eol_callback_for_testing(
+      run_loop.QuitClosure());
+
+  // Create and set pref value to invoke policy handler.
+  base::Value requirement_list(base::Value::Type::LIST);
+  requirement_list.Append(
+      CreateRequirement(kNewVersion, kLongWarning, kLongWarning));
+  SetPolicyPref(CreatePolicyValue(std::move(requirement_list),
+                                  false /* unmanaged_user_restricted */));
+  run_loop.Run();
+  EXPECT_TRUE(
+      GetMinimumVersionPolicyHandler()->IsDeadlineTimerRunningForTesting());
+
+  // Check Chromebox notification is shown for end of life with the warning
+  // time.
+  base::string16 expected_title =
+      base::ASCIIToUTF16("Return Chromebox within 10 days");
+  base::string16 expected_message = base::ASCIIToUTF16(
+      "managed.com requires you to back up your data and return this Chromebox "
+      "before the deadline.");
+  VerifyUpdateRequiredNotification(expected_title, expected_message);
+
+  // Expire notification timer to show new notification a week before deadline.
+  const base::TimeDelta warning = base::TimeDelta::FromDays(kLongWarning - 7);
+  task_environment.FastForwardBy(warning);
+
+  base::string16 expected_title_one_week =
+      base::ASCIIToUTF16("Return Chromebox within 1 week");
+  VerifyUpdateRequiredNotification(expected_title_one_week, expected_message);
+}
+
 }  // namespace policy
diff --git a/chrome/browser/chromeos/ui/update_required_notification.cc b/chrome/browser/chromeos/ui/update_required_notification.cc
index 40f34e73..4a55ab0 100644
--- a/chrome/browser/chromeos/ui/update_required_notification.cc
+++ b/chrome/browser/chromeos/ui/update_required_notification.cc
@@ -6,6 +6,7 @@
 
 #include "ash/public/cpp/notification_utils.h"
 #include "base/bind.h"
+#include "base/i18n/message_formatter.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/notifications/system_notification_helper.h"
@@ -14,15 +15,16 @@
 #include "ui/base/l10n/l10n_util.h"
 
 using NotificationType = policy::MinimumVersionPolicyHandler::NotificationType;
+using MessageFormatter = base::i18n::MessageFormatter;
 
 namespace chromeos {
 namespace {
 
 const char kUpdateRequiredNotificationId[] = "policy.update_required";
 
-base::string16 GetTitle(NotificationType type, int days_remaining) {
-  // TODO(https://crbug.com/1048607): Add and use title strings for weeks if
-  // |days_remaining| >= 7.
+base::string16 GetTitle(NotificationType type,
+                        int days_remaining,
+                        const base::string16& device_type) {
   // |days_remaining| could be zero if we are very close to the deadline, like
   // 10 minutes as we round of the time remaining into days. In this case, we
   // need to show the last day notification title which does not mention the
@@ -33,53 +35,49 @@
     case NotificationType::kNoConnection:
     case NotificationType::kMeteredConnection:
       return (days_remaining % 7)
-                 ? l10n_util::GetPluralStringFUTF16(
-                       IDS_UPDATE_REQUIRED_NETWORK_LIMITATION_TITLE_DAYS,
-                       days_remaining)
-                 : l10n_util::GetPluralStringFUTF16(
-                       IDS_UPDATE_REQUIRED_NETWORK_LIMITATION_TITLE_WEEKS,
-                       days_remaining / 7);
+                 ? MessageFormatter::FormatWithNumberedArgs(
+                       l10n_util::GetStringUTF16(
+                           IDS_UPDATE_REQUIRED_NETWORK_LIMITATION_TITLE_DAYS),
+                       days_remaining, device_type)
+                 : MessageFormatter::FormatWithNumberedArgs(
+                       l10n_util::GetStringUTF16(
+                           IDS_UPDATE_REQUIRED_NETWORK_LIMITATION_TITLE_WEEKS),
+                       days_remaining / 7, device_type);
     case NotificationType::kEolReached:
       return (days_remaining % 7)
-                 ? l10n_util::GetPluralStringFUTF16(
-                       IDS_UPDATE_REQUIRED_EOL_TITLE_DAYS, days_remaining)
-                 : l10n_util::GetPluralStringFUTF16(
-                       IDS_UPDATE_REQUIRED_EOL_TITLE_WEEKS, days_remaining / 7);
+                 ? MessageFormatter::FormatWithNumberedArgs(
+                       l10n_util::GetStringUTF16(
+                           IDS_UPDATE_REQUIRED_EOL_TITLE_DAYS),
+                       days_remaining, device_type)
+                 : MessageFormatter::FormatWithNumberedArgs(
+                       l10n_util::GetStringUTF16(
+                           IDS_UPDATE_REQUIRED_EOL_TITLE_WEEKS),
+                       days_remaining / 7, device_type);
   }
 }
 
 base::string16 GetMessage(NotificationType type,
                           const std::string& domain_name,
-                          int days_remaining) {
-  if (days_remaining > 1) {
-    switch (type) {
-      case NotificationType::kNoConnection:
-        return l10n_util::GetStringFUTF16(
-            IDS_UPDATE_REQUIRED_NO_NETWORK_MESSAGE,
-            base::UTF8ToUTF16(domain_name));
-      case NotificationType::kMeteredConnection:
-        return l10n_util::GetStringFUTF16(
-            IDS_UPDATE_REQUIRED_METERED_NETWORK_MESSAGE,
-            base::UTF8ToUTF16(domain_name));
-      case NotificationType::kEolReached:
-        return l10n_util::GetStringFUTF16(IDS_UPDATE_REQUIRED_EOL_MESSAGE,
-                                          base::UTF8ToUTF16(domain_name));
-    }
-  }
-
+                          int days_remaining,
+                          const base::string16& device_type) {
+  // |days_remaining| could be zero if we are very close to the deadline, like
+  // 10 minutes as we round of the time remaining into days. In this case, we
+  // need to show the last day notification.
+  days_remaining = days_remaining > 1 ? days_remaining : 1;
   switch (type) {
     case NotificationType::kNoConnection:
-      return l10n_util::GetStringFUTF16(
-          IDS_UPDATE_REQUIRED_NO_NETWORK_MESSAGE_IMMEDIATE,
-          base::UTF8ToUTF16(domain_name));
+      return MessageFormatter::FormatWithNumberedArgs(
+          l10n_util::GetStringUTF16(IDS_UPDATE_REQUIRED_NO_NETWORK_MESSAGE),
+          days_remaining, base::UTF8ToUTF16(domain_name));
     case NotificationType::kMeteredConnection:
-      return l10n_util::GetStringFUTF16(
-          IDS_UPDATE_REQUIRED_METERED_NETWORK_MESSAGE_IMMEDIATE,
-          base::UTF8ToUTF16(domain_name));
+      return MessageFormatter::FormatWithNumberedArgs(
+          l10n_util::GetStringUTF16(
+              IDS_UPDATE_REQUIRED_METERED_NETWORK_MESSAGE),
+          days_remaining, base::UTF8ToUTF16(domain_name));
     case NotificationType::kEolReached:
-      return l10n_util::GetStringFUTF16(
-          IDS_UPDATE_REQUIRED_EOL_MESSAGE_IMMEDIATE,
-          base::UTF8ToUTF16(domain_name));
+      return MessageFormatter::FormatWithNumberedArgs(
+          l10n_util::GetStringUTF16(IDS_UPDATE_REQUIRED_EOL_MESSAGE),
+          days_remaining, base::UTF8ToUTF16(domain_name), device_type);
   }
 }
 
@@ -121,14 +119,16 @@
 void UpdateRequiredNotification::Show(NotificationType type,
                                       base::TimeDelta warning_time,
                                       const std::string& domain_name,
+                                      const base::string16& device_type,
                                       base::OnceClosure button_click_callback,
                                       base::OnceClosure close_callback) {
   const int days_remaining = warning_time.InDays();
   notification_button_click_callback_ = std::move(button_click_callback);
   notification_close_callback_ = std::move(close_callback);
 
-  base::string16 title = GetTitle(type, days_remaining);
-  base::string16 body = GetMessage(type, domain_name, days_remaining);
+  base::string16 title = GetTitle(type, days_remaining, device_type);
+  base::string16 body =
+      GetMessage(type, domain_name, days_remaining, device_type);
   base::string16 button = GetButtonText(type);
   if (title.empty() || body.empty() || button.empty()) {
     NOTREACHED();
diff --git a/chrome/browser/chromeos/ui/update_required_notification.h b/chrome/browser/chromeos/ui/update_required_notification.h
index 23ec6c4d..be4158d 100644
--- a/chrome/browser/chromeos/ui/update_required_notification.h
+++ b/chrome/browser/chromeos/ui/update_required_notification.h
@@ -41,6 +41,7 @@
   void Show(policy::MinimumVersionPolicyHandler::NotificationType type,
             base::TimeDelta warning_time,
             const std::string& domain_name,
+            const base::string16& device_type,
             base::OnceClosure button_click_callback,
             base::OnceClosure close_callback);
 
diff --git a/chrome/browser/extensions/api/bookmarks/bookmark_apitest.cc b/chrome/browser/extensions/api/bookmarks/bookmark_apitest.cc
index 78136b1..658df15 100644
--- a/chrome/browser/extensions/api/bookmarks/bookmark_apitest.cc
+++ b/chrome/browser/extensions/api/bookmarks/bookmark_apitest.cc
@@ -49,7 +49,13 @@
                          BookmarksApiTest,
                          ::testing::Values(ContextType::kServiceWorker));
 
-IN_PROC_BROWSER_TEST_P(BookmarksApiTest, Bookmarks) {
+// Flaky on all platforms but Mac.  https://crbug.com/1112903
+#if defined(OS_MAC)
+#define MAYBE_Bookmarks Bookmarks
+#else
+#define MAYBE_Bookmarks DISABLED_Bookmarks
+#endif
+IN_PROC_BROWSER_TEST_P(BookmarksApiTest, MAYBE_Bookmarks) {
   // Add test managed bookmarks to verify that the bookmarks API can read them
   // and can't modify them.
   Profile* profile = browser()->profile();
diff --git a/chrome/browser/local_discovery/service_discovery_client_mac.h b/chrome/browser/local_discovery/service_discovery_client_mac.h
index 531ee39..61b31746 100644
--- a/chrome/browser/local_discovery/service_discovery_client_mac.h
+++ b/chrome/browser/local_discovery/service_discovery_client_mac.h
@@ -74,19 +74,15 @@
   void SetActivelyRefreshServices(bool actively_refresh_services) override;
   std::string GetServiceType() const override;
 
-  void StartOnDiscoveryThread(
-      ServiceWatcher::UpdatedCallback callback,
-      scoped_refptr<base::SingleThreadTaskRunner> callback_runner);
-  void DiscoverOnDiscoveryThread();
-
   // These members should only be accessed on the object creator's sequence.
   const std::string service_type_;
   ServiceWatcher::UpdatedCallback callback_;
   bool started_ = false;
 
   scoped_refptr<base::SingleThreadTaskRunner> service_discovery_runner_;
-  // |browser_| lives on the |service_discovery_runner_|. It is released
-  // by move()ing it to StopServiceBrowser().
+  // |browser_| lives on the |service_discovery_runner_|, though it is
+  // initialized on the object creator's sequence. It is released by move()ing
+  // it to StopServiceBrowser().
   base::scoped_nsobject<NetServiceBrowser> browser_;
 
   base::WeakPtrFactory<ServiceWatcherImplMac> weak_factory_{this};
@@ -110,9 +106,6 @@
   void OnResolveComplete(RequestStatus status,
                          const ServiceDescription& description);
 
-  void StartResolvingOnDiscoveryThread(
-      ServiceResolver::ResolveCompleteCallback callback,
-      scoped_refptr<base::SingleThreadTaskRunner> callback_runner);
   void StopResolving();
 
   // These members should only be accessed on the object creator's sequence.
@@ -121,8 +114,9 @@
   bool has_resolved_ = false;
 
   scoped_refptr<base::SingleThreadTaskRunner> service_discovery_runner_;
-  // |resolver_| lives on the |service_discovery_runner_|. It is released
-  // by move()ing it to StopServiceResolver().
+  // |resolver_| lives on the |service_discovery_runner_|, though it is
+  // initialized on the object creator's sequence. It is released by move()ing
+  // it to StopServiceResolver().
   base::scoped_nsobject<NetServiceResolver> resolver_;
 
   base::WeakPtrFactory<ServiceResolverImplMac> weak_factory_{this};
diff --git a/chrome/browser/local_discovery/service_discovery_client_mac.mm b/chrome/browser/local_discovery/service_discovery_client_mac.mm
index 61264c42..42b53255 100644
--- a/chrome/browser/local_discovery/service_discovery_client_mac.mm
+++ b/chrome/browser/local_discovery/service_discovery_client_mac.mm
@@ -26,16 +26,18 @@
 
 @interface NetServiceBrowser
     : NSObject <NSNetServiceBrowserDelegate, NSNetServiceDelegate>
-// Creates a new NSNetServiceBrowser and starts listening for discovery
-// notifications. Calls the |callback| on the |callbackRunner| when
-// changes are detected.
+// Creates a new Browser instance for |serviceType|, which will call
+// |callback| on |callbackRunner| when changes are detected. This does NOT
+// start listening, as that must be done on the discovery thread via
+// -discoverServices.
 - (instancetype)initWithServiceType:(const std::string&)serviceType
                            callback:(ServiceWatcher::UpdatedCallback)callback
                      callbackRunner:
                          (scoped_refptr<base::SingleThreadTaskRunner>)
                              callbackRunner;
 
-// Forces a new scan for services.
+// Creates a new NSNetServiceBrowser and starts listening for discovery
+// notifications.
 - (void)discoverServices;
 
 // Stops listening for discovery notifications.
@@ -43,14 +45,17 @@
 @end
 
 @interface NetServiceResolver : NSObject <NSNetServiceDelegate>
-// Begins resolving the local service named |name|. Calls the |callback|
-// on the |callbackRunner| when done or an error occurs.
+// Creates a new resolver instance for service named |name|. Calls the
+// |callback| on the |callbackRunner| when done or an error occurs.
 - (instancetype)
     initWithServiceName:(const std::string&)name
        resolvedCallback:(ServiceResolver::ResolveCompleteCallback)callback
          callbackRunner:
              (scoped_refptr<base::SingleThreadTaskRunner>)callbackRunner;
 
+// Begins a resolve request for the service.
+- (void)resolveService;
+
 // Stops any in-flight resolve operation.
 - (void)stop;
 @end
@@ -63,12 +68,25 @@
 
 const NSTimeInterval kResolveTimeout = 10.0;
 
-// Takes ownership of |browser| and tells it to stop.
+// These functions are used to PostTask with ObjC objects, without needing to
+// manage the lifetime of a C++ pointer for either the Watcher or Resolver.
+// Clients of those classes can delete the C++ object while operations on the
+// ObjC objects are still in flight. Because the ObjC objects are reference
+// counted, the strong references passed to these functions ensure the object
+// remains alive until for the duration of the operation.
+
+void StartServiceBrowser(base::scoped_nsobject<NetServiceBrowser> browser) {
+  [browser discoverServices];
+}
+
 void StopServiceBrowser(base::scoped_nsobject<NetServiceBrowser> browser) {
   [browser stop];
 }
 
-// Takes ownership of |resolver| and tells it to stop.
+void StartServiceResolver(base::scoped_nsobject<NetServiceResolver> resolver) {
+  [resolver resolveService];
+}
+
 void StopServiceResolver(base::scoped_nsobject<NetServiceResolver> resolver) {
   [resolver stop];
 }
@@ -212,23 +230,25 @@
 void ServiceWatcherImplMac::Start() {
   DCHECK(!started_);
   VLOG(1) << "ServiceWatcherImplMac::Start";
-  service_discovery_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&ServiceWatcherImplMac::StartOnDiscoveryThread,
-                                base::Unretained(this),
-                                base::BindRepeating(
-                                    &ServiceWatcherImplMac::OnServicesUpdate,
-                                    weak_factory_.GetWeakPtr()),
-                                base::ThreadTaskRunnerHandle::Get()));
+
+  browser_.reset([[NetServiceBrowser alloc]
+      initWithServiceType:service_type_
+                 callback:base::BindRepeating(
+                              &ServiceWatcherImplMac::OnServicesUpdate,
+                              weak_factory_.GetWeakPtr())
+           callbackRunner:base::ThreadTaskRunnerHandle::Get()]);
   started_ = true;
 }
 
 void ServiceWatcherImplMac::DiscoverNewServices() {
   DCHECK(started_);
   VLOG(1) << "ServiceWatcherImplMac::DiscoverNewServices";
+  // Provide an additional reference on the browser_, in case |this|
+  // gets deleted and releases its reference.
   service_discovery_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&ServiceWatcherImplMac::DiscoverOnDiscoveryThread,
-                     base::Unretained(this)));
+      FROM_HERE, base::BindOnce(&StartServiceBrowser,
+                                base::scoped_nsobject<NetServiceBrowser>(
+                                    [browser_ retain])));
 }
 
 void ServiceWatcherImplMac::SetActivelyRefreshServices(
@@ -248,22 +268,6 @@
   callback_.Run(update, service + "." + service_type_);
 }
 
-void ServiceWatcherImplMac::StartOnDiscoveryThread(
-    ServiceWatcher::UpdatedCallback callback,
-    scoped_refptr<base::SingleThreadTaskRunner> callback_runner) {
-  DCHECK(service_discovery_runner_->RunsTasksInCurrentSequence());
-
-  browser_.reset([[NetServiceBrowser alloc]
-      initWithServiceType:service_type_
-                 callback:std::move(callback)
-           callbackRunner:callback_runner]);
-}
-
-void ServiceWatcherImplMac::DiscoverOnDiscoveryThread() {
-  DCHECK(service_discovery_runner_->RunsTasksInCurrentSequence());
-  [browser_ discoverServices];
-}
-
 // Service Resolver ////////////////////////////////////////////////////////////
 
 ServiceResolverImplMac::ServiceResolverImplMac(
@@ -280,13 +284,18 @@
 
 void ServiceResolverImplMac::StartResolving() {
   VLOG(1) << "Resolving service " << service_name_;
+  resolver_.reset([[NetServiceResolver alloc]
+      initWithServiceName:service_name_
+         resolvedCallback:base::BindOnce(
+                              &ServiceResolverImplMac::OnResolveComplete,
+                              weak_factory_.GetWeakPtr())
+           callbackRunner:base::ThreadTaskRunnerHandle::Get()]);
+  // Provide an additional reference on the resolver_, in case |this|
+  // gets deleted and releases its reference.
   service_discovery_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&ServiceResolverImplMac::StartResolvingOnDiscoveryThread,
-                     base::Unretained(this),
-                     base::BindOnce(&ServiceResolverImplMac::OnResolveComplete,
-                                    weak_factory_.GetWeakPtr()),
-                     base::ThreadTaskRunnerHandle::Get()));
+      FROM_HERE, base::BindOnce(&StartServiceResolver,
+                                base::scoped_nsobject<NetServiceResolver>(
+                                    [resolver_ retain])));
 }
 
 std::string ServiceResolverImplMac::GetName() const {
@@ -308,17 +317,6 @@
     std::move(callback_).Run(status, description);
 }
 
-void ServiceResolverImplMac::StartResolvingOnDiscoveryThread(
-    ServiceResolver::ResolveCompleteCallback callback,
-    scoped_refptr<base::SingleThreadTaskRunner> callback_runner) {
-  DCHECK(service_discovery_runner_->RunsTasksInCurrentSequence());
-
-  resolver_.reset([[NetServiceResolver alloc]
-      initWithServiceName:service_name_
-         resolvedCallback:std::move(callback)
-           callbackRunner:callback_runner]);
-}
-
 void ServiceResolverImplMac::StopResolving() {
   service_discovery_runner_->PostTask(
       FROM_HERE, base::BindOnce(&StopServiceResolver, std::move(resolver_)));
@@ -366,8 +364,6 @@
     _callbackRunner = callbackRunner;
 
     _services.reset([[NSMutableArray alloc] initWithCapacity:1]);
-    _browser.reset([[NSNetServiceBrowser alloc] init]);
-    [_browser setDelegate:self];
   }
   return self;
 }
@@ -378,6 +374,11 @@
 }
 
 - (void)discoverServices {
+  if (!_browser) {
+    _browser.reset([[NSNetServiceBrowser alloc] init]);
+    [_browser setDelegate:self];
+  }
+
   base::scoped_nsobject<NSString> instance, type, domain;
   if (!local_discovery::ExtractServiceInfo(_serviceType, false, &instance,
                                            &type, &domain)) {
@@ -392,6 +393,8 @@
 }
 
 - (void)stop {
+  [_browser stop];
+
   // Work around a 10.12 bug: NSNetServiceBrowser doesn't lose interest in its
   // weak delegate during deallocation, so a subsequently-deallocated delegate
   // attempts to clear the pointer to itself in an NSNetServiceBrowser that's
@@ -413,7 +416,6 @@
 - (void)netServiceBrowser:(NSNetServiceBrowser*)netServiceBrowser
            didFindService:(NSNetService*)netService
                moreComing:(BOOL)moreServicesComing {
-  // Start monitoring this service for updates.
   [netService setDelegate:self];
   [netService startMonitoring];
   [_services addObject:netService];
@@ -432,10 +434,16 @@
         FROM_HERE, base::BindOnce(_callback, ServiceWatcher::UPDATE_REMOVED,
                                   base::SysNSStringToUTF8([netService name])));
 
-    // Stop monitoring this service for updates.
-    DCHECK_EQ(netService, [_services objectAtIndex:index]);
+    // Stop monitoring this service for updates. The |netService| object may be
+    // different than the one stored in |_services|, even though they represent
+    // the same service. Stop monitoring and clear the delegate on both.
     [netService stopMonitoring];
     [netService setDelegate:nil];
+
+    netService = [_services objectAtIndex:index];
+    [netService stopMonitoring];
+    [netService setDelegate:nil];
+
     [_services removeObjectAtIndex:index];
   }
 }
@@ -470,24 +478,6 @@
     _serviceName = serviceName;
     _callback = std::move(callback);
     _callbackRunner = callbackRunner;
-
-    base::scoped_nsobject<NSString> instance, type, domain;
-    if (!local_discovery::ExtractServiceInfo(_serviceName, true, &instance,
-                                             &type, &domain)) {
-      [self updateServiceDescription:ServiceResolver::STATUS_KNOWN_NONEXISTENT];
-      return self;
-    }
-
-    VLOG(1) << "ServiceResolverImplMac::"
-            << "StartResolvingOnDiscoveryThread: " << serviceName
-            << ", instance: " << instance << ", type: " << type
-            << ", domain: " << domain;
-
-    _service.reset([[NSNetService alloc] initWithDomain:domain
-                                                   type:type
-                                                   name:instance]);
-    [_service setDelegate:self];
-    [_service resolveWithTimeout:local_discovery::kResolveTimeout];
   }
   return self;
 }
@@ -497,7 +487,28 @@
   [super dealloc];
 }
 
+- (void)resolveService {
+  base::scoped_nsobject<NSString> instance, type, domain;
+  if (!local_discovery::ExtractServiceInfo(_serviceName, true, &instance, &type,
+                                           &domain)) {
+    [self updateServiceDescription:ServiceResolver::STATUS_KNOWN_NONEXISTENT];
+    return;
+  }
+
+  VLOG(1) << "-[ServiceResolver resolveService] " << _serviceName
+          << ", instance: " << instance << ", type: " << type
+          << ", domain: " << domain;
+
+  _service.reset([[NSNetService alloc] initWithDomain:domain
+                                                 type:type
+                                                 name:instance]);
+  [_service setDelegate:self];
+  [_service resolveWithTimeout:local_discovery::kResolveTimeout];
+}
+
 - (void)stop {
+  [_service stop];
+
   // Work around a 10.12 bug: NSNetService doesn't lose interest in its weak
   // delegate during deallocation, so a subsequently-deallocated delegate
   // attempts to clear the pointer to itself in an NSNetService that's already
diff --git a/chrome/browser/local_discovery/service_discovery_client_mac_unittest.mm b/chrome/browser/local_discovery/service_discovery_client_mac_unittest.mm
index c8a58a78b..db3547a 100644
--- a/chrome/browser/local_discovery/service_discovery_client_mac_unittest.mm
+++ b/chrome/browser/local_discovery/service_discovery_client_mac_unittest.mm
@@ -77,11 +77,6 @@
     num_resolves_++;
   }
 
-  void StopDiscoveryThread() {
-    client_->service_discovery_thread_->FlushForTesting();
-    client_->service_discovery_thread_.reset();
-  }
-
   ServiceDiscoveryClient* client() { return client_.get(); }
 
  protected:
@@ -119,10 +114,32 @@
       ServiceWatcher::UPDATE_REMOVED, test_service_name);
   EXPECT_EQ(last_service_name_, test_service_name + "." + test_service_type);
   EXPECT_EQ(num_updates_, 3);
+}
 
-  // Explicitly flush and stop the thread that |watcher| is using before
-  // |watcher| goes out of scope.
-  StopDiscoveryThread();
+TEST_F(ServiceDiscoveryClientMacTest, DeleteWatcherAfterStart) {
+  const std::string test_service_type = "_testing._tcp.local";
+
+  std::unique_ptr<ServiceWatcher> watcher = client()->CreateServiceWatcher(
+      test_service_type,
+      base::BindRepeating(&ServiceDiscoveryClientMacTest::OnServiceUpdated,
+                          base::Unretained(this)));
+  watcher->Start();
+  watcher.reset();
+
+  EXPECT_EQ(0, num_updates_);
+}
+
+TEST_F(ServiceDiscoveryClientMacTest, DeleteResolverAfterStart) {
+  const std::string test_service_name = "Test.123";
+
+  std::unique_ptr<ServiceResolver> resolver = client()->CreateServiceResolver(
+      test_service_name,
+      base::BindRepeating(&ServiceDiscoveryClientMacTest::OnResolveComplete,
+                          base::Unretained(this)));
+  resolver->StartResolving();
+  resolver.reset();
+
+  EXPECT_EQ(0, num_resolves_);
 }
 
 TEST_F(ServiceDiscoveryClientMacTest, ParseServiceRecord) {
diff --git a/chrome/browser/nearby_sharing/fake_nearby_connection.cc b/chrome/browser/nearby_sharing/fake_nearby_connection.cc
index a826874..2f5a523 100644
--- a/chrome/browser/nearby_sharing/fake_nearby_connection.cc
+++ b/chrome/browser/nearby_sharing/fake_nearby_connection.cc
@@ -18,7 +18,7 @@
 
 void FakeNearbyConnection::Write(std::vector<uint8_t> bytes) {
   DCHECK(!closed_);
-  NOTIMPLEMENTED();
+  write_data_.push(std::move(bytes));
 }
 
 void FakeNearbyConnection::Close() {
@@ -38,15 +38,24 @@
 
 void FakeNearbyConnection::AppendReadableData(std::vector<uint8_t> bytes) {
   DCHECK(!closed_);
-  data_.push(std::move(bytes));
+  read_data_.push(std::move(bytes));
   MaybeRunCallback();
 }
 
+std::vector<uint8_t> FakeNearbyConnection::GetWrittenData() {
+  if (write_data_.empty())
+    return {};
+
+  std::vector<uint8_t> bytes = std::move(write_data_.front());
+  write_data_.pop();
+  return bytes;
+}
+
 void FakeNearbyConnection::MaybeRunCallback() {
   DCHECK(!closed_);
-  if (!callback_ || data_.empty())
+  if (!callback_ || read_data_.empty())
     return;
-  auto item = std::move(data_.front());
-  data_.pop();
+  auto item = std::move(read_data_.front());
+  read_data_.pop();
   std::move(callback_).Run(std::move(item));
 }
diff --git a/chrome/browser/nearby_sharing/fake_nearby_connection.h b/chrome/browser/nearby_sharing/fake_nearby_connection.h
index 07980c18..0dc9be4 100644
--- a/chrome/browser/nearby_sharing/fake_nearby_connection.h
+++ b/chrome/browser/nearby_sharing/fake_nearby_connection.h
@@ -22,13 +22,15 @@
   void RegisterForDisconnection(base::OnceClosure listener) override;
 
   void AppendReadableData(std::vector<uint8_t> bytes);
+  std::vector<uint8_t> GetWrittenData();
 
  private:
   void MaybeRunCallback();
 
   bool closed_ = false;
   ReadCallback callback_;
-  std::queue<std::vector<uint8_t>> data_;
+  std::queue<std::vector<uint8_t>> read_data_;
+  std::queue<std::vector<uint8_t>> write_data_;
   std::vector<base::OnceClosure> disconnect_listeners_;
 };
 
diff --git a/chrome/browser/nearby_sharing/fake_nearby_connections_manager.cc b/chrome/browser/nearby_sharing/fake_nearby_connections_manager.cc
index 5581e22..01debf03 100644
--- a/chrome/browser/nearby_sharing/fake_nearby_connections_manager.cc
+++ b/chrome/browser/nearby_sharing/fake_nearby_connections_manager.cc
@@ -105,6 +105,11 @@
   return base::nullopt;
 }
 
+void FakeNearbyConnectionsManager::UpgradeBandwidth(
+    const std::string& endpoint_id) {
+  upgrade_bandwidth_endpoint_ids_.insert(endpoint_id);
+}
+
 bool FakeNearbyConnectionsManager::IsAdvertising() {
   return advertising_listener_ != nullptr;
 }
@@ -124,3 +129,8 @@
 PowerLevel FakeNearbyConnectionsManager::GetAdvertisingPowerLevel() {
   return advertising_power_level_;
 }
+
+bool FakeNearbyConnectionsManager::DidUpgradeBandwidth(
+    const std::string& endpoint_id) {
+  return (upgrade_bandwidth_endpoint_ids_.count(endpoint_id) > 0);
+}
diff --git a/chrome/browser/nearby_sharing/fake_nearby_connections_manager.h b/chrome/browser/nearby_sharing/fake_nearby_connections_manager.h
index 70b1445..fbebd68 100644
--- a/chrome/browser/nearby_sharing/fake_nearby_connections_manager.h
+++ b/chrome/browser/nearby_sharing/fake_nearby_connections_manager.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_NEARBY_SHARING_FAKE_NEARBY_CONNECTIONS_MANAGER_H_
 
 #include <memory>
+#include <set>
 #include <string>
 #include <utility>
 #include <vector>
@@ -47,6 +48,7 @@
   void ClearIncomingPayloads() override;
   base::Optional<std::vector<uint8_t>> GetRawAuthenticationToken(
       const std::string& endpoint_id) override;
+  void UpgradeBandwidth(const std::string& endpoint_id) override;
 
   // Testing methods
   bool IsAdvertising();
@@ -54,6 +56,7 @@
   bool IsShutdown();
   DataUsage GetAdvertisingDataUsage();
   PowerLevel GetAdvertisingPowerLevel();
+  bool DidUpgradeBandwidth(const std::string& endpoint_id);
 
  private:
   IncomingConnectionListener* advertising_listener_ = nullptr;
@@ -61,6 +64,7 @@
   bool is_shutdown_ = false;
   DataUsage advertising_data_usage_ = DataUsage::kUnknown;
   PowerLevel advertising_power_level_ = PowerLevel::kUnknown;
+  std::set<std::string> upgrade_bandwidth_endpoint_ids_;
 };
 
 #endif  // CHROME_BROWSER_NEARBY_SHARING_FAKE_NEARBY_CONNECTIONS_MANAGER_H_
diff --git a/chrome/browser/nearby_sharing/incoming_share_target_info.h b/chrome/browser/nearby_sharing/incoming_share_target_info.h
index db4b651d..22347a4 100644
--- a/chrome/browser/nearby_sharing/incoming_share_target_info.h
+++ b/chrome/browser/nearby_sharing/incoming_share_target_info.h
@@ -53,7 +53,7 @@
  private:
   base::Optional<std::string> endpoint_id_;
   base::Optional<NearbyShareDecryptedPublicCertificate> certificate_;
-  NearbyConnection* connection_;
+  NearbyConnection* connection_ = nullptr;
   base::Optional<std::string> token_;
 };
 
diff --git a/chrome/browser/nearby_sharing/nearby_connections_manager.h b/chrome/browser/nearby_sharing/nearby_connections_manager.h
index ca383b0..ad84579 100644
--- a/chrome/browser/nearby_sharing/nearby_connections_manager.h
+++ b/chrome/browser/nearby_sharing/nearby_connections_manager.h
@@ -124,6 +124,9 @@
   // Gets the raw authentication token for the |endpoint_id|.
   virtual base::Optional<std::vector<uint8_t>> GetRawAuthenticationToken(
       const std::string& endpoint_id) = 0;
+
+  // Initiates bandwidth upgrade for |endpoint_id|.
+  virtual void UpgradeBandwidth(const std::string& endpoint_id) = 0;
 };
 
 #endif  // CHROME_BROWSER_NEARBY_SHARING_NEARBY_CONNECTIONS_MANAGER_H_
diff --git a/chrome/browser/nearby_sharing/nearby_connections_manager_impl.cc b/chrome/browser/nearby_sharing/nearby_connections_manager_impl.cc
index 72c51ec0..275964c 100644
--- a/chrome/browser/nearby_sharing/nearby_connections_manager_impl.cc
+++ b/chrome/browser/nearby_sharing/nearby_connections_manager_impl.cc
@@ -178,6 +178,11 @@
   return it->second->raw_authentication_token;
 }
 
+void NearbyConnectionsManagerImpl::UpgradeBandwidth(
+    const std::string& endpoint_id) {
+  // TODO(crbug/1076008): Implement.
+}
+
 void NearbyConnectionsManagerImpl::OnNearbyProfileChanged(Profile* profile) {
   NS_LOG(VERBOSE) << __func__;
 }
diff --git a/chrome/browser/nearby_sharing/nearby_connections_manager_impl.h b/chrome/browser/nearby_sharing/nearby_connections_manager_impl.h
index c39c818..1c4e3745 100644
--- a/chrome/browser/nearby_sharing/nearby_connections_manager_impl.h
+++ b/chrome/browser/nearby_sharing/nearby_connections_manager_impl.h
@@ -60,6 +60,7 @@
   void ClearIncomingPayloads() override;
   base::Optional<std::vector<uint8_t>> GetRawAuthenticationToken(
       const std::string& endpoint_id) override;
+  void UpgradeBandwidth(const std::string& endpoint_id) override;
 
  private:
   using DiscoveryOptions =
diff --git a/chrome/browser/nearby_sharing/nearby_notification_manager.cc b/chrome/browser/nearby_sharing/nearby_notification_manager.cc
index ab8939ec..ea4c7ef 100644
--- a/chrome/browser/nearby_sharing/nearby_notification_manager.cc
+++ b/chrome/browser/nearby_sharing/nearby_notification_manager.cc
@@ -7,6 +7,7 @@
 #include "base/notreached.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string16.h"
+#include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "chrome/app/vector_icons/vector_icons.h"
@@ -123,34 +124,37 @@
   return l10n_util::GetPluralStringFUTF16(resource_id, text_count + file_count);
 }
 
-base::string16 GetProgressNotificationTitle(const ShareTarget& share_target) {
-  int resource_id = share_target.is_incoming
-                        ? IDS_NEARBY_NOTIFICATION_RECEIVE_PROGRESS_TITLE
-                        : IDS_NEARBY_NOTIFICATION_SEND_PROGRESS_TITLE;
+base::string16 FormatNotificationTitle(const ShareTarget& share_target,
+                                       int resource_id) {
   base::string16 attachments = GetAttachmentsString(share_target);
   base::string16 device_name = base::ASCIIToUTF16(share_target.device_name);
+  size_t attachment_count = share_target.file_attachments.size() +
+                            share_target.text_attachments.size();
 
-  return l10n_util::GetStringFUTF16(resource_id, attachments, device_name);
+  return base::ReplaceStringPlaceholders(
+      l10n_util::GetPluralStringFUTF16(resource_id, attachment_count),
+      {attachments, device_name}, /*offsets=*/nullptr);
+}
+
+base::string16 GetProgressNotificationTitle(const ShareTarget& share_target) {
+  return FormatNotificationTitle(
+      share_target, share_target.is_incoming
+                        ? IDS_NEARBY_NOTIFICATION_RECEIVE_PROGRESS_TITLE
+                        : IDS_NEARBY_NOTIFICATION_SEND_PROGRESS_TITLE);
 }
 
 base::string16 GetSuccessNotificationTitle(const ShareTarget& share_target) {
-  int resource_id = share_target.is_incoming
+  return FormatNotificationTitle(
+      share_target, share_target.is_incoming
                         ? IDS_NEARBY_NOTIFICATION_RECEIVE_SUCCESS_TITLE
-                        : IDS_NEARBY_NOTIFICATION_SEND_SUCCESS_TITLE;
-  base::string16 attachments = GetAttachmentsString(share_target);
-  base::string16 device_name = base::ASCIIToUTF16(share_target.device_name);
-
-  return l10n_util::GetStringFUTF16(resource_id, attachments, device_name);
+                        : IDS_NEARBY_NOTIFICATION_SEND_SUCCESS_TITLE);
 }
 
 base::string16 GetFailureNotificationTitle(const ShareTarget& share_target) {
-  int resource_id = share_target.is_incoming
+  return FormatNotificationTitle(
+      share_target, share_target.is_incoming
                         ? IDS_NEARBY_NOTIFICATION_RECEIVE_FAILURE_TITLE
-                        : IDS_NEARBY_NOTIFICATION_SEND_FAILURE_TITLE;
-  base::string16 attachments = GetAttachmentsString(share_target);
-  base::string16 device_name = base::ASCIIToUTF16(share_target.device_name);
-
-  return l10n_util::GetStringFUTF16(resource_id, attachments, device_name);
+                        : IDS_NEARBY_NOTIFICATION_SEND_FAILURE_TITLE);
 }
 
 base::string16 GetConnectionRequestNotificationMessage(
@@ -159,9 +163,12 @@
   base::string16 attachments = GetAttachmentsString(share_target);
   base::string16 device_name = base::ASCIIToUTF16(share_target.device_name);
 
-  base::string16 message = l10n_util::GetStringFUTF16(
-      IDS_NEARBY_NOTIFICATION_CONNECTION_REQUEST_MESSAGE, device_name,
-      attachments);
+  size_t attachment_count = share_target.file_attachments.size() +
+                            share_target.text_attachments.size();
+  base::string16 message = base::ReplaceStringPlaceholders(
+      l10n_util::GetPluralStringFUTF16(
+          IDS_NEARBY_NOTIFICATION_CONNECTION_REQUEST_MESSAGE, attachment_count),
+      {device_name, attachments}, /*offsets=*/nullptr);
 
   if (transfer_metadata.token()) {
     base::string16 token = l10n_util::GetStringFUTF16(
diff --git a/chrome/browser/nearby_sharing/nearby_notification_manager_unittest.cc b/chrome/browser/nearby_sharing/nearby_notification_manager_unittest.cc
index e8b07ee..9c5f45047 100644
--- a/chrome/browser/nearby_sharing/nearby_notification_manager_unittest.cc
+++ b/chrome/browser/nearby_sharing/nearby_notification_manager_unittest.cc
@@ -8,6 +8,7 @@
 #include <vector>
 
 #include "base/strings/strcat.h"
+#include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
@@ -158,6 +159,18 @@
     : public NearbyNotificationManagerTest,
       public testing::WithParamInterface<ConnectionRequestTestParam> {};
 
+base::string16 FormatNotificationTitle(
+    int resource_id,
+    const AttachmentsTestParamInternal& param,
+    const std::string& device_name) {
+  size_t total = param.text_attachments.size() + param.file_attachments.size();
+  return base::ReplaceStringPlaceholders(
+      l10n_util::GetPluralStringFUTF16(resource_id, total),
+      {l10n_util::GetPluralStringFUTF16(param.expected_resource_id, total),
+       base::ASCIIToUTF16(device_name)},
+      /*offsets=*/nullptr);
+}
+
 }  // namespace
 
 TEST_F(NearbyNotificationManagerTest, RegistersAsBackgroundSurfaces) {
@@ -277,14 +290,10 @@
   TransferMetadata transfer_metadata = TransferMetadataBuilder().build();
   manager()->ShowProgress(share_target, transfer_metadata);
 
-  int expected_resource_id =
+  base::string16 expected = FormatNotificationTitle(
       is_incoming ? IDS_NEARBY_NOTIFICATION_RECEIVE_PROGRESS_TITLE
-                  : IDS_NEARBY_NOTIFICATION_SEND_PROGRESS_TITLE;
-  size_t total = param.text_attachments.size() + param.file_attachments.size();
-  base::string16 expected = l10n_util::GetStringFUTF16(
-      expected_resource_id,
-      l10n_util::GetPluralStringFUTF16(param.expected_resource_id, total),
-      base::ASCIIToUTF16(device_name));
+                  : IDS_NEARBY_NOTIFICATION_SEND_PROGRESS_TITLE,
+      param, device_name);
 
   std::vector<message_center::Notification> notifications =
       GetDisplayedNotifications();
@@ -311,14 +320,10 @@
 
   manager()->ShowSuccess(share_target);
 
-  int expected_resource_id = is_incoming
-                                 ? IDS_NEARBY_NOTIFICATION_RECEIVE_SUCCESS_TITLE
-                                 : IDS_NEARBY_NOTIFICATION_SEND_SUCCESS_TITLE;
-  size_t total = param.text_attachments.size() + param.file_attachments.size();
-  base::string16 expected = l10n_util::GetStringFUTF16(
-      expected_resource_id,
-      l10n_util::GetPluralStringFUTF16(param.expected_resource_id, total),
-      base::ASCIIToUTF16(device_name));
+  base::string16 expected = FormatNotificationTitle(
+      is_incoming ? IDS_NEARBY_NOTIFICATION_RECEIVE_SUCCESS_TITLE
+                  : IDS_NEARBY_NOTIFICATION_SEND_SUCCESS_TITLE,
+      param, device_name);
 
   std::vector<message_center::Notification> notifications =
       GetDisplayedNotifications();
@@ -345,14 +350,10 @@
 
   manager()->ShowFailure(share_target);
 
-  int expected_resource_id = is_incoming
-                                 ? IDS_NEARBY_NOTIFICATION_RECEIVE_FAILURE_TITLE
-                                 : IDS_NEARBY_NOTIFICATION_SEND_FAILURE_TITLE;
-  size_t total = param.text_attachments.size() + param.file_attachments.size();
-  base::string16 expected = l10n_util::GetStringFUTF16(
-      expected_resource_id,
-      l10n_util::GetPluralStringFUTF16(param.expected_resource_id, total),
-      base::ASCIIToUTF16(device_name));
+  base::string16 expected = FormatNotificationTitle(
+      is_incoming ? IDS_NEARBY_NOTIFICATION_RECEIVE_FAILURE_TITLE
+                  : IDS_NEARBY_NOTIFICATION_SEND_FAILURE_TITLE,
+      param, device_name);
 
   std::vector<message_center::Notification> notifications =
       GetDisplayedNotifications();
@@ -397,11 +398,14 @@
 
   base::string16 expected_title = l10n_util::GetStringUTF16(
       IDS_NEARBY_NOTIFICATION_CONNECTION_REQUEST_TITLE);
+  base::string16 plural_message = l10n_util::GetPluralStringFUTF16(
+      IDS_NEARBY_NOTIFICATION_CONNECTION_REQUEST_MESSAGE, 1);
 
-  base::string16 expected_message = l10n_util::GetStringFUTF16(
-      IDS_NEARBY_NOTIFICATION_CONNECTION_REQUEST_MESSAGE,
-      base::ASCIIToUTF16(device_name),
-      l10n_util::GetPluralStringFUTF16(IDS_NEARBY_FILE_ATTACHMENTS_IMAGES, 1));
+  base::string16 expected_message = base::ReplaceStringPlaceholders(
+      plural_message,
+      {base::ASCIIToUTF16(device_name),
+       l10n_util::GetPluralStringFUTF16(IDS_NEARBY_FILE_ATTACHMENTS_IMAGES, 1)},
+      /*offsets=*/nullptr);
 
   if (with_token) {
     expected_message = base::StrCat(
diff --git a/chrome/browser/nearby_sharing/nearby_per_session_discovery_manager_unittest.cc b/chrome/browser/nearby_sharing/nearby_per_session_discovery_manager_unittest.cc
index 4026a95..627a105 100644
--- a/chrome/browser/nearby_sharing/nearby_per_session_discovery_manager_unittest.cc
+++ b/chrome/browser/nearby_sharing/nearby_per_session_discovery_manager_unittest.cc
@@ -109,6 +109,10 @@
 
 TEST_F(NearbyPerSessionDiscoveryManagerTest, OnShareTargetDiscovered) {
   MockShareTargetListener listener;
+  EXPECT_CALL(sharing_service(),
+              RegisterSendSurface(testing::_, testing::_, testing::_))
+      .WillOnce(testing::Return(NearbySharingService::StatusCodes::kOk));
+
   manager().StartDiscovery(listener.Bind(), base::DoNothing());
 
   ShareTarget share_target;
@@ -124,6 +128,10 @@
 
 TEST_F(NearbyPerSessionDiscoveryManagerTest, OnShareTargetLost) {
   MockShareTargetListener listener;
+  EXPECT_CALL(sharing_service(),
+              RegisterSendSurface(testing::_, testing::_, testing::_))
+      .WillOnce(testing::Return(NearbySharingService::StatusCodes::kOk));
+
   manager().StartDiscovery(listener.Bind(), base::DoNothing());
 
   ShareTarget share_target;
@@ -150,6 +158,10 @@
 TEST_F(NearbyPerSessionDiscoveryManagerTest, SelectShareTarget_SendSuccess) {
   // Setup share target
   MockShareTargetListener listener;
+  EXPECT_CALL(sharing_service(),
+              RegisterSendSurface(testing::_, testing::_, testing::_))
+      .WillOnce(testing::Return(NearbySharingService::StatusCodes::kOk));
+
   manager().StartDiscovery(listener.Bind(), base::DoNothing());
   ShareTarget share_target;
   manager().OnShareTargetDiscovered(share_target);
@@ -173,6 +185,10 @@
 TEST_F(NearbyPerSessionDiscoveryManagerTest, SelectShareTarget_SendError) {
   // Setup share target
   MockShareTargetListener listener;
+  EXPECT_CALL(sharing_service(),
+              RegisterSendSurface(testing::_, testing::_, testing::_))
+      .WillOnce(testing::Return(NearbySharingService::StatusCodes::kOk));
+
   manager().StartDiscovery(listener.Bind(), base::DoNothing());
   ShareTarget share_target;
   manager().OnShareTargetDiscovered(share_target);
@@ -198,6 +214,10 @@
 TEST_F(NearbyPerSessionDiscoveryManagerTest, OnTransferUpdate_WaitRemote) {
   // Setup share target
   MockShareTargetListener listener;
+  EXPECT_CALL(sharing_service(),
+              RegisterSendSurface(testing::_, testing::_, testing::_))
+      .WillOnce(testing::Return(NearbySharingService::StatusCodes::kOk));
+
   manager().StartDiscovery(listener.Bind(), base::DoNothing());
   ShareTarget share_target;
   manager().OnShareTargetDiscovered(share_target);
@@ -219,6 +239,10 @@
 TEST_F(NearbyPerSessionDiscoveryManagerTest, OnTransferUpdate_WaitLocal) {
   // Setup share target
   MockShareTargetListener listener;
+  EXPECT_CALL(sharing_service(),
+              RegisterSendSurface(testing::_, testing::_, testing::_))
+      .WillOnce(testing::Return(NearbySharingService::StatusCodes::kOk));
+
   manager().StartDiscovery(listener.Bind(), base::DoNothing());
   ShareTarget share_target;
   manager().OnShareTargetDiscovered(share_target);
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service.h b/chrome/browser/nearby_sharing/nearby_sharing_service.h
index 86624d9..e1807fc 100644
--- a/chrome/browser/nearby_sharing/nearby_sharing_service.h
+++ b/chrome/browser/nearby_sharing/nearby_sharing_service.h
@@ -27,10 +27,12 @@
 class NearbySharingService : public KeyedService {
  public:
   enum class StatusCodes {
-    // The operation was successful.
-    kOk,
     // The operation failed, without any more information.
     kError,
+    // The operation was successful.
+    kOk,
+    // The operation failed since it was called in an invalid order.
+    kOutOfOrderApiCall,
   };
 
   enum class ReceiveSurfaceState {
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
index db53e858..1e89156 100644
--- a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
+++ b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
@@ -32,6 +32,8 @@
 constexpr base::TimeDelta kReadFramesTimeout = base::TimeDelta::FromSeconds(15);
 constexpr base::TimeDelta kReadResponseFrameTimeout =
     base::TimeDelta::FromSeconds(60);
+constexpr base::TimeDelta kIncomingRejectionDelay =
+    base::TimeDelta::FromSeconds(2);
 
 std::string ReceiveSurfaceStateToString(
     NearbySharingService::ReceiveSurfaceState state) {
@@ -292,12 +294,50 @@
 void NearbySharingServiceImpl::Accept(
     const ShareTarget& share_target,
     StatusCodesCallback status_codes_callback) {
-  std::move(status_codes_callback).Run(StatusCodes::kOk);
+  base::Optional<std::pair<ShareTarget, TransferMetadata>> metadata =
+      share_target.is_incoming ? last_incoming_metadata_
+                               : last_outgoing_metadata_;
+  if (!metadata || metadata->second.status() !=
+                       TransferMetadata::Status::kAwaitingLocalConfirmation) {
+    std::move(status_codes_callback).Run(StatusCodes::kOutOfOrderApiCall);
+    return;
+  }
+
+  StatusCodes status_code = share_target.is_incoming
+                                ? ReceivePayloads(share_target)
+                                : SendPayloads(share_target);
+  std::move(status_codes_callback).Run(status_code);
 }
 
 void NearbySharingServiceImpl::Reject(
     const ShareTarget& share_target,
     StatusCodesCallback status_codes_callback) {
+  NearbyConnection* connection = GetIncomingConnection(share_target);
+  if (!connection) {
+    NS_LOG(WARNING) << __func__ << ": Reject invoked for unknown share target";
+    std::move(status_codes_callback).Run(StatusCodes::kOutOfOrderApiCall);
+    return;
+  }
+
+  base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE,
+      base::BindOnce(&NearbySharingServiceImpl::CloseConnection,
+                     weak_ptr_factory_.GetWeakPtr(), share_target),
+      kIncomingRejectionDelay);
+
+  connection->RegisterForDisconnection(
+      base::BindOnce(&NearbySharingServiceImpl::UnregisterShareTarget,
+                     weak_ptr_factory_.GetWeakPtr(), share_target));
+
+  WriteResponse(*connection, sharing::nearby::ConnectionResponseFrame::REJECT);
+  NS_LOG(VERBOSE) << __func__
+                  << ": Successfully wrote a rejection response frame";
+
+  OnIncomingTransferUpdate(share_target,
+                           TransferMetadataBuilder()
+                               .set_status(TransferMetadata::Status::kRejected)
+                               .build());
+
   std::move(status_codes_callback).Run(StatusCodes::kOk);
 }
 
@@ -350,6 +390,7 @@
   share_target.is_incoming = true;
 
   incoming_share_target_info_map_[share_target.id].set_connection(connection);
+  incoming_share_target_info_map_[share_target.id].set_endpoint_id(endpoint_id);
   connection->RegisterForDisconnection(
       base::BindOnce(&NearbySharingServiceImpl::UnregisterShareTarget,
                      weak_ptr_factory_.GetWeakPtr(), share_target));
@@ -708,6 +749,68 @@
   }
 }
 
+NearbySharingService::StatusCodes NearbySharingServiceImpl::ReceivePayloads(
+    const ShareTarget& share_target) {
+  mutual_acceptance_timeout_alarm_.Cancel();
+
+  NearbyConnection* connection = GetIncomingConnection(share_target);
+  if (!connection) {
+    NS_LOG(WARNING) << __func__ << ": Accept invoked for unknown share target";
+    return StatusCodes::kOutOfOrderApiCall;
+  }
+
+  // TODO(himanshujaju) - Implement payload tracker.
+
+  for (const auto& attachment_id : share_target.GetAttachmentIds()) {
+    base::Optional<int64_t> payload_id = GetAttachmentPayloadId(attachment_id);
+    if (!payload_id) {
+      NS_LOG(WARNING) << __func__
+                      << ": Failed to retrieve payload for attachment id - "
+                      << attachment_id;
+      continue;
+    }
+
+    NS_LOG(VERBOSE) << __func__
+                    << ": Started listening for progress on payload - "
+                    << *payload_id;
+    // TODO(himanshujaju) - Register payload listener.
+    NS_LOG(VERBOSE) << __func__
+                    << ": Accepted incoming files from share target - "
+                    << share_target.device_name;
+  }
+
+  WriteResponse(*connection, sharing::nearby::ConnectionResponseFrame::ACCEPT);
+  NS_LOG(VERBOSE) << __func__ << ": Successfully wrote response frame";
+
+  OnIncomingTransferUpdate(
+      share_target,
+      TransferMetadataBuilder()
+          .set_status(TransferMetadata::Status::kAwaitingRemoteAcceptance)
+          .set_token(GetIncomingShareTargetInfo(share_target).token())
+          .build());
+
+  base::Optional<std::string> endpoint_id =
+      GetIncomingShareTargetInfo(share_target).endpoint_id();
+  if (endpoint_id) {
+    nearby_connections_manager_->UpgradeBandwidth(*endpoint_id);
+  } else {
+    NS_LOG(WARNING) << __func__
+                    << ": Failed to initiate bandwidth upgrade. No endpoint_id "
+                       "found for target - "
+                    << share_target.device_name;
+    return StatusCodes::kOutOfOrderApiCall;
+  }
+
+  return StatusCodes::kOk;
+}
+
+NearbySharingService::StatusCodes NearbySharingServiceImpl::SendPayloads(
+    const ShareTarget& share_target) {
+  // TODO(crbug.com/1085067) - Implement.
+
+  return StatusCodes::kOk;
+}
+
 void NearbySharingServiceImpl::WriteResponse(
     NearbyConnection& connection,
     sharing::nearby::ConnectionResponseFrame::Status status) {
@@ -761,6 +864,17 @@
   }
 }
 
+void NearbySharingServiceImpl::CloseConnection(
+    const ShareTarget& share_target) {
+  NearbyConnection* connection = GetIncomingConnection(share_target);
+  if (!connection) {
+    NS_LOG(WARNING) << __func__ << ": Invalid connection for target - "
+                    << share_target.device_name;
+    return;
+  }
+  connection->Close();
+}
+
 void NearbySharingServiceImpl::ReceiveIntroduction(
     ShareTarget share_target,
     base::Optional<std::string> token) {
@@ -1000,3 +1114,12 @@
     int64_t payload_id) {
   attachment_info_map_[attachment.id()].payload_id = payload_id;
 }
+
+base::Optional<int64_t> NearbySharingServiceImpl::GetAttachmentPayloadId(
+    const base::UnguessableToken& attachment_id) {
+  auto it = attachment_info_map_.find(attachment_id);
+  if (it == attachment_info_map_.end())
+    return base::nullopt;
+
+  return it->second.payload_id;
+}
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.h b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.h
index f6d42740..4d5b6aa 100644
--- a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.h
+++ b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.h
@@ -135,12 +135,17 @@
   void InvalidateReceiveSurfaceState();
   void InvalidateAdvertisingState();
   void StopAdvertising();
+
+  StatusCodes ReceivePayloads(const ShareTarget& share_target);
+  StatusCodes SendPayloads(const ShareTarget& share_target);
+
   void WriteResponse(
       NearbyConnection& connection,
       sharing::nearby::ConnectionResponseFrame::Status reponse_status);
   void Fail(const ShareTarget& share_target, TransferMetadata::Status status);
   void OnIncomingTransferUpdate(const ShareTarget& share_target,
                                 TransferMetadata metadata);
+  void CloseConnection(const ShareTarget& share_target);
   void ReceiveIntroduction(ShareTarget share_target,
                            base::Optional<std::string> token);
   void OnReceivedIntroduction(
@@ -167,6 +172,8 @@
       const ShareTarget& share_target);
   void ClearOutgoingShareTargetInfoMap();
   void SetAttachmentPayloadId(const Attachment& attachment, int64_t payload_id);
+  base::Optional<int64_t> GetAttachmentPayloadId(
+      const base::UnguessableToken& attachment_id);
 
   PrefService* prefs_;
   Profile* profile_;
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service_impl_unittest.cc b/chrome/browser/nearby_sharing/nearby_sharing_service_impl_unittest.cc
index b5169dd..a3e6e4e 100644
--- a/chrome/browser/nearby_sharing/nearby_sharing_service_impl_unittest.cc
+++ b/chrome/browser/nearby_sharing/nearby_sharing_service_impl_unittest.cc
@@ -141,6 +141,27 @@
 
 namespace {
 
+const char kEndpointId[] = "endpoint_id";
+
+sharing::mojom::FramePtr GetValidIntroductionFrame() {
+  std::vector<sharing::mojom::TextMetadataPtr> mojo_text_metadatas;
+  for (int i = 1; i <= 3; i++) {
+    mojo_text_metadatas.push_back(sharing::mojom::TextMetadata::New(
+        "title " + base::NumberToString(i),
+        static_cast<sharing::mojom::TextMetadata::Type>(i), i, i, i));
+  }
+
+  sharing::mojom::V1FramePtr mojo_v1frame = sharing::mojom::V1Frame::New();
+  mojo_v1frame->set_introduction(sharing::mojom::IntroductionFrame::New(
+      std::vector<sharing::mojom::FileMetadataPtr>(),
+      std::move(mojo_text_metadatas), base::nullopt,
+      std::vector<sharing::mojom::WifiCredentialsMetadataPtr>()));
+
+  sharing::mojom::FramePtr mojo_frame = sharing::mojom::Frame::New();
+  mojo_frame->set_v1(std::move(mojo_v1frame));
+  return mojo_frame;
+}
+
 class NearbySharingServiceImplTest : public testing::Test {
  public:
   NearbySharingServiceImplTest() {
@@ -768,9 +789,20 @@
   EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
   EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
 
-  service_->OnIncomingConnection("endpoint_id", {}, &connection);
+  service_->OnIncomingConnection(kEndpointId, {}, &connection);
   run_loop.Run();
 
+  // Check data written to connection.
+  std::vector<uint8_t> data = connection.GetWrittenData();
+  sharing::nearby::Frame frame;
+  frame.ParseFromArray(data.data(), data.size());
+
+  EXPECT_TRUE(frame.has_v1());
+  EXPECT_TRUE(frame.v1().has_connection_response());
+  EXPECT_EQ(
+      sharing::nearby::ConnectionResponseFrame::UNSUPPORTED_ATTACHMENT_TYPE,
+      frame.v1().connection_response().status());
+
   // To avoid UAF in OnIncomingTransferUpdate().
   service_->UnregisterReceiveSurface(&callback);
 }
@@ -784,25 +816,7 @@
       .WillOnce(testing::Invoke(
           [&](const std::vector<uint8_t>& data,
               MockNearbySharingDecoder::DecodeFrameCallback callback) {
-            // TODO(himanshujaju) - Write helper functions for these.
-            std::vector<sharing::mojom::TextMetadataPtr> mojo_text_metadatas;
-            for (int i = 1; i <= 3; i++) {
-              mojo_text_metadatas.push_back(sharing::mojom::TextMetadata::New(
-                  "title " + base::NumberToString(i),
-                  static_cast<sharing::mojom::TextMetadata::Type>(i), i, i, i));
-            }
-
-            sharing::mojom::V1FramePtr mojo_v1frame =
-                sharing::mojom::V1Frame::New();
-            mojo_v1frame->set_introduction(
-                sharing::mojom::IntroductionFrame::New(
-                    std::vector<sharing::mojom::FileMetadataPtr>(),
-                    std::move(mojo_text_metadatas), base::nullopt,
-                    std::vector<sharing::mojom::WifiCredentialsMetadataPtr>()));
-
-            sharing::mojom::FramePtr mojo_frame = sharing::mojom::Frame::New();
-            mojo_frame->set_v1(std::move(mojo_v1frame));
-            std::move(callback).Run(std::move(mojo_frame));
+            std::move(callback).Run(GetValidIntroductionFrame());
           }));
 
   EXPECT_CALL(mock_nearby_process_manager(),
@@ -828,9 +842,183 @@
   EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
   EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
 
+  service_->OnIncomingConnection(kEndpointId, {}, &connection);
+  run_loop.Run();
+
+  // To avoid UAF in OnIncomingTransferUpdate().
+  service_->UnregisterReceiveSurface(&callback);
+}
+
+TEST_F(NearbySharingServiceImplTest, AcceptInvalidShareTarget) {
+  ShareTarget share_target;
+  base::RunLoop run_loop;
+  service_->Accept(
+      share_target,
+      base::BindLambdaForTesting(
+          [&](NearbySharingServiceImpl::StatusCodes status_code) {
+            EXPECT_EQ(NearbySharingServiceImpl::StatusCodes::kOutOfOrderApiCall,
+                      status_code);
+            run_loop.Quit();
+          }));
+
+  run_loop.Run();
+}
+
+TEST_F(NearbySharingServiceImplTest, AcceptValidShareTarget) {
+  // TODO(himanshujaju) - Refactor common set up.
+  std::string intro = "introduction_frame";
+  std::vector<uint8_t> bytes(intro.begin(), intro.end());
+  NiceMock<MockNearbySharingDecoder> mock_decoder;
+  EXPECT_CALL(mock_decoder, DecodeFrame(testing::Eq(bytes), testing::_))
+      .WillOnce(testing::Invoke(
+          [&](const std::vector<uint8_t>& data,
+              MockNearbySharingDecoder::DecodeFrameCallback callback) {
+            std::move(callback).Run(GetValidIntroductionFrame());
+          }));
+
+  EXPECT_CALL(mock_nearby_process_manager(),
+              GetOrStartNearbySharingDecoder(testing::_))
+      .WillRepeatedly(testing::Return(&mock_decoder));
+
+  ShareTarget share_target;
+  FakeNearbyConnection connection;
+  connection.AppendReadableData(bytes);
+  ui::ScopedSetIdleState unlocked(ui::IDLE_STATE_IDLE);
+  SetConnectionType(net::NetworkChangeNotifier::CONNECTION_WIFI);
+  NiceMock<MockTransferUpdateCallback> callback;
+  base::RunLoop run_loop;
+  EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_))
+      .WillOnce(testing::Invoke([&](const ShareTarget& incoming_share_target,
+                                    TransferMetadata metadata) {
+        EXPECT_EQ(TransferMetadata::Status::kAwaitingLocalConfirmation,
+                  metadata.status());
+        share_target = incoming_share_target;
+        run_loop.Quit();
+      }));
+
+  NearbySharingService::StatusCodes result = service_->RegisterReceiveSurface(
+      &callback, NearbySharingService::ReceiveSurfaceState::kForeground);
+  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
+  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
+
+  service_->OnIncomingConnection(kEndpointId, {}, &connection);
+  run_loop.Run();
+
+  base::RunLoop run_loop_accept;
+  EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_))
+      .WillOnce(testing::Invoke(
+          [](const ShareTarget& share_target, TransferMetadata metadata) {
+            EXPECT_EQ(TransferMetadata::Status::kAwaitingRemoteAcceptance,
+                      metadata.status());
+          }));
+
+  service_->Accept(share_target,
+                   base::BindLambdaForTesting(
+                       [&](NearbySharingServiceImpl::StatusCodes status_code) {
+                         EXPECT_EQ(NearbySharingServiceImpl::StatusCodes::kOk,
+                                   status_code);
+                         run_loop_accept.Quit();
+                       }));
+
+  run_loop_accept.Run();
+
+  EXPECT_TRUE(
+      fake_nearby_connections_manager_->DidUpgradeBandwidth(kEndpointId));
+  // Check data written to connection.
+  std::vector<uint8_t> data = connection.GetWrittenData();
+  sharing::nearby::Frame frame;
+  frame.ParseFromArray(data.data(), data.size());
+
+  EXPECT_TRUE(frame.has_v1());
+  EXPECT_TRUE(frame.v1().has_connection_response());
+  EXPECT_EQ(sharing::nearby::ConnectionResponseFrame::ACCEPT,
+            frame.v1().connection_response().status());
+
+  // To avoid UAF in OnIncomingTransferUpdate().
+  service_->UnregisterReceiveSurface(&callback);
+}
+
+TEST_F(NearbySharingServiceImplTest, RejectInvalidShareTarget) {
+  ShareTarget share_target;
+  base::RunLoop run_loop;
+  service_->Reject(
+      share_target,
+      base::BindLambdaForTesting(
+          [&](NearbySharingServiceImpl::StatusCodes status_code) {
+            EXPECT_EQ(NearbySharingServiceImpl::StatusCodes::kOutOfOrderApiCall,
+                      status_code);
+            run_loop.Quit();
+          }));
+
+  run_loop.Run();
+}
+
+TEST_F(NearbySharingServiceImplTest, RejectValidShareTarget) {
+  std::string intro = "introduction_frame";
+  std::vector<uint8_t> bytes(intro.begin(), intro.end());
+  NiceMock<MockNearbySharingDecoder> mock_decoder;
+  EXPECT_CALL(mock_decoder, DecodeFrame(testing::Eq(bytes), testing::_))
+      .WillOnce(testing::Invoke(
+          [&](const std::vector<uint8_t>& data,
+              MockNearbySharingDecoder::DecodeFrameCallback callback) {
+            std::move(callback).Run(GetValidIntroductionFrame());
+          }));
+
+  EXPECT_CALL(mock_nearby_process_manager(),
+              GetOrStartNearbySharingDecoder(testing::_))
+      .WillRepeatedly(testing::Return(&mock_decoder));
+
+  ShareTarget share_target;
+  FakeNearbyConnection connection;
+  connection.AppendReadableData(bytes);
+  ui::ScopedSetIdleState unlocked(ui::IDLE_STATE_IDLE);
+  SetConnectionType(net::NetworkChangeNotifier::CONNECTION_WIFI);
+  NiceMock<MockTransferUpdateCallback> callback;
+  base::RunLoop run_loop;
+  EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_))
+      .WillOnce(testing::Invoke([&](const ShareTarget& incoming_share_target,
+                                    TransferMetadata metadata) {
+        EXPECT_EQ(TransferMetadata::Status::kAwaitingLocalConfirmation,
+                  metadata.status());
+        share_target = incoming_share_target;
+        run_loop.Quit();
+      }));
+
+  NearbySharingService::StatusCodes result = service_->RegisterReceiveSurface(
+      &callback, NearbySharingService::ReceiveSurfaceState::kForeground);
+  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
+  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
+
   service_->OnIncomingConnection("endpoint_id", {}, &connection);
   run_loop.Run();
 
+  base::RunLoop run_loop_reject;
+  EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_))
+      .WillOnce(testing::Invoke(
+          [](const ShareTarget& share_target, TransferMetadata metadata) {
+            EXPECT_EQ(TransferMetadata::Status::kRejected, metadata.status());
+          }));
+
+  service_->Reject(share_target,
+                   base::BindLambdaForTesting(
+                       [&](NearbySharingServiceImpl::StatusCodes status_code) {
+                         EXPECT_EQ(NearbySharingServiceImpl::StatusCodes::kOk,
+                                   status_code);
+                         run_loop_reject.Quit();
+                       }));
+
+  run_loop_reject.Run();
+
+  // Check data written to connection.
+  std::vector<uint8_t> data = connection.GetWrittenData();
+  sharing::nearby::Frame frame;
+  frame.ParseFromArray(data.data(), data.size());
+
+  EXPECT_TRUE(frame.has_v1());
+  EXPECT_TRUE(frame.v1().has_connection_response());
+  EXPECT_EQ(sharing::nearby::ConnectionResponseFrame::REJECT,
+            frame.v1().connection_response().status());
+
   // To avoid UAF in OnIncomingTransferUpdate().
   service_->UnregisterReceiveSurface(&callback);
 }
diff --git a/chrome/browser/nearby_sharing/outgoing_share_target_info.h b/chrome/browser/nearby_sharing/outgoing_share_target_info.h
index 360b1194..e00db25 100644
--- a/chrome/browser/nearby_sharing/outgoing_share_target_info.h
+++ b/chrome/browser/nearby_sharing/outgoing_share_target_info.h
@@ -66,10 +66,10 @@
  private:
   base::Optional<std::string> endpoint_id_;
   base::Optional<NearbyShareDecryptedPublicCertificate> certificate_;
-  NearbyConnection* connection_;
+  NearbyConnection* connection_ = nullptr;
   base::Optional<std::string> obfuscated_gaia_id_;
   base::Optional<std::string> token_;
-  bool is_connected_;
+  bool is_connected_ = false;
 };
 
 #endif  // CHROME_BROWSER_NEARBY_SHARING_OUTGOING_SHARE_TARGET_INFO_H_
diff --git a/chrome/browser/nearby_sharing/share_target.cc b/chrome/browser/nearby_sharing/share_target.cc
index e0d4cdce..4f1da8cb 100644
--- a/chrome/browser/nearby_sharing/share_target.cc
+++ b/chrome/browser/nearby_sharing/share_target.cc
@@ -34,3 +34,15 @@
 ShareTarget& ShareTarget::operator=(ShareTarget&&) = default;
 
 ShareTarget::~ShareTarget() = default;
+
+std::vector<base::UnguessableToken> ShareTarget::GetAttachmentIds() const {
+  std::vector<base::UnguessableToken> attachments;
+
+  for (const auto& file : file_attachments)
+    attachments.push_back(file.id());
+
+  for (const auto& text : text_attachments)
+    attachments.push_back(text.id());
+
+  return attachments;
+}
diff --git a/chrome/browser/nearby_sharing/share_target.h b/chrome/browser/nearby_sharing/share_target.h
index 696f03a..9c8c616 100644
--- a/chrome/browser/nearby_sharing/share_target.h
+++ b/chrome/browser/nearby_sharing/share_target.h
@@ -37,6 +37,8 @@
     return !text_attachments.empty() || !file_attachments.empty();
   }
 
+  std::vector<base::UnguessableToken> GetAttachmentIds() const;
+
   base::UnguessableToken id = base::UnguessableToken::Create();
   std::string device_name;
   // Uri that points to an image of the ShareTarget, if one exists.
diff --git a/chrome/browser/page_load_metrics/observers/javascript_frameworks_ukm_observer.cc b/chrome/browser/page_load_metrics/observers/javascript_frameworks_ukm_observer.cc
new file mode 100644
index 0000000..28272847
--- /dev/null
+++ b/chrome/browser/page_load_metrics/observers/javascript_frameworks_ukm_observer.cc
@@ -0,0 +1,32 @@
+// 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/page_load_metrics/observers/javascript_frameworks_ukm_observer.h"
+
+#include "services/metrics/public/cpp/ukm_builders.h"
+#include "services/metrics/public/cpp/ukm_recorder.h"
+
+JavascriptFrameworksUkmObserver::JavascriptFrameworksUkmObserver() = default;
+
+JavascriptFrameworksUkmObserver::~JavascriptFrameworksUkmObserver() = default;
+
+void JavascriptFrameworksUkmObserver::OnLoadingBehaviorObserved(
+    content::RenderFrameHost* rfh,
+    int behavior_flag) {
+  RecordNextJS();
+}
+
+void JavascriptFrameworksUkmObserver::RecordNextJS() {
+  if (nextjs_detected ||
+      (GetDelegate().GetMainFrameMetadata().behavior_flags &
+       blink::LoadingBehaviorFlag::kLoadingBehaviorNextJSFrameworkUsed) == 0) {
+    return;
+  }
+
+  ukm::builders::JavascriptFrameworkPageLoad builder(
+      GetDelegate().GetSourceId());
+  builder.SetNextJSPageLoad(true);
+  nextjs_detected = true;
+  builder.Record(ukm::UkmRecorder::Get());
+}
diff --git a/chrome/browser/page_load_metrics/observers/javascript_frameworks_ukm_observer.h b/chrome/browser/page_load_metrics/observers/javascript_frameworks_ukm_observer.h
new file mode 100644
index 0000000..53bdcbc7
--- /dev/null
+++ b/chrome/browser/page_load_metrics/observers/javascript_frameworks_ukm_observer.h
@@ -0,0 +1,28 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_JAVASCRIPT_FRAMEWORKS_UKM_OBSERVER_H_
+#define CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_JAVASCRIPT_FRAMEWORKS_UKM_OBSERVER_H_
+
+#include "components/page_load_metrics/browser/page_load_metrics_observer.h"
+
+// If URL-Keyed-Metrics (UKM) is enabled in the system, this is used to
+// populate it with JavaScript framework-related page-load metrics.
+class JavascriptFrameworksUkmObserver
+    : public page_load_metrics::PageLoadMetricsObserver {
+ public:
+  JavascriptFrameworksUkmObserver();
+  ~JavascriptFrameworksUkmObserver() override;
+
+  void OnLoadingBehaviorObserved(content::RenderFrameHost* rfh,
+                                 int behavior_flag) override;
+
+ private:
+  bool nextjs_detected = false;
+  void RecordNextJS();
+
+  DISALLOW_COPY_AND_ASSIGN(JavascriptFrameworksUkmObserver);
+};
+
+#endif  // CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_JAVASCRIPT_FRAMEWORKS_UKM_OBSERVER_H_
diff --git a/chrome/browser/page_load_metrics/observers/javascript_frameworks_ukm_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/javascript_frameworks_ukm_observer_browsertest.cc
new file mode 100644
index 0000000..757eddf
--- /dev/null
+++ b/chrome/browser/page_load_metrics/observers/javascript_frameworks_ukm_observer_browsertest.cc
@@ -0,0 +1,114 @@
+// 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/page_load_metrics/observers/foreground_duration_ukm_observer.h"
+
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/webui_url_constants.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "components/page_load_metrics/browser/page_load_metrics_test_waiter.h"
+#include "components/ukm/test_ukm_recorder.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/test_utils.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
+#include "services/metrics/public/cpp/ukm_source.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/window_open_disposition.h"
+#include "url/gurl.h"
+
+using UkmEntry = ukm::builders::JavascriptFrameworkPageLoad;
+
+class JavascriptFrameworksUkmObserverBrowserTest : public InProcessBrowserTest {
+ public:
+  JavascriptFrameworksUkmObserverBrowserTest() = default;
+  ~JavascriptFrameworksUkmObserverBrowserTest() override = default;
+  void PreRunTestOnMainThread() override {
+    InProcessBrowserTest::PreRunTestOnMainThread();
+    test_ukm_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>();
+  }
+
+ protected:
+  void StartHttpsServer(net::EmbeddedTestServer::ServerCertificate cert) {
+    https_test_server_ = std::make_unique<net::EmbeddedTestServer>(
+        net::EmbeddedTestServer::TYPE_HTTPS);
+    https_test_server_->SetSSLConfig(cert);
+    https_test_server_->ServeFilesFromSourceDirectory("chrome/test/data");
+    ASSERT_TRUE(https_test_server_->Start());
+  }
+  void ExpectMetricValueForUrl(const GURL& url,
+                               const char* metric_name,
+                               const int expected_value) {
+    for (auto* entry :
+         test_ukm_recorder_->GetEntriesByName(UkmEntry::kEntryName)) {
+      auto* source = test_ukm_recorder_->GetSourceForSourceId(entry->source_id);
+      if (source && source->url() == url) {
+        test_ukm_recorder_->EntryHasMetric(entry, metric_name);
+        test_ukm_recorder_->ExpectEntryMetric(entry, metric_name,
+                                              expected_value);
+      }
+    }
+  }
+  void ExpectMetricCountForUrl(const GURL& url,
+                               const char* metric_name,
+                               const int expected_count) {
+    int count = 0;
+    for (auto* entry :
+         test_ukm_recorder_->GetEntriesByName(UkmEntry::kEntryName)) {
+      auto* source = test_ukm_recorder_->GetSourceForSourceId(entry->source_id);
+      if (source && source->url() == url &&
+          test_ukm_recorder_->EntryHasMetric(entry, metric_name)) {
+        count++;
+      }
+    }
+    EXPECT_EQ(count, expected_count);
+  }
+  void CloseAllTabs() {
+    TabStripModel* tab_strip_model = browser()->tab_strip_model();
+    content::WebContentsDestroyedWatcher destroyed_watcher(
+        tab_strip_model->GetActiveWebContents());
+    tab_strip_model->CloseAllTabs();
+    destroyed_watcher.Wait();
+  }
+  net::EmbeddedTestServer* https_test_server() {
+    return https_test_server_.get();
+  }
+
+ private:
+  std::unique_ptr<ukm::TestAutoSetUkmRecorder> test_ukm_recorder_;
+  std::unique_ptr<net::EmbeddedTestServer> https_test_server_;
+  DISALLOW_COPY_AND_ASSIGN(JavascriptFrameworksUkmObserverBrowserTest);
+};
+
+IN_PROC_BROWSER_TEST_F(JavascriptFrameworksUkmObserverBrowserTest,
+                       NoNextjsFrameworkDetected) {
+  page_load_metrics::PageLoadMetricsTestWaiter waiter(
+      browser()->tab_strip_model()->GetActiveWebContents());
+  waiter.AddPageExpectation(
+      page_load_metrics::PageLoadMetricsTestWaiter::TimingField::kLoadEvent);
+  StartHttpsServer(net::EmbeddedTestServer::CERT_OK);
+  GURL url = https_test_server()->GetURL("/english_page.html");
+  ui_test_utils::NavigateToURL(browser(), url);
+  waiter.Wait();
+  CloseAllTabs();
+  ExpectMetricCountForUrl(url, "NextJSPageLoad", 0);
+}
+
+IN_PROC_BROWSER_TEST_F(JavascriptFrameworksUkmObserverBrowserTest,
+                       NextjsFrameworkDetected) {
+  page_load_metrics::PageLoadMetricsTestWaiter waiter(
+      browser()->tab_strip_model()->GetActiveWebContents());
+  waiter.AddPageExpectation(
+      page_load_metrics::PageLoadMetricsTestWaiter::TimingField::kLoadEvent);
+  StartHttpsServer(net::EmbeddedTestServer::CERT_OK);
+  GURL url = https_test_server()->GetURL("/page_load_metrics/nextjs_page.html");
+  ui_test_utils::NavigateToURL(browser(), url);
+  waiter.Wait();
+  CloseAllTabs();
+  ExpectMetricCountForUrl(url, "NextJSPageLoad", 1);
+}
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc b/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
index 3b123e9..f20c73f 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
+++ b/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
@@ -19,6 +19,7 @@
 #include "chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/observers/isolated_prerender_page_load_metrics_observer.h"
+#include "chrome/browser/page_load_metrics/observers/javascript_frameworks_ukm_observer.h"
 #include "chrome/browser/page_load_metrics/observers/live_tab_count_page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/observers/loading_predictor_page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/observers/local_network_requests_page_load_metrics_observer.h"
@@ -96,6 +97,7 @@
   if (!IsPrerendering()) {
     tracker->AddObserver(std::make_unique<AbortsPageLoadMetricsObserver>());
     tracker->AddObserver(std::make_unique<AMPPageLoadMetricsObserver>());
+    tracker->AddObserver(std::make_unique<JavascriptFrameworksUkmObserver>());
     tracker->AddObserver(std::make_unique<SchemePageLoadMetricsObserver>());
     tracker->AddObserver(std::make_unique<FromGWSPageLoadMetricsObserver>());
     tracker->AddObserver(std::make_unique<ForegroundDurationUKMObserver>());
diff --git a/chrome/browser/password_check/android/BUILD.gn b/chrome/browser/password_check/android/BUILD.gn
index dcc8ebeb..6a6b66a 100644
--- a/chrome/browser/password_check/android/BUILD.gn
+++ b/chrome/browser/password_check/android/BUILD.gn
@@ -78,6 +78,7 @@
     "//chrome/browser/password_check/android:password_check_java_enums",
     "//chrome/browser/password_check/android:public_java",
     "//chrome/test/android:chrome_java_test_support",
+    "//third_party/android_deps:androidx_appcompat_appcompat_java",
     "//third_party/hamcrest:hamcrest_java",
     "//third_party/junit",
     "//ui/android:ui_full_java",
@@ -111,6 +112,8 @@
     "//components/embedder_support/android:util_java",
     "//content/public/test/android:content_java_test_support",
     "//third_party/android_deps:androidx_annotation_annotation_java",
+    "//third_party/android_deps:androidx_appcompat_appcompat_java",
+    "//third_party/android_deps:androidx_appcompat_appcompat_resources_java",
     "//third_party/android_deps:androidx_fragment_fragment_java",
     "//third_party/android_deps:androidx_recyclerview_recyclerview_java",
     "//third_party/android_deps:androidx_test_runner_java",
diff --git a/chrome/browser/password_check/android/internal/BUILD.gn b/chrome/browser/password_check/android/internal/BUILD.gn
index 4c0f019..f0fea941 100644
--- a/chrome/browser/password_check/android/internal/BUILD.gn
+++ b/chrome/browser/password_check/android/internal/BUILD.gn
@@ -66,6 +66,7 @@
     "//components/browser_ui/widget/android:java",
     "//components/embedder_support/android:util_java",
     "//third_party/android_deps:androidx_annotation_annotation_java",
+    "//third_party/android_deps:androidx_appcompat_appcompat_java",
     "//third_party/android_deps:androidx_fragment_fragment_java",
     "//third_party/android_deps:androidx_lifecycle_lifecycle_common_java",
     "//third_party/android_deps:androidx_preference_preference_java",
@@ -77,6 +78,7 @@
   sources = [
     "java/src/org/chromium/chrome/browser/password_check/PasswordCheckBridge.java",
     "java/src/org/chromium/chrome/browser/password_check/PasswordCheckCoordinator.java",
+    "java/src/org/chromium/chrome/browser/password_check/PasswordCheckDeletionDialogFragment.java",
     "java/src/org/chromium/chrome/browser/password_check/PasswordCheckImpl.java",
     "java/src/org/chromium/chrome/browser/password_check/PasswordCheckMediator.java",
     "java/src/org/chromium/chrome/browser/password_check/PasswordCheckProperties.java",
@@ -93,9 +95,17 @@
 }
 
 android_resources("java_resources") {
-  deps = [ ":java_strings_grd" ]
+  deps = [
+    ":java_strings_grd",
+    "//components/browser_ui/settings/android:java_resources",
+    "//components/browser_ui/styles/android:java_resources",
+  ]
+
   sources = [
+    "java/res/drawable-night/password_check_positive.xml",
     "java/res/drawable/ic_autofill_assistant_white_24dp.xml",
+    "java/res/drawable/ic_check_circle_filled_green_24dp.xml",
+    "java/res/drawable/password_check_positive.xml",
     "java/res/layout/password_check_compromised_credential_item.xml",
     "java/res/layout/password_check_compromised_credential_with_script_item.xml",
     "java/res/layout/password_check_header_item.xml",
diff --git a/chrome/browser/password_check/android/internal/java/res/drawable-night/password_check_positive.xml b/chrome/browser/password_check/android/internal/java/res/drawable-night/password_check_positive.xml
new file mode 100644
index 0000000..272f8f9
--- /dev/null
+++ b/chrome/browser/password_check/android/internal/java/res/drawable-night/password_check_positive.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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. -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    tools:targetApi="21"
+    tools:ignore="VectorRaster"
+    android:width="360dp"
+    android:height="120dp"
+    android:viewportWidth="360"
+    android:viewportHeight="120">
+    <path android:pathData="M0 0h360v120H0z"
+        android:fillColor="#28282B"
+        android:fillType="evenOdd"/>
+    <path android:pathData="M288.585 52.215V47c10.735 0 19.175-3 25.09-8.955 9.29-9.36 9.325-23.015 9.325-23.15l5.25-0.04c0 0.645 0 15.9-10.815 26.82-6.935 6.995-16.645 10.54-28.85 10.54z"
+        android:fillColor="#414447"/>
+    <path android:pathData="M253.87 83h-5.245a40.45 40.45 0 0 1 5-18c4.605-8.21 14.4-18 34.96-18v5.215c-14.465 0-24.685 5.17-30.385 15.36A35.345 35.345 0 0 0 253.87 83z"
+        android:fillColor="#81C995"/>
+    <path android:pathData="M56 57.915H38.175v-0.27a8.91 8.91 0 0 1 17.82 0L56 57.915zm-17.275-0.54H55.45a8.37 8.37 0 0 0-16.73 0h0.005zM335 88.66h20v4h-20z"
+        android:fillColor="#414447"/>
+    <path android:pathData="M338.268 98.32l10-17.32 3.464 2-10 17.32z"
+        android:fillColor="#414447"/>
+    <path android:pathData="M348.268 100.32l-10-17.32 3.464-2 10 17.32z"
+        android:fillColor="#414447"/>
+    <path android:pathData="M254.61 94.5h-90.72V32.325a2.65 2.65 0 0 1 2.64-2.64h85.44a2.65 2.65 0 0 1 2.64 2.64V94.5z"
+        android:strokeWidth=".5"
+        android:fillColor="#262628"
+        android:strokeColor="#4E5154"/>
+    <path android:pathData="M250.29 30.225A3.785 3.785 0 0 1 254.07 34v59.945h-89.64V34a3.785 3.785 0 0 1 3.78-3.78h82.08m0-0.54h-82.08a4.335 4.335 0 0 0-4.32 4.32v60.5h90.72V34a4.335 4.335 0 0 0-4.32-4.32zm-99.36 68.585h116.64v0.54H150.93v-0.54z"
+        android:fillColor="#414447"/>
+    <path android:pathData="M118 18h56a6 6 0 0 1 6 6v80a6 6 0 0 1-6 6h-56a6 6 0 0 1-6-6V24a6 6 0 0 1 6-6z"
+        android:strokeWidth=".5"
+        android:fillColor="#262628"
+        android:strokeColor="#4E5154"/>
+    <path android:pathData="M224.75 56c1.242 0.002 2.249 1.075 2.25 2.4v19.2c-0.001 1.325-1.008 2.398-2.25 2.4h-76.5c-1.242-0.002-2.249-1.075-2.25-2.4V58.4c0.001-1.325 1.008-2.398 2.25-2.4h76.5z"
+        android:strokeWidth=".5"
+        android:fillColor="#262628"
+        android:strokeColor="#4E5154"/>
+    <path android:pathData="M216 62a1 1 0 0 1 1 1v10a1 1 0 0 1-1 1 1 1 0 0 1-1-1V63a1 1 0 0 1 1-1zm-45 5h10v2h-10z"
+        android:fillColor="#8AB4F8"/>
+    <path android:pathData="M172.634 71.83l5-8.66 1.732 1-5 8.66z"
+        android:fillColor="#8AB4F8"/>
+    <path android:pathData="M177.634 72.83l-5-8.66 1.732-1 5 8.66zM185 67h10v2h-10z"
+        android:fillColor="#8AB4F8"/>
+    <path android:pathData="M186.634 71.83l5-8.66 1.732 1-5 8.66z"
+        android:fillColor="#8AB4F8"/>
+    <path android:pathData="M191.634 72.83l-5-8.66 1.732-1 5 8.66zM199 67h10v2h-10z"
+        android:fillColor="#8AB4F8"/>
+    <path android:pathData="M200.634 71.83l5-8.66 1.732 1-5 8.66z"
+        android:fillColor="#8AB4F8"/>
+    <path android:pathData="M205.634 72.83l-5-8.66 1.732-1 5 8.66z"
+        android:fillColor="#8AB4F8"/>
+    <path android:pathData="M126 68a20 20 0 1 1 40 0 20 20 0 1 1-40 0"
+        android:fillColor="#81C995"/>
+    <path android:pathData="M143.214 74.75l-6.964-6.478 1.964-1.827 5 4.638 10.572-9.833 1.964 1.84z"
+        android:fillColor="#28282B"
+        android:fillType="evenOdd"/>
+    <path android:pathData="M146 10a7 7 0 0 1 7 7v7h-14v-7a7 7 0 0 1 7-7z"
+        android:strokeWidth=".5"
+        android:fillColor="#262628"
+        android:strokeColor="#4E5154"/>
+    <path android:pathData="M143 17a3 3 0 1 1 6 0 3 3 0 1 1-6 0m19 7h-32a6 6 0 0 0-6 6v4h44v-4a6 6 0 0 0-6-6z"
+        android:strokeWidth=".5"
+        android:fillColor="#262628"
+        android:strokeColor="#4E5154"/>
+    <path android:pathData="M79.6 58.42a12.935 12.935 0 0 0-10.1 4.82A8.62 8.62 0 0 0 58 71.38h34.56c0-7.158-5.802-12.96-12.96-12.96z"
+        android:fillColor="#28282B"/>
+    <path android:pathData="M92.83 71.65h-35.1v-0.27a8.89 8.89 0 0 1 11.695-8.455A13.23 13.23 0 0 1 92.83 71.38v0.27zm-34.555-0.54h34a12.69 12.69 0 0 0-22.56-7.7l-0.12 0.15-0.18-0.065A8.35 8.35 0 0 0 58.26 71.11h0.015z"
+        android:fillColor="#4E5154"/>
+    <path android:pathData="M38.12 82.36l3.705-3.705c7.59 7.59 15.69 11.43 24.075 11.41 13.17-0.03 22.855-9.655 22.95-9.75l3.735 3.675c-0.45 0.46-11.235 11.25-26.61 11.315C56.12 95.345 46.75 91 38.12 82.36z"
+        android:fillColor="#F7BB2A"/>
+    <path android:pathData="M-8.2 79.58l-3.705-3.705a40.45 40.45 0 0 1 16.25-9.18c9.075-2.57 22.945-2.58 37.5 11.96L38.14 82.36C27.89 72.13 17 68.555 5.77 71.735A35.345 35.345 0 0 0-8.2 79.58z"
+        android:fillColor="#414447"/>
+</vector>
diff --git a/chrome/browser/password_check/android/internal/java/res/drawable/ic_check_circle_filled_green_24dp.xml b/chrome/browser/password_check/android/internal/java/res/drawable/ic_check_circle_filled_green_24dp.xml
new file mode 100644
index 0000000..ff95b6d
--- /dev/null
+++ b/chrome/browser/password_check/android/internal/java/res/drawable/ic_check_circle_filled_green_24dp.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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. -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path
+        android:pathData="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-4-4 1.4-1.4 2.6 2.6 6.6-6.6L18 9l-8 8z"
+        android:fillColor="@color/default_green"/>
+</vector>
diff --git a/chrome/browser/password_check/android/internal/java/res/drawable/password_check_positive.xml b/chrome/browser/password_check/android/internal/java/res/drawable/password_check_positive.xml
new file mode 100644
index 0000000..eb49de5
--- /dev/null
+++ b/chrome/browser/password_check/android/internal/java/res/drawable/password_check_positive.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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. -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    tools:targetApi="21"
+    tools:ignore="VectorRaster"
+    android:width="360dp"
+    android:height="120dp"
+    android:viewportWidth="360"
+    android:viewportHeight="120">
+    <path android:pathData="M0 0h360v120H0z"
+        android:fillColor="#F8F9FA"
+        android:fillType="evenOdd"/>
+    <path android:pathData="M288.585 52.215V47c10.735 0 19.175-3 25.09-8.955 9.29-9.36 9.325-23.015 9.325-23.15l5.25-0.04c0 0.645 0 15.9-10.815 26.82-6.935 6.995-16.645 10.54-28.85 10.54z"
+        android:fillColor="#E8E9EB"/>
+    <path android:pathData="M253.87 83h-5.245a40.45 40.45 0 0 1 5-18c4.605-8.21 14.4-18 34.96-18v5.215c-14.465 0-24.685 5.17-30.385 15.36A35.345 35.345 0 0 0 253.87 83z"
+        android:fillColor="#34A751"/>
+    <path android:pathData="M56 57.915H38.175v-0.27a8.91 8.91 0 0 1 17.82 0L56 57.915zm-17.275-0.54H55.45a8.37 8.37 0 0 0-16.73 0h0.005z"
+        android:fillColor="#BDC0C5"/>
+    <path android:pathData="M335 88.66h20v4h-20z"
+        android:fillColor="#E8E9EB"/>
+    <path android:pathData="M338.268 98.32l10-17.32 3.464 2-10 17.32z"
+        android:fillColor="#E8E9EB"/>
+    <path android:pathData="M348.268 100.32l-10-17.32 3.464-2 10 17.32z"
+        android:fillColor="#E8E9EB"/>
+    <path android:pathData="M254.61 94.5h-90.72V32.325a2.65 2.65 0 0 1 2.64-2.64h85.44a2.65 2.65 0 0 1 2.64 2.64V94.5z"
+        android:fillColor="#F8F9FA"/>
+    <path android:pathData="M250.29 30.225A3.785 3.785 0 0 1 254.07 34v59.945h-89.64V34a3.785 3.785 0 0 1 3.78-3.78h82.08m0-0.54h-82.08a4.335 4.335 0 0 0-4.32 4.32v60.5h90.72V34a4.335 4.335 0 0 0-4.32-4.32zm-99.36 68.585h116.64v0.54H150.93v-0.54z"
+        android:fillColor="#BDC0C5"/>
+    <path android:pathData="M118 18h56a6 6 0 0 1 6 6v80a6 6 0 0 1-6 6h-56a6 6 0 0 1-6-6V24a6 6 0 0 1 6-6z"
+        android:strokeWidth=".5"
+        android:fillColor="#F8F9FA"
+        android:strokeColor="#BDC0C5"/>
+    <path android:pathData="M224.75 55.75h-76.5c-0.692 0-1.319 0.299-1.773 0.783a2.728 2.728 0 0 0-0.727 1.867v19.2c0 0.73 0.28 1.39 0.727 1.867 0.454 0.484 1.081 0.782 1.773 0.783h76.5c0.692 0 1.319-0.299 1.773-0.783a2.728 2.728 0 0 0 0.727-1.867V58.4c0-0.73-0.28-1.39-0.727-1.867a2.426 2.426 0 0 0-1.773-0.783z"
+        android:strokeWidth=".5"
+        android:fillColor="#F8F9FA"
+        android:strokeColor="#BDC0C5"/>
+    <path android:pathData="M216 62a1 1 0 0 1 1 1v10a1 1 0 0 1-1 1 1 1 0 0 1-1-1V63a1 1 0 0 1 1-1zm-45 5h10v2h-10z"
+        android:fillColor="#3A7BEE"/>
+    <path android:pathData="M172.634 71.83l5-8.66 1.732 1-5 8.66z"
+        android:fillColor="#3A7BEE"/>
+    <path android:pathData="M177.634 72.83l-5-8.66 1.732-1 5 8.66zM185 67h10v2h-10z"
+        android:fillColor="#3A7BEE"/>
+    <path android:pathData="M186.634 71.83l5-8.66 1.732 1-5 8.66z"
+        android:fillColor="#3A7BEE"/>
+    <path android:pathData="M191.634 72.83l-5-8.66 1.732-1 5 8.66zM199 67h10v2h-10z"
+        android:fillColor="#3A7BEE"/>
+    <path android:pathData="M200.634 71.83l5-8.66 1.732 1-5 8.66z"
+        android:fillColor="#3A7BEE"/>
+    <path android:pathData="M205.634 72.83l-5-8.66 1.732-1 5 8.66z"
+        android:fillColor="#3A7BEE"/>
+    <path android:pathData="M126 68a20 20 0 1 1 40 0 20 20 0 1 1-40 0"
+        android:fillColor="#34A751"
+        android:fillType="evenOdd"/>
+    <path android:pathData="M143.214 74.75l-6.964-6.478 1.964-1.827 5 4.638 10.572-9.833 1.964 1.84z"
+        android:fillColor="#FFF"
+        android:fillType="evenOdd"/>
+    <path android:pathData="M146 10a7 7 0 0 1 7 7v7h-14v-7a7 7 0 0 1 7-7z"
+        android:strokeWidth=".5"
+        android:fillColor="#F8F9FA"
+        android:strokeColor="#BDC0C5"/>
+    <path android:pathData="M143 17a3 3 0 1 1 6 0 3 3 0 1 1-6 0m19 7h-32a6 6 0 0 0-6 6v4h44v-4a6 6 0 0 0-6-6z"
+        android:strokeWidth=".5"
+        android:fillColor="#F8F9FA"
+        android:strokeColor="#BDC0C5"/>
+    <path android:pathData="M79.6 58.42a12.935 12.935 0 0 0-10.1 4.82A8.62 8.62 0 0 0 58 71.38h34.56c0-7.158-5.802-12.96-12.96-12.96z"
+        android:fillColor="#FFF"/>
+    <path android:pathData="M92.83 71.65h-35.1v-0.27a8.89 8.89 0 0 1 11.695-8.455A13.23 13.23 0 0 1 92.83 71.38v0.27zm-34.555-0.54h34a12.69 12.69 0 0 0-22.56-7.7l-0.12 0.15-0.18-0.065A8.35 8.35 0 0 0 58.26 71.11h0.015z"
+        android:fillColor="#BDC0C5"/>
+    <path android:pathData="M38.12 82.36l3.705-3.705c7.59 7.59 15.69 11.43 24.075 11.41 13.17-0.03 22.855-9.655 22.95-9.75l3.735 3.675c-0.45 0.46-11.235 11.25-26.61 11.315C56.12 95.345 46.75 91 38.12 82.36z"
+        android:fillColor="#F7BB2A"/>
+    <path android:pathData="M-8.2 79.58l-3.705-3.705a40.45 40.45 0 0 1 16.25-9.18c9.075-2.57 22.945-2.58 37.5 11.96L38.14 82.36C27.89 72.13 17 68.555 5.77 71.735A35.345 35.345 0 0 0-8.2 79.58z"
+        android:fillColor="#E8E9EB"/>
+</vector>
diff --git a/chrome/browser/password_check/android/internal/java/res/layout/password_check_compromised_credential_item.xml b/chrome/browser/password_check/android/internal/java/res/layout/password_check_compromised_credential_item.xml
index 83456ca..df04cc49 100644
--- a/chrome/browser/password_check/android/internal/java/res/layout/password_check_compromised_credential_item.xml
+++ b/chrome/browser/password_check/android/internal/java/res/layout/password_check_compromised_credential_item.xml
@@ -25,6 +25,7 @@
             android:id="@+id/credential_origin"
             android:layout_height="wrap_content"
             android:layout_width="match_parent"
+            android:layoutDirection="ltr"
             android:textAppearance="@style/TextAppearance.TextLarge.Primary" />
 
         <TextView
diff --git a/chrome/browser/password_check/android/internal/java/res/layout/password_check_header_item.xml b/chrome/browser/password_check/android/internal/java/res/layout/password_check_header_item.xml
index 71e67816..f0a9f6d 100644
--- a/chrome/browser/password_check/android/internal/java/res/layout/password_check_header_item.xml
+++ b/chrome/browser/password_check/android/internal/java/res/layout/password_check_header_item.xml
@@ -6,18 +6,91 @@
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_height="wrap_content"
     android:layout_width="match_parent"
-    android:gravity="end"
-    android:orientation="horizontal">
+    android:orientation="vertical">
 
-  <ImageButton
-    android:id="@+id/check_status_restart_button"
-    android:background="?android:attr/selectableItemBackground"
-    android:contentDescription="@string/accessibility_password_check_restart_button"
-    android:layout_gravity="center_vertical"
-    android:layout_marginEnd="@dimen/check_status_restart_button_margin_end"
-    android:layout_height="@dimen/check_status_restart_button_clickable_surface_size"
-    android:layout_width="@dimen/check_status_restart_button_clickable_surface_size"
-    android:src="@drawable/ic_refresh_white_24dp"
-    app:tint="@color/default_icon_color"/>
+  <LinearLayout
+      android:layout_height="wrap_content"
+      android:layout_width="match_parent"
+      android:background="@color/password_check_neutral_background"
+      android:orientation="horizontal">
+
+    <ImageView android:id="@+id/check_status_illustration"
+      android:importantForAccessibility="no"
+      android:layout_width="@dimen/check_status_illustration_width"
+      android:layout_height="@dimen/check_status_illustration_height"
+      android:layout_gravity="start"
+      android:visibility="visible"/>
+
+  </LinearLayout>
+
+  <LinearLayout
+      android:layout_height="wrap_content"
+      android:layout_width="match_parent"
+      android:orientation="horizontal">
+
+    <ProgressBar
+        android:id="@+id/check_status_progress"
+        android:indeterminate="true"
+        android:layout_width="@dimen/check_status_icon_size"
+        android:layout_height="@dimen/check_status_icon_size"
+        android:layout_marginEnd="@dimen/check_status_icon_margin_horizontal"
+        android:layout_marginStart="@dimen/check_status_icon_margin_horizontal"
+        android:layout_gravity="center_vertical"
+        android:visibility="gone" />
+
+    <ImageView
+        android:importantForAccessibility="no"
+        android:id="@+id/check_status_icon"
+        android:layout_width="@dimen/check_status_icon_size"
+        android:layout_height="match_parent"
+        android:layout_marginEnd="@dimen/check_status_icon_margin_horizontal"
+        android:layout_marginStart="@dimen/check_status_icon_margin_horizontal"
+        android:visibility="gone" />
+
+    <LinearLayout
+        android:id="@+id/check_status_text_layout"
+        android:layout_height="wrap_content"
+        android:layout_width="0dp"
+        android:layout_weight="1"
+        android:orientation="vertical">
+
+      <TextView
+          android:id="@+id/check_status_message"
+          android:layout_height="wrap_content"
+          android:layout_width="wrap_content"
+          android:textAppearance="@style/TextAppearance.TextLarge.Primary" />
+
+      <TextView
+          android:id="@+id/check_status_description"
+          android:layout_marginTop="@dimen/check_status_description_margin_top"
+          android:layout_height="wrap_content"
+          android:layout_width="wrap_content"
+          android:textAppearance="@style/TextAppearance.TextSmall.Secondary"
+          android:visibility="gone" />
+
+    </LinearLayout>
+
+    <ImageButton
+        android:id="@+id/check_status_restart_button"
+        android:background="?android:attr/selectableItemBackground"
+        android:contentDescription="@string/accessibility_password_check_restart_button"
+        android:layout_gravity="center_vertical|end"
+        android:layout_marginEnd="@dimen/check_status_restart_button_margin_end"
+        android:layout_height="@dimen/check_status_restart_button_clickable_surface_size"
+        android:layout_width="@dimen/check_status_restart_button_clickable_surface_size"
+        android:src="@drawable/ic_refresh_white_24dp"
+        app:tint="@color/default_icon_color"/>
+
+  </LinearLayout>
+
+  <View style="@style/HorizontalDivider"/>
+
+  <TextView
+      android:id="@+id/check_status_subtitle"
+      android:layout_margin="@dimen/check_status_subtitle_margin"
+      android:layout_height="wrap_content"
+      android:layout_width="wrap_content"
+      android:textAppearance="@style/TextAppearance.TextSmall.Secondary"
+      android:visibility="gone" />
 
 </LinearLayout>
\ No newline at end of file
diff --git a/chrome/browser/password_check/android/internal/java/res/values/dimens.xml b/chrome/browser/password_check/android/internal/java/res/values/dimens.xml
index c85ccf9..f254933d 100644
--- a/chrome/browser/password_check/android/internal/java/res/values/dimens.xml
+++ b/chrome/browser/password_check/android/internal/java/res/values/dimens.xml
@@ -4,8 +4,19 @@
      found in the LICENSE file. -->
 
 <resources>
+  <dimen name="check_status_description_margin_top">2dp</dimen>
+  <dimen name="check_status_icon_margin_horizontal">16dp</dimen>
+  <dimen name="check_status_icon_size">24dp</dimen>
+  <dimen name="check_status_illustration_height">120dp</dimen>
+  <dimen name="check_status_illustration_width">360dp</dimen>
   <dimen name="check_status_restart_button_clickable_surface_size">48dp</dimen>
   <dimen name="check_status_restart_button_margin_end">4dp</dimen>
+  <dimen name="check_status_subtitle_margin">16dp</dimen>
+
+  <!-- Margin for the header message, it depends on the status -->
+  <dimen name="check_status_message_error_margin_vertical">24dp</dimen>
+  <dimen name="check_status_message_idle_margin_vertical">27dp</dimen>
+  <dimen name="check_status_message_running_margin_vertical">36dp</dimen>
 
   <dimen name="compromised_credential_row_button_margin_top">16dp</dimen>
   <dimen name="compromised_credential_row_more_padding_end">8dp</dimen>
diff --git a/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckDeletionDialogFragment.java b/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckDeletionDialogFragment.java
new file mode 100644
index 0000000..7ba63c96
--- /dev/null
+++ b/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckDeletionDialogFragment.java
@@ -0,0 +1,69 @@
+// 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.
+
+package org.chromium.chrome.browser.password_check;
+
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.DialogFragment;
+
+import org.chromium.chrome.browser.password_check.internal.R;
+
+/**
+ * Shows the dialog that confirms the user really wants to delete a credential.
+ */
+public class PasswordCheckDeletionDialogFragment extends DialogFragment {
+    /**
+     * This interface combines handling the clicks on the buttons and the general dismissal of the
+     * dialog.
+     */
+    interface Handler extends DialogInterface.OnClickListener {
+        /** Handle the dismissal of the dialog.*/
+        void onDismiss();
+    }
+
+    // This handler is used to answer the user actions on the dialog.
+    private final Handler mHandler;
+    private final String mOrigin;
+
+    PasswordCheckDeletionDialogFragment(Handler handler, String origin) {
+        mHandler = handler;
+        mOrigin = origin;
+    }
+
+    /**
+     * Opens the dialog with the confirmation and sets the button listener to a fragment identified
+     * by ID passed in arguments.
+     */
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        return new AlertDialog
+                .Builder(getActivity(), R.style.Theme_Chromium_AlertDialog_NoActionBar)
+                .setTitle(R.string.password_check_delete_credential_dialog_title)
+                .setPositiveButton(
+                        R.string.password_check_delete_credential_dialog_confirm, mHandler)
+                .setNegativeButton(R.string.password_check_credential_dialog_cancel, mHandler)
+                .setMessage(
+                        getString(R.string.password_check_delete_credential_dialog_body, mOrigin))
+                .create();
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        if (savedInstanceState != null) {
+            dismiss();
+            return;
+        }
+    }
+
+    @Override
+    public void onDismiss(DialogInterface dialog) {
+        super.onDismiss(dialog);
+        if (mHandler != null) mHandler.onDismiss();
+    }
+}
diff --git a/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckMediator.java b/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckMediator.java
index 01d5e89..975ab44 100644
--- a/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckMediator.java
+++ b/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckMediator.java
@@ -6,9 +6,20 @@
 
 import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.CompromisedCredentialProperties.COMPROMISED_CREDENTIAL;
 import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.CompromisedCredentialProperties.CREDENTIAL_HANDLER;
+import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.DELETION_CONFIRMATION_HANDLER;
+import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.DELETION_ORIGIN;
+import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.CHECK_PROGRESS;
 import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.CHECK_STATUS;
+import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.CHECK_TIMESTAMP;
+import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.COMPROMISED_CREDENTIALS_COUNT;
+import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.UNKNOWN_PROGRESS;
 import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.ITEMS;
 
+import android.content.DialogInterface;
+import android.util.Pair;
+
+import androidx.appcompat.app.AlertDialog;
+
 import org.chromium.base.Consumer;
 import org.chromium.ui.modelutil.ListModel;
 import org.chromium.ui.modelutil.MVCListAdapter.ListItem;
@@ -34,6 +45,16 @@
     void initialize(PropertyModel model, PasswordCheckComponentUi.Delegate delegate) {
         mModel = model;
         mDelegate = delegate;
+        ListModel<ListItem> items = mModel.get(ITEMS);
+        assert items.size() == 0;
+
+        items.add(new ListItem(PasswordCheckProperties.ItemType.HEADER,
+                new PropertyModel.Builder(PasswordCheckProperties.HeaderProperties.ALL_KEYS)
+                        .with(CHECK_PROGRESS, UNKNOWN_PROGRESS)
+                        .with(CHECK_STATUS, PasswordCheckUIStatus.RUNNING)
+                        .with(CHECK_TIMESTAMP, null)
+                        .with(COMPROMISED_CREDENTIALS_COUNT, null)
+                        .build()));
         getPasswordCheck().addObserver(this, true);
     }
 
@@ -46,7 +67,12 @@
         CompromisedCredential[] credentials = getPasswordCheck().getCompromisedCredentials();
         assert credentials != null;
         ListModel<ListItem> items = mModel.get(ITEMS);
-        assert items.size() >= 1 : "Needs to initialize list with header before adding items!";
+        if (items.size() == 0) {
+            items.add(new ListItem(PasswordCheckProperties.ItemType.HEADER,
+                    new PropertyModel.Builder(PasswordCheckProperties.HeaderProperties.ALL_KEYS)
+                            .with(CHECK_STATUS, PasswordCheckUIStatus.RUNNING)
+                            .build()));
+        }
 
         for (CompromisedCredential credential : credentials) {
             items.add(new ListItem(credential.hasScript()
@@ -67,14 +93,34 @@
     @Override
     public void onPasswordCheckStatusChanged(@PasswordCheckUIStatus int status) {
         ListModel<ListItem> items = mModel.get(ITEMS);
-        if (items.size() == 0) {
-            items.add(new ListItem(PasswordCheckProperties.ItemType.HEADER,
-                    new PropertyModel.Builder(PasswordCheckProperties.HeaderProperties.ALL_KEYS)
-                            .with(CHECK_STATUS, status)
-                            .build()));
-        } else {
-            items.get(0).model.set(CHECK_STATUS, status);
+        assert items.size() >= 1;
+
+        PropertyModel header = items.get(0).model;
+        header.set(CHECK_STATUS, status);
+        header.set(
+                CHECK_PROGRESS, status == PasswordCheckUIStatus.RUNNING ? UNKNOWN_PROGRESS : null);
+        Long checkTimestamp = null;
+        Integer compromisedCredentialCount = null;
+        if (status == PasswordCheckUIStatus.IDLE) {
+            compromisedCredentialCount = getPasswordCheck().getCompromisedCredentialsCount();
+            // TODO(crbug.com/1109691): Retrieve the timestamp of the last check from the bridge.
+            checkTimestamp = 0L;
         }
+        header.set(CHECK_TIMESTAMP, checkTimestamp);
+        header.set(COMPROMISED_CREDENTIALS_COUNT, compromisedCredentialCount);
+    }
+
+    void onPasswordCheckProgressChanged(Pair<Integer, Integer> progress) {
+        ListModel<ListItem> items = mModel.get(ITEMS);
+        assert items.size() >= 1;
+        assert progress.first >= 0;
+        assert progress.second >= progress.first;
+
+        PropertyModel header = items.get(0).model;
+        header.set(CHECK_STATUS, PasswordCheckUIStatus.RUNNING);
+        header.set(CHECK_PROGRESS, progress);
+        header.set(CHECK_TIMESTAMP, null);
+        header.set(COMPROMISED_CREDENTIALS_COUNT, null);
     }
 
     @Override
@@ -100,7 +146,22 @@
 
     @Override
     public void onRemove(CompromisedCredential credential) {
-        mDelegate.removeCredential(credential);
+        mModel.set(DELETION_ORIGIN, credential.getOriginUrl());
+        mModel.set(
+                DELETION_CONFIRMATION_HANDLER, new PasswordCheckDeletionDialogFragment.Handler() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        if (which != AlertDialog.BUTTON_POSITIVE) return;
+                        mDelegate.removeCredential(credential);
+                        mModel.set(DELETION_CONFIRMATION_HANDLER, null);
+                        mModel.set(DELETION_ORIGIN, null);
+                    }
+
+                    @Override
+                    public void onDismiss() {
+                        mModel.set(DELETION_CONFIRMATION_HANDLER, null);
+                    }
+                });
     }
 
     @Override
diff --git a/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckProperties.java b/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckProperties.java
index 9881cc623..0d73caf 100644
--- a/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckProperties.java
+++ b/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckProperties.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.password_check;
 
+import android.util.Pair;
+
 import androidx.annotation.IntDef;
 
 import org.chromium.ui.modelutil.ListModel;
@@ -20,8 +22,13 @@
 class PasswordCheckProperties {
     static final PropertyModel.ReadableObjectPropertyKey<ListModel<MVCListAdapter.ListItem>> ITEMS =
             new PropertyModel.ReadableObjectPropertyKey<>("items");
+    static final PropertyModel.WritableObjectPropertyKey<
+            PasswordCheckDeletionDialogFragment.Handler> DELETION_CONFIRMATION_HANDLER =
+            new PropertyModel.WritableObjectPropertyKey<>("deletion_confirmation_handler");
+    static final PropertyModel.WritableObjectPropertyKey<String> DELETION_ORIGIN =
+            new PropertyModel.WritableObjectPropertyKey<>("deletion_origin");
 
-    static final PropertyKey[] ALL_KEYS = {ITEMS};
+    static final PropertyKey[] ALL_KEYS = {ITEMS, DELETION_CONFIRMATION_HANDLER, DELETION_ORIGIN};
 
     static PropertyModel createDefaultModel() {
         return new PropertyModel.Builder(ALL_KEYS).with(ITEMS, new ListModel<>()).build();
@@ -47,10 +54,21 @@
      * Properties defining the header (banner logo and status line).
      */
     static class HeaderProperties {
+        static final PropertyModel
+                .WritableObjectPropertyKey<Pair<Integer, Integer>> CHECK_PROGRESS =
+                new PropertyModel.WritableObjectPropertyKey<>("check_progress");
         static final PropertyModel.WritableIntPropertyKey CHECK_STATUS =
                 new PropertyModel.WritableIntPropertyKey("check_status");
+        static final PropertyModel.WritableObjectPropertyKey<Long> CHECK_TIMESTAMP =
+                new PropertyModel.WritableObjectPropertyKey<>("check_timestamp");
+        static final PropertyModel
+                .WritableObjectPropertyKey<Integer> COMPROMISED_CREDENTIALS_COUNT =
+                new PropertyModel.WritableObjectPropertyKey<>("compromised_credentials_count");
 
-        static final PropertyKey[] ALL_KEYS = {CHECK_STATUS};
+        static final PropertyKey[] ALL_KEYS = {
+                CHECK_PROGRESS, CHECK_STATUS, CHECK_TIMESTAMP, COMPROMISED_CREDENTIALS_COUNT};
+
+        static final Pair<Integer, Integer> UNKNOWN_PROGRESS = new Pair<>(-1, -1);
 
         private HeaderProperties() {}
     }
diff --git a/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckViewBinder.java b/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckViewBinder.java
index 93d40fb..08b8983c 100644
--- a/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckViewBinder.java
+++ b/chrome/browser/password_check/android/internal/java/src/org/chromium/chrome/browser/password_check/PasswordCheckViewBinder.java
@@ -6,16 +6,28 @@
 
 import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.CompromisedCredentialProperties.COMPROMISED_CREDENTIAL;
 import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.CompromisedCredentialProperties.CREDENTIAL_HANDLER;
+import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.DELETION_CONFIRMATION_HANDLER;
+import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.DELETION_ORIGIN;
+import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.CHECK_PROGRESS;
 import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.CHECK_STATUS;
+import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.CHECK_TIMESTAMP;
+import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.COMPROMISED_CREDENTIALS_COUNT;
+import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.UNKNOWN_PROGRESS;
 import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.ITEMS;
 import static org.chromium.components.embedder_support.util.UrlUtilities.stripScheme;
 
 import android.content.Context;
+import android.content.res.Resources;
+import android.util.Pair;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import androidx.annotation.VisibleForTesting;
+
 import org.chromium.chrome.browser.password_check.PasswordCheckProperties.ItemType;
 import org.chromium.chrome.browser.password_check.internal.R;
 import org.chromium.components.browser_ui.widget.listmenu.BasicListMenu;
@@ -50,6 +62,11 @@
                             PasswordCheckProperties::getItemType,
                             PasswordCheckViewBinder::connectPropertyModel),
                     PasswordCheckViewBinder::createViewHolder));
+        } else if (propertyKey == DELETION_CONFIRMATION_HANDLER) {
+            view.showDialogFragment(new PasswordCheckDeletionDialogFragment(
+                    model.get(DELETION_CONFIRMATION_HANDLER), model.get(DELETION_ORIGIN)));
+        } else if (propertyKey == DELETION_ORIGIN) {
+            // Binding not necessary (only used indirectly).
         } else {
             assert false : "Unhandled update to property:" + propertyKey;
         }
@@ -152,22 +169,27 @@
      * @param key   The {@link PropertyKey} which changed.
      */
     private static void bindHeaderView(PropertyModel model, View view, PropertyKey key) {
-        if (key == CHECK_STATUS) {
-            // TODO(crbug.com/1101256): Set text and illustration based on status.
-            @PasswordCheckUIStatus
-            int status = model.get(CHECK_STATUS);
-            ImageButton restartButton = view.findViewById(R.id.check_status_restart_button);
-            if (status != PasswordCheckUIStatus.RUNNING) {
-                restartButton.setVisibility(View.VISIBLE);
-                restartButton.setClickable(true);
-                restartButton.setOnClickListener(unusedView
-                        -> {
-                                // TODO(crbug.com/1092444): Add call to restart the check.
-                        });
-            } else {
-                restartButton.setVisibility(View.GONE);
-                restartButton.setClickable(false);
-            }
+        Pair<Integer, Integer> progress = model.get(CHECK_PROGRESS);
+        @PasswordCheckUIStatus
+        int status = model.get(CHECK_STATUS);
+        Long checkTimestamp = model.get(CHECK_TIMESTAMP);
+        Integer compromisedCredentialsCount = model.get(COMPROMISED_CREDENTIALS_COUNT);
+
+        if (key == CHECK_PROGRESS) {
+            updateStatusText(view, status, compromisedCredentialsCount, checkTimestamp, progress);
+        } else if (key == CHECK_STATUS) {
+            updateActionButton(view, status);
+            updateStatusIcon(view, status, compromisedCredentialsCount);
+            updateStatusIllustration(view, status, compromisedCredentialsCount);
+            updateStatusText(view, status, compromisedCredentialsCount, checkTimestamp, progress);
+            updateStatusSubtitle(view, status, compromisedCredentialsCount);
+        } else if (key == CHECK_TIMESTAMP) {
+            updateStatusText(view, status, compromisedCredentialsCount, checkTimestamp, progress);
+        } else if (key == COMPROMISED_CREDENTIALS_COUNT) {
+            updateStatusIcon(view, status, compromisedCredentialsCount);
+            updateStatusIllustration(view, status, compromisedCredentialsCount);
+            updateStatusText(view, status, compromisedCredentialsCount, checkTimestamp, progress);
+            updateStatusSubtitle(view, status, compromisedCredentialsCount);
         } else {
             assert false : "Unhandled update to property:" + key;
         }
@@ -175,6 +197,244 @@
 
     private PasswordCheckViewBinder() {}
 
+    private static void updateActionButton(View view, @PasswordCheckUIStatus int status) {
+        ImageButton restartButton = view.findViewById(R.id.check_status_restart_button);
+        if (status != PasswordCheckUIStatus.RUNNING) {
+            restartButton.setVisibility(View.VISIBLE);
+            restartButton.setClickable(true);
+            restartButton.setOnClickListener(unusedView
+                    -> {
+                            // TODO(crbug.com/1109691): Add call to restart the check.
+                    });
+        } else {
+            restartButton.setVisibility(View.GONE);
+            restartButton.setClickable(false);
+        }
+    }
+
+    private static void updateStatusIcon(
+            View view, @PasswordCheckUIStatus int status, Integer compromisedCredentialsCount) {
+        // TODO(crbug.com/1114051): Set default values for header properties.
+        if (status == PasswordCheckUIStatus.IDLE && compromisedCredentialsCount == null) return;
+        ImageView statusIcon = view.findViewById(R.id.check_status_icon);
+        statusIcon.setImageResource(getIconResource(status, compromisedCredentialsCount));
+        statusIcon.setVisibility(getIconVisibility(status));
+        view.findViewById(R.id.check_status_progress)
+                .setVisibility(getProgressBarVisibility(status));
+    }
+
+    private static int getIconResource(
+            @PasswordCheckUIStatus int status, Integer compromisedCredentialsCount) {
+        switch (status) {
+            case PasswordCheckUIStatus.IDLE:
+                assert compromisedCredentialsCount != null;
+                return compromisedCredentialsCount == 0
+                        ? R.drawable.ic_check_circle_filled_green_24dp
+                        : org.chromium.chrome.R.drawable.ic_warning_red_24dp;
+            case PasswordCheckUIStatus.RUNNING:
+                return 0;
+            case PasswordCheckUIStatus.ERROR_OFFLINE:
+            case PasswordCheckUIStatus.ERROR_NO_PASSWORDS:
+            case PasswordCheckUIStatus.ERROR_SIGNED_OUT:
+            case PasswordCheckUIStatus.ERROR_QUOTA_LIMIT:
+            case PasswordCheckUIStatus.ERROR_QUOTA_LIMIT_ACCOUNT_CHECK:
+            case PasswordCheckUIStatus.ERROR_UNKNOWN:
+                return org.chromium.chrome.R.drawable.ic_error_grey800_24dp_filled;
+            default:
+                assert false : "Unhandled check status " + status + "on icon update";
+        }
+        return 0;
+    }
+
+    private static int getIconVisibility(@PasswordCheckUIStatus int status) {
+        return status == PasswordCheckUIStatus.RUNNING ? View.GONE : View.VISIBLE;
+    }
+
+    private static int getProgressBarVisibility(@PasswordCheckUIStatus int status) {
+        return status == PasswordCheckUIStatus.RUNNING ? View.VISIBLE : View.GONE;
+    }
+
+    private static void updateStatusText(View view, @PasswordCheckUIStatus int status,
+            Integer compromisedCredentialsCount, Long checkTimestamp,
+            Pair<Integer, Integer> progress) {
+        // TODO(crbug.com/1114051): Set default values for header properties.
+        if (status == PasswordCheckUIStatus.IDLE
+                && (compromisedCredentialsCount == null || checkTimestamp == null)) {
+            return;
+        }
+        if (status == PasswordCheckUIStatus.RUNNING && progress == null) return;
+
+        TextView statusMessage = view.findViewById(R.id.check_status_message);
+        statusMessage.setText(
+                getStatusMessage(view, status, compromisedCredentialsCount, progress));
+
+        LinearLayout textLayout = view.findViewById(R.id.check_status_text_layout);
+        int verticalMargin = getDimensionPixelOffset(view, getStatusTextMargin(status));
+        textLayout.setPadding(0, verticalMargin, 0, verticalMargin);
+
+        TextView statusDescription = view.findViewById(R.id.check_status_description);
+        statusDescription.setText(getStatusDescription(view, checkTimestamp));
+        statusDescription.setVisibility(getStatusDescriptionVisibility(status));
+    }
+
+    private static String getStatusMessage(View view, @PasswordCheckUIStatus int status,
+            Integer compromisedCredentialsCount, Pair<Integer, Integer> progress) {
+        switch (status) {
+            case PasswordCheckUIStatus.IDLE:
+                assert compromisedCredentialsCount != null;
+                return compromisedCredentialsCount == 0
+                        ? getString(view, R.string.password_check_status_message_idle_no_leaks)
+                        : view.getContext().getResources().getQuantityString(
+                                R.plurals.password_check_status_message_idle_with_leaks,
+                                compromisedCredentialsCount, compromisedCredentialsCount);
+            case PasswordCheckUIStatus.RUNNING:
+                assert progress != null;
+                if (progress.equals(UNKNOWN_PROGRESS)) {
+                    return getString(view, R.string.password_check_status_message_initial_running);
+                } else {
+                    return String.format(
+                            getString(view, R.string.password_check_status_message_running),
+                            progress.first, progress.second);
+                }
+            case PasswordCheckUIStatus.ERROR_OFFLINE:
+                return getString(view, R.string.password_check_status_message_error_offline);
+            case PasswordCheckUIStatus.ERROR_NO_PASSWORDS:
+                return getString(view, R.string.password_check_status_message_error_no_passwords);
+            case PasswordCheckUIStatus.ERROR_SIGNED_OUT:
+                return getString(view, R.string.password_check_status_message_error_signed_out);
+            case PasswordCheckUIStatus.ERROR_QUOTA_LIMIT:
+                return getString(view, R.string.password_check_status_message_error_quota_limit);
+            case PasswordCheckUIStatus.ERROR_QUOTA_LIMIT_ACCOUNT_CHECK:
+                return getString(view,
+                        R.string.password_check_status_message_error_quota_limit_account_check);
+            case PasswordCheckUIStatus.ERROR_UNKNOWN:
+                return getString(view, R.string.password_check_status_message_error_unknown);
+            default:
+                assert false : "Unhandled check status " + status + "on message update";
+        }
+        return null;
+    }
+
+    private static int getStatusTextMargin(@PasswordCheckUIStatus int status) {
+        switch (status) {
+            case PasswordCheckUIStatus.IDLE:
+                return R.dimen.check_status_message_idle_margin_vertical;
+            case PasswordCheckUIStatus.RUNNING:
+                return R.dimen.check_status_message_running_margin_vertical;
+            case PasswordCheckUIStatus.ERROR_OFFLINE:
+            case PasswordCheckUIStatus.ERROR_NO_PASSWORDS:
+            case PasswordCheckUIStatus.ERROR_SIGNED_OUT:
+            case PasswordCheckUIStatus.ERROR_QUOTA_LIMIT:
+            case PasswordCheckUIStatus.ERROR_QUOTA_LIMIT_ACCOUNT_CHECK:
+            case PasswordCheckUIStatus.ERROR_UNKNOWN:
+                return R.dimen.check_status_message_error_margin_vertical;
+            default:
+                assert false : "Unhandled check status " + status + "on text margin update";
+        }
+        return 0;
+    }
+
+    private static String getStatusDescription(View view, Long checkTimestamp) {
+        if (checkTimestamp == null) return null;
+        Resources res = view.getContext().getResources();
+        return res.getString(R.string.password_check_status_description_idle,
+                getTimestamp(res, System.currentTimeMillis() - checkTimestamp));
+    }
+
+    @VisibleForTesting
+    protected static String getTimestamp(Resources res, long timeDeltaMs) {
+        if (timeDeltaMs < 0) timeDeltaMs = 0;
+
+        int daysElapsed = (int) (timeDeltaMs / (24L * 60L * 60L * 1000L));
+        int hoursElapsed = (int) (timeDeltaMs / (60L * 60L * 1000L));
+        int minutesElapsed = (int) (timeDeltaMs / (60L * 1000L));
+
+        String relativeTime;
+        if (daysElapsed > 0L) {
+            relativeTime = res.getQuantityString(
+                    org.chromium.chrome.R.plurals.n_days_ago, daysElapsed, daysElapsed);
+        } else if (hoursElapsed > 0L) {
+            relativeTime = res.getQuantityString(
+                    org.chromium.chrome.R.plurals.n_hours_ago, hoursElapsed, hoursElapsed);
+        } else if (minutesElapsed > 0L) {
+            relativeTime = res.getQuantityString(
+                    org.chromium.chrome.R.plurals.n_minutes_ago, minutesElapsed, minutesElapsed);
+        } else {
+            relativeTime = res.getString(R.string.password_check_just_now);
+        }
+        return relativeTime;
+    }
+
+    private static int getStatusDescriptionVisibility(@PasswordCheckUIStatus int status) {
+        return status == PasswordCheckUIStatus.IDLE ? View.VISIBLE : View.GONE;
+    }
+
+    private static void updateStatusIllustration(
+            View view, @PasswordCheckUIStatus int status, Integer compromisedCredentialsCount) {
+        // TODO(crbug.com/1114051): Set default values for header properties.
+        if (status == PasswordCheckUIStatus.IDLE && compromisedCredentialsCount == null) return;
+        ImageView statusIllustration = view.findViewById(R.id.check_status_illustration);
+        statusIllustration.setImageResource(
+                getIllustrationResource(status, compromisedCredentialsCount));
+    }
+
+    private static int getIllustrationResource(
+            @PasswordCheckUIStatus int status, Integer compromisedCredentialsCount) {
+        switch (status) {
+            case PasswordCheckUIStatus.IDLE:
+                assert compromisedCredentialsCount != null;
+                return compromisedCredentialsCount == 0 ? R.drawable.password_check_positive
+                                                        : R.drawable.password_checkup_warning;
+            case PasswordCheckUIStatus.RUNNING:
+            case PasswordCheckUIStatus.ERROR_OFFLINE:
+            case PasswordCheckUIStatus.ERROR_NO_PASSWORDS:
+            case PasswordCheckUIStatus.ERROR_SIGNED_OUT:
+            case PasswordCheckUIStatus.ERROR_QUOTA_LIMIT:
+            case PasswordCheckUIStatus.ERROR_QUOTA_LIMIT_ACCOUNT_CHECK:
+            case PasswordCheckUIStatus.ERROR_UNKNOWN:
+                return R.drawable.password_check_neutral;
+            default:
+                assert false : "Unhandled check status " + status + "on illustration update";
+        }
+        return 0;
+    }
+
+    private static void updateStatusSubtitle(
+            View view, @PasswordCheckUIStatus int status, Integer compromisedCredentialsCount) {
+        // TODO(crbug.com/1114051): Set default values for header properties.
+        if (status == PasswordCheckUIStatus.IDLE && compromisedCredentialsCount == null) return;
+        TextView statusSubtitle = view.findViewById(R.id.check_status_subtitle);
+        statusSubtitle.setText(getSubtitleText(view, status, compromisedCredentialsCount));
+        statusSubtitle.setVisibility(getSubtitleVisibility(status));
+    }
+
+    private static String getSubtitleText(
+            View view, @PasswordCheckUIStatus int status, Integer compromisedCredentialsCount) {
+        switch (status) {
+            case PasswordCheckUIStatus.IDLE:
+                assert compromisedCredentialsCount != null;
+                return compromisedCredentialsCount == 0
+                        ? getString(view, R.string.password_check_status_subtitle_no_findings)
+                        : getString(view,
+                                R.string.password_check_status_subtitle_found_compromised_credentials);
+            case PasswordCheckUIStatus.RUNNING:
+            case PasswordCheckUIStatus.ERROR_OFFLINE:
+            case PasswordCheckUIStatus.ERROR_NO_PASSWORDS:
+            case PasswordCheckUIStatus.ERROR_SIGNED_OUT:
+            case PasswordCheckUIStatus.ERROR_QUOTA_LIMIT:
+            case PasswordCheckUIStatus.ERROR_QUOTA_LIMIT_ACCOUNT_CHECK:
+            case PasswordCheckUIStatus.ERROR_UNKNOWN:
+                return null;
+            default:
+                assert false : "Unhandled check status " + status + "on icon update";
+        }
+        return null;
+    }
+
+    private static int getSubtitleVisibility(@PasswordCheckUIStatus int status) {
+        return status == PasswordCheckUIStatus.IDLE ? View.VISIBLE : View.GONE;
+    }
+
     private static ListMenu createCredentialMenu(Context context, CompromisedCredential credential,
             PasswordCheckCoordinator.CredentialEventHandler credentialHandler) {
         MVCListAdapter.ModelList menuItems = new MVCListAdapter.ModelList();
@@ -190,4 +450,12 @@
         };
         return new BasicListMenu(context, menuItems, delegate);
     }
+
+    private static String getString(View view, int resourceId) {
+        return view.getContext().getResources().getString(resourceId);
+    }
+
+    private static int getDimensionPixelOffset(View view, int resourceId) {
+        return view.getContext().getResources().getDimensionPixelOffset(resourceId);
+    }
 }
diff --git a/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings.grd b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings.grd
index 2e1364f4..691e944 100644
--- a/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings.grd
+++ b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings.grd
@@ -187,10 +187,69 @@
       <message name="IDS_PASSWORD_CHECK_CREDENTIAL_ROW_SCRIPT_BUTTON_EXPLANATION" desc="Small description explaining that an automated password change can be done with a script.">
         Let Google Assistant help you change your password
       </message>
+      <message name="IDS_PASSWORD_CHECK_STATUS_DESCRIPTION_IDLE" desc="Small description explaining that the password check has been completed and showing how long ago the last check has been successfully completed.">
+        Checked passwords · <ph name="TIME_SINCE_LAST_CHECK">%1$s<ex>Just now</ex></ph>
+      </message>
+      <message name="IDS_PASSWORD_CHECK_STATUS_MESSAGE_ERROR_NO_PASSWORDS" desc="Error message explaining that the password check failed because the user has no passwords on this device.">
+        No saved passwords. Chrome can check your passwords when you save them.
+      </message>
+      <message name="IDS_PASSWORD_CHECK_STATUS_MESSAGE_ERROR_OFFLINE" desc="Error message explaining that the password check failed because the user is offline.">
+        Chrome can't check your passwords. Try checking your internet connection.
+      </message>
+      <message name="IDS_PASSWORD_CHECK_STATUS_MESSAGE_ERROR_QUOTA_LIMIT" desc="Error message explaining that the password check failed because the user has exceeded their quota.">
+        Chrome couldn't check all passwords. Try again tomorrow.
+      </message>
+      <message name="IDS_PASSWORD_CHECK_STATUS_MESSAGE_ERROR_QUOTA_LIMIT_ACCOUNT_CHECK" desc="Error message explaining that the password check failed because the user has exceeded their quota and redirecting to check in the Google Account.">
+        Chrome couldn't check all passwords. Try again tomorrow or check passwords in your Google Account.
+      </message>
+      <message name="IDS_PASSWORD_CHECK_STATUS_MESSAGE_ERROR_SIGNED_OUT" desc="Error message explaining that the password check failed because the user is signed-out.">
+        Chrome can check your passwords when you sign in with your Google Account.
+      </message>
+      <message name="IDS_PASSWORD_CHECK_STATUS_MESSAGE_ERROR_UNKNOWN" desc="Error message explaining that the password check failed for unknown reasons.">
+        Chrome can't check your passwords. Try again.
+      </message>
+      <message name="IDS_PASSWORD_CHECK_STATUS_MESSAGE_IDLE_NO_LEAKS" desc="Message explaining that the password check has been completed and no leaked passwords have been found.">
+        No compromised passwords
+      </message>
+      <message name="IDS_PASSWORD_CHECK_STATUS_MESSAGE_IDLE_WITH_LEAKS" desc="Message explaining that the password check has been completed and some leaked passwords have been found.">
+        {COMPROMISED_PASSWORDS, plural, =1 {# compromised password} other {# compromised passwords}}
+      </message>
+      <message name="IDS_PASSWORD_CHECK_STATUS_MESSAGE_INITIAL_RUNNING" desc="Status message shown when the check for leaked passwords is running and we have not yet information regarding the progress.">
+        Checking passwords…
+      </message>
+      <message name="IDS_PASSWORD_CHECK_STATUS_MESSAGE_RUNNING" desc="Status message shown when the check for leaked passwords is running.">
+        Checking passwords (<ph name="ANALYSED_PASSWORDS">%1$s<ex>1</ex></ph> of <ph name="TOTAL_PASSWORDS">%2$s<ex>42</ex></ph>)…
+      </message>
+      <message name="IDS_PASSWORD_CHECK_STATUS_SUBTITLE_NO_FINDINGS" desc="A small paragraph below the status message that informs the user that Chrome notifies them in real-time when using compromised passwords.">
+        Chrome will notify you when you sign in with a compromised password.
+      </message>
+      <message name="IDS_PASSWORD_CHECK_STATUS_SUBTITLE_FOUND_COMPROMISED_CREDENTIALS" desc="A small paragraph below the status message that explains how to proceed with the compromised passwords listed below.">
+        The following accounts use passwords which were exposed in a third-party data breach or entered on a deceptive site. Change these passwords immediately to keep your accounts safe.
+      </message>
+
       <!-- Accessibility strings -->
       <message name="IDS_ACCESSIBILITY_PASSWORD_CHECK_RESTART_BUTTON" desc="Content description for the button to restart the password check.">
         Restart password check
       </message>
+
+      <!-- Password Check Dialog strings -->
+      <message name="IDS_PASSWORD_CHECK_CREDENTIAL_DIALOG_CANCEL" desc="The caption the button closing the prompt to delete a stored password.">
+        Cancel
+      </message>
+      <message name="IDS_PASSWORD_CHECK_DELETE_CREDENTIAL_DIALOG_BODY" desc="The body of a prompt to confirm that the user intends to delete the stored password.">
+        Deleting this password will not delete your account on <ph name="SITE">%1$s<ex>example.com</ex></ph>. Change your password or delete your account on <ph name="SITE">%1$s<ex>example.com</ex></ph> to keep it safe from others.
+      </message>
+      <message name="IDS_PASSWORD_CHECK_DELETE_CREDENTIAL_DIALOG_TITLE" desc="The title of a prompt to confirm that the user intends to delete the stored password.">
+        Delete password?
+      </message>
+      <message name="IDS_PASSWORD_CHECK_DELETE_CREDENTIAL_DIALOG_CONFIRM" desc="The caption the button confirming that the user intends to delete the stored password.">
+        Delete password
+      </message>
+
+      <!-- Utility string to show the timestamp -->
+      <message name="IDS_PASSWORD_CHECK_JUST_NOW" desc="A time label for a check that happened just now. For example 'Checked passwords · Just now'">
+        Just now
+      </message>
     </messages>
   </release>
 </grit>
diff --git a/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_CREDENTIAL_DIALOG_CANCEL.png.sha1 b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_CREDENTIAL_DIALOG_CANCEL.png.sha1
new file mode 100644
index 0000000..d7a2bc26
--- /dev/null
+++ b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_CREDENTIAL_DIALOG_CANCEL.png.sha1
@@ -0,0 +1 @@
+247a40688e167d85b78fc2bfc755ff73bacab2fe
\ No newline at end of file
diff --git a/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_DELETE_CREDENTIAL_DIALOG_BODY.png.sha1 b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_DELETE_CREDENTIAL_DIALOG_BODY.png.sha1
new file mode 100644
index 0000000..09007fe0d
--- /dev/null
+++ b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_DELETE_CREDENTIAL_DIALOG_BODY.png.sha1
@@ -0,0 +1 @@
+19b07efe24ab4f8af6385168f1eb1a2209b850a6
\ No newline at end of file
diff --git a/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_DELETE_CREDENTIAL_DIALOG_CONFIRM.png.sha1 b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_DELETE_CREDENTIAL_DIALOG_CONFIRM.png.sha1
new file mode 100644
index 0000000..09007fe0d
--- /dev/null
+++ b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_DELETE_CREDENTIAL_DIALOG_CONFIRM.png.sha1
@@ -0,0 +1 @@
+19b07efe24ab4f8af6385168f1eb1a2209b850a6
\ No newline at end of file
diff --git a/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_DELETE_CREDENTIAL_DIALOG_TITLE.png.sha1 b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_DELETE_CREDENTIAL_DIALOG_TITLE.png.sha1
new file mode 100644
index 0000000..09007fe0d
--- /dev/null
+++ b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_DELETE_CREDENTIAL_DIALOG_TITLE.png.sha1
@@ -0,0 +1 @@
+19b07efe24ab4f8af6385168f1eb1a2209b850a6
\ No newline at end of file
diff --git a/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_JUST_NOW.png.sha1 b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_JUST_NOW.png.sha1
new file mode 100644
index 0000000..7b4a78b
--- /dev/null
+++ b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_JUST_NOW.png.sha1
@@ -0,0 +1 @@
+693aefb5231f2fa632d467c4febe56e5f4cd28b4
\ No newline at end of file
diff --git a/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_DESCRIPTION_IDLE.png.sha1 b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_DESCRIPTION_IDLE.png.sha1
new file mode 100644
index 0000000..7b4a78b
--- /dev/null
+++ b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_DESCRIPTION_IDLE.png.sha1
@@ -0,0 +1 @@
+693aefb5231f2fa632d467c4febe56e5f4cd28b4
\ No newline at end of file
diff --git a/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_MESSAGE_ERROR_NO_PASSWORDS.png.sha1 b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_MESSAGE_ERROR_NO_PASSWORDS.png.sha1
new file mode 100644
index 0000000..9a5f3d8
--- /dev/null
+++ b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_MESSAGE_ERROR_NO_PASSWORDS.png.sha1
@@ -0,0 +1 @@
+37501e0b338eacedb6f0c9790b2164449344fcea
\ No newline at end of file
diff --git a/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_MESSAGE_ERROR_OFFLINE.png.sha1 b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_MESSAGE_ERROR_OFFLINE.png.sha1
new file mode 100644
index 0000000..cadd52e
--- /dev/null
+++ b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_MESSAGE_ERROR_OFFLINE.png.sha1
@@ -0,0 +1 @@
+fcb59be745a5ffbb21fcd8f78f1608f6817910d7
\ No newline at end of file
diff --git a/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_MESSAGE_ERROR_QUOTA_LIMIT.png.sha1 b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_MESSAGE_ERROR_QUOTA_LIMIT.png.sha1
new file mode 100644
index 0000000..05a9b458
--- /dev/null
+++ b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_MESSAGE_ERROR_QUOTA_LIMIT.png.sha1
@@ -0,0 +1 @@
+811cf4590b3be61c9fefc6e597b32b2dff0ce457
\ No newline at end of file
diff --git a/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_MESSAGE_ERROR_QUOTA_LIMIT_ACCOUNT_CHECK.png.sha1 b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_MESSAGE_ERROR_QUOTA_LIMIT_ACCOUNT_CHECK.png.sha1
new file mode 100644
index 0000000..9fab944
--- /dev/null
+++ b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_MESSAGE_ERROR_QUOTA_LIMIT_ACCOUNT_CHECK.png.sha1
@@ -0,0 +1 @@
+d7b9987fb0a45cf5f829ba2750b0d9dcb8564a60
\ No newline at end of file
diff --git a/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_MESSAGE_ERROR_SIGNED_OUT.png.sha1 b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_MESSAGE_ERROR_SIGNED_OUT.png.sha1
new file mode 100644
index 0000000..9bf71f1
--- /dev/null
+++ b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_MESSAGE_ERROR_SIGNED_OUT.png.sha1
@@ -0,0 +1 @@
+b061adfb99b4ca91369d20095a3d06eefe969938
\ No newline at end of file
diff --git a/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_MESSAGE_ERROR_UNKNOWN.png.sha1 b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_MESSAGE_ERROR_UNKNOWN.png.sha1
new file mode 100644
index 0000000..0f4d518
--- /dev/null
+++ b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_MESSAGE_ERROR_UNKNOWN.png.sha1
@@ -0,0 +1 @@
+85f3e05d78d519c0be4eca57e88ad3a74d2394c5
\ No newline at end of file
diff --git a/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_MESSAGE_IDLE_NO_LEAKS.png.sha1 b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_MESSAGE_IDLE_NO_LEAKS.png.sha1
new file mode 100644
index 0000000..7b4a78b
--- /dev/null
+++ b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_MESSAGE_IDLE_NO_LEAKS.png.sha1
@@ -0,0 +1 @@
+693aefb5231f2fa632d467c4febe56e5f4cd28b4
\ No newline at end of file
diff --git a/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_MESSAGE_IDLE_WITH_LEAKS.png.sha1 b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_MESSAGE_IDLE_WITH_LEAKS.png.sha1
new file mode 100644
index 0000000..4bc3f098
--- /dev/null
+++ b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_MESSAGE_IDLE_WITH_LEAKS.png.sha1
@@ -0,0 +1 @@
+f49f6f620eb105d574ea8b989701a56f6ec02b8b
\ No newline at end of file
diff --git a/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_MESSAGE_INITIAL_RUNNING.png.sha1 b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_MESSAGE_INITIAL_RUNNING.png.sha1
new file mode 100644
index 0000000..dffa078
--- /dev/null
+++ b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_MESSAGE_INITIAL_RUNNING.png.sha1
@@ -0,0 +1 @@
+bb35ab5685cea0b9a1ff8515f76b3f5b58179194
\ No newline at end of file
diff --git a/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_MESSAGE_RUNNING.png.sha1 b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_MESSAGE_RUNNING.png.sha1
new file mode 100644
index 0000000..0aefc891
--- /dev/null
+++ b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_MESSAGE_RUNNING.png.sha1
@@ -0,0 +1 @@
+7ed062035e44451197ebccfc7a52e9297e669c40
\ No newline at end of file
diff --git a/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_SUBTITLE_FOUND_COMPROMISED_CREDENTIALS.png.sha1 b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_SUBTITLE_FOUND_COMPROMISED_CREDENTIALS.png.sha1
new file mode 100644
index 0000000..e760214e
--- /dev/null
+++ b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_SUBTITLE_FOUND_COMPROMISED_CREDENTIALS.png.sha1
@@ -0,0 +1 @@
+d3100fe343b3a22a832057b2a8601a1b21fbaa46
\ No newline at end of file
diff --git a/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_SUBTITLE_NO_FINDINGS.png.sha1 b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_SUBTITLE_NO_FINDINGS.png.sha1
new file mode 100644
index 0000000..79a9293
--- /dev/null
+++ b/chrome/browser/password_check/android/internal/java/strings/android_password_check_strings_grd/IDS_PASSWORD_CHECK_STATUS_SUBTITLE_NO_FINDINGS.png.sha1
@@ -0,0 +1 @@
+425a59baae355b71eb9db31a165b0719006a80f3
\ No newline at end of file
diff --git a/chrome/browser/password_check/android/java/src/org/chromium/chrome/browser/password_check/PasswordCheckFragmentView.java b/chrome/browser/password_check/android/java/src/org/chromium/chrome/browser/password_check/PasswordCheckFragmentView.java
index 249aa57..616855f 100644
--- a/chrome/browser/password_check/android/java/src/org/chromium/chrome/browser/password_check/PasswordCheckFragmentView.java
+++ b/chrome/browser/password_check/android/java/src/org/chromium/chrome/browser/password_check/PasswordCheckFragmentView.java
@@ -8,6 +8,7 @@
 import android.os.Bundle;
 import android.view.MenuItem;
 
+import androidx.fragment.app.DialogFragment;
 import androidx.preference.PreferenceFragmentCompat;
 
 /**
@@ -74,4 +75,9 @@
     private Context getStyledContext() {
         return getPreferenceManager().getContext();
     }
+
+    void showDialogFragment(DialogFragment passwordCheckDeletionDialogFragment) {
+        if (passwordCheckDeletionDialogFragment == null) return;
+        passwordCheckDeletionDialogFragment.show(getParentFragmentManager(), null);
+    }
 }
diff --git a/chrome/browser/password_check/android/javatests/src/org/chromium/chrome/browser/password_check/PasswordCheckIntegrationTest.java b/chrome/browser/password_check/android/javatests/src/org/chromium/chrome/browser/password_check/PasswordCheckIntegrationTest.java
index 3d74fbb2..edfde3c 100644
--- a/chrome/browser/password_check/android/javatests/src/org/chromium/chrome/browser/password_check/PasswordCheckIntegrationTest.java
+++ b/chrome/browser/password_check/android/javatests/src/org/chromium/chrome/browser/password_check/PasswordCheckIntegrationTest.java
@@ -70,6 +70,7 @@
 
     @Test
     @MediumTest
+    @DisabledTest(message = "crbug.com/1114096")
     public void testDoesNotDestroyComponentIfNotFirstInSettingsStack() {
         PasswordCheckFactory.getOrCreate();
         SettingsActivity activity = setUpUiLaunchedFromSettings();
diff --git a/chrome/browser/password_check/android/javatests/src/org/chromium/chrome/browser/password_check/PasswordCheckViewTest.java b/chrome/browser/password_check/android/javatests/src/org/chromium/chrome/browser/password_check/PasswordCheckViewTest.java
index 41fbac1..54dc295c 100644
--- a/chrome/browser/password_check/android/javatests/src/org/chromium/chrome/browser/password_check/PasswordCheckViewTest.java
+++ b/chrome/browser/password_check/android/javatests/src/org/chromium/chrome/browser/password_check/PasswordCheckViewTest.java
@@ -11,27 +11,55 @@
 
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
 
 import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.CompromisedCredentialProperties.COMPROMISED_CREDENTIAL;
 import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.CompromisedCredentialProperties.CREDENTIAL_HANDLER;
+import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.DELETION_CONFIRMATION_HANDLER;
+import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.DELETION_ORIGIN;
+import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.CHECK_PROGRESS;
 import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.CHECK_STATUS;
+import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.CHECK_TIMESTAMP;
+import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.COMPROMISED_CREDENTIALS_COUNT;
+import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.UNKNOWN_PROGRESS;
 import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.ITEMS;
+import static org.chromium.chrome.browser.password_check.PasswordCheckUIStatus.ERROR_NO_PASSWORDS;
+import static org.chromium.chrome.browser.password_check.PasswordCheckUIStatus.ERROR_OFFLINE;
+import static org.chromium.chrome.browser.password_check.PasswordCheckUIStatus.ERROR_QUOTA_LIMIT;
+import static org.chromium.chrome.browser.password_check.PasswordCheckUIStatus.ERROR_QUOTA_LIMIT_ACCOUNT_CHECK;
+import static org.chromium.chrome.browser.password_check.PasswordCheckUIStatus.ERROR_SIGNED_OUT;
+import static org.chromium.chrome.browser.password_check.PasswordCheckUIStatus.ERROR_UNKNOWN;
+import static org.chromium.chrome.browser.password_check.PasswordCheckUIStatus.IDLE;
+import static org.chromium.chrome.browser.password_check.PasswordCheckUIStatus.RUNNING;
 import static org.chromium.content_public.browser.test.util.CriteriaHelper.pollUiThread;
 import static org.chromium.content_public.browser.test.util.TestThreadUtils.runOnUiThreadBlocking;
 
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
 import android.os.Bundle;
+import android.util.Pair;
 import android.view.View;
 import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.ProgressBar;
 import android.widget.TextView;
 
 import androidx.annotation.IdRes;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.content.res.AppCompatResources;
 import androidx.recyclerview.widget.RecyclerView;
 import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -70,6 +98,13 @@
     private static final CompromisedCredential SCRIPTED =
             new CompromisedCredential("script.com", "Charlie", "secret", false, true);
 
+    private static final int LEAKS_COUNT = 2;
+
+    private static final long S_TO_MS = 1000;
+    private static final long MIN_TO_MS = 60 * S_TO_MS;
+    private static final long H_TO_MS = 60 * MIN_TO_MS;
+    private static final long DAY_TO_MS = 24 * H_TO_MS;
+
     private PropertyModel mModel = PasswordCheckProperties.createDefaultModel();
     private PasswordCheckFragmentView mPasswordCheckView;
 
@@ -100,10 +135,10 @@
     @MediumTest
     public void testDisplaysHeaderAndCredential() {
         runOnUiThreadBlocking(() -> {
-            mModel.get(ITEMS).add(buildHeader(PasswordCheckUIStatus.IDLE));
+            mModel.get(ITEMS).add(buildHeader(RUNNING));
             mModel.get(ITEMS).add(buildCredentialItem(ANA));
         });
-        pollUiThread(() -> Criteria.checkThat(getPasswordCheckViewList().getChildCount(), is(2)));
+        waitForListViewToHaveLength(2);
         // Has a change passwords button.
         assertNotNull(getCredentialChangeButtonAt(1));
         assertThat(getCredentialChangeButtonAt(1).getVisibility(), is(View.VISIBLE));
@@ -119,20 +154,228 @@
 
     @Test
     @MediumTest
-    public void testStatusDisplaysRestartAction() {
+    public void testStatusIllustrationPositive() {
+        Long checkTimestamp = System.currentTimeMillis();
         runOnUiThreadBlocking(
-                () -> { mModel.get(ITEMS).add(buildHeader(PasswordCheckUIStatus.IDLE)); });
-        pollUiThread(() -> Criteria.checkThat(getPasswordCheckViewList().getChildCount(), is(1)));
+                () -> { mModel.get(ITEMS).add(buildHeader(IDLE, 0, checkTimestamp)); });
+        waitForListViewToHaveLength(1);
+        assertIllustration(R.drawable.password_check_positive);
+    }
+
+    @Test
+    @MediumTest
+    public void testStatusIllustrationWarning() {
+        Long checkTimestamp = System.currentTimeMillis();
+        runOnUiThreadBlocking(
+                () -> { mModel.get(ITEMS).add(buildHeader(IDLE, LEAKS_COUNT, checkTimestamp)); });
+        waitForListViewToHaveLength(1);
+        assertIllustration(R.drawable.password_checkup_warning);
+    }
+
+    @Test
+    @MediumTest
+    public void testStatusIllustrationNeutral() {
+        runOnUiThreadBlocking(() -> { mModel.get(ITEMS).add(buildHeader(ERROR_OFFLINE)); });
+        waitForListViewToHaveLength(1);
+        assertIllustration(R.drawable.password_check_neutral);
+    }
+
+    @Test
+    @MediumTest
+    public void testStatusDisplaysIconOnIdleNoLeaks() {
+        Long checkTimestamp = System.currentTimeMillis();
+        runOnUiThreadBlocking(
+                () -> { mModel.get(ITEMS).add(buildHeader(IDLE, 0, checkTimestamp)); });
+        waitForListViewToHaveLength(1);
+        assertDisplaysIcon(R.drawable.ic_check_circle_filled_green_24dp);
+    }
+
+    @Test
+    @MediumTest
+    public void testStatusDisplaysIconOnIdleWithLeaks() {
+        Long checkTimestamp = System.currentTimeMillis();
+        runOnUiThreadBlocking(
+                () -> { mModel.get(ITEMS).add(buildHeader(IDLE, LEAKS_COUNT, checkTimestamp)); });
+        waitForListViewToHaveLength(1);
+        assertDisplaysIcon(org.chromium.chrome.R.drawable.ic_warning_red_24dp);
+    }
+
+    @Test
+    @MediumTest
+    public void testStatusDisplaysIconOnError() {
+        runOnUiThreadBlocking(() -> { mModel.get(ITEMS).add(buildHeader(ERROR_OFFLINE)); });
+        waitForListViewToHaveLength(1);
+        assertDisplaysIcon(org.chromium.chrome.R.drawable.ic_error_grey800_24dp_filled);
+    }
+
+    @Test
+    @MediumTest
+    public void testStatusDisplaysProgressBarOnRunning() {
+        runOnUiThreadBlocking(() -> { mModel.get(ITEMS).add(buildHeader(RUNNING)); });
+        waitForListViewToHaveLength(1);
+        assertThat(getHeaderIcon().getVisibility(), is(View.GONE));
+        assertThat(getHeaderProgressBar().getVisibility(), is(View.VISIBLE));
+    }
+
+    @Test
+    @MediumTest
+    public void testStatusDisplaysRestartAction() {
+        Long checkTimestamp = System.currentTimeMillis();
+        runOnUiThreadBlocking(
+                () -> { mModel.get(ITEMS).add(buildHeader(IDLE, 0, checkTimestamp)); });
+        waitForListViewToHaveLength(1);
         assertThat(getActionButton().getVisibility(), is(View.VISIBLE));
+        assertTrue(getActionButton().isClickable());
     }
 
     @Test
     @MediumTest
     public void testStatusNotDisplaysRestartAction() {
-        runOnUiThreadBlocking(
-                () -> { mModel.get(ITEMS).add(buildHeader(PasswordCheckUIStatus.RUNNING)); });
-        pollUiThread(() -> Criteria.checkThat(getPasswordCheckViewList().getChildCount(), is(1)));
+        runOnUiThreadBlocking(() -> { mModel.get(ITEMS).add(buildHeader(RUNNING)); });
+        waitForListViewToHaveLength(1);
         assertThat(getActionButton().getVisibility(), is(View.GONE));
+        assertFalse(getActionButton().isClickable());
+    }
+
+    @Test
+    @MediumTest
+    public void testStatusRunnningText() {
+        runOnUiThreadBlocking(
+                () -> { mModel.get(ITEMS).add(buildHeader(RUNNING, UNKNOWN_PROGRESS)); });
+        waitForListViewToHaveLength(1);
+        assertThat(getHeaderMessage().getText(),
+                is(getString(R.string.password_check_status_message_initial_running)));
+        assertThat(getHeaderMessage().getVisibility(), is(View.VISIBLE));
+        assertThat(getHeaderDescription().getVisibility(), is(View.GONE));
+    }
+
+    @Test
+    @MediumTest
+    public void testStatusIdleNoLeaksText() {
+        Long checkTimestamp = System.currentTimeMillis();
+        runOnUiThreadBlocking(
+                () -> { mModel.get(ITEMS).add(buildHeader(IDLE, 0, checkTimestamp)); });
+        waitForListViewToHaveLength(1);
+        assertThat(getHeaderMessage().getText(),
+                is(getString(R.string.password_check_status_message_idle_no_leaks)));
+        assertThat(getHeaderMessage().getVisibility(), is(View.VISIBLE));
+        assertThat(getHeaderDescription().getVisibility(), is(View.VISIBLE));
+    }
+
+    @Test
+    @MediumTest
+    public void testStatusIdleWithLeaksText() {
+        Long checkTimestamp = System.currentTimeMillis();
+        runOnUiThreadBlocking(
+                () -> { mModel.get(ITEMS).add(buildHeader(IDLE, LEAKS_COUNT, checkTimestamp)); });
+        waitForListViewToHaveLength(1);
+        assertThat(getHeaderMessage().getText(),
+                is(mPasswordCheckView.getContext().getResources().getQuantityString(
+                        R.plurals.password_check_status_message_idle_with_leaks, LEAKS_COUNT,
+                        LEAKS_COUNT)));
+        assertThat(getHeaderMessage().getVisibility(), is(View.VISIBLE));
+        assertThat(getHeaderDescription().getVisibility(), is(View.VISIBLE));
+    }
+
+    @Test
+    @MediumTest
+    public void testStatusErrorOfflineText() {
+        runOnUiThreadBlocking(() -> { mModel.get(ITEMS).add(buildHeader(ERROR_OFFLINE)); });
+        waitForListViewToHaveLength(1);
+        assertThat(getHeaderMessage().getText(),
+                is(getString(R.string.password_check_status_message_error_offline)));
+        assertThat(getHeaderMessage().getVisibility(), is(View.VISIBLE));
+        assertThat(getHeaderDescription().getVisibility(), is(View.GONE));
+    }
+
+    @Test
+    @MediumTest
+    public void testStatusErrorNoPasswordsText() {
+        runOnUiThreadBlocking(() -> { mModel.get(ITEMS).add(buildHeader(ERROR_NO_PASSWORDS)); });
+        waitForListViewToHaveLength(1);
+        assertThat(getHeaderMessage().getText(),
+                is(getString(R.string.password_check_status_message_error_no_passwords)));
+        assertThat(getHeaderMessage().getVisibility(), is(View.VISIBLE));
+        assertThat(getHeaderDescription().getVisibility(), is(View.GONE));
+    }
+
+    @Test
+    @MediumTest
+    public void testStatusErrorQuotaLimitText() {
+        runOnUiThreadBlocking(() -> { mModel.get(ITEMS).add(buildHeader(ERROR_QUOTA_LIMIT)); });
+        waitForListViewToHaveLength(1);
+        assertThat(getHeaderMessage().getText(),
+                is(getString(R.string.password_check_status_message_error_quota_limit)));
+        assertThat(getHeaderMessage().getVisibility(), is(View.VISIBLE));
+        assertThat(getHeaderDescription().getVisibility(), is(View.GONE));
+    }
+
+    @Test
+    @MediumTest
+    public void testStatusErrorQuotaLimitAccountCheckText() {
+        runOnUiThreadBlocking(
+                () -> { mModel.get(ITEMS).add(buildHeader(ERROR_QUOTA_LIMIT_ACCOUNT_CHECK)); });
+        waitForListViewToHaveLength(1);
+        assertThat(getHeaderMessage().getText(),
+                is(getString(
+                        R.string.password_check_status_message_error_quota_limit_account_check)));
+        assertThat(getHeaderMessage().getVisibility(), is(View.VISIBLE));
+        assertThat(getHeaderDescription().getVisibility(), is(View.GONE));
+    }
+
+    @Test
+    @MediumTest
+    public void testStatusErrorSignedOutText() {
+        runOnUiThreadBlocking(() -> { mModel.get(ITEMS).add(buildHeader(ERROR_SIGNED_OUT)); });
+        waitForListViewToHaveLength(1);
+        assertThat(getHeaderMessage().getText(),
+                is(getString(R.string.password_check_status_message_error_signed_out)));
+        assertThat(getHeaderMessage().getVisibility(), is(View.VISIBLE));
+        assertThat(getHeaderDescription().getVisibility(), is(View.GONE));
+    }
+
+    @Test
+    @MediumTest
+    public void testStatusErrorUnknownText() {
+        runOnUiThreadBlocking(() -> { mModel.get(ITEMS).add(buildHeader(ERROR_UNKNOWN)); });
+        waitForListViewToHaveLength(1);
+        assertThat(getHeaderMessage().getText(),
+                is(getString(R.string.password_check_status_message_error_unknown)));
+        assertThat(getHeaderMessage().getVisibility(), is(View.VISIBLE));
+        assertThat(getHeaderDescription().getVisibility(), is(View.GONE));
+    }
+
+    @Test
+    @MediumTest
+    public void testStatusDysplaysSubtitleOnIdleNoLeaks() {
+        Long checkTimestamp = System.currentTimeMillis();
+        runOnUiThreadBlocking(
+                () -> { mModel.get(ITEMS).add(buildHeader(IDLE, 0, checkTimestamp)); });
+        waitForListViewToHaveLength(1);
+        assertThat(getHeaderSubtitle().getText(),
+                is(getString(R.string.password_check_status_subtitle_no_findings)));
+        assertThat(getHeaderSubtitle().getVisibility(), is(View.VISIBLE));
+    }
+
+    @Test
+    @MediumTest
+    public void testStatusDysplaysSubtitleOnIdleWithLeaks() {
+        Long checkTimestamp = System.currentTimeMillis();
+        runOnUiThreadBlocking(
+                () -> { mModel.get(ITEMS).add(buildHeader(IDLE, LEAKS_COUNT, checkTimestamp)); });
+        waitForListViewToHaveLength(1);
+        assertThat(getHeaderSubtitle().getText(),
+                is(getString(
+                        R.string.password_check_status_subtitle_found_compromised_credentials)));
+        assertThat(getHeaderSubtitle().getVisibility(), is(View.VISIBLE));
+    }
+
+    @Test
+    @MediumTest
+    public void testStatusNotDysplaysSubtitle() {
+        runOnUiThreadBlocking(() -> { mModel.get(ITEMS).add(buildHeader(ERROR_UNKNOWN)); });
+        waitForListViewToHaveLength(1);
+        assertThat(getHeaderSubtitle().getVisibility(), is(View.GONE));
     }
 
     @Test
@@ -142,7 +385,7 @@
             mModel.get(ITEMS).add(buildCredentialItem(PHISHED));
             mModel.get(ITEMS).add(buildCredentialItem(LEAKED));
         });
-        pollUiThread(() -> Criteria.checkThat(getPasswordCheckViewList().getChildCount(), is(2)));
+        waitForListViewToHaveLength(2);
 
         // The phished credential is rendered first:
         assertThat(getCredentialOriginAt(0).getText(), is(PHISHED.getOriginUrl()));
@@ -192,7 +435,7 @@
     @MediumTest
     public void testClickingChangePasswordTriggersHandler() {
         runOnUiThreadBlocking(() -> mModel.get(ITEMS).add(buildCredentialItem(ANA)));
-        pollUiThread(() -> Criteria.checkThat(getPasswordCheckViewList().getChildCount(), is(1)));
+        waitForListViewToHaveLength(1);
 
         TouchCommon.singleClickView(getCredentialChangeButtonAt(0));
 
@@ -203,7 +446,7 @@
     @MediumTest
     public void testClickingChangePasswordWithScriptTriggersHandler() {
         runOnUiThreadBlocking(() -> mModel.get(ITEMS).add(buildCredentialItem(SCRIPTED)));
-        pollUiThread(() -> Criteria.checkThat(getPasswordCheckViewList().getChildCount(), is(1)));
+        waitForListViewToHaveLength(1);
 
         TouchCommon.singleClickView(getCredentialChangeButtonWithScriptAt(0));
 
@@ -214,7 +457,7 @@
     @MediumTest
     public void testClickingDeleteInMoreMenuTriggersHandler() {
         runOnUiThreadBlocking(() -> mModel.get(ITEMS).add(buildCredentialItem(ANA)));
-        pollUiThread(() -> Criteria.checkThat(getPasswordCheckViewList().getChildCount(), is(1)));
+        waitForListViewToHaveLength(1);
 
         TouchCommon.singleClickView(getCredentialMoreButtonAt(0));
 
@@ -226,10 +469,59 @@
         verify(mMockHandler).onRemove(eq(ANA));
     }
 
+    @Test
+    @SmallTest
+    public void testGetTimestampStrings() {
+        Resources res = mPasswordCheckView.getContext().getResources();
+        assertThat(PasswordCheckViewBinder.getTimestamp(res, 10 * S_TO_MS), is("Just now"));
+        assertThat(PasswordCheckViewBinder.getTimestamp(res, MIN_TO_MS), is("1 minute ago"));
+        assertThat(PasswordCheckViewBinder.getTimestamp(res, 17 * MIN_TO_MS), is("17 minutes ago"));
+        assertThat(PasswordCheckViewBinder.getTimestamp(res, H_TO_MS), is("1 hour ago"));
+        assertThat(PasswordCheckViewBinder.getTimestamp(res, 13 * H_TO_MS), is("13 hours ago"));
+        assertThat(PasswordCheckViewBinder.getTimestamp(res, DAY_TO_MS), is("1 day ago"));
+        assertThat(PasswordCheckViewBinder.getTimestamp(res, 2 * DAY_TO_MS), is("2 days ago"));
+        assertThat(PasswordCheckViewBinder.getTimestamp(res, 315 * DAY_TO_MS), is("315 days ago"));
+    }
+
+    @Test
+    @MediumTest
+    public void testConfirmingDeletionDialogTriggersHandler() {
+        PasswordCheckDeletionDialogFragment.Handler mockHandler =
+                mock(PasswordCheckDeletionDialogFragment.Handler.class);
+        mModel.set(DELETION_ORIGIN, ANA.getOriginUrl());
+        runOnUiThreadBlocking(() -> mModel.set(DELETION_CONFIRMATION_HANDLER, mockHandler));
+
+        onView(withText(R.string.password_check_delete_credential_dialog_confirm))
+                .inRoot(withDecorView(
+                        not(is(mPasswordCheckView.getActivity().getWindow().getDecorView()))))
+                .perform(click());
+
+        verify(mockHandler).onClick(any(), eq(AlertDialog.BUTTON_POSITIVE));
+    }
+
+    private MVCListAdapter.ListItem buildHeader(@PasswordCheckUIStatus int status,
+            Integer compromisedCredentialsCount, Long checkTimestamp) {
+        return buildHeader(status, compromisedCredentialsCount, checkTimestamp, null);
+    }
+
+    private MVCListAdapter.ListItem buildHeader(
+            @PasswordCheckUIStatus int status, Pair<Integer, Integer> progress) {
+        return buildHeader(status, null, null, progress);
+    }
+
     private MVCListAdapter.ListItem buildHeader(@PasswordCheckUIStatus int status) {
+        return buildHeader(status, null, null, null);
+    }
+
+    private MVCListAdapter.ListItem buildHeader(@PasswordCheckUIStatus int status,
+            Integer compromisedCredentialsCount, Long checkTimestamp,
+            Pair<Integer, Integer> progress) {
         return new MVCListAdapter.ListItem(PasswordCheckProperties.ItemType.HEADER,
                 new PropertyModel.Builder(HeaderProperties.ALL_KEYS)
+                        .with(CHECK_PROGRESS, progress)
                         .with(CHECK_STATUS, status)
+                        .with(CHECK_TIMESTAMP, checkTimestamp)
+                        .with(COMPROMISED_CREDENTIALS_COUNT, compromisedCredentialsCount)
                         .build());
     }
 
@@ -251,10 +543,59 @@
         mTestRule.startSettingsActivity(fragmentArgs);
     }
 
+    private void waitForListViewToHaveLength(int length) {
+        pollUiThread(
+                () -> Criteria.checkThat(getPasswordCheckViewList().getChildCount(), is(length)));
+    }
+
+    private void assertDisplaysIcon(int resourceId) {
+        assertThat(getHeaderIcon().getVisibility(), is(View.VISIBLE));
+        assertThat(getHeaderProgressBar().getVisibility(), is(View.GONE));
+        Drawable icon = getHeaderIcon().getDrawable();
+        int widthPx = icon.getIntrinsicWidth();
+        int heightPx = icon.getIntrinsicHeight();
+        assertTrue(getBitmap(
+                AppCompatResources.getDrawable(mPasswordCheckView.getContext(), resourceId),
+                widthPx, heightPx)
+                           .sameAs(getBitmap(icon, widthPx, heightPx)));
+    }
+
+    private void assertIllustration(int resourceId) {
+        Drawable illustration =
+                ((ImageView) getStatus().findViewById(R.id.check_status_illustration))
+                        .getDrawable();
+        int widthPx = illustration.getIntrinsicWidth();
+        int heightPx = illustration.getIntrinsicHeight();
+        assertTrue(getBitmap(
+                AppCompatResources.getDrawable(mPasswordCheckView.getContext(), resourceId),
+                widthPx, heightPx)
+                           .sameAs(getBitmap(illustration, widthPx, heightPx)));
+    }
+
     private View getStatus() {
         return mPasswordCheckView.getListView().getChildAt(0);
     }
 
+    private ImageView getHeaderIcon() {
+        return getStatus().findViewById(R.id.check_status_icon);
+    }
+
+    private ProgressBar getHeaderProgressBar() {
+        return getStatus().findViewById(R.id.check_status_progress);
+    }
+
+    private TextView getHeaderDescription() {
+        return getStatus().findViewById(R.id.check_status_description);
+    }
+
+    private TextView getHeaderMessage() {
+        return getStatus().findViewById(R.id.check_status_message);
+    }
+
+    private TextView getHeaderSubtitle() {
+        return getStatus().findViewById(R.id.check_status_subtitle);
+    }
+
     private ImageButton getActionButton() {
         return getStatus().findViewById(R.id.check_status_restart_button);
     }
@@ -303,4 +644,12 @@
         return verify(mock,
                 timeout(ScalableTimeout.scaleTimeout(CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL)));
     }
+
+    private Bitmap getBitmap(Drawable drawable, int widthPx, int heightPx) {
+        Bitmap bitmap = Bitmap.createBitmap(widthPx, heightPx, Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(bitmap);
+        drawable.setBounds(0, 0, widthPx, heightPx);
+        drawable.draw(canvas);
+        return bitmap;
+    }
 }
diff --git a/chrome/browser/password_check/android/junit/src/org/chromium/chrome/browser/password_check/PasswordCheckControllerTest.java b/chrome/browser/password_check/android/junit/src/org/chromium/chrome/browser/password_check/PasswordCheckControllerTest.java
index ee3a4933..e9195f06 100644
--- a/chrome/browser/password_check/android/junit/src/org/chromium/chrome/browser/password_check/PasswordCheckControllerTest.java
+++ b/chrome/browser/password_check/android/junit/src/org/chromium/chrome/browser/password_check/PasswordCheckControllerTest.java
@@ -7,16 +7,30 @@
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.is;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertThat;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.CompromisedCredentialProperties.COMPROMISED_CREDENTIAL;
 import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.CompromisedCredentialProperties.CREDENTIAL_HANDLER;
+import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.DELETION_CONFIRMATION_HANDLER;
+import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.CHECK_PROGRESS;
 import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.CHECK_STATUS;
+import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.CHECK_TIMESTAMP;
+import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.COMPROMISED_CREDENTIALS_COUNT;
+import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.UNKNOWN_PROGRESS;
 import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.ITEMS;
+import static org.chromium.chrome.browser.password_check.PasswordCheckUIStatus.ERROR_OFFLINE;
 import static org.chromium.chrome.browser.password_check.PasswordCheckUIStatus.IDLE;
+import static org.chromium.chrome.browser.password_check.PasswordCheckUIStatus.RUNNING;
+
+import android.content.DialogInterface;
+import android.util.Pair;
+
+import androidx.appcompat.app.AlertDialog;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -51,6 +65,8 @@
     @Rule
     public TestRule mFeaturesProcessorRule = new Features.JUnitProcessor();
 
+    private static final Pair<Integer, Integer> PROGRESS_UPDATE = new Pair<>(2, 19);
+
     @Mock
     private PasswordCheckComponentUi.Delegate mDelegate;
     @Mock
@@ -87,6 +103,11 @@
     }
 
     @Test
+    public void testInitializeRunningHeader() {
+        assertRunningHeader(mModel.get(ITEMS).get(0), UNKNOWN_PROGRESS);
+    }
+
+    @Test
     public void testCreatesHeaderForStatus() {
         mMediator.onPasswordCheckStatusChanged(IDLE);
         ListModel<MVCListAdapter.ListItem> itemList = mModel.get(ITEMS);
@@ -95,6 +116,35 @@
     }
 
     @Test
+    public void testUpdateStatusHeaderOnError() {
+        assertRunningHeader(mModel.get(ITEMS).get(0), UNKNOWN_PROGRESS);
+        mMediator.onPasswordCheckStatusChanged(ERROR_OFFLINE);
+        ListModel<MVCListAdapter.ListItem> itemList = mModel.get(ITEMS);
+        assertThat(itemList.size(), is(1));
+        MVCListAdapter.ListItem header = itemList.get(0);
+        assertHeaderTypeWithStatus(header, ERROR_OFFLINE);
+        assertNull(header.model.get(CHECK_PROGRESS));
+        assertNull(header.model.get(CHECK_TIMESTAMP));
+        assertNull(header.model.get(COMPROMISED_CREDENTIALS_COUNT));
+    }
+
+    @Test
+    public void testUpdateStatusHeaderOnIdle() {
+        assertRunningHeader(mModel.get(ITEMS).get(0), UNKNOWN_PROGRESS);
+        mMediator.onPasswordCheckStatusChanged(IDLE);
+        ListModel<MVCListAdapter.ListItem> itemList = mModel.get(ITEMS);
+        assertThat(itemList.size(), is(1));
+        assertIdleHeader(itemList.get(0));
+    }
+
+    @Test
+    public void testUpdateProgressHeader() {
+        assertRunningHeader(mModel.get(ITEMS).get(0), UNKNOWN_PROGRESS);
+        mMediator.onPasswordCheckProgressChanged(PROGRESS_UPDATE);
+        assertRunningHeader(mModel.get(ITEMS).get(0), PROGRESS_UPDATE);
+    }
+
+    @Test
     public void testCreatesEntryForExistingCredentials() {
         when(mPasswordCheck.getCompromisedCredentials())
                 .thenReturn(new CompromisedCredential[] {ANA});
@@ -125,8 +175,15 @@
 
     @Test
     public void testRemovingElementTriggersDelegate() {
+        // Removing sets a valid handler:
         mMediator.onRemove(ANA);
+        assertNotNull(mModel.get(DELETION_CONFIRMATION_HANDLER));
+
+        // When the handler is triggered (because the dialog was confirmed), remove the credential:
+        mModel.get(DELETION_CONFIRMATION_HANDLER)
+                .onClick(mock(DialogInterface.class), AlertDialog.BUTTON_POSITIVE);
         verify(mDelegate).removeCredential(eq(ANA));
+        assertNull(mModel.get(DELETION_CONFIRMATION_HANDLER));
     }
 
     @Test
@@ -140,4 +197,25 @@
         mMediator.onChangePasswordWithScriptButtonClick(BOB);
         verify(mLaunchCctWithScriptConsumer).accept(eq(BOB));
     }
+
+    private void assertIdleHeader(MVCListAdapter.ListItem header) {
+        assertHeaderTypeWithStatus(header, IDLE);
+        assertNull(header.model.get(CHECK_PROGRESS));
+        assertNotNull(header.model.get(CHECK_TIMESTAMP));
+        assertNotNull(header.model.get(COMPROMISED_CREDENTIALS_COUNT));
+    }
+
+    private void assertRunningHeader(
+            MVCListAdapter.ListItem header, Pair<Integer, Integer> progress) {
+        assertHeaderTypeWithStatus(header, RUNNING);
+        assertThat(header.model.get(CHECK_PROGRESS), is(progress));
+        assertNull(header.model.get(CHECK_TIMESTAMP));
+        assertNull(header.model.get(COMPROMISED_CREDENTIALS_COUNT));
+    }
+
+    private void assertHeaderTypeWithStatus(
+            MVCListAdapter.ListItem header, @PasswordCheckUIStatus int status) {
+        assertThat(header.type, is(ItemType.HEADER));
+        assertThat(header.model.get(CHECK_STATUS), is(status));
+    }
 }
diff --git a/chrome/browser/password_manager/android/account_chooser_dialog_android.cc b/chrome/browser/password_manager/android/account_chooser_dialog_android.cc
index 4b7a0b79..0e8d583 100644
--- a/chrome/browser/password_manager/android/account_chooser_dialog_android.cc
+++ b/chrome/browser/password_manager/android/account_chooser_dialog_android.cc
@@ -102,14 +102,14 @@
     content::WebContents* web_contents,
     std::vector<std::unique_ptr<autofill::PasswordForm>> local_credentials,
     const url::Origin& origin,
-    const ManagePasswordsState::CredentialsCallback& callback)
+    ManagePasswordsState::CredentialsCallback callback)
     : content::WebContentsObserver(web_contents),
       web_contents_(web_contents),
       origin_(origin) {
   passwords_data_.set_client(
       ChromePasswordManagerClient::FromWebContents(web_contents_));
   passwords_data_.OnRequestCredentials(std::move(local_credentials), origin);
-  passwords_data_.set_credentials_callback(callback);
+  passwords_data_.set_credentials_callback(std::move(callback));
 }
 
 AccountChooserDialogAndroid::~AccountChooserDialogAndroid() {}
diff --git a/chrome/browser/password_manager/android/account_chooser_dialog_android.h b/chrome/browser/password_manager/android/account_chooser_dialog_android.h
index fb14d5e..52af6e1 100644
--- a/chrome/browser/password_manager/android/account_chooser_dialog_android.h
+++ b/chrome/browser/password_manager/android/account_chooser_dialog_android.h
@@ -26,7 +26,7 @@
       content::WebContents* web_contents,
       std::vector<std::unique_ptr<autofill::PasswordForm>> local_credentials,
       const url::Origin& origin,
-      const ManagePasswordsState::CredentialsCallback& callback);
+      ManagePasswordsState::CredentialsCallback callback);
 
   ~AccountChooserDialogAndroid() override;
   void Destroy(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
diff --git a/chrome/browser/password_manager/android/account_chooser_dialog_android_unittest.cc b/chrome/browser/password_manager/android/account_chooser_dialog_android_unittest.cc
index 2ebfed1..ff57929e 100644
--- a/chrome/browser/password_manager/android/account_chooser_dialog_android_unittest.cc
+++ b/chrome/browser/password_manager/android/account_chooser_dialog_android_unittest.cc
@@ -67,8 +67,8 @@
   return new AccountChooserDialogAndroid(
       web_contents(), std::move(credentials),
       url::Origin::Create(GURL("https://example.com")),
-      base::Bind(&AccountChooserDialogAndroidTest::OnChooseCredential,
-                 base::Unretained(this)));
+      base::BindOnce(&AccountChooserDialogAndroidTest::OnChooseCredential,
+                     base::Unretained(this)));
 }
 
 AccountChooserDialogAndroid*
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc
index aad896cf..48d7bfa 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -413,22 +413,23 @@
 bool ChromePasswordManagerClient::PromptUserToChooseCredentials(
     std::vector<std::unique_ptr<autofill::PasswordForm>> local_forms,
     const url::Origin& origin,
-    const CredentialsCallback& callback) {
+    CredentialsCallback callback) {
   // Set up an intercept callback if the prompt is zero-clickable (e.g. just one
   // form provided).
-  CredentialsCallback intercept =
-      base::Bind(&PasswordManagerClientHelper::OnCredentialsChosen,
-                 base::Unretained(&helper_), callback, local_forms.size() == 1);
+  CredentialsCallback intercept = base::BindOnce(
+      &PasswordManagerClientHelper::OnCredentialsChosen,
+      base::Unretained(&helper_), std::move(callback), local_forms.size() == 1);
 #if defined(OS_ANDROID)
   // Deletes itself on the event from Java counterpart, when user interacts with
   // dialog.
   AccountChooserDialogAndroid* acccount_chooser_dialog =
       new AccountChooserDialogAndroid(web_contents(), std::move(local_forms),
-                                      origin, intercept);
+                                      origin, std::move(intercept));
   return acccount_chooser_dialog->ShowDialog();
 #else
   return PasswordsClientUIDelegateFromWebContents(web_contents())
-      ->OnChooseCredentials(std::move(local_forms), origin, intercept);
+      ->OnChooseCredentials(std::move(local_forms), origin,
+                            std::move(intercept));
 #endif
 }
 
@@ -1166,7 +1167,7 @@
   log_manager_ = autofill::LogManager::Create(
       password_manager::PasswordManagerLogRouterFactory::GetForBrowserContext(
           profile_),
-      base::Bind(
+      base::BindRepeating(
           &ContentPasswordManagerDriverFactory::RequestSendLoggingAvailability,
           base::Unretained(driver_factory_)));
 
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.h b/chrome/browser/password_manager/chrome_password_manager_client.h
index 060b94a..d7296bce 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.h
+++ b/chrome/browser/password_manager/chrome_password_manager_client.h
@@ -103,7 +103,7 @@
   bool PromptUserToChooseCredentials(
       std::vector<std::unique_ptr<autofill::PasswordForm>> local_forms,
       const url::Origin& origin,
-      const CredentialsCallback& callback) override;
+      CredentialsCallback callback) override;
   void ShowTouchToFill(
       password_manager::PasswordManagerDriver* driver) override;
   // Returns a pointer to the BiometricAuthenticator which is created on demand.
diff --git a/chrome/browser/password_manager/password_manager_browsertest.cc b/chrome/browser/password_manager/password_manager_browsertest.cc
index 8c6a11a0..827f118 100644
--- a/chrome/browser/password_manager/password_manager_browsertest.cc
+++ b/chrome/browser/password_manager/password_manager_browsertest.cc
@@ -1423,7 +1423,8 @@
 
   // Teach the embedded server to handle requests by issuing the basic auth
   // challenge.
-  http_test_server.RegisterRequestHandler(base::Bind(&HandleTestAuthRequest));
+  http_test_server.RegisterRequestHandler(
+      base::BindRepeating(&HandleTestAuthRequest));
   ASSERT_TRUE(http_test_server.Start());
 
   LoginPromptBrowserTestObserver login_observer;
@@ -2822,7 +2823,8 @@
   // already started at this point and adding the request handler to it would
   // not be thread safe.
   net::EmbeddedTestServer http_test_server;
-  http_test_server.RegisterRequestHandler(base::Bind(&HandleTestAuthRequest));
+  http_test_server.RegisterRequestHandler(
+      base::BindRepeating(&HandleTestAuthRequest));
   ASSERT_TRUE(http_test_server.Start());
 
   // Save credentials for "test realm" in the store.
@@ -3570,7 +3572,8 @@
 
   // Teach the embedded server to handle requests by issuing the basic auth
   // challenge.
-  http_test_server.RegisterRequestHandler(base::Bind(&HandleTestAuthRequest));
+  http_test_server.RegisterRequestHandler(
+      base::BindRepeating(&HandleTestAuthRequest));
   ASSERT_TRUE(http_test_server.Start());
 
   LoginPromptBrowserTestObserver login_observer;
diff --git a/chrome/browser/password_manager/password_manager_test_base.cc b/chrome/browser/password_manager/password_manager_test_base.cc
index 450225e7..816ed87f 100644
--- a/chrome/browser/password_manager/password_manager_test_base.cc
+++ b/chrome/browser/password_manager/password_manager_test_base.cc
@@ -81,7 +81,7 @@
   bool OnChooseCredentials(
       std::vector<std::unique_ptr<autofill::PasswordForm>> local_credentials,
       const url::Origin& origin,
-      const ManagePasswordsState::CredentialsCallback& callback) override;
+      ManagePasswordsState::CredentialsCallback callback) override;
   void OnPasswordAutofilled(
       const std::vector<const autofill::PasswordForm*>& password_forms,
       const url::Origin& origin,
@@ -209,10 +209,10 @@
 bool CustomManagePasswordsUIController::OnChooseCredentials(
     std::vector<std::unique_ptr<autofill::PasswordForm>> local_credentials,
     const url::Origin& origin,
-    const ManagePasswordsState::CredentialsCallback& callback) {
+    ManagePasswordsState::CredentialsCallback callback) {
   ProcessStateExpectations(password_manager::ui::CREDENTIAL_REQUEST_STATE);
   return ManagePasswordsUIController::OnChooseCredentials(
-      std::move(local_credentials), origin, callback);
+      std::move(local_credentials), origin, std::move(callback));
 }
 
 void CustomManagePasswordsUIController::OnPasswordAutofilled(
diff --git a/chrome/browser/password_manager/password_store_x.cc b/chrome/browser/password_manager/password_store_x.cc
index 5e10a16..76249d1b 100644
--- a/chrome/browser/password_manager/password_store_x.cc
+++ b/chrome/browser/password_manager/password_store_x.cc
@@ -162,7 +162,7 @@
 }
 
 PasswordStoreChangeList PasswordStoreX::RemoveLoginsByURLAndTimeImpl(
-    const base::Callback<bool(const GURL&)>& url_filter,
+    const base::RepeatingCallback<bool(const GURL&)>& url_filter,
     base::Time delete_begin,
     base::Time delete_end) {
   CheckMigration();
@@ -179,7 +179,7 @@
 }
 
 PasswordStoreChangeList PasswordStoreX::DisableAutoSignInForOriginsImpl(
-    const base::Callback<bool(const GURL&)>& origin_filter) {
+    const base::RepeatingCallback<bool(const GURL&)>& origin_filter) {
   CheckMigration();
   return PasswordStoreDefault::DisableAutoSignInForOriginsImpl(origin_filter);
 }
diff --git a/chrome/browser/password_manager/password_store_x.h b/chrome/browser/password_manager/password_store_x.h
index 6ac6dfc..399ff9a1 100644
--- a/chrome/browser/password_manager/password_store_x.h
+++ b/chrome/browser/password_manager/password_store_x.h
@@ -88,14 +88,14 @@
   password_manager::PasswordStoreChangeList RemoveLoginImpl(
       const autofill::PasswordForm& form) override;
   password_manager::PasswordStoreChangeList RemoveLoginsByURLAndTimeImpl(
-      const base::Callback<bool(const GURL&)>& url_filter,
+      const base::RepeatingCallback<bool(const GURL&)>& url_filter,
       base::Time delete_begin,
       base::Time delete_end) override;
   password_manager::PasswordStoreChangeList RemoveLoginsCreatedBetweenImpl(
       base::Time delete_begin,
       base::Time delete_end) override;
   password_manager::PasswordStoreChangeList DisableAutoSignInForOriginsImpl(
-      const base::Callback<bool(const GURL&)>& origin_filter) override;
+      const base::RepeatingCallback<bool(const GURL&)>& origin_filter) override;
   std::vector<std::unique_ptr<autofill::PasswordForm>> FillMatchingLogins(
       const FormDigest& form) override;
   std::vector<std::unique_ptr<autofill::PasswordForm>>
diff --git a/chrome/browser/payments/ssl_validity_checker.cc b/chrome/browser/payments/ssl_validity_checker.cc
index a8e21d7..fd4e82e 100644
--- a/chrome/browser/payments/ssl_validity_checker.cc
+++ b/chrome/browser/payments/ssl_validity_checker.cc
@@ -15,21 +15,6 @@
 #include "url/gurl.h"
 
 namespace payments {
-namespace {
-
-// Returns the security level of |web_contents|. The |web_contents| parameter
-// should not be null.
-security_state::SecurityLevel GetSecurityLevel(
-    content::WebContents* web_contents) {
-  DCHECK(web_contents);
-  SecurityStateTabHelper::CreateForWebContents(web_contents);
-  SecurityStateTabHelper* helper =
-      SecurityStateTabHelper::FromWebContents(web_contents);
-  DCHECK(helper);
-  return helper->GetSecurityLevel();
-}
-
-}  // namespace
 
 // static std::string
 std::string SslValidityChecker::GetInvalidSslCertificateErrorMessage(
@@ -97,4 +82,17 @@
   return true;
 }
 
+// static
+// Returns the security level of |web_contents|. The |web_contents|
+// parameter should not be null.
+security_state::SecurityLevel SslValidityChecker::GetSecurityLevel(
+    content::WebContents* web_contents) {
+  DCHECK(web_contents);
+  SecurityStateTabHelper::CreateForWebContents(web_contents);
+  SecurityStateTabHelper* helper =
+      SecurityStateTabHelper::FromWebContents(web_contents);
+  DCHECK(helper);
+  return helper->GetSecurityLevel();
+}
+
 }  // namespace payments
diff --git a/chrome/browser/payments/ssl_validity_checker.h b/chrome/browser/payments/ssl_validity_checker.h
index 7cd70d5a..9e38d1f 100644
--- a/chrome/browser/payments/ssl_validity_checker.h
+++ b/chrome/browser/payments/ssl_validity_checker.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "base/macros.h"
+#include "components/security_state/core/security_state.h"
 
 namespace content {
 class WebContents;
@@ -33,6 +34,9 @@
   static bool IsValidPageInPaymentHandlerWindow(
       content::WebContents* web_contents);
 
+  static security_state::SecurityLevel GetSecurityLevel(
+      content::WebContents* web_contents);
+
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(SslValidityChecker);
 };
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index 961aae6..48e50583e 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -252,6 +252,9 @@
   { key::kLegacySameSiteCookieBehaviorEnabled,
     prefs::kManagedDefaultLegacyCookieAccessSetting,
     base::Value::Type::INTEGER },
+  { key::kInsecurePrivateNetworkRequestsAllowed,
+    prefs::kManagedDefaultInsecurePrivateNetworkSetting,
+    base::Value::Type::BOOLEAN },
   { key::kDefaultPluginsSetting,
     prefs::kManagedDefaultPluginsSetting,
     base::Value::Type::INTEGER },
@@ -282,6 +285,9 @@
   { key::kLegacySameSiteCookieBehaviorEnabledForDomainList,
     prefs::kManagedLegacyCookieAccessAllowedForDomains,
     base::Value::Type::LIST },
+  { key::kInsecurePrivateNetworkRequestsAllowedForUrls,
+    prefs::kManagedInsecurePrivateNetworkAllowedForUrls,
+    base::Value::Type::LIST },
   { key::kPluginsAllowedForUrls,
     prefs::kManagedPluginsAllowedForUrls,
     base::Value::Type::LIST },
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille_background.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille_background.js
index 8af79b26..162b4e1 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille_background.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille_background.js
@@ -126,6 +126,11 @@
     this.displayManager_.panRight();
   }
 
+  /** @override */
+  route(displayPosition) {
+    return this.displayManager_.route(displayPosition);
+  }
+
   /**
    * @param {!NavBraille} newContent
    * @param {?string} newContentId
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/output.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/output.js
index ce51005b..15ead75 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/output.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/output.js
@@ -2151,7 +2151,7 @@
   article: {msgId: 'role_article', inherits: 'abstractItem'},
   application: {msgId: 'role_application', inherits: 'abstractContainer'},
   banner: {msgId: 'role_banner', inherits: 'abstractContainer'},
-  button: {msgId: 'role_button', earconId: 'BUTTON', inherits: 'button'},
+  button: {msgId: 'role_button', earconId: 'BUTTON'},
   buttonDropDown: {msgId: 'role_button', earconId: 'BUTTON'},
   checkBox: {msgId: 'role_checkbox'},
   columnHeader: {msgId: 'role_columnheader', inherits: 'cell'},
@@ -2420,10 +2420,6 @@
       speak: `$earcon(ALERT_MODAL) $name $nameOrTextContent $description $state
           $role`
     },
-    button: {
-      speak: `$name $node(activeDescendant) $state $restriction $role
-          $description`
-    },
     cell: {
       enter: {
         speak: `$cellIndexText $node(tableCellColumnHeaders) $nameFromNode
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/output_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/output_test.js
index b7d90ef..159e3a7 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/output_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/output_test.js
@@ -327,11 +327,12 @@
           ['Time control', [{value: 'role', start: 0, end: 12}]],
           ['Date control', [{value: 'role', start: 0, end: 12}]],
           [
-            'No file chosen, Choose File|Button',
+            'Choose File|No file chosen|Button',
             [
-              {value: 'name', start: 0, end: 27},
-              {value: new Output.EarconAction('BUTTON'), start: 0, end: 27},
-              {value: 'role', start: 28, end: 34}
+              {value: 'name', start: 0, end: 11},
+              {value: new Output.EarconAction('BUTTON'), start: 0, end: 11},
+              {value: 'value', start: 12, end: 26},
+              {value: 'role', start: 27, end: 33}
             ]
           ],
           '||Search', '||Edit text'
@@ -341,7 +342,7 @@
         const expectedBrailleValues = [
           ' ed', ' @ed 8dot', ' pwded', ' #ed', {string_: 'spnbtn', spans_: []},
           {string_: 'time'}, {string_: 'date'},
-          {string_: 'No file chosen, Choose File btn'}, ' search', ' ed'
+          {string_: 'Choose File No file chosen btn'}, ' search', ' ed'
         ];
         assertEquals(expectedSpeechValues.length, expectedBrailleValues.length);
 
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/braille/braille_display_manager.js b/chrome/browser/resources/chromeos/accessibility/chromevox/braille/braille_display_manager.js
index 7bf27996..22fdb82 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/braille/braille_display_manager.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/braille/braille_display_manager.js
@@ -388,11 +388,8 @@
         this.panRight();
         break;
       case BrailleKeyCommand.ROUTING:
-        event.displayPosition = this.brailleToTextPosition_(
-            event.displayPosition +
-            this.panStrategy_.viewPort.firstRow *
-                this.panStrategy_.displaySize.columns);
-      // fall through
+        this.route(event.displayPosition);
+        break;
       default:
         this.commandListener_(event, this.content_);
         break;
@@ -428,6 +425,24 @@
   }
 
   /**
+   * Moves the cursor to the given braille position.
+   * @param {number|undefined} braillePosition The 0-based position relative to
+   *     the start of the currently displayed text. The position is given in
+   *     braille cells, not text cells.
+   */
+  route(braillePosition) {
+    if (braillePosition == undefined) {
+      return;
+    }
+    const displayPosition = this.brailleToTextPosition_(
+        braillePosition +
+        this.panStrategy_.viewPort.firstRow *
+            this.panStrategy_.displaySize.columns);
+    this.commandListener_(
+        {command: BrailleKeyCommand.ROUTING, displayPosition}, this.content_);
+  }
+
+  /**
    * Sets a cursor within translated content.
    * @param {ArrayBuffer} buffer Buffer to add cursor to.
    * @param {number} startIndex The start index to place the cursor.
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/common/braille_interface.js b/chrome/browser/resources/chromeos/accessibility/chromevox/common/braille_interface.js
index 840627d..31badde 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/common/braille_interface.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/common/braille_interface.js
@@ -58,4 +58,12 @@
    * Requests the braille display pan right.
    */
   panRight() {}
+
+  /**
+   * Moves the cursor to the given braille position.
+   * @param {number|undefined} braillePosition The 0-based position relative to
+   *     the start of the currently displayed text. The position is given in
+   *     braille cells, not text cells.
+   */
+  route(braillePosition) {}
 };
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.js b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.js
index 648ad34..f1d334c3 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.js
@@ -660,8 +660,24 @@
       }
     };
 
+    const routeCursor = function(event) {
+      const cell = event.target;
+      if (cell.tagName == 'TD') {
+        const displayPosition = parseInt(cell.id.split('-')[0], 10);
+        if (Number.isNaN(displayPosition)) {
+          throw new Error(
+              'The display position is calculated assuming that the cell ID ' +
+              'is formatted like int-string. For example, 0-brailleCell is a ' +
+              'valid cell ID.');
+        }
+        chrome.extension.getBackgroundPage()['ChromeVox'].braille.route(
+            displayPosition);
+      }
+    };
+
     Panel.brailleContainer_.addEventListener('mouseover', addBorders);
     Panel.brailleContainer_.addEventListener('mouseout', removeBorders);
+    Panel.brailleContainer_.addEventListener('click', routeCursor);
 
     // Clear the tables.
     let rowCount = Panel.brailleTableElement_.rows.length;
diff --git a/chrome/browser/resources/chromeos/login/update_required_card.html b/chrome/browser/resources/chromeos/login/update_required_card.html
index 389e2a26..4bc443bd 100644
--- a/chrome/browser/resources/chromeos/login/update_required_card.html
+++ b/chrome/browser/resources/chromeos/login/update_required_card.html
@@ -120,11 +120,16 @@
 
     <oobe-dialog
         hidden="[[showOn_(ui_state, 'eol')]]" id="eolDialog"
-        title-key="eolTitle" subtitle-key="eolMessage" role="dialog"
-        aria-label$="[[i18nDynamic(locale, 'eolTitle')]]">
+        role="dialog" aria-labelledby="eolTitle">
       <hd-iron-icon slot="oobe-icon" id="eolAlertIcon"
           icon1x="oobe-32:warning" icon2x="oobe-64:warning">
       </hd-iron-icon>
+      <h1 id="eolTitle" slot="title">
+        [[i18nDynamic(locale, 'eolTitle', deviceName)]]
+      </h1>
+      <div slot="subtitle">
+        [[i18nDynamic(locale, 'eolMessage', deviceName)]]
+      </div>
       <div slot="footer" class="flex layout vertical">
         <div id="adminMessageContainer"
             hidden="[[isEmpty_(eolAdminMessage_)]]">
diff --git a/chrome/browser/resources/settings/metrics_browser_proxy.js b/chrome/browser/resources/settings/metrics_browser_proxy.js
index 243bedb3..d312574 100644
--- a/chrome/browser/resources/settings/metrics_browser_proxy.js
+++ b/chrome/browser/resources/settings/metrics_browser_proxy.js
@@ -53,8 +53,10 @@
   SAFETY_CHECK_PASSWORDS_MANAGE: 2,
   SAFETY_CHECK_SAFE_BROWSING_MANAGE: 3,
   SAFETY_CHECK_EXTENSIONS_REVIEW: 4,
+  SAFETY_CHECK_CHROME_CLEANER_REBOOT: 5,
+  SAFETY_CHECK_CHROME_CLEANER_REVIEW_INFECTED_STATE: 6,
   // Leave this at the end.
-  COUNT: 5,
+  COUNT: 7,
 };
 
 /** @interface */
diff --git a/chrome/browser/resources/settings/safety_check_page/safety_check_chrome_cleaner_child.js b/chrome/browser/resources/settings/safety_check_page/safety_check_chrome_cleaner_child.js
index 5b7372a..ba84f21 100644
--- a/chrome/browser/resources/settings/safety_check_page/safety_check_chrome_cleaner_child.js
+++ b/chrome/browser/resources/settings/safety_check_page/safety_check_chrome_cleaner_child.js
@@ -155,17 +155,35 @@
     }
   },
 
+  /**
+   * @param {!SafetyCheckInteractions} safetyCheckInteraction
+   * @param {!string} userAction
+   * @private
+   */
+  logUserInteraction_: function(safetyCheckInteraction, userAction) {
+    // Log user interaction both in user action and histogram.
+    this.metricsBrowserProxy_.recordSafetyCheckInteractionHistogram(
+        safetyCheckInteraction);
+    this.metricsBrowserProxy_.recordAction(userAction);
+  },
+
   /** @private */
   onButtonClick_: function() {
-    // TODO(crbug.com/1087263): Add metrics for safety check CCT child user
-    // actions.
     switch (this.status_) {
       case SafetyCheckChromeCleanerStatus.INFECTED:
+        this.logUserInteraction_(
+            SafetyCheckInteractions
+                .SAFETY_CHECK_CHROME_CLEANER_REVIEW_INFECTED_STATE,
+            'Settings.SafetyCheck.ChromeCleanerReviewInfectedState');
+        // Navigate to Chrome cleaner UI.
         Router.getInstance().navigateTo(
             routes.CHROME_CLEANUP,
             /* dynamicParams= */ null, /* removeSearch= */ true);
         break;
       case SafetyCheckChromeCleanerStatus.REBOOT_REQUIRED:
+        this.logUserInteraction_(
+            SafetyCheckInteractions.SAFETY_CHECK_CHROME_CLEANER_REBOOT,
+            'Settings.SafetyCheck.ChromeCleanerReboot');
         this.chromeCleanupBrowserProxy_.restartComputer();
         break;
       default:
diff --git a/chrome/browser/sync/profile_sync_service_factory.cc b/chrome/browser/sync/profile_sync_service_factory.cc
index 51deffd..8b3b7aa 100644
--- a/chrome/browser/sync/profile_sync_service_factory.cc
+++ b/chrome/browser/sync/profile_sync_service_factory.cc
@@ -83,10 +83,6 @@
 #include "chromeos/constants/chromeos_features.h"
 #endif  // defined(OS_CHROMEOS)
 
-#if defined(OS_WIN)
-#include "chrome/browser/sync/roaming_profile_directory_deleter_win.h"
-#endif  // defined(OS_WIN)
-
 namespace {
 
 void UpdateNetworkTimeOnUIThread(base::Time network_time,
@@ -271,12 +267,6 @@
 
   auto pss =
       std::make_unique<syncer::ProfileSyncService>(std::move(init_params));
-
-#if defined(OS_WIN)
-  if (!local_sync_backend_enabled)
-    DeleteRoamingUserDataDirectoryLater();
-#endif
-
   pss->Initialize();
 
   // Hook PSS into PersonalDataManager (a circular dependency).
diff --git a/chrome/browser/sync/roaming_profile_directory_deleter_win.cc b/chrome/browser/sync/roaming_profile_directory_deleter_win.cc
deleted file mode 100644
index 99c2cbab..0000000
--- a/chrome/browser/sync/roaming_profile_directory_deleter_win.cc
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/sync/roaming_profile_directory_deleter_win.h"
-
-#include "base/bind.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/metrics/histogram_functions.h"
-#include "base/path_service.h"
-#include "base/task/post_task.h"
-#include "base/task/thread_pool.h"
-#include "chrome/common/chrome_paths_internal.h"
-
-namespace {
-
-enum class RoamingUserDataDirectoryDeletionResult {
-  kError = 0,         // An unexpected error occurred during processing.
-  kDoesNotExist = 1,  // Roaming User Data dir does not exist.
-  kSucceeded = 2,     // Roaming User Data dir was deleted.
-  kFailed = 3,        // Roaming User Data dir could not be deleted.
-  kNotInAppData = 4,  // Roaming User Data dir is not within the AppData dir.
-  kMaxValue = kNotInAppData
-};
-
-// Deletes the user's roaming User Data directory if it is empty, along with any
-// of its parent directories leading up to the user's roaming AppData directory.
-RoamingUserDataDirectoryDeletionResult DeleteRoamingUserDataDirectoryImpl() {
-  base::FilePath to_delete;
-  if (!chrome::GetDefaultRoamingUserDataDirectory(&to_delete))
-    return RoamingUserDataDirectoryDeletionResult::kError;
-  if (!base::DirectoryExists(to_delete))
-    return RoamingUserDataDirectoryDeletionResult::kDoesNotExist;
-
-  base::FilePath app_data;
-  if (!base::PathService::Get(base::DIR_APP_DATA, &app_data))
-    return RoamingUserDataDirectoryDeletionResult::kError;
-  if (!app_data.IsParent(to_delete))
-    return RoamingUserDataDirectoryDeletionResult::kNotInAppData;
-
-  // Consider a failure to delete the deepest dir a failure. This likely means
-  // that the directory is not empty. Deleting intermediate dirs between it and
-  // the user's AppData directory is best-effort.
-  auto result = RoamingUserDataDirectoryDeletionResult::kFailed;
-  do {
-    // A non-recursive directory delete will fail if the directory is not empty.
-    if (!base::DeleteFile(to_delete))
-      return result;
-    result = RoamingUserDataDirectoryDeletionResult::kSucceeded;
-    to_delete = to_delete.DirName();
-  } while (app_data.IsParent(to_delete));
-  return result;
-}
-
-void DeleteRoamingUserDataDirectory() {
-  auto result = DeleteRoamingUserDataDirectoryImpl();
-  base::UmaHistogramEnumeration("Sync.DeleteRoamingUserDataDirectory", result);
-}
-
-}  // namespace
-
-void DeleteRoamingUserDataDirectoryLater() {
-  base::ThreadPool::PostTask(
-      FROM_HERE,
-      {base::TaskPriority::BEST_EFFORT,
-       base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN, base::MayBlock()},
-      base::BindOnce(&DeleteRoamingUserDataDirectory));
-}
diff --git a/chrome/browser/sync/roaming_profile_directory_deleter_win.h b/chrome/browser/sync/roaming_profile_directory_deleter_win.h
deleted file mode 100644
index a1d833e5..0000000
--- a/chrome/browser/sync/roaming_profile_directory_deleter_win.h
+++ /dev/null
@@ -1,21 +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.
-
-// In support of roaming profiles on Windows, Chrome can be configured to store
-// some profile data in a roaming profile location. Chrome accidentally created
-// this roaming User Data directory during sync startup even when roaming
-// profiles were not being used; see https://crbug.com/980487. This file here
-// provides a mechanism to clean up empty User Data directories created in the
-// default roaming profile location. This code should be deleted once the
-// DeleteRoamingUserDataDirectory metric indicates that most of the affected
-// population has been cleaned up.
-
-#ifndef CHROME_BROWSER_SYNC_ROAMING_PROFILE_DIRECTORY_DELETER_WIN_H_
-#define CHROME_BROWSER_SYNC_ROAMING_PROFILE_DIRECTORY_DELETER_WIN_H_
-
-// Deletes an empty roaming User Data directory at some later time in the
-// background.
-void DeleteRoamingUserDataDirectoryLater();
-
-#endif  // CHROME_BROWSER_SYNC_ROAMING_PROFILE_DIRECTORY_DELETER_WIN_H_
diff --git a/chrome/browser/sync/roaming_profile_directory_deleter_win_unittest.cc b/chrome/browser/sync/roaming_profile_directory_deleter_win_unittest.cc
deleted file mode 100644
index cd55c2e..0000000
--- a/chrome/browser/sync/roaming_profile_directory_deleter_win_unittest.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/sync/roaming_profile_directory_deleter_win.h"
-
-#include "base/base_paths.h"
-#include "base/files/file_util.h"
-#include "base/path_service.h"
-#include "base/test/scoped_path_override.h"
-#include "base/test/task_environment.h"
-#include "chrome/common/chrome_paths_internal.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-class DeleteRoamingUserDataDirectoryTest : public ::testing::Test {
- protected:
-  void SetUp() override {
-    // Get the path to the faux AppData directory and make sure it's empty (it
-    // had better be).
-    ASSERT_TRUE(base::PathService::Get(base::DIR_APP_DATA, &app_data_dir_));
-    ASSERT_TRUE(base::DirectoryExists(app_data_dir_));
-    ASSERT_TRUE(base::IsDirectoryEmpty(app_data_dir_));
-  }
-
-  // Creates the roaming User Data directory within the faux AppData dir. |dir|,
-  // if not null, is populated with the path to the created directory.
-  void MakeRoamingUserDataDirectory(base::FilePath* dir) {
-    roaming_user_data_dir_.emplace();
-    ASSERT_TRUE(
-        chrome::GetDefaultRoamingUserDataDirectory(&*roaming_user_data_dir_));
-    ASSERT_TRUE(base::CreateDirectory(*roaming_user_data_dir_));
-    if (dir)
-      *dir = *roaming_user_data_dir_;
-  }
-
-  const base::FilePath& app_data_dir() const { return app_data_dir_; }
-
-  void RunTasksUntilIdle() { task_environment_.RunUntilIdle(); }
-
- private:
-  base::test::TaskEnvironment task_environment_;
-  base::ScopedPathOverride app_data_override_{base::DIR_APP_DATA};
-  base::FilePath app_data_dir_;
-  base::Optional<base::FilePath> roaming_user_data_dir_;
-};
-
-// Tests that the roaming AppData directory is not touched when there is no
-// User Data dir within it.
-TEST_F(DeleteRoamingUserDataDirectoryTest, DoesNotExist) {
-  DeleteRoamingUserDataDirectoryLater();
-  RunTasksUntilIdle();
-  ASSERT_TRUE(base::DirectoryExists(app_data_dir()));
-  ASSERT_TRUE(base::IsDirectoryEmpty(app_data_dir()));
-}
-
-// Tests that an empty User Data directory and empty intermediate directories
-// are deleted.
-TEST_F(DeleteRoamingUserDataDirectoryTest, EmptyUserData) {
-  ASSERT_NO_FATAL_FAILURE(MakeRoamingUserDataDirectory(nullptr));
-  DeleteRoamingUserDataDirectoryLater();
-  RunTasksUntilIdle();
-  ASSERT_TRUE(base::DirectoryExists(app_data_dir()));
-  ASSERT_TRUE(base::IsDirectoryEmpty(app_data_dir()));
-}
-
-// Tests that a non-empty User Data directory is not touched.
-TEST_F(DeleteRoamingUserDataDirectoryTest, NonEmptyUserData) {
-  base::FilePath roaming_user_data_dir;
-  ASSERT_NO_FATAL_FAILURE(MakeRoamingUserDataDirectory(&roaming_user_data_dir));
-  ASSERT_EQ(
-      base::WriteFile(
-          roaming_user_data_dir.Append(FILE_PATH_LITERAL("file.txt")), "hi", 2),
-      2);
-  DeleteRoamingUserDataDirectoryLater();
-  RunTasksUntilIdle();
-  ASSERT_TRUE(base::DirectoryExists(roaming_user_data_dir));
-  ASSERT_FALSE(base::IsDirectoryEmpty(roaming_user_data_dir));
-}
diff --git a/chrome/browser/sync/test/integration/single_client_sessions_sync_test.cc b/chrome/browser/sync/test/integration/single_client_sessions_sync_test.cc
index a2ccdf2..89eb3f1 100644
--- a/chrome/browser/sync/test/integration/single_client_sessions_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_sessions_sync_test.cc
@@ -591,8 +591,10 @@
   ExpectNavigationChain({first_url, second_url});
 }
 
+// Flaky for reasons that likely have nothing to do with the test itself. See
+// crbug.com/1043899 and crbug.com/992207.
 IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest,
-                       NavigationChainAlteredDestructively) {
+                       DISABLED_NavigationChainAlteredDestructively) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(CheckInitialState(0));
 
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index f88d4aa..719b870 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -2639,6 +2639,8 @@
       "views/close_bubble_on_tab_activation_helper.h",
       "views/hats/hats_bubble_view.cc",
       "views/hats/hats_bubble_view.h",
+      "views/hats/hats_next_web_dialog.cc",
+      "views/hats/hats_next_web_dialog.h",
       "views/hats/hats_web_dialog.cc",
       "views/hats/hats_web_dialog.h",
       "views/profiles/incognito_menu_view.cc",
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd
index 4e5d2e5..953788b 100644
--- a/chrome/browser/ui/android/strings/android_chrome_strings.grd
+++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -1683,6 +1683,26 @@
         Update <ph name="PRODUCT_NAME">%1$s<ex>Chrome</ex></ph> to start sync
       </message>
 
+      <!-- Sync error card button strings -->
+      <message name="IDS_ANDROID_SYNC_DISABLED_ERROR_CARD_BUTTON" desc="Button text for android sync disabled error in sync error cards.">
+        Enable Android system sync
+      </message>
+      <message name="IDS_CLIENT_OUT_OF_DATE_ERROR_CARD_BUTTON" desc="Button text for client out of date error in sync error cards.">
+          Update <ph name="PRODUCT_NAME">%1$s<ex>Chrome</ex></ph>
+      </message>
+      <message name="IDS_PASSPHRASE_REQUIRED_ERROR_CARD_BUTTON" desc="Button text for passphrase required error in sync error cards.">
+        Enter passphrase
+      </message>
+      <message name="IDS_AUTH_ERROR_CARD_BUTTON" desc="Button text for auth error in sync error cards.">
+        Sign in again
+      </message>
+      <message name="IDS_SYNC_SETUP_INCOMPLETE_ERROR_CARD_CONFIRM_BUTTON" desc="Positive button text for advanced sync interrupted error in sync error cards.">
+        Confirm sync
+      </message>
+      <message name="IDS_TRUSTED_VAULT_ERROR_CARD_BUTTON" desc="Button text for trusted vault error in sync error cards.">
+        Unlock with Screen Lock
+      </message>
+
       <!-- Sync error strings -->
       <message name="IDS_SYNC_ERROR_GENERIC" desc="Sync error string for generic error. [CHAR-LIMIT=80]">
         Sync has stopped working
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ANDROID_SYNC_DISABLED_ERROR_CARD_BUTTON.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ANDROID_SYNC_DISABLED_ERROR_CARD_BUTTON.png.sha1
new file mode 100644
index 0000000..6a51d668
--- /dev/null
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ANDROID_SYNC_DISABLED_ERROR_CARD_BUTTON.png.sha1
@@ -0,0 +1 @@
+af3521f0b1ac2f72a1da64c6b416893f95381cb5
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_AUTH_ERROR_CARD_BUTTON.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_AUTH_ERROR_CARD_BUTTON.png.sha1
new file mode 100644
index 0000000..06d18af
--- /dev/null
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_AUTH_ERROR_CARD_BUTTON.png.sha1
@@ -0,0 +1 @@
+6572c00b3bb97e2b4090429604a2fc8bf687a997
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_CLIENT_OUT_OF_DATE_ERROR_CARD_BUTTON.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_CLIENT_OUT_OF_DATE_ERROR_CARD_BUTTON.png.sha1
new file mode 100644
index 0000000..e742c60
--- /dev/null
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_CLIENT_OUT_OF_DATE_ERROR_CARD_BUTTON.png.sha1
@@ -0,0 +1 @@
+d1c6f2bdc04c1881f1f359815945a5fb4d54795f
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PASSPHRASE_REQUIRED_ERROR_CARD_BUTTON.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PASSPHRASE_REQUIRED_ERROR_CARD_BUTTON.png.sha1
new file mode 100644
index 0000000..064c9e9
--- /dev/null
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PASSPHRASE_REQUIRED_ERROR_CARD_BUTTON.png.sha1
@@ -0,0 +1 @@
+f3bbcc26b06b1d1e17272adf06d006640ce8fc24
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_SYNC_SETUP_INCOMPLETE_ERROR_CARD_CONFIRM_BUTTON.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_SYNC_SETUP_INCOMPLETE_ERROR_CARD_CONFIRM_BUTTON.png.sha1
new file mode 100644
index 0000000..04c73e3
--- /dev/null
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_SYNC_SETUP_INCOMPLETE_ERROR_CARD_CONFIRM_BUTTON.png.sha1
@@ -0,0 +1 @@
+5cffa109f7e1342aee38d93b7231229553f2d1fd
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_TRUSTED_VAULT_ERROR_CARD_BUTTON.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_TRUSTED_VAULT_ERROR_CARD_BUTTON.png.sha1
new file mode 100644
index 0000000..15dbe2e
--- /dev/null
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_TRUSTED_VAULT_ERROR_CARD_BUTTON.png.sha1
@@ -0,0 +1 @@
+db6a020704f635af736f9724f5de4f072c33e8f2
\ No newline at end of file
diff --git a/chrome/browser/ui/commander/fuzzy_finder.h b/chrome/browser/ui/commander/fuzzy_finder.h
index 708b981..4b01797 100644
--- a/chrome/browser/ui/commander/fuzzy_finder.h
+++ b/chrome/browser/ui/commander/fuzzy_finder.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_UI_COMMANDER_FUZZY_FINDER_H_
 #define CHROME_BROWSER_UI_COMMANDER_FUZZY_FINDER_H_
 
+#include <vector>
+
 #include "base/strings/string16.h"
 #include "ui/gfx/range/range.h"
 
diff --git a/chrome/browser/ui/hats/hats_service.cc b/chrome/browser/ui/hats/hats_service.cc
index 2ddb9a5..1c1d697 100644
--- a/chrome/browser/ui/hats/hats_service.cc
+++ b/chrome/browser/ui/hats/hats_service.cc
@@ -51,6 +51,8 @@
 constexpr double kHatsSurveyProbabilityDefault = 0;
 
 constexpr char kHatsSurveyEnSiteIDDefault[] = "bhej2dndhpc33okm6xexsbyv4y";
+constexpr char kHatsNextSurveyTriggerIDDefault[] =
+    "zishSVViB0kPN8UwQ150VGjBKuBP";
 
 constexpr base::TimeDelta kMinimumTimeBetweenSurveyStarts =
     base::TimeDelta::FromDays(60);
@@ -151,12 +153,16 @@
                 .Get()));
   }
   // Ensure a default survey exists (for demo purpose).
+  auto* default_survey_id =
+      base::FeatureList::IsEnabled(
+          features::kHappinessTrackingSurveysForDesktopMigration)
+          ? kHatsNextSurveyTriggerIDDefault
+          : kHatsSurveyEnSiteIDDefault;
   if (survey_configs_by_triggers_.find(kHatsSurveyTriggerSatisfaction) ==
       survey_configs_by_triggers_.end()) {
     survey_configs_by_triggers_.emplace(
         kHatsSurveyTriggerSatisfaction,
-        SurveyConfig(kHatsSurveyProbabilityDefault,
-                     kHatsSurveyEnSiteIDDefault));
+        SurveyConfig(kHatsSurveyProbabilityDefault, default_survey_id));
   }
 }
 
@@ -421,14 +427,23 @@
   DCHECK(survey_configs_by_triggers_.find(trigger) !=
          survey_configs_by_triggers_.end());
 
-  if (!checker_)
-    checker_ = std::make_unique<HatsSurveyStatusChecker>(profile_);
-  checker_->CheckSurveyStatus(
-      survey_configs_by_triggers_[trigger].en_site_id_,
-      base::BindOnce(&HatsService::ShowSurvey, weak_ptr_factory_.GetWeakPtr(),
-                     browser, trigger),
-      base::BindOnce(&HatsService::OnSurveyStatusError,
-                     weak_ptr_factory_.GetWeakPtr(), trigger));
+  if (base::FeatureList::IsEnabled(
+          features::kHappinessTrackingSurveysForDesktopMigration)) {
+    // Bypass the checker for showing HaTS Next surveys as the survey website
+    // itself will determine eligibility. This is communicated via updates to
+    // HatsNextWebDialog::OnSurveyStateUpdateReceived.
+    browser->window()->ShowHatsBubble(
+        survey_configs_by_triggers_[trigger].en_site_id_);
+  } else {
+    if (!checker_)
+      checker_ = std::make_unique<HatsSurveyStatusChecker>(profile_);
+    checker_->CheckSurveyStatus(
+        survey_configs_by_triggers_[trigger].en_site_id_,
+        base::BindOnce(&HatsService::ShowSurvey, weak_ptr_factory_.GetWeakPtr(),
+                       browser, trigger),
+        base::BindOnce(&HatsService::OnSurveyStatusError,
+                       weak_ptr_factory_.GetWeakPtr(), trigger));
+  }
 }
 
 void HatsService::ShowSurvey(Browser* browser, const std::string& trigger) {
diff --git a/chrome/browser/ui/passwords/manage_passwords_state.cc b/chrome/browser/ui/passwords/manage_passwords_state.cc
index 89a97b6..8f5db8c 100644
--- a/chrome/browser/ui/passwords/manage_passwords_state.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_state.cc
@@ -186,8 +186,7 @@
       << state_;
   if (state_ == password_manager::ui::CREDENTIAL_REQUEST_STATE) {
     if (!credentials_callback_.is_null()) {
-      credentials_callback_.Run(nullptr);
-      credentials_callback_.Reset();
+      std::move(credentials_callback_).Run(nullptr);
     }
   }
   SetState(state);
@@ -233,10 +232,9 @@
 
 void ManagePasswordsState::ChooseCredential(const PasswordForm* form) {
   DCHECK_EQ(password_manager::ui::CREDENTIAL_REQUEST_STATE, state());
-  DCHECK(!credentials_callback().is_null());
+  DCHECK(!credentials_callback_.is_null());
 
-  credentials_callback().Run(form);
-  set_credentials_callback(ManagePasswordsState::CredentialsCallback());
+  std::move(credentials_callback_).Run(form);
 }
 
 void ManagePasswordsState::ClearData() {
diff --git a/chrome/browser/ui/passwords/manage_passwords_state.h b/chrome/browser/ui/passwords/manage_passwords_state.h
index a7b799bb..77f29c94 100644
--- a/chrome/browser/ui/passwords/manage_passwords_state.h
+++ b/chrome/browser/ui/passwords/manage_passwords_state.h
@@ -27,7 +27,7 @@
 class ManagePasswordsState {
  public:
   using CredentialsCallback =
-      base::Callback<void(const autofill::PasswordForm*)>;
+      base::OnceCallback<void(const autofill::PasswordForm*)>;
 
   ManagePasswordsState();
   ~ManagePasswordsState();
@@ -110,8 +110,8 @@
   const CredentialsCallback& credentials_callback() {
     return credentials_callback_;
   }
-  void set_credentials_callback(const CredentialsCallback& callback) {
-    credentials_callback_ = callback;
+  void set_credentials_callback(CredentialsCallback callback) {
+    credentials_callback_ = std::move(callback);
   }
 
   bool auth_for_account_storage_opt_in_failed() const {
diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
index bc69bfbb..d4a699b 100644
--- a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
@@ -193,7 +193,7 @@
 bool ManagePasswordsUIController::OnChooseCredentials(
     std::vector<std::unique_ptr<autofill::PasswordForm>> local_credentials,
     const url::Origin& origin,
-    const ManagePasswordsState::CredentialsCallback& callback) {
+    ManagePasswordsState::CredentialsCallback callback) {
   DCHECK(!local_credentials.empty());
   if (!HasBrowserWindow())
     return false;
@@ -205,7 +205,7 @@
   if (!local_credentials[0]->is_public_suffix_match)
     locals = CopyFormVector(local_credentials);
   passwords_data_.OnRequestCredentials(std::move(locals), origin);
-  passwords_data_.set_credentials_callback(callback);
+  passwords_data_.set_credentials_callback(std::move(callback));
   auto* raw_controller = new CredentialManagerDialogControllerImpl(
       Profile::FromBrowserContext(web_contents()->GetBrowserContext()), this);
   dialog_controller_.reset(raw_controller);
diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller.h b/chrome/browser/ui/passwords/manage_passwords_ui_controller.h
index a8ed0be..1362eec 100644
--- a/chrome/browser/ui/passwords/manage_passwords_ui_controller.h
+++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller.h
@@ -78,7 +78,7 @@
   bool OnChooseCredentials(
       std::vector<std::unique_ptr<autofill::PasswordForm>> local_credentials,
       const url::Origin& origin,
-      const ManagePasswordsState::CredentialsCallback& callback) override;
+      ManagePasswordsState::CredentialsCallback callback) override;
   void OnAutoSignin(
       std::vector<std::unique_ptr<autofill::PasswordForm>> local_forms,
       const url::Origin& origin) override;
diff --git a/chrome/browser/ui/passwords/passwords_client_ui_delegate.h b/chrome/browser/ui/passwords/passwords_client_ui_delegate.h
index 9538a76..474f74d 100644
--- a/chrome/browser/ui/passwords/passwords_client_ui_delegate.h
+++ b/chrome/browser/ui/passwords/passwords_client_ui_delegate.h
@@ -66,7 +66,7 @@
   virtual bool OnChooseCredentials(
       std::vector<std::unique_ptr<autofill::PasswordForm>> local_credentials,
       const url::Origin& origin,
-      const base::Callback<void(const autofill::PasswordForm*)>& callback) = 0;
+      base::OnceCallback<void(const autofill::PasswordForm*)> callback) = 0;
 
   // Called when user is auto signed in to the site. |local_forms[0]| contains
   // the credential returned to the site. |origin| is a URL of the site.
diff --git a/chrome/browser/ui/views/hats/hats_browsertest.cc b/chrome/browser/ui/views/hats/hats_browsertest.cc
index 276ce99..20a27d11 100644
--- a/chrome/browser/ui/views/hats/hats_browsertest.cc
+++ b/chrome/browser/ui/views/hats/hats_browsertest.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/ui/test/test_browser_dialog.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/hats/hats_bubble_view.h"
+#include "chrome/browser/ui/views/hats/hats_next_web_dialog.h"
 #include "chrome/browser/ui/views/hats/hats_web_dialog.h"
 #include "chrome/common/chrome_paths.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
@@ -178,3 +179,91 @@
             settings_map->GetContentSetting(
                 url2, url2, ContentSettingsType::COOKIES, std::string()));
 }
+
+class MockHatsNextWebDialog : public HatsNextWebDialog {
+ public:
+  MockHatsNextWebDialog(Browser* browser,
+                        const std::string& trigger_id,
+                        const GURL& hats_survey_url,
+                        const base::TimeDelta& timeout)
+      : HatsNextWebDialog(browser, trigger_id, hats_survey_url, timeout) {}
+
+  MOCK_METHOD0(ShowWidget, void());
+  MOCK_METHOD0(CloseWidget, void());
+};
+
+typedef InProcessBrowserTest HatsNextWebDialogBrowserTest;
+
+// Test that the web dialog correctly receives change to history state that
+// indicates a survey is ready to be shown.
+IN_PROC_BROWSER_TEST_F(HatsNextWebDialogBrowserTest, SurveyLoaded) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  auto* dialog = new MockHatsNextWebDialog(
+      browser(), "load_for_testing",
+      embedded_test_server()->GetURL("/hats/hats_next_mock.html"),
+      base::TimeDelta::FromSeconds(100));
+
+  // The hats_next_mock.html will provide a state update to the dialog to
+  // indicate that the survey has been loaded.
+  base::RunLoop run_loop;
+  EXPECT_CALL(*dialog, ShowWidget)
+      .WillOnce(testing::Invoke([dialog, &run_loop]() {
+        EXPECT_FALSE(dialog->IsWaitingForSurveyForTesting());
+        run_loop.Quit();
+      }));
+  run_loop.Run();
+}
+
+// Test that the web dialog correctly receives change to history state that
+// indicates the survey window should be closed.
+IN_PROC_BROWSER_TEST_F(HatsNextWebDialogBrowserTest, SurveyClosed) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  auto* dialog = new MockHatsNextWebDialog(
+      browser(), "close_for_testing",
+      embedded_test_server()->GetURL("/hats/hats_next_mock.html"),
+      base::TimeDelta::FromSeconds(100));
+
+  // The hats_next_mock.html will provide a state update to the dialog to
+  // indicate that the survey window should be closed.
+  base::RunLoop run_loop;
+  EXPECT_CALL(*dialog, CloseWidget).WillOnce([&run_loop]() {
+    run_loop.Quit();
+  });
+  run_loop.Run();
+}
+
+// Test that if the survey does not indicate it is ready for display before the
+// timeout the widget is closed.
+IN_PROC_BROWSER_TEST_F(HatsNextWebDialogBrowserTest, SurveyTimeout) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  auto* dialog = new MockHatsNextWebDialog(
+      browser(), "invalid_test",
+      embedded_test_server()->GetURL("/hats/non_existent.html"),
+      base::TimeDelta::FromMilliseconds(1));
+
+  base::RunLoop run_loop;
+  EXPECT_CALL(*dialog, CloseWidget).WillOnce([&run_loop]() {
+    run_loop.Quit();
+  });
+  run_loop.Run();
+}
+
+IN_PROC_BROWSER_TEST_F(HatsNextWebDialogBrowserTest, UnknownURLFragment) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  // Check that providing an unknown URL fragment results in the dialog being
+  // closed.
+  auto* dialog = new MockHatsNextWebDialog(
+      browser(), "invalid_url_fragment_for_testing",
+      embedded_test_server()->GetURL("/hats/hats_next_mock.html"),
+      base::TimeDelta::FromSeconds(100));
+
+  base::RunLoop run_loop;
+  EXPECT_CALL(*dialog, CloseWidget).WillOnce([&run_loop]() {
+    run_loop.Quit();
+  });
+  run_loop.Run();
+}
diff --git a/chrome/browser/ui/views/hats/hats_bubble_view.cc b/chrome/browser/ui/views/hats/hats_bubble_view.cc
index a30506b..3665342 100644
--- a/chrome/browser/ui/views/hats/hats_bubble_view.cc
+++ b/chrome/browser/ui/views/hats/hats_bubble_view.cc
@@ -13,7 +13,9 @@
 #include "chrome/browser/ui/views/frame/app_menu_button.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/toolbar_button_provider.h"
+#include "chrome/browser/ui/views/hats/hats_next_web_dialog.h"
 #include "chrome/browser/ui/views/hats/hats_web_dialog.h"
+#include "chrome/common/chrome_features.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/theme_resources.h"
@@ -70,7 +72,13 @@
   // The bubble will only show after the survey content is retrieved.
   // If it fails due to no internet connection or any other reason, the bubble
   // will not show.
-  HatsWebDialog::Create(browser, site_id);
+  if (base::FeatureList::IsEnabled(
+          features::kHappinessTrackingSurveysForDesktopMigration)) {
+    // Self deleting on close.
+    new HatsNextWebDialog(browser, site_id);
+  } else {
+    HatsWebDialog::Create(browser, site_id);
+  }
 }
 
 void HatsBubbleView::Show(Browser* browser,
diff --git a/chrome/browser/ui/views/hats/hats_next_web_dialog.cc b/chrome/browser/ui/views/hats/hats_next_web_dialog.cc
new file mode 100644
index 0000000..fbdeb26b
--- /dev/null
+++ b/chrome/browser/ui/views/hats/hats_next_web_dialog.cc
@@ -0,0 +1,193 @@
+// 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/views/hats/hats_next_web_dialog.h"
+
+#include "chrome/browser/ui/browser_dialogs.h"
+
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_destroyer.h"
+#include "chrome/browser/ui/views/frame/app_menu_button.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/frame/toolbar_button_provider.h"
+#include "chrome/browser/ui/views/hats/hats_bubble_view.h"
+#include "chrome/browser/ui/webui/chrome_web_contents_handler.h"
+#include "chrome/common/chrome_features.h"
+#include "chrome/common/chrome_isolated_world_ids.h"
+#include "components/constrained_window/constrained_window_views.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/render_frame_host.h"
+#include "net/base/url_util.h"
+#include "ui/base/ui_base_types.h"
+#include "ui/views/bubble/bubble_dialog_delegate_view.h"
+#include "ui/views/bubble/bubble_frame_view.h"
+#include "ui/views/controls/webview/web_dialog_view.h"
+#include "ui/views/layout/fill_layout.h"
+
+// A thin wrapper that forwards the reference part of the URL associated with
+// navigation events to the enclosing web dialog.
+class HatsNextWebDialog::WebContentsObserver
+    : public content::WebContentsObserver {
+ public:
+  WebContentsObserver(content::WebContents* contents, HatsNextWebDialog* dialog)
+      : content::WebContentsObserver(contents), dialog_(dialog) {}
+
+  // content::WebContentsObserver overrides.
+  void DidStartNavigation(
+      content::NavigationHandle* navigation_handle) override {
+    if (navigation_handle->IsSameDocument() &&
+        navigation_handle->IsRendererInitiated()) {
+      dialog_->OnSurveyStateUpdateReceived(navigation_handle->GetURL().ref());
+    }
+  }
+
+ private:
+  HatsNextWebDialog* dialog_;
+};
+
+HatsNextWebDialog::HatsNextWebDialog(Browser* browser,
+                                     const std::string& trigger_id)
+    : HatsNextWebDialog(
+          browser,
+          trigger_id,
+          GURL("https://storage.googleapis.com/chrome_hats/index.html"),
+          base::TimeDelta::FromSeconds(10)) {}
+
+ui::ModalType HatsNextWebDialog::GetDialogModalType() const {
+  return ui::MODAL_TYPE_NONE;
+}
+
+base::string16 HatsNextWebDialog::GetDialogTitle() const {
+  return base::string16();
+}
+
+GURL HatsNextWebDialog::GetDialogContentURL() const {
+  GURL param_url =
+      net::AppendQueryParameter(hats_survey_url_, "trigger_id", trigger_id_);
+  if (base::FeatureList::IsEnabled(
+          features::kHappinessTrackingSurveysForDesktopDemo)) {
+    param_url = net::AppendQueryParameter(param_url, "enable_testing", "true");
+  }
+  return param_url;
+}
+
+void HatsNextWebDialog::GetWebUIMessageHandlers(
+    std::vector<content::WebUIMessageHandler*>* handlers) const {}
+
+void HatsNextWebDialog::GetDialogSize(gfx::Size* size) const {}
+
+bool HatsNextWebDialog::CanResizeDialog() const {
+  return false;
+}
+
+std::string HatsNextWebDialog::GetDialogArgs() const {
+  return std::string();
+}
+
+void HatsNextWebDialog::OnDialogClosed(const std::string& json_retval) {}
+
+void HatsNextWebDialog::OnCloseContents(content::WebContents* source,
+                                        bool* out_close_dialog) {
+  *out_close_dialog = true;
+}
+
+bool HatsNextWebDialog::ShouldShowCloseButton() const {
+  return false;
+}
+
+bool HatsNextWebDialog::ShouldShowDialogTitle() const {
+  return false;
+}
+
+bool HatsNextWebDialog::HandleContextMenu(
+    content::RenderFrameHost* render_frame_host,
+    const content::ContextMenuParams& params) {
+  return true;
+}
+
+gfx::Size HatsNextWebDialog::CalculatePreferredSize() const {
+  // Default width/height of the dialog in screen size, these values are derived
+  // from the size of the HaTS HTML component displayed by this dialog.
+  constexpr int kDefaultHatsDialogWidth = 363;
+  constexpr int kDefaultHatsDialogHeight = 440;
+  return gfx::Size(kDefaultHatsDialogWidth, kDefaultHatsDialogHeight);
+}
+
+void HatsNextWebDialog::OnProfileWillBeDestroyed(Profile* profile) {
+  DCHECK_EQ(profile, otr_profile_);
+  otr_profile_ = nullptr;
+}
+
+HatsNextWebDialog::HatsNextWebDialog(Browser* browser,
+                                     const std::string& trigger_id,
+                                     const GURL& hats_survey_url,
+                                     const base::TimeDelta& timeout)
+    : BubbleDialogDelegateView(BrowserView::GetBrowserViewForBrowser(browser)
+                                   ->toolbar_button_provider()
+                                   ->GetAppMenuButton(),
+                               views::BubbleBorder::TOP_RIGHT),
+      otr_profile_(browser->profile()->GetOffTheRecordProfile(
+          Profile::OTRProfileID::CreateUnique("HaTSNext:WebDialog"))),
+      trigger_id_(trigger_id),
+      hats_survey_url_(hats_survey_url),
+      timeout_(timeout),
+      close_bubble_helper_(this, browser) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  otr_profile_->AddObserver(this);
+  set_close_on_deactivate(false);
+
+  SetButtons(ui::DIALOG_BUTTON_NONE);
+
+  SetLayoutManager(std::make_unique<views::FillLayout>());
+  auto* web_view = AddChildView(std::make_unique<views::WebDialogView>(
+      otr_profile_, this, std::make_unique<ChromeWebContentsHandler>(),
+      /* use_dialog_frame */ true));
+  widget_ = views::BubbleDialogDelegateView::CreateBubble(this);
+
+  web_contents_observer_ =
+      std::make_unique<WebContentsObserver>(web_view->web_contents(), this);
+
+  loading_timer_.Start(FROM_HERE, timeout_,
+                       base::BindOnce(&HatsNextWebDialog::CloseWidget,
+                                      weak_factory_.GetWeakPtr()));
+}
+
+HatsNextWebDialog::~HatsNextWebDialog() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  if (otr_profile_) {
+    otr_profile_->RemoveObserver(this);
+    ProfileDestroyer::DestroyProfileWhenAppropriate(otr_profile_);
+  }
+}
+
+void HatsNextWebDialog::OnSurveyStateUpdateReceived(std::string state) {
+  loading_timer_.AbandonAndStop();
+
+  if (state == "loaded") {
+    ShowWidget();
+  } else if (state == "close") {
+    CloseWidget();
+  } else {
+    LOG(ERROR) << "Unknown state provided in URL fragment by HaTS survey:"
+               << state;
+    CloseWidget();
+  }
+}
+
+void HatsNextWebDialog::SetHatsSurveyURLforTesting(GURL url) {
+  hats_survey_url_ = url;
+}
+
+void HatsNextWebDialog::ShowWidget() {
+  widget_->Show();
+}
+
+void HatsNextWebDialog::CloseWidget() {
+  widget_->Close();
+}
+
+bool HatsNextWebDialog::IsWaitingForSurveyForTesting() {
+  return loading_timer_.IsRunning();
+}
diff --git a/chrome/browser/ui/views/hats/hats_next_web_dialog.h b/chrome/browser/ui/views/hats/hats_next_web_dialog.h
new file mode 100644
index 0000000..dcb2babf
--- /dev/null
+++ b/chrome/browser/ui/views/hats/hats_next_web_dialog.h
@@ -0,0 +1,113 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_HATS_HATS_NEXT_WEB_DIALOG_H_
+#define CHROME_BROWSER_UI_VIEWS_HATS_HATS_NEXT_WEB_DIALOG_H_
+
+#include "chrome/browser/profiles/profile_observer.h"
+#include "chrome/browser/ui/views/close_bubble_on_tab_activation_helper.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "ui/views/bubble/bubble_dialog_delegate_view.h"
+#include "ui/views/controls/webview/web_dialog_view.h"
+#include "ui/views/window/dialog_delegate.h"
+#include "ui/web_dialogs/web_dialog_delegate.h"
+
+class Browser;
+class Profile;
+
+namespace views {
+class Widget;
+}  // namespace views
+
+// A dialog for displaying a Happiness Tracking Survey (HaTS) NEXT survey to
+// the user. The dialog presents a WebContents which connects to a publicly
+// accessible, Chrome specific, webpage which is responsible for displaying the
+// survey to users. The webpage has additional logic to provide information to
+// this dialog via URL fragments, such as whether a survey is ready to be shown
+// to the user.
+class HatsNextWebDialog : public ui::WebDialogDelegate,
+                          public views::BubbleDialogDelegateView,
+                          public content::WebContentsDelegate,
+                          public ProfileObserver {
+ public:
+  HatsNextWebDialog(Browser* browser, const std::string& trigger_id);
+  ~HatsNextWebDialog() override;
+  HatsNextWebDialog(const HatsNextWebDialog&) = delete;
+  HatsNextWebDialog& operator=(const HatsNextWebDialog&) = delete;
+
+  // 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;
+  bool CanResizeDialog() const override;
+  std::string GetDialogArgs() const override;
+  void OnDialogClosed(const std::string& json_retval) override;
+  void OnCloseContents(content::WebContents* source,
+                       bool* out_close_dialog) override;
+  bool ShouldShowCloseButton() const override;
+  bool ShouldShowDialogTitle() const override;
+  bool HandleContextMenu(content::RenderFrameHost* render_frame_host,
+                         const content::ContextMenuParams& params) override;
+
+  // BubbleDialogDelegateView:
+  gfx::Size CalculatePreferredSize() const override;
+
+  // ProfileObserver:
+  void OnProfileWillBeDestroyed(Profile* profile) override;
+
+ protected:
+  FRIEND_TEST_ALL_PREFIXES(HatsNextWebDialogBrowserTest, SurveyLoaded);
+
+  HatsNextWebDialog(Browser* browser,
+                    const std::string& trigger_id,
+                    const GURL& hats_survey_url_,
+                    const base::TimeDelta& timeout);
+
+  class WebContentsObserver;
+
+  // Fired by the observer when the survey page has pushed state to the window
+  // via URL fragments.
+  void OnSurveyStateUpdateReceived(std::string state);
+
+  // Provides mechanism to override URL requested by the dialog. Must be called
+  // before CreateWebDialog() to take effect.
+  void SetHatsSurveyURLforTesting(GURL url);
+
+  // Displays the widget to the user, called when the dialog believes a survey
+  // ready for display. Virtual to allow mocking in tests.
+  virtual void ShowWidget();
+
+  // Called by the dialog to close the widget due to timeout or the survey being
+  // closed. Virtual to allow mocking in tests.
+  virtual void CloseWidget();
+
+  // Returns whether the dialog is still waiting for the survey to load.
+  bool IsWaitingForSurveyForTesting();
+
+ private:
+  // A timer to prevent unresponsive loading of survey dialog.
+  base::OneShotTimer loading_timer_;
+
+  // The off-the-record profile used for browsing to the Chrome HaTS webpage.
+  Profile* otr_profile_;
+
+  // The HaTS Next survey trigger ID that is provided to the HaTS webpage.
+  const std::string& trigger_id_;
+
+  views::Widget* widget_ = nullptr;
+
+  std::unique_ptr<WebContentsObserver> web_contents_observer_;
+  GURL hats_survey_url_;
+
+  base::TimeDelta timeout_;
+
+  CloseBubbleOnTabActivationHelper close_bubble_helper_;
+
+  base::WeakPtrFactory<HatsNextWebDialog> weak_factory_{this};
+};
+
+#endif  // CHROME_BROWSER_UI_VIEWS_HATS_HATS_NEXT_WEB_DIALOG_H_
diff --git a/chrome/browser/ui/views/passwords/password_dialog_view_browsertest.cc b/chrome/browser/ui/views/passwords/password_dialog_view_browsertest.cc
index 736590e6..3b872c9 100644
--- a/chrome/browser/ui/views/passwords/password_dialog_view_browsertest.cc
+++ b/chrome/browser/ui/views/passwords/password_dialog_view_browsertest.cc
@@ -185,8 +185,8 @@
     const url::Origin& origin) {
   client()->PromptUserToChooseCredentials(
       std::move(local_credentials), origin,
-      base::Bind(&PasswordDialogViewTest::OnChooseCredential,
-                 base::Unretained(this)));
+      base::BindOnce(&PasswordDialogViewTest::OnChooseCredential,
+                     base::Unretained(this)));
   EXPECT_EQ(password_manager::ui::CREDENTIAL_REQUEST_STATE,
             controller()->GetState());
 }
@@ -407,8 +407,8 @@
       ChromePasswordManagerClient::FromWebContents(tab);
   client->PromptUserToChooseCredentials(
       std::move(local_credentials), url::Origin::Create(origin),
-      base::Bind(&PasswordDialogViewTest::OnChooseCredential,
-                 base::Unretained(this)));
+      base::BindOnce(&PasswordDialogViewTest::OnChooseCredential,
+                     base::Unretained(this)));
   EXPECT_EQ(password_manager::ui::CREDENTIAL_REQUEST_STATE,
             controller()->GetState());
   EXPECT_TRUE(controller()->current_account_chooser());
diff --git a/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc b/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc
index d492652a..59add058 100644
--- a/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc
+++ b/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc
@@ -15,11 +15,13 @@
 #include "chrome/browser/ui/views/payments/payment_request_dialog_view.h"
 #include "chrome/browser/ui/views/payments/payment_request_views_util.h"
 #include "chrome/grit/generated_resources.h"
+#include "components/omnibox/browser/location_bar_model_util.h"
 #include "components/payments/content/icon/icon_size.h"
 #include "components/payments/core/features.h"
 #include "components/payments/core/native_error_strings.h"
 #include "components/payments/core/payments_experimental_features.h"
 #include "components/payments/core/url_util.h"
+#include "components/security_state/core/security_state.h"
 #include "components/vector_icons/vector_icons.h"
 #include "components/web_modal/web_contents_modal_dialog_manager.h"
 #include "components/web_modal/web_contents_modal_dialog_manager_delegate.h"
@@ -67,6 +69,7 @@
   ReadOnlyOriginView(const base::string16& page_title,
                      const GURL& origin,
                      const SkBitmap* icon_bitmap,
+                     security_state::SecurityLevel security_level,
                      SkColor background_color,
                      views::ButtonListener* site_settings_listener) {
     auto title_origin_container = std::make_unique<views::View>();
@@ -105,15 +108,15 @@
                        1.0, views::GridLayout::ColumnSize::kUsePreferred, 0, 0);
     origin_layout->StartRow(views::GridLayout::kFixedSize, 0);
     if (PaymentsExperimentalFeatures::IsEnabled(
-            features::kPaymentHandlerLockIcon) &&
-        origin.SchemeIs(url::kHttpsScheme)) {
+            features::kPaymentHandlerSecurityIcon)) {
       // TODO(https://crbug.com/1052493):
       // Selecting the correct icon based on the SSL certificate state
       // and adding test coverage for this code path.
-      auto lock_icon = std::make_unique<views::ImageView>();
-      lock_icon->SetImage(gfx::CreateVectorIcon(vector_icons::kLockIcon, 16,
-                                                gfx::kChromeIconGrey));
-      origin_layout->AddView(std::move(lock_icon));
+      auto security_icon = std::make_unique<views::ImageView>();
+      security_icon->SetImage(gfx::CreateVectorIcon(
+          location_bar_model::GetSecurityVectorIcon(security_level), 16,
+          gfx::kChromeIconGrey));
+      origin_layout->AddView(std::move(security_icon));
     }
     auto* origin_label = origin_layout->AddView(
         std::make_unique<views::Label>(base::UTF8ToUTF16(origin.host())));
@@ -264,7 +267,10 @@
       GetHeaderBackground(header_view);
   return std::make_unique<ReadOnlyOriginView>(
       GetPaymentHandlerDialogTitle(web_contents()), origin,
-      state()->selected_app()->icon_bitmap(), background->get_color(), this);
+      state()->selected_app()->icon_bitmap(),
+      web_contents() ? SslValidityChecker::GetSecurityLevel(web_contents())
+                     : security_state::NONE,
+      background->get_color(), this);
 }
 
 std::unique_ptr<views::Background>
@@ -293,6 +299,7 @@
 void PaymentHandlerWebFlowViewController::VisibleSecurityStateChanged(
     content::WebContents* source) {
   DCHECK_EQ(source, web_contents());
+  UpdateHeaderView();
   if (!SslValidityChecker::IsValidPageInPaymentHandlerWindow(source))
     AbortPayment();
 }
diff --git a/chrome/browser/ui/webui/chromeos/login/update_required_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/update_required_screen_handler.cc
index 865adc31..148452c 100644
--- a/chrome/browser/ui/webui/chromeos/login/update_required_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/update_required_screen_handler.cc
@@ -46,6 +46,8 @@
   builder->Add("checkingForUpdatesTitle", IDS_CHECKING_FOR_UPDATES);
   builder->Add("updatingTitle", IDS_UPDATING_SCREEN_TITLE);
   builder->Add("updatingMessage", IDS_UPDATE_REQUIRED_UPDATING_MESSAGE);
+  builder->AddF("updatingMessage", IDS_UPDATE_REQUIRED_UPDATING_MESSAGE,
+                ui::GetChromeOSDeviceName());
   builder->Add("downloading", IDS_DOWNLOADING);
   builder->Add("downloadingTimeLeftLong", IDS_DOWNLOADING_TIME_LEFT_LONG);
   builder->Add("downloadingTimeLeftStatusOneHour",
diff --git a/chrome/browser/ui/webui/management_ui_handler.cc b/chrome/browser/ui/webui/management_ui_handler.cc
index 6ef3722..9e84d6f2 100644
--- a/chrome/browser/ui/webui/management_ui_handler.cc
+++ b/chrome/browser/ui/webui/management_ui_handler.cc
@@ -657,7 +657,8 @@
   response->SetStringPath(
       "eolMessage",
       l10n_util::GetStringFUTF16(IDS_MANAGEMENT_UPDATE_REQUIRED_EOL_MESSAGE,
-                                 base::UTF8ToUTF16(GetDeviceDomain())));
+                                 base::UTF8ToUTF16(GetDeviceDomain()),
+                                 ui::GetChromeOSDeviceName()));
   std::string eol_admin_message;
   chromeos::CrosSettings::Get()->GetString(
       chromeos::kDeviceMinimumVersionAueMessage, &eol_admin_message);
diff --git a/chrome/browser/ui/webui/management_ui_handler_unittest.cc b/chrome/browser/ui/webui/management_ui_handler_unittest.cc
index 00663e9..f39e275 100644
--- a/chrome/browser/ui/webui/management_ui_handler_unittest.cc
+++ b/chrome/browser/ui/webui/management_ui_handler_unittest.cc
@@ -829,9 +829,10 @@
   handler_.EnableUpdateRequiredEolInfo(true);
   SetUpProfileAndHandler();
 
-  EXPECT_EQ(GetUpdateRequiredEolMessage(),
-            l10n_util::GetStringFUTF16(
-                IDS_MANAGEMENT_UPDATE_REQUIRED_EOL_MESSAGE, device_domain()));
+  EXPECT_EQ(
+      GetUpdateRequiredEolMessage(),
+      l10n_util::GetStringFUTF16(IDS_MANAGEMENT_UPDATE_REQUIRED_EOL_MESSAGE,
+                                 device_domain(), ui::GetChromeOSDeviceName()));
   EXPECT_EQ(GetPageSubtitle(),
             l10n_util::GetStringFUTF16(IDS_MANAGEMENT_SUBTITLE_MANAGED_BY,
                                        l10n_util::GetStringUTF16(device_type),
diff --git a/chrome/browser/ui/webui/settings/chromeos/main_section.cc b/chrome/browser/ui/webui/settings/chromeos/main_section.cc
index 65cd4db3..0611621 100644
--- a/chrome/browser/ui/webui/settings/chromeos/main_section.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/main_section.cc
@@ -6,6 +6,7 @@
 
 #include "ash/public/cpp/resources/grit/ash_public_unscaled_resources.h"
 #include "base/feature_list.h"
+#include "base/i18n/message_formatter.h"
 #include "base/i18n/number_formatting.h"
 #include "base/no_destructor.h"
 #include "base/strings/utf_string_conversions.h"
@@ -34,6 +35,7 @@
 #include "content/public/browser/web_ui_data_source.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/webui/web_ui_util.h"
+#include "ui/chromeos/devicetype_utils.h"
 
 namespace chromeos {
 namespace settings {
@@ -82,18 +84,19 @@
           base::UTF8ToUTF16(connector->GetEnterpriseDisplayDomain());
       base::string16 link_url =
           base::UTF8ToUTF16(chrome::kChromeUIManagementURL);
-      if (days_remaining == 1) {
-        eol_return_banner_text = l10n_util::GetStringFUTF16(
-            IDS_SETTINGS_UPDATE_REQUIRED_EOL_BANNER_LAST_DAY, domain_name,
-            link_url);
-      } else if (days_remaining == 7) {
+      if (days_remaining == 7) {
         eol_return_banner_text = l10n_util::GetStringFUTF16(
             IDS_SETTINGS_UPDATE_REQUIRED_EOL_BANNER_ONE_WEEK, domain_name,
-            link_url);
+            ui::GetChromeOSDeviceName(), link_url);
       } else {
-        eol_return_banner_text = l10n_util::GetStringFUTF16(
-            IDS_SETTINGS_UPDATE_REQUIRED_EOL_BANNER_DAYS, domain_name,
-            base::FormatNumber(days_remaining), link_url);
+        eol_return_banner_text =
+            base::i18n::MessageFormatter::FormatWithNumberedArgs(
+                l10n_util::GetStringUTF16(
+                    IDS_SETTINGS_UPDATE_REQUIRED_EOL_BANNER_DAYS),
+                days_remaining,
+                base::UTF8ToUTF16(connector->GetEnterpriseDisplayDomain()),
+                ui::GetChromeOSDeviceName(),
+                base::UTF8ToUTF16(chrome::kChromeUIManagementURL));
       }
     }
   }
diff --git a/chrome/browser/web_applications/extensions/system_web_app_manager_bookmark_apps_unittest.cc b/chrome/browser/web_applications/extensions/system_web_app_manager_bookmark_apps_unittest.cc
index 4d8e45e..4d337730 100644
--- a/chrome/browser/web_applications/extensions/system_web_app_manager_bookmark_apps_unittest.cc
+++ b/chrome/browser/web_applications/extensions/system_web_app_manager_bookmark_apps_unittest.cc
@@ -399,6 +399,8 @@
   EXPECT_FALSE(install_requests[2].force_reinstall);
 }
 
+// Deprecated. See corresponding SystemWebAppManagerTest.InstallResultHistogram
+// test for web apps.
 TEST_F(SystemWebAppManagerTestBookmarkApps, InstallResultHistogram) {
   base::HistogramTester histograms;
   const std::string settings_app_install_result_histogram =
diff --git a/chrome/browser/web_applications/system_web_app_manager_unittest.cc b/chrome/browser/web_applications/system_web_app_manager_unittest.cc
index 91b57ab9..b00e125a 100644
--- a/chrome/browser/web_applications/system_web_app_manager_unittest.cc
+++ b/chrome/browser/web_applications/system_web_app_manager_unittest.cc
@@ -9,16 +9,20 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/containers/flat_map.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/task_traits.h"
 #include "base/test/bind_test_util.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/web_applications/components/externally_installed_web_app_prefs.h"
+#include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
 #include "chrome/browser/web_applications/components/web_app_icon_generator.h"
 #include "chrome/browser/web_applications/components/web_app_provider_base.h"
 #include "chrome/browser/web_applications/pending_app_manager_impl.h"
+#include "chrome/browser/web_applications/system_web_app_manager.h"
 #include "chrome/browser/web_applications/test/test_app_shortcut_manager.h"
 #include "chrome/browser/web_applications/test/test_data_retriever.h"
 #include "chrome/browser/web_applications/test/test_file_handler_manager.h"
@@ -669,6 +673,119 @@
   EXPECT_FALSE(install_requests[2].force_reinstall);
 }
 
+TEST_F(SystemWebAppManagerTest, InstallResultHistogram) {
+  base::HistogramTester histograms;
+  const std::string settings_app_install_result_histogram =
+      std::string(SystemWebAppManager::kInstallResultHistogramName) + ".Apps." +
+      kSettingsAppNameForLogging;
+  const std::string discover_app_install_result_histogram =
+      std::string(SystemWebAppManager::kInstallResultHistogramName) + ".Apps." +
+      kDiscoverAppNameForLogging;
+  // Profile category for Chrome OS testing environment is "Other".
+  const std::string profile_install_result_histogram =
+      std::string(SystemWebAppManager::kInstallResultHistogramName) +
+      ".Profiles.Other";
+
+  InitEmptyRegistrar();
+
+  {
+    PrepareSystemAppDataToRetrieve({{AppUrl1(), AppIconUrl1()}});
+    PrepareLoadUrlResults({AppUrl1()});
+
+    base::flat_map<SystemAppType, SystemAppInfo> system_apps;
+    system_apps.emplace(SystemAppType::SETTINGS,
+                        SystemAppInfo(kSettingsAppNameForLogging, AppUrl1()));
+    system_web_app_manager().SetSystemAppsForTesting(system_apps);
+
+    histograms.ExpectTotalCount(
+        SystemWebAppManager::kInstallResultHistogramName, 0);
+    histograms.ExpectTotalCount(settings_app_install_result_histogram, 0);
+    histograms.ExpectTotalCount(profile_install_result_histogram, 0);
+    histograms.ExpectTotalCount(
+        SystemWebAppManager::kInstallDurationHistogramName, 0);
+
+    StartAndWaitForAppsToSynchronize();
+
+    histograms.ExpectTotalCount(
+        SystemWebAppManager::kInstallResultHistogramName, 1);
+    histograms.ExpectBucketCount(
+        SystemWebAppManager::kInstallResultHistogramName,
+        InstallResultCode::kSuccessNewInstall, 1);
+    histograms.ExpectTotalCount(settings_app_install_result_histogram, 1);
+    histograms.ExpectBucketCount(settings_app_install_result_histogram,
+                                 InstallResultCode::kSuccessNewInstall, 1);
+    histograms.ExpectTotalCount(profile_install_result_histogram, 1);
+    histograms.ExpectBucketCount(profile_install_result_histogram,
+                                 InstallResultCode::kSuccessNewInstall, 1);
+    histograms.ExpectTotalCount(
+        SystemWebAppManager::kInstallDurationHistogramName, 1);
+  }
+
+  pending_app_manager().SetPreInstallCallback(base::BindLambdaForTesting(
+      [](const ExternalInstallOptions&) { return false; }));
+
+  {
+    base::flat_map<SystemAppType, SystemAppInfo> system_apps;
+    system_apps.emplace(SystemAppType::SETTINGS,
+                        SystemAppInfo(kSettingsAppNameForLogging, AppUrl1()));
+    system_apps.emplace(SystemAppType::DISCOVER,
+                        SystemAppInfo(kDiscoverAppNameForLogging, AppUrl2()));
+    system_web_app_manager().SetSystemAppsForTesting(system_apps);
+
+    StartAndWaitForAppsToSynchronize();
+
+    histograms.ExpectTotalCount(
+        SystemWebAppManager::kInstallResultHistogramName, 3);
+    histograms.ExpectBucketCount(
+        SystemWebAppManager::kInstallResultHistogramName,
+        InstallResultCode::kWebAppDisabled, 2);
+    histograms.ExpectTotalCount(settings_app_install_result_histogram, 2);
+    histograms.ExpectBucketCount(settings_app_install_result_histogram,
+                                 InstallResultCode::kWebAppDisabled, 1);
+    histograms.ExpectBucketCount(discover_app_install_result_histogram,
+                                 InstallResultCode::kWebAppDisabled, 1);
+  }
+  {
+    base::flat_map<SystemAppType, SystemAppInfo> system_apps;
+    system_apps.emplace(SystemAppType::SETTINGS,
+                        SystemAppInfo(kSettingsAppNameForLogging, AppUrl1()));
+    system_web_app_manager().SetSystemAppsForTesting(system_apps);
+
+    histograms.ExpectTotalCount(
+        SystemWebAppManager::kInstallDurationHistogramName, 2);
+    histograms.ExpectBucketCount(
+        settings_app_install_result_histogram,
+        InstallResultCode::kCancelledOnWebAppProviderShuttingDown, 0);
+    histograms.ExpectBucketCount(
+        profile_install_result_histogram,
+        InstallResultCode::kCancelledOnWebAppProviderShuttingDown, 0);
+
+    {
+      SystemWebAppWaiter waiter(&system_web_app_manager());
+      system_web_app_manager().Start();
+      system_web_app_manager().Shutdown();
+      waiter.Wait();
+    }
+
+    histograms.ExpectBucketCount(
+        SystemWebAppManager::kInstallResultHistogramName,
+        InstallResultCode::kCancelledOnWebAppProviderShuttingDown, 1);
+    histograms.ExpectBucketCount(
+        SystemWebAppManager::kInstallResultHistogramName,
+        InstallResultCode::kWebAppDisabled, 2);
+
+    histograms.ExpectBucketCount(
+        settings_app_install_result_histogram,
+        InstallResultCode::kCancelledOnWebAppProviderShuttingDown, 1);
+    histograms.ExpectBucketCount(
+        profile_install_result_histogram,
+        InstallResultCode::kCancelledOnWebAppProviderShuttingDown, 1);
+    // If install was interrupted by shutdown, do not report duration.
+    histograms.ExpectTotalCount(
+        SystemWebAppManager::kInstallDurationHistogramName, 2);
+  }
+}
+
 TEST_F(SystemWebAppManagerTest, AbandonFailedInstalls) {
   const std::vector<ExternalInstallOptions>& install_requests =
       pending_app_manager().install_requests();
diff --git a/chrome/browser/web_applications/test/test_pending_app_manager_impl.cc b/chrome/browser/web_applications/test/test_pending_app_manager_impl.cc
index b42259cc..a83b958 100644
--- a/chrome/browser/web_applications/test/test_pending_app_manager_impl.cc
+++ b/chrome/browser/web_applications/test/test_pending_app_manager_impl.cc
@@ -15,6 +15,13 @@
 
 void TestPendingAppManagerImpl::Install(ExternalInstallOptions install_options,
                                         OnceInstallCallback callback) {
+  if (pre_install_callback_ && !pre_install_callback_.Run(install_options)) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(std::move(callback), install_options.url,
+                                  InstallResultCode::kWebAppDisabled));
+    return;
+  }
+
   install_requests_.push_back(install_options);
   PendingAppManagerImpl::Install(install_options, std::move(callback));
 }
@@ -22,6 +29,12 @@
 void TestPendingAppManagerImpl::InstallApps(
     std::vector<ExternalInstallOptions> install_options_list,
     const RepeatingInstallCallback& callback) {
+  if (pre_install_callback_) {
+    for (auto& install_options : install_options_list)
+      Install(std::move(install_options), callback);
+    return;
+  }
+
   std::copy(install_options_list.begin(), install_options_list.end(),
             std::back_inserter(install_requests_));
   if (!drop_requests_for_testing_) {
@@ -40,4 +53,9 @@
                                        std::move(callback));
 }
 
+void TestPendingAppManagerImpl::SetPreInstallCallback(
+    PreInstallCallback callback) {
+  pre_install_callback_ = std::move(callback);
+}
+
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/test/test_pending_app_manager_impl.h b/chrome/browser/web_applications/test/test_pending_app_manager_impl.h
index 2527a67..9cef237 100644
--- a/chrome/browser/web_applications/test/test_pending_app_manager_impl.h
+++ b/chrome/browser/web_applications/test/test_pending_app_manager_impl.h
@@ -7,6 +7,8 @@
 
 #include <vector>
 
+#include "base/optional.h"
+#include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/pending_app_manager_impl.h"
 
 namespace web_app {
@@ -35,10 +37,16 @@
     drop_requests_for_testing_ = drop_requests_for_testing;
   }
 
+  using PreInstallCallback =
+      base::RepeatingCallback<bool(const ExternalInstallOptions&)>;
+
+  void SetPreInstallCallback(PreInstallCallback callback);
+
  private:
   std::vector<ExternalInstallOptions> install_requests_;
   std::vector<GURL> uninstall_requests_;
   bool drop_requests_for_testing_ = false;
+  PreInstallCallback pre_install_callback_;
 };
 
 }  // namespace web_app
diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc
index e24ad8c..128286a 100644
--- a/chrome/installer/setup/setup_main.cc
+++ b/chrome/installer/setup/setup_main.cc
@@ -602,7 +602,7 @@
   install_status = UninstallProduct(modify_params, remove_all, force, cmd_line);
 
   installer::CleanUpInstallationDirectoryAfterUninstall(
-      original_state, installer_state, setup_exe, &install_status);
+      installer_state.target_path(), setup_exe, &install_status);
 
   // The app and vendor dirs may now be empty. Make a last-ditch attempt to
   // delete them.
diff --git a/chrome/installer/setup/uninstall.cc b/chrome/installer/setup/uninstall.cc
index 8d3b5f3..ab11edc 100644
--- a/chrome/installer/setup/uninstall.cc
+++ b/chrome/installer/setup/uninstall.cc
@@ -314,8 +314,7 @@
 // to change the current directory to the TMP directory. On Windows, each
 // process has a handle to its CWD. If setup.exe's CWD happens to be within the
 // install directory, deletion will fail as a result of the open handle.
-bool MoveSetupOutOfInstallFolder(const InstallerState& installer_state,
-                                 const base::FilePath& setup_exe) {
+bool MoveSetupOutOfInstallFolder(const base::FilePath& setup_exe) {
   // The list of files which setup.exe depends on at runtime. Typically this is
   // solely setup.exe itself, but in component builds this also includes the
   // DLLs installed by setup.exe.
@@ -1079,15 +1078,13 @@
 }
 
 void CleanUpInstallationDirectoryAfterUninstall(
-    const InstallationState& original_state,
-    const InstallerState& installer_state,
+    const base::FilePath& target_path,
     const base::FilePath& setup_exe,
     InstallStatus* uninstall_status) {
   if (*uninstall_status != UNINSTALL_SUCCESSFUL &&
       *uninstall_status != UNINSTALL_REQUIRES_REBOOT) {
     return;
   }
-  const base::FilePath target_path(installer_state.target_path());
   if (target_path.empty()) {
     LOG(ERROR) << "No installation destination path.";
     *uninstall_status = UNINSTALL_FAILED;
@@ -1104,7 +1101,7 @@
   // In order to be able to remove the folder in which we're running, we need to
   // move setup.exe out of the install folder.
   // TODO(tommi): What if the temp folder is on a different volume?
-  MoveSetupOutOfInstallFolder(installer_state, setup_exe);
+  MoveSetupOutOfInstallFolder(setup_exe);
 
   // Remove files from "...\<product>\Application\<version>\Installer"
   if (!RemoveInstallerFiles(install_directory)) {
diff --git a/chrome/installer/setup/uninstall.h b/chrome/installer/setup/uninstall.h
index 0b17f86..8116bab3 100644
--- a/chrome/installer/setup/uninstall.h
+++ b/chrome/installer/setup/uninstall.h
@@ -19,7 +19,6 @@
 
 namespace installer {
 
-class InstallationState;
 class InstallerState;
 struct ModifyParams;
 
@@ -70,15 +69,13 @@
 // installer archive may be deleted. Empty directories will be pruned (or
 // scheduled for pruning after reboot, if necessary).
 //
-// original_state: The installation state of all products on the system.
-// installer_state: State associated with this operation.
+// target_path: Installation directory.
 // setup_exe: The path to the currently running setup.exe, which will be moved
 //     into a temporary directory to allow for deletion of the installation
 //     directory.
 // uninstall_status: the uninstall status so far (may change during invocation).
 void CleanUpInstallationDirectoryAfterUninstall(
-    const InstallationState& original_state,
-    const InstallerState& installer_state,
+    const base::FilePath& target_path,
     const base::FilePath& setup_exe,
     InstallStatus* uninstall_status);
 
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 418d9a4..4eaa8ff3 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1060,6 +1060,7 @@
       "../browser/page_load_metrics/observers/foreground_duration_ukm_observer_browsertest.cc",
       "../browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_page_load_metrics_observer_browsertest.cc",
       "../browser/page_load_metrics/observers/isolated_prerender_page_load_metrics_observer_browsertest.cc",
+      "../browser/page_load_metrics/observers/javascript_frameworks_ukm_observer_browsertest.cc",
       "../browser/page_load_metrics/observers/live_tab_count_page_load_metrics_observer_browsertest.cc",
       "../browser/page_load_metrics/observers/multi_tab_loading_page_load_metrics_observer_browsertest.cc",
       "../browser/page_load_metrics/observers/resource_metrics_observer_browsertest.cc",
@@ -3643,7 +3644,6 @@
       "../browser/chrome_browser_main_win_unittest.cc",
       "../browser/notifications/win/fake_notification_image_retainer.cc",
       "../browser/notifications/win/fake_notification_image_retainer.h",
-      "../browser/sync/roaming_profile_directory_deleter_win_unittest.cc",
       "../browser/ui/views/try_chrome_dialog_win/button_layout_unittest.cc",
     ]
     if (enable_widevine) {
diff --git a/chrome/test/data/hats/hats_next_mock.html b/chrome/test/data/hats/hats_next_mock.html
new file mode 100644
index 0000000..fd60fe2
--- /dev/null
+++ b/chrome/test/data/hats/hats_next_mock.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<html>
+  <head>
+    <script>
+      const params = new URLSearchParams(window.location.search);
+
+      if (params.get('trigger_id') == "load_for_testing") {
+        history.pushState('', '', '#loaded');
+      }
+
+      if (params.get('trigger_id') == "close_for_testing") {
+        history.pushState('', '', '#close');
+      }
+
+      if (params.get('trigger_id') == "invalid_url_fragment_for_testing") {
+        history.pushState('', '', '#foo');
+      }
+    </script>
+  </head>
+  <body>
+  </body>
+</html>
diff --git a/chrome/test/data/page_load_metrics/nextjs_page.html b/chrome/test/data/page_load_metrics/nextjs_page.html
new file mode 100644
index 0000000..c70f54b
--- /dev/null
+++ b/chrome/test/data/page_load_metrics/nextjs_page.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<script>
+  window.__NEXT_DATA__ = {
+    buildId: 'test',
+  };
+</script>
+<body>
+  <div id="__next">
+    This is a test to see if a page with a
+    <pre>window.__NEXT_DATA__</pre>
+    JavaScript object and has a node with id
+    <pre>__next</pre>
+    is using the Next.js Javascript framework.
+  </div>
+</body>
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index b306f83..a6cc2fd 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -1971,6 +1971,30 @@
     ]
   },
 
+  "InsecurePrivateNetworkRequestsAllowed": {
+    "os": ["win", "linux", "mac", "chromeos"],
+    "policy_pref_mapping_test": [
+      {
+        "policies": { "InsecurePrivateNetworkRequestsAllowed": false },
+        "prefs": { "profile.managed_default_content_settings.insecure_private_network": {} }
+      },
+      {
+        "policies": { "InsecurePrivateNetworkRequestsAllowed": true },
+        "prefs": { "profile.managed_default_content_settings.insecure_private_network": {} }
+      }
+    ]
+  },
+
+  "InsecurePrivateNetworkRequestsAllowedForUrls": {
+    "os": ["win", "linux", "mac", "chromeos"],
+    "policy_pref_mapping_test": [
+      {
+        "policies": { "InsecurePrivateNetworkRequestsAllowedForUrls": ["[*.]google.com"] },
+        "prefs": { "profile.managed_insecure_private_network_allowed_for_urls": {} }
+      }
+    ]
+  },
+
   "DefaultPluginsSetting": {
     "os": ["win", "linux", "mac", "chromeos"],
     "policy_pref_mapping_test": [
diff --git a/chrome/test/data/webui/settings/safety_check_chrome_cleaner_test.js b/chrome/test/data/webui/settings/safety_check_chrome_cleaner_test.js
index 56dacd3..09329c0 100644
--- a/chrome/test/data/webui/settings/safety_check_chrome_cleaner_test.js
+++ b/chrome/test/data/webui/settings/safety_check_chrome_cleaner_test.js
@@ -104,13 +104,19 @@
     page.remove();
   });
 
-  /** @return {!Promise} */
-  async function expectChromeCleanerRouteButtonClickActions() {
-    // User clicks review extensions button.
-    page.$$('#safetyCheckChild').$$('#button').click();
-    // // TODO(crbug.com/1087263): Ensure UMA is logged.
-    // Ensure the correct Settings page is shown.
-    assertEquals(routes.CHROME_CLEANUP, Router.getInstance().getCurrentRoute());
+  /**
+   * @param {!SafetyCheckInteractions} safetyCheckInteraction
+   * @param {!string} userAction
+   * @return {!Promise}
+   * @private
+   */
+  async function expectLogging(safetyCheckInteraction, userAction) {
+    assertEquals(
+        safetyCheckInteraction,
+        await metricsBrowserProxy.whenCalled(
+            'recordSafetyCheckInteractionHistogram'));
+    assertEquals(
+        userAction, await metricsBrowserProxy.whenCalled('recordAction'));
   }
 
   test('chromeCleanerHiddenUiTest', function() {
@@ -130,7 +136,7 @@
     });
   });
 
-  test('chromeCleanerInfectedTest', function() {
+  test('chromeCleanerInfectedTest', async function() {
     fireSafetyCheckChromeCleanerEvent(SafetyCheckChromeCleanerStatus.INFECTED);
     flush();
     assertSafetyCheckChild({
@@ -141,10 +147,17 @@
       buttonAriaLabel: 'Review device software',
       buttonClass: 'action-button',
     });
-    expectChromeCleanerRouteButtonClickActions();
+    // User clicks the button.
+    page.$$('#safetyCheckChild').$$('#button').click();
+    await expectLogging(
+        SafetyCheckInteractions
+            .SAFETY_CHECK_CHROME_CLEANER_REVIEW_INFECTED_STATE,
+        'Settings.SafetyCheck.ChromeCleanerReviewInfectedState');
+    // Ensure the correct Settings page is shown.
+    assertEquals(routes.CHROME_CLEANUP, Router.getInstance().getCurrentRoute());
   });
 
-  test('chromeCleanerRebootRequiredUiTest', function() {
+  test('chromeCleanerRebootRequiredUiTest', async function() {
     fireSafetyCheckChromeCleanerEvent(
         SafetyCheckChromeCleanerStatus.REBOOT_REQUIRED);
     flush();
@@ -156,9 +169,11 @@
       buttonAriaLabel: 'Restart computer',
       buttonClass: 'action-button',
     });
-    // User clicks review extensions button.
+    // User clicks the button.
     page.$$('#safetyCheckChild').$$('#button').click();
-    // TODO(crbug.com/1087263): Ensure UMA is logged.
+    await expectLogging(
+        SafetyCheckInteractions.SAFETY_CHECK_CHROME_CLEANER_REBOOT,
+        'Settings.SafetyCheck.ChromeCleanerReboot');
     // Ensure the browser proxy call is done.
     return chromeCleanupBrowserProxy.whenCalled('restartComputer');
   });
diff --git a/chrome/test/data/webui/test_api.js b/chrome/test/data/webui/test_api.js
index faba0fd..f100e365 100644
--- a/chrome/test/data/webui/test_api.js
+++ b/chrome/test/data/webui/test_api.js
@@ -67,7 +67,7 @@
  * will break. animationend events should still work.
  */
 Test.disableAnimationsAndTransitions = function() {
-  let all = document.body.querySelectorAll('*, * /deep/ *');
+  let all = document.body.querySelectorAll('*');
   const ZERO_MS_IMPORTANT = '0ms !important';
   for (let i = 0, l = all.length; i < l; ++i) {
     let style = all[i].style;
diff --git a/chromeos/dbus/cros_healthd/DEPS b/chromeos/dbus/cros_healthd/DEPS
index 08eb7e09..c939e19 100644
--- a/chromeos/dbus/cros_healthd/DEPS
+++ b/chromeos/dbus/cros_healthd/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
   "+chromeos/services/cros_healthd/public/mojom",
+  "+chromeos/services/network_health/public/mojom",
   "+mojo/public",
-]
\ No newline at end of file
+]
diff --git a/chromeos/dbus/cros_healthd/fake_cros_healthd_client.cc b/chromeos/dbus/cros_healthd/fake_cros_healthd_client.cc
index 5632d91..de695d5 100644
--- a/chromeos/dbus/cros_healthd/fake_cros_healthd_client.cc
+++ b/chromeos/dbus/cros_healthd/fake_cros_healthd_client.cc
@@ -88,5 +88,14 @@
   fake_service_.EmitLidClosedEventForTesting();
 }
 
+void FakeCrosHealthdClient::RequestNetworkHealthForTesting(
+    chromeos::network_health::mojom::NetworkHealthService::
+        GetHealthSnapshotCallback callback) {
+  // Flush the receiver, so any requests to send the NetworkHealthService remote
+  // are processed before the request is emitted.
+  receiver_.FlushForTesting();
+  fake_service_.RequestNetworkHealthForTesting(std::move(callback));
+}
+
 }  // namespace cros_healthd
 }  // namespace chromeos
diff --git a/chromeos/dbus/cros_healthd/fake_cros_healthd_client.h b/chromeos/dbus/cros_healthd/fake_cros_healthd_client.h
index 42e2c9e..6b313d0 100644
--- a/chromeos/dbus/cros_healthd/fake_cros_healthd_client.h
+++ b/chromeos/dbus/cros_healthd/fake_cros_healthd_client.h
@@ -68,6 +68,11 @@
   // Calls the lid event OnLidClosed on all registered lid observers.
   void EmitLidClosedEventForTesting();
 
+  // Requests the network health state using the NetworkHealthService remote.
+  void RequestNetworkHealthForTesting(
+      chromeos::network_health::mojom::NetworkHealthService::
+          GetHealthSnapshotCallback callback);
+
  private:
   FakeCrosHealthdService fake_service_;
   mojo::Receiver<mojom::CrosHealthdServiceFactory> receiver_{&fake_service_};
diff --git a/chromeos/dbus/cros_healthd/fake_cros_healthd_service.cc b/chromeos/dbus/cros_healthd/fake_cros_healthd_service.cc
index 72c9ff9..0b48af2 100644
--- a/chromeos/dbus/cros_healthd/fake_cros_healthd_service.cc
+++ b/chromeos/dbus/cros_healthd/fake_cros_healthd_service.cc
@@ -27,6 +27,12 @@
   event_receiver_set_.Add(this, std::move(service));
 }
 
+void FakeCrosHealthdService::SendNetworkHealthService(
+    mojo::PendingRemote<chromeos::network_health::mojom::NetworkHealthService>
+        remote) {
+  network_health_remote_.Bind(std::move(remote));
+}
+
 void FakeCrosHealthdService::GetAvailableRoutines(
     GetAvailableRoutinesCallback callback) {
   std::move(callback).Run(available_routines_);
@@ -194,5 +200,11 @@
     observer->OnLidClosed();
 }
 
+void FakeCrosHealthdService::RequestNetworkHealthForTesting(
+    chromeos::network_health::mojom::NetworkHealthService::
+        GetHealthSnapshotCallback callback) {
+  network_health_remote_->GetHealthSnapshot(std::move(callback));
+}
+
 }  // namespace cros_healthd
 }  // namespace chromeos
diff --git a/chromeos/dbus/cros_healthd/fake_cros_healthd_service.h b/chromeos/dbus/cros_healthd/fake_cros_healthd_service.h
index 12d1595..2e0dbfb 100644
--- a/chromeos/dbus/cros_healthd/fake_cros_healthd_service.h
+++ b/chromeos/dbus/cros_healthd/fake_cros_healthd_service.h
@@ -12,6 +12,7 @@
 #include "chromeos/services/cros_healthd/public/mojom/cros_healthd_diagnostics.mojom.h"
 #include "chromeos/services/cros_healthd/public/mojom/cros_healthd_events.mojom.h"
 #include "chromeos/services/cros_healthd/public/mojom/cros_healthd_probe.mojom.h"
+#include "chromeos/services/network_health/public/mojom/network_health.mojom.h"
 #include "mojo/public/cpp/bindings/receiver_set.h"
 #include "mojo/public/cpp/bindings/remote_set.h"
 
@@ -36,6 +37,9 @@
   void GetDiagnosticsService(
       mojom::CrosHealthdDiagnosticsServiceRequest service) override;
   void GetEventService(mojom::CrosHealthdEventServiceRequest service) override;
+  void SendNetworkHealthService(
+      mojo::PendingRemote<chromeos::network_health::mojom::NetworkHealthService>
+          remote) override;
 
   // CrosHealthdDiagnosticsService overrides:
   void GetAvailableRoutines(GetAvailableRoutinesCallback callback) override;
@@ -128,6 +132,11 @@
   // Calls the lid event OnLidClosed for all registered lid observers.
   void EmitLidClosedEventForTesting();
 
+  // Requests the network health state using the network_health_remote_.
+  void RequestNetworkHealthForTesting(
+      chromeos::network_health::mojom::NetworkHealthService::
+          GetHealthSnapshotCallback callback);
+
  private:
   // Used as the response to any GetAvailableRoutines IPCs received.
   std::vector<mojom::DiagnosticRoutineEnum> available_routines_;
@@ -149,6 +158,10 @@
       diagnostics_receiver_set_;
   mojo::ReceiverSet<mojom::CrosHealthdEventService> event_receiver_set_;
 
+  // NetworkHealthService remote.
+  mojo::Remote<chromeos::network_health::mojom::NetworkHealthService>
+      network_health_remote_;
+
   // Collection of registered Bluetooth observers.
   mojo::RemoteSet<mojom::CrosHealthdBluetoothObserver> bluetooth_observers_;
   // Collection of registered lid observers.
diff --git a/chromeos/services/cros_healthd/DEPS b/chromeos/services/cros_healthd/DEPS
index b5a57d6..fb9ea0f8 100644
--- a/chromeos/services/cros_healthd/DEPS
+++ b/chromeos/services/cros_healthd/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
   "+chromeos/dbus",
+  "+chromeos/services/network_health/public/mojom",
   "+mojo/public",
 ]
diff --git a/chromeos/services/cros_healthd/public/cpp/service_connection.cc b/chromeos/services/cros_healthd/public/cpp/service_connection.cc
index b86eed8..16d9252 100644
--- a/chromeos/services/cros_healthd/public/cpp/service_connection.cc
+++ b/chromeos/services/cros_healthd/public/cpp/service_connection.cc
@@ -112,6 +112,12 @@
   void GetDiagnosticsService(
       mojom::CrosHealthdDiagnosticsServiceRequest service) override;
   void GetProbeService(mojom::CrosHealthdProbeServiceRequest service) override;
+  void SetBindNetworkHealthServiceCallback(
+      BindNetworkHealthServiceCallback callback) override;
+
+  // Uses |bind_network_health_callback_| if set to bind a remote to the
+  // NetworkHealthService and send the PendingRemote to the CrosHealthdService.
+  void BindAndSendNetworkHealthService();
 
   // Binds the factory interface |cros_healthd_service_factory_| to an
   // implementation in the cros_healthd daemon, if it is not already bound. The
@@ -144,6 +150,10 @@
       cros_healthd_diagnostics_service_;
   mojo::Remote<mojom::CrosHealthdEventService> cros_healthd_event_service_;
 
+  // Repeating callback that binds a mojo::PendingRemote to the
+  // NetworkHealthService and returns it.
+  BindNetworkHealthServiceCallback bind_network_health_callback_;
+
   SEQUENCE_CHECKER(sequence_checker_);
 
   base::WeakPtrFactory<ServiceConnectionImpl> weak_factory_{this};
@@ -353,6 +363,22 @@
   cros_healthd_service_factory_->GetDiagnosticsService(std::move(service));
 }
 
+void ServiceConnectionImpl::SetBindNetworkHealthServiceCallback(
+    BindNetworkHealthServiceCallback callback) {
+  bind_network_health_callback_ = std::move(callback);
+  BindAndSendNetworkHealthService();
+}
+
+void ServiceConnectionImpl::BindAndSendNetworkHealthService() {
+  if (bind_network_health_callback_.is_null())
+    return;
+
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  EnsureCrosHealthdServiceFactoryIsBound();
+  auto remote = bind_network_health_callback_.Run();
+  cros_healthd_service_factory_->SendNetworkHealthService(std::move(remote));
+}
+
 void ServiceConnectionImpl::GetProbeService(
     mojom::CrosHealthdProbeServiceRequest service) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -428,6 +454,11 @@
   cros_healthd_event_service_.reset();
 
   EnsureCrosHealthdServiceFactoryIsBound();
+  // If the cros_healthd_service_factory_ was able to be rebound, resend the
+  // Chrome services to the CrosHealthd instance.
+  if (cros_healthd_service_factory_.is_bound()) {
+    BindAndSendNetworkHealthService();
+  }
 }
 
 void ServiceConnectionImpl::OnBootstrapMojoConnectionResponse(
diff --git a/chromeos/services/cros_healthd/public/cpp/service_connection.h b/chromeos/services/cros_healthd/public/cpp/service_connection.h
index 774be6e2..87d194e 100644
--- a/chromeos/services/cros_healthd/public/cpp/service_connection.h
+++ b/chromeos/services/cros_healthd/public/cpp/service_connection.h
@@ -10,9 +10,11 @@
 #include <cstdint>
 #include <string>
 
+#include "base/callback_forward.h"
 #include "base/optional.h"
 #include "chromeos/services/cros_healthd/public/mojom/cros_healthd.mojom.h"
 #include "chromeos/services/cros_healthd/public/mojom/cros_healthd_events.mojom.h"
+#include "chromeos/services/network_health/public/mojom/network_health.mojom.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 
 namespace chromeos {
@@ -25,6 +27,10 @@
  public:
   static ServiceConnection* GetInstance();
 
+  using BindNetworkHealthServiceCallback =
+      base::RepeatingCallback<mojo::PendingRemote<
+          chromeos::network_health::mojom::NetworkHealthService>()>;
+
   // Retrieve a list of available diagnostic routines. See
   // src/chromeos/service/cros_healthd/public/mojom/cros_healthd.mojom for
   // details.
@@ -201,6 +207,12 @@
   virtual void GetProbeService(
       mojom::CrosHealthdProbeServiceRequest service) = 0;
 
+  // Sets a callback to request bind a PendingRemote to the
+  // NetworkHealthService. This callback is invoked once when it is set, and
+  // anytime the mojo connection to CrosHealthd is disconnected.
+  virtual void SetBindNetworkHealthServiceCallback(
+      BindNetworkHealthServiceCallback callback) = 0;
+
  protected:
   ServiceConnection() = default;
   virtual ~ServiceConnection() = default;
diff --git a/chromeos/services/cros_healthd/public/cpp/service_connection_unittest.cc b/chromeos/services/cros_healthd/public/cpp/service_connection_unittest.cc
index 6661dfb..89c3f6b 100644
--- a/chromeos/services/cros_healthd/public/cpp/service_connection_unittest.cc
+++ b/chromeos/services/cros_healthd/public/cpp/service_connection_unittest.cc
@@ -24,6 +24,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using ::chromeos::network_health::mojom::NetworkHealthService;
 using ::testing::_;
 using ::testing::Invoke;
 using ::testing::StrictMock;
@@ -139,6 +140,29 @@
   mojo::Receiver<mojom::CrosHealthdPowerObserver> receiver_;
 };
 
+class MockNetworkHealthService : public NetworkHealthService {
+ public:
+  MockNetworkHealthService() : receiver_{this} {}
+  MockNetworkHealthService(const MockNetworkHealthService&) = delete;
+  MockNetworkHealthService& operator=(const MockNetworkHealthService&) = delete;
+
+  MOCK_METHOD(void,
+              GetNetworkList,
+              (NetworkHealthService::GetNetworkListCallback),
+              (override));
+  MOCK_METHOD(void,
+              GetHealthSnapshot,
+              (NetworkHealthService::GetHealthSnapshotCallback),
+              (override));
+
+  mojo::PendingRemote<NetworkHealthService> pending_remote() {
+    return receiver_.BindNewPipeAndPassRemote();
+  }
+
+ private:
+  mojo::Receiver<NetworkHealthService> receiver_;
+};
+
 class CrosHealthdServiceConnectionTest : public testing::Test {
  public:
   CrosHealthdServiceConnectionTest() = default;
@@ -451,6 +475,32 @@
   run_loop.Run();
 }
 
+// Test that we can set the callback to get the NetworkHealthService remote and
+// request the network health state snapshot.
+TEST_F(CrosHealthdServiceConnectionTest, SetBindNetworkHealthService) {
+  MockNetworkHealthService service;
+  ServiceConnection::GetInstance()->SetBindNetworkHealthServiceCallback(
+      base::BindLambdaForTesting(
+          [&service] { return service.pending_remote(); }));
+
+  base::RunLoop run_loop;
+  auto canned_response = network_health::mojom::NetworkHealthState::New();
+  EXPECT_CALL(service, GetHealthSnapshot(_))
+      .WillOnce(
+          Invoke([&](NetworkHealthService::GetHealthSnapshotCallback callback) {
+            std::move(callback).Run(canned_response.Clone());
+          }));
+
+  FakeCrosHealthdClient::Get()->RequestNetworkHealthForTesting(
+      base::BindLambdaForTesting(
+          [&](network_health::mojom::NetworkHealthStatePtr response) {
+            EXPECT_EQ(canned_response, response);
+            run_loop.Quit();
+          }));
+
+  run_loop.Run();
+}
+
 // Test that we can probe telemetry info.
 TEST_F(CrosHealthdServiceConnectionTest, ProbeTelemetryInfo) {
   auto response = mojom::TelemetryInfo::New();
diff --git a/chromeos/services/cros_healthd/public/mojom/BUILD.gn b/chromeos/services/cros_healthd/public/mojom/BUILD.gn
index 3bea3e0..422a06e 100644
--- a/chromeos/services/cros_healthd/public/mojom/BUILD.gn
+++ b/chromeos/services/cros_healthd/public/mojom/BUILD.gn
@@ -5,6 +5,7 @@
 import("//mojo/public/tools/bindings/mojom.gni")
 
 mojom("mojom") {
+  deps = [ "//chromeos/services/network_health/public/mojom" ]
   sources = [
     "cros_healthd.mojom",
     "cros_healthd_diagnostics.mojom",
diff --git a/chromeos/services/cros_healthd/public/mojom/cros_healthd.mojom b/chromeos/services/cros_healthd/public/mojom/cros_healthd.mojom
index 41ecfc3..adada98 100644
--- a/chromeos/services/cros_healthd/public/mojom/cros_healthd.mojom
+++ b/chromeos/services/cros_healthd/public/mojom/cros_healthd.mojom
@@ -13,9 +13,11 @@
 import "chromeos/services/cros_healthd/public/mojom/cros_healthd_diagnostics.mojom";
 import "chromeos/services/cros_healthd/public/mojom/cros_healthd_events.mojom";
 import "chromeos/services/cros_healthd/public/mojom/cros_healthd_probe.mojom";
+import "chromeos/services/network_health/public/mojom/network_health.mojom";
 
 // Factory interface which allows remote ends to request implementations of the
-// probe or diagnostics services.
+// probe or diagnostics services or to receive network services sent from
+// Chrome.
 interface CrosHealthdServiceFactory {
   // Returns a bound interface to the diagnostics service.
   GetDiagnosticsService(CrosHealthdDiagnosticsService& service);
@@ -23,6 +25,10 @@
   GetEventService(CrosHealthdEventService& service);
   // Returns a bound interface to the probe service.
   GetProbeService(CrosHealthdProbeService& service);
+  // Sends a bound interface to the Network Health service in Chrome.
+  SendNetworkHealthService(
+      pending_remote<
+          chromeos.network_health.mojom.NetworkHealthService> remote);
 };
 
 // Diagnostics interface exposed by the cros_healthd daemon. Consumed in Chrome
diff --git a/components/autofill_assistant/browser/controller.cc b/components/autofill_assistant/browser/controller.cc
index b15ec88..01203468 100644
--- a/components/autofill_assistant/browser/controller.cc
+++ b/components/autofill_assistant/browser/controller.cc
@@ -42,15 +42,6 @@
 // message.
 static constexpr int kAutostartInitialProgress = 5;
 
-// Parameter that allows setting the color of the overlay.
-const char kOverlayColorParameterName[] = "OVERLAY_COLORS";
-
-// Parameter that contains the current session username. Should be synced with
-// |SESSION_USERNAME_PARAMETER| from
-// .../password_manager/PasswordChangeLauncher.java
-// TODO(b/151401974): Eliminate duplicate parameter definitions.
-const char kPasswordChangeUsernameParameterName[] = "PASSWORD_CHANGE_USERNAME";
-
 // Experiment for toggling the new progress bar.
 const char kProgressBarExperiment[] = "4400697";
 
@@ -1027,7 +1018,7 @@
     SetDetails(std::move(details));
 
   const base::Optional<std::string> overlay_color =
-      trigger_context_->GetParameter(kOverlayColorParameterName);
+      trigger_context_->GetOverlayColors();
   if (overlay_color) {
     std::unique_ptr<OverlayColors> colors = std::make_unique<OverlayColors>();
     std::vector<std::string> color_strings =
@@ -1045,9 +1036,11 @@
     SetOverlayColors(std::move(colors));
   }
   const base::Optional<std::string> password_change_username =
-      trigger_context_->GetParameter(kPasswordChangeUsernameParameterName);
+      trigger_context_->GetPasswordChangeUsername();
   if (password_change_username) {
-    user_data_->selected_login_.emplace(web_contents()->GetLastCommittedURL(),
+    DCHECK(
+        GetCurrentURL().is_valid());  // At least |deeplink_url_| must be set.
+    user_data_->selected_login_.emplace(GetCurrentURL().GetOrigin(),
                                         *password_change_username);
   }
 
@@ -1087,20 +1080,10 @@
       state_ != AutofillAssistantState::TRACKING) {
     return false;
   }
-  // Verify a password change intent before running.
-  // TODO(b/151391231): Remove when intent signing is implemented.
-  if (trigger_context->GetParameter(kPasswordChangeUsernameParameterName)) {
-    auto* password_manager_client = client_->GetPasswordManagerClient();
-    if (!password_manager_client ||
-        !password_manager_client->WasCredentialLeakDialogShown()) {
-      VLOG(1) << "Failed to start a password change flow.";
-      return false;
-    }
-  }
 
   trigger_context_ = std::move(trigger_context);
-  InitFromParameters();
   deeplink_url_ = deeplink_url;
+  InitFromParameters();
 
   // Force a re-evaluation of the script, to get a chance to autostart.
   if (state_ == AutofillAssistantState::TRACKING)
diff --git a/components/autofill_assistant/browser/controller_unittest.cc b/components/autofill_assistant/browser/controller_unittest.cc
index 308b7362..b9c01176 100644
--- a/components/autofill_assistant/browser/controller_unittest.cc
+++ b/components/autofill_assistant/browser/controller_unittest.cc
@@ -24,7 +24,6 @@
 #include "components/autofill_assistant/browser/service.h"
 #include "components/autofill_assistant/browser/trigger_context.h"
 #include "components/autofill_assistant/browser/web/mock_web_controller.h"
-#include "components/password_manager/core/browser/stub_password_manager_client.h"
 #include "content/public/test/navigation_simulator.h"
 #include "content/public/test/test_browser_context.h"
 #include "content/public/test/test_renderer_host.h"
@@ -62,12 +61,6 @@
 
 namespace {
 
-class MockPasswordManagerClient
-    : public password_manager::StubPasswordManagerClient {
- public:
-  MOCK_CONST_METHOD0(WasCredentialLeakDialogShown, bool());
-};
-
 // Same as non-mock, but provides default mock callbacks.
 struct MockCollectUserDataOptions : public CollectUserDataOptions {
   MockCollectUserDataOptions() {
@@ -104,8 +97,6 @@
     mock_service_ = service.get();
 
     ON_CALL(mock_client_, GetWebContents).WillByDefault(Return(web_contents()));
-    ON_CALL(mock_client_, GetPasswordManagerClient)
-        .WillByDefault(Return(&mock_password_manager_client_));
     ON_CALL(mock_client_, HasHadUI()).WillByDefault(Return(true));
 
     controller_ = std::make_unique<Controller>(
@@ -228,7 +219,6 @@
   MockWebController* mock_web_controller_;
   NiceMock<MockClient> mock_client_;
   NiceMock<MockControllerObserver> mock_observer_;
-  MockPasswordManagerClient mock_password_manager_client_;
   std::unique_ptr<Controller> controller_;
 };
 
@@ -2398,9 +2388,6 @@
 }
 
 TEST_F(ControllerTest, StartPasswordChangeFlow) {
-  EXPECT_CALL(mock_password_manager_client_, WasCredentialLeakDialogShown())
-      .WillOnce(Return(true));
-
   GURL initialUrl("http://example.com/password");
   EXPECT_CALL(*mock_service_, OnGetScriptsForUrl(Eq(initialUrl), _, _))
       .WillOnce(RunOnceCallback<2>(true, ""));
@@ -2413,24 +2400,6 @@
   EXPECT_EQ(GetUserData()->selected_login_->username, username);
 }
 
-TEST_F(ControllerTest, BlockPasswordChangeFlow) {
-  // If the password manager doesn't confirm that a leak dialog was shown, the
-  // flow should not start.
-  EXPECT_CALL(mock_password_manager_client_, WasCredentialLeakDialogShown())
-      .WillOnce(Return(false));
-
-  GURL initialUrl("http://example.com/password");
-  EXPECT_CALL(*mock_service_, OnGetScriptsForUrl(Eq(initialUrl), _, _))
-      .Times(0);
-  std::map<std::string, std::string> parameters;
-  std::string username = "test_username";
-  parameters["PASSWORD_CHANGE_USERNAME"] = username;
-
-  EXPECT_FALSE(
-      controller_->Start(initialUrl, TriggerContext::Create(parameters, "")));
-  EXPECT_FALSE(GetUserData()->selected_login_);
-}
-
 TEST_F(ControllerTest, EndPromptWithOnEndNavigation) {
   // A single script, with a prompt action and on_end_navigation enabled.
   SupportsScriptResponseProto script_response;
diff --git a/components/autofill_assistant/browser/trigger_context.cc b/components/autofill_assistant/browser/trigger_context.cc
index ae904963..cccf4bca 100644
--- a/components/autofill_assistant/browser/trigger_context.cc
+++ b/components/autofill_assistant/browser/trigger_context.cc
@@ -5,6 +5,17 @@
 #include "components/autofill_assistant/browser/trigger_context.h"
 #include "base/strings/string_split.h"
 
+namespace {
+// Parameter that allows setting the color of the overlay.
+const char kOverlayColorParameterName[] = "OVERLAY_COLORS";
+
+// Parameter that contains the current session username. Should be synced with
+// |SESSION_USERNAME_PARAMETER| from
+// .../password_manager/PasswordChangeLauncher.java
+// TODO(b/151401974): Eliminate duplicate parameter definitions.
+const char kPasswordChangeUsernameParameterName[] = "PASSWORD_CHANGE_USERNAME";
+}  // namespace
+
 namespace autofill_assistant {
 
 // static
@@ -28,6 +39,14 @@
 TriggerContext::TriggerContext() {}
 TriggerContext::~TriggerContext() {}
 
+base::Optional<std::string> TriggerContext::GetOverlayColors() const {
+  return GetParameter(kOverlayColorParameterName);
+}
+
+base::Optional<std::string> TriggerContext::GetPasswordChangeUsername() const {
+  return GetParameter(kPasswordChangeUsernameParameterName);
+}
+
 TriggerContextImpl::TriggerContextImpl() {}
 
 TriggerContextImpl::TriggerContextImpl(
diff --git a/components/autofill_assistant/browser/trigger_context.h b/components/autofill_assistant/browser/trigger_context.h
index 5c6695f..cb201d3 100644
--- a/components/autofill_assistant/browser/trigger_context.h
+++ b/components/autofill_assistant/browser/trigger_context.h
@@ -44,6 +44,10 @@
   virtual base::Optional<std::string> GetParameter(
       const std::string& name) const = 0;
 
+  // Getters for specific parameters.
+  base::Optional<std::string> GetOverlayColors() const;
+  base::Optional<std::string> GetPasswordChangeUsername() const;
+
   // Returns a comma-separated set of experiment ids.
   virtual std::string experiment_ids() const = 0;
 
diff --git a/components/browser_ui/site_settings/android/java/res/xml/single_website_preferences.xml b/components/browser_ui/site_settings/android/java/res/xml/single_website_preferences.xml
index c78921a1..e32059c 100644
--- a/components/browser_ui/site_settings/android/java/res/xml/single_website_preferences.xml
+++ b/components/browser_ui/site_settings/android/java/res/xml/single_website_preferences.xml
@@ -7,6 +7,10 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto">
 
+    <org.chromium.components.browser_ui.settings.TextMessagePreference
+        android:key="page_description"
+        app:iconSpaceReserved="false"
+        android:summary="@string/website_settings_permissions_description"/>
     <org.chromium.components.browser_ui.settings.ChromeBasePreference
         android:key="os_permissions_warning" />
     <org.chromium.components.browser_ui.settings.ChromeBasePreference
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java
index 94c2306..2fce3b4 100644
--- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java
+++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java
@@ -55,9 +55,11 @@
 
     // Preference keys, see single_website_preferences.xml
     // Headings:
+    public static final String PREF_PAGE_DESCRIPTION = "page_description";
+    public static final String PREF_SITE_HEADING = "site_heading";
     public static final String PREF_SITE_TITLE = "site_title";
     public static final String PREF_USAGE = "site_usage";
-    public static final String PREF_PERMISSIONS = "site_permissions";
+    public static final String PREF_PERMISSIONS_HEADER = "site_permissions";
     public static final String PREF_OS_PERMISSIONS_WARNING = "os_permissions_warning";
     public static final String PREF_OS_PERMISSIONS_WARNING_EXTRA = "os_permissions_warning_extra";
     public static final String PREF_OS_PERMISSIONS_WARNING_DIVIDER =
@@ -97,6 +99,20 @@
             "vr_permission_list", // PermissionInfo.Type.VIRTUAL_REALITY
     };
 
+    // A list of preferences keys that will be hidden on this page if this boolean below is true
+    private boolean mHideNonPermissionPreferences;
+    private static final String[] NON_PERMISSION_PREFERENCES = {
+            PREF_SITE_HEADING,
+            PREF_SITE_TITLE,
+            PREF_USAGE,
+            PREF_PERMISSIONS_HEADER,
+            PREF_CLEAR_DATA,
+    };
+
+    // Determines if this page will refresh its permissions display after clear and reset is
+    // clicked.
+    private boolean mRefreshAfterReset;
+
     private static final int REQUEST_CODE_NOTIFICATION_CHANNEL_SETTINGS = 1;
 
     private final SiteDataCleaner mSiteDataCleaner = new SiteDataCleaner();
@@ -173,7 +189,11 @@
     @Override
     public void onActivityCreated(Bundle savedInstanceState) {
         getActivity().setTitle(R.string.prefs_site_settings);
+        init();
+        super.onActivityCreated(savedInstanceState);
+    }
 
+    private void init() {
         Object extraSite = getArguments().getSerializable(EXTRA_SITE);
         Object extraSiteAddress = getArguments().getSerializable(EXTRA_SITE_ADDRESS);
 
@@ -193,8 +213,6 @@
 
         // Disable animations of preference changes.
         getListView().setItemAnimator(null);
-
-        super.onActivityCreated(savedInstanceState);
     }
 
     @Override
@@ -215,6 +233,14 @@
         }
     }
 
+    public void setHideNonPermissionPreferences(boolean hide) {
+        mHideNonPermissionPreferences = hide;
+    }
+
+    public void setRefreshAfterReset(boolean refresh) {
+        mRefreshAfterReset = refresh;
+    }
+
     /**
      * Given an address and a list of sets of websites, returns a new site with the same origin
      * as |address| which has merged into it the permissions and storage info of the matching input
@@ -298,6 +324,9 @@
      * Must only be called once mSite is set.
      */
     private void displaySitePermissions() {
+        if (getPreferenceScreen() != null) {
+            getPreferenceScreen().removeAll();
+        }
         SettingsUtils.addPreferencesFromResource(this, R.xml.single_website_preferences);
 
         Set<String> permissionPreferenceKeys =
@@ -325,7 +354,16 @@
             removePreferenceSafely(PREF_USAGE);
         }
         if (!hasPermissionsPreferences()) {
-            removePreferenceSafely(PREF_PERMISSIONS);
+            removePreferenceSafely(PREF_PERMISSIONS_HEADER);
+        }
+
+        // Remove certain preferences explicitly
+        if (mHideNonPermissionPreferences) {
+            for (String key : NON_PERMISSION_PREFERENCES) {
+                removePreferenceSafely(key);
+            }
+        } else {
+            removePreferenceSafely(PREF_PAGE_DESCRIPTION);
         }
     }
 
@@ -630,7 +668,7 @@
                         mObjectUserPermissionCount--;
 
                         if (!hasPermissionsPreferences()) {
-                            removePreferenceSafely(PREF_PERMISSIONS);
+                            removePreferenceSafely(PREF_PERMISSIONS_HEADER);
                         }
                     });
 
@@ -947,7 +985,8 @@
     }
 
     private void popBackIfNoSettings() {
-        if (!hasPermissionsPreferences() && !hasUsagePreferences() && getActivity() != null) {
+        if (!hasPermissionsPreferences() && !hasUsagePreferences() && getActivity() != null
+                && !mRefreshAfterReset) {
             getActivity().finish();
         }
     }
@@ -1022,7 +1061,9 @@
         RecordHistogram.recordEnumeratedHistogram("SingleWebsitePreferences.NavigatedFromToReset",
                 navigationSource, SettingsNavigationSource.NUM_ENTRIES);
 
-        if (finishActivityImmediately) {
+        if (mRefreshAfterReset) {
+            init();
+        } else if (finishActivityImmediately) {
             getActivity().finish();
         }
     }
diff --git a/components/browser_ui/strings/android/site_settings.grdp b/components/browser_ui/strings/android/site_settings.grdp
index ac881a0b..900e3bd 100644
--- a/components/browser_ui/strings/android/site_settings.grdp
+++ b/components/browser_ui/strings/android/site_settings.grdp
@@ -141,6 +141,9 @@
   <message name="IDS_WEBSITE_SETTINGS_PERMISSIONS_CATEGORY" desc="The headline above all the permissions on the website details page.">
     Permissions
   </message>
+  <message name="IDS_WEBSITE_SETTINGS_PERMISSIONS_DESCRIPTION" desc="The description explaining what the website site settings page is for">
+    Control this site's access to your device
+  </message>
   <message name="IDS_WEBSITE_SETTINGS_PERMISSIONS_ALLOW" desc="Summary text explaining that Chrome will allow a website to access some permission, e.g. JavaScript: allow.">
     Allow
   </message>
diff --git a/components/browser_ui/strings/android/site_settings_grdp/IDS_WEBSITE_SETTINGS_PERMISSIONS_DESCRIPTION.png.sha1 b/components/browser_ui/strings/android/site_settings_grdp/IDS_WEBSITE_SETTINGS_PERMISSIONS_DESCRIPTION.png.sha1
new file mode 100644
index 0000000..9a64213
--- /dev/null
+++ b/components/browser_ui/strings/android/site_settings_grdp/IDS_WEBSITE_SETTINGS_PERMISSIONS_DESCRIPTION.png.sha1
@@ -0,0 +1 @@
+f68142b0dd7a41429e034a7babddf7f3b757a58f
\ No newline at end of file
diff --git a/components/management_strings.grdp b/components/management_strings.grdp
index 021b1f6..7893c0e 100644
--- a/components/management_strings.grdp
+++ b/components/management_strings.grdp
@@ -131,7 +131,7 @@
 
     <!-- Chrome OS update required end-of-life reached section -->
     <message name="IDS_MANAGEMENT_UPDATE_REQUIRED_EOL_MESSAGE" desc="Message indicating that the device needs to be returned back before the deadline because the device has reached end-of-life and an update is required as per policy.">
-      <ph name="ENROLLMENT_DOMAIN">$1<ex>example.com</ex></ph> requires you to back up your data and return this device.
+      <ph name="ENROLLMENT_DOMAIN">$1<ex>example.com</ex></ph> requires you to back up your data and return this <ph name="DEVICE_TYPE">$2<ex>Chromebook</ex></ph>.
     </message>
     <message name="IDS_MANAGEMENT_UPDATE_REQUIRED_EOL_ADMIN_MESSAGE_TITLE" desc="Message indicating return instructions from the device administrator because the device cannot be updated as it has reached its end of life.">
       Instructions from your device administrator:
diff --git a/components/management_strings_grdp/IDS_MANAGEMENT_UPDATE_REQUIRED_EOL_MESSAGE.png.sha1 b/components/management_strings_grdp/IDS_MANAGEMENT_UPDATE_REQUIRED_EOL_MESSAGE.png.sha1
index 899c5f0..7795ff5 100644
--- a/components/management_strings_grdp/IDS_MANAGEMENT_UPDATE_REQUIRED_EOL_MESSAGE.png.sha1
+++ b/components/management_strings_grdp/IDS_MANAGEMENT_UPDATE_REQUIRED_EOL_MESSAGE.png.sha1
@@ -1 +1 @@
-77b24830ccafd697853d3c65b46deb8817d5a68a
\ No newline at end of file
+ea56cc738e3b91a31f8f1dd23f1b53688f85cd0f
\ No newline at end of file
diff --git a/components/omnibox/browser/BUILD.gn b/components/omnibox/browser/BUILD.gn
index 8dcfb538..7957916 100644
--- a/components/omnibox/browser/BUILD.gn
+++ b/components/omnibox/browser/BUILD.gn
@@ -276,6 +276,8 @@
     "location_bar_model_delegate.h",
     "location_bar_model_impl.cc",
     "location_bar_model_impl.h",
+    "location_bar_model_util.cc",
+    "location_bar_model_util.h",
   ]
 
   public_deps = [
diff --git a/components/omnibox/browser/location_bar_model_impl.cc b/components/omnibox/browser/location_bar_model_impl.cc
index 5270e37..4fe8d91 100644
--- a/components/omnibox/browser/location_bar_model_impl.cc
+++ b/components/omnibox/browser/location_bar_model_impl.cc
@@ -15,6 +15,7 @@
 #include "components/dom_distiller/core/url_utils.h"
 #include "components/omnibox/browser/buildflags.h"
 #include "components/omnibox/browser/location_bar_model_delegate.h"
+#include "components/omnibox/browser/location_bar_model_util.h"
 #include "components/omnibox/common/omnibox_features.h"
 #include "components/search_engines/template_url_service.h"
 #include "components/security_state/core/security_state.h"
@@ -29,7 +30,6 @@
 
 #if (!defined(OS_ANDROID) || BUILDFLAG(ENABLE_VR)) && !defined(OS_IOS)
 #include "components/omnibox/browser/vector_icons.h"  // nogncheck
-#include "components/vector_icons/vector_icons.h"     // nogncheck
 #endif
 
 using metrics::OmniboxEventProto;
@@ -205,35 +205,9 @@
 
   if (IsOfflinePage())
     return omnibox::kOfflinePinIcon;
-
-  security_state::SecurityLevel security_level = GetSecurityLevel();
-  switch (security_level) {
-    case security_state::NONE:
-      return omnibox::kHttpIcon;
-    case security_state::WARNING:
-      // When kMarkHttpAsParameterDangerWarning is enabled, show a danger
-      // triangle icon.
-      if (security_state::ShouldShowDangerTriangleForWarningLevel()) {
-        return omnibox::kNotSecureWarningIcon;
-      }
-      return omnibox::kHttpIcon;
-    case security_state::SECURE:
-      return omnibox::kHttpsValidIcon;
-    case security_state::SECURE_WITH_POLICY_INSTALLED_CERT:
-      return vector_icons::kBusinessIcon;
-    case security_state::DANGEROUS:
-      return omnibox::kNotSecureWarningIcon;
-    case security_state::SECURITY_LEVEL_COUNT:
-      NOTREACHED();
-      return omnibox::kHttpIcon;
-  }
-  NOTREACHED();
-  return omnibox::kHttpIcon;
-#else
-  NOTREACHED();
-  static const gfx::VectorIcon dummy = {};
-  return dummy;
 #endif
+
+  return location_bar_model::GetSecurityVectorIcon(GetSecurityLevel());
 }
 
 base::string16 LocationBarModelImpl::GetSecureDisplayText() const {
diff --git a/components/omnibox/browser/location_bar_model_util.cc b/components/omnibox/browser/location_bar_model_util.cc
new file mode 100644
index 0000000..27c4ec8
--- /dev/null
+++ b/components/omnibox/browser/location_bar_model_util.cc
@@ -0,0 +1,50 @@
+// 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 "components/omnibox/browser/location_bar_model_util.h"
+
+#include "build/build_config.h"
+#include "components/omnibox/browser/buildflags.h"
+#include "ui/gfx/vector_icon_types.h"
+
+#if (!defined(OS_ANDROID) || BUILDFLAG(ENABLE_VR)) && !defined(OS_IOS)
+#include "components/omnibox/browser/vector_icons.h"  // nogncheck
+#include "components/vector_icons/vector_icons.h"     // nogncheck
+#endif
+
+namespace location_bar_model {
+
+const gfx::VectorIcon& GetSecurityVectorIcon(
+    security_state::SecurityLevel security_level) {
+#if (!defined(OS_ANDROID) || BUILDFLAG(ENABLE_VR)) && !defined(OS_IOS)
+  switch (security_level) {
+    case security_state::NONE:
+      return omnibox::kHttpIcon;
+    case security_state::WARNING:
+      // When kMarkHttpAsParameterDangerWarning is enabled, show a danger
+      // triangle icon.
+      if (security_state::ShouldShowDangerTriangleForWarningLevel()) {
+        return omnibox::kNotSecureWarningIcon;
+      }
+      return omnibox::kHttpIcon;
+    case security_state::SECURE:
+      return omnibox::kHttpsValidIcon;
+    case security_state::SECURE_WITH_POLICY_INSTALLED_CERT:
+      return vector_icons::kBusinessIcon;
+    case security_state::DANGEROUS:
+      return omnibox::kNotSecureWarningIcon;
+    case security_state::SECURITY_LEVEL_COUNT:
+      NOTREACHED();
+      return omnibox::kHttpIcon;
+  }
+  NOTREACHED();
+  return omnibox::kHttpIcon;
+#else
+  NOTREACHED();
+  static const gfx::VectorIcon dummy = {};
+  return dummy;
+#endif
+}
+
+}  // namespace location_bar_model
diff --git a/components/omnibox/browser/location_bar_model_util.h b/components/omnibox/browser/location_bar_model_util.h
new file mode 100644
index 0000000..00803fc
--- /dev/null
+++ b/components/omnibox/browser/location_bar_model_util.h
@@ -0,0 +1,23 @@
+// 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 COMPONENTS_OMNIBOX_BROWSER_LOCATION_BAR_MODEL_UTIL_H_
+#define COMPONENTS_OMNIBOX_BROWSER_LOCATION_BAR_MODEL_UTIL_H_
+
+#include "components/security_state/core/security_state.h"
+
+namespace gfx {
+struct VectorIcon;
+}  // namespace gfx
+
+namespace location_bar_model {
+
+// Get the vector icon according to security level.
+// It indicates security state of the page.
+const gfx::VectorIcon& GetSecurityVectorIcon(
+    security_state::SecurityLevel security_level);
+
+}  // namespace location_bar_model
+
+#endif  // COMPONENTS_OMNIBOX_BROWSER_LOCATION_BAR_MODEL_UTIL_H_
diff --git a/components/page_info/android/java/res/layout/page_info_v2.xml b/components/page_info/android/java/res/layout/page_info_v2.xml
index 57a6f45..7be7185 100644
--- a/components/page_info/android/java/res/layout/page_info_v2.xml
+++ b/components/page_info/android/java/res/layout/page_info_v2.xml
@@ -71,11 +71,6 @@
             android:layout_height="wrap_content"
             android:layout_width="match_parent"/>
         <org.chromium.components.page_info.PageInfoRowView
-            android:id="@+id/page_info_performance_row"
-            android:visibility="gone"
-            android:layout_height="wrap_content"
-            android:layout_width="match_parent"/>
-        <org.chromium.components.page_info.PageInfoRowView
             android:id="@+id/page_info_permissions_row"
             android:visibility="gone"
             android:layout_height="wrap_content"
diff --git a/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameBitmapPainter.java b/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameBitmapPainter.java
index 91609ef8..1c89c39 100644
--- a/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameBitmapPainter.java
+++ b/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameBitmapPainter.java
@@ -52,12 +52,12 @@
         if (mTileSize.getWidth() <= 0 || mTileSize.getHeight() <= 0) return;
 
         final int rowStart = mViewPort.top / mTileSize.getHeight();
-        final int rowEnd = (int) Math.ceil((double) mViewPort.bottom / mTileSize.getHeight());
+        int rowEnd = (int) Math.ceil((double) mViewPort.bottom / mTileSize.getHeight());
         final int colStart = mViewPort.left / mTileSize.getWidth();
-        final int colEnd = (int) Math.ceil((double) mViewPort.right / mTileSize.getWidth());
-        if (rowEnd > mBitmapMatrix.length || colEnd > mBitmapMatrix[rowEnd - 1].length) {
-            return;
-        }
+        int colEnd = (int) Math.ceil((double) mViewPort.right / mTileSize.getWidth());
+
+        rowEnd = Math.min(rowEnd, mBitmapMatrix.length);
+        colEnd = Math.min(colEnd, rowEnd > 1 ? mBitmapMatrix[rowEnd - 1].length : 0);
 
         for (int row = rowStart; row < rowEnd; row++) {
             for (int col = colStart; col < colEnd; col++) {
diff --git a/components/password_manager/core/browser/credential_manager_impl_unittest.cc b/components/password_manager/core/browser/credential_manager_impl_unittest.cc
index a20567a..c8ddff31 100644
--- a/components/password_manager/core/browser/credential_manager_impl_unittest.cc
+++ b/components/password_manager/core/browser/credential_manager_impl_unittest.cc
@@ -72,7 +72,7 @@
   MOCK_METHOD3(PromptUserToChooseCredentialsPtr,
                bool(const std::vector<autofill::PasswordForm*>& local_forms,
                     const url::Origin& origin,
-                    const CredentialsCallback& callback));
+                    CredentialsCallback callback));
   MOCK_METHOD3(PasswordWasAutofilled,
                void(const std::vector<const autofill::PasswordForm*>&,
                     const url::Origin&,
@@ -131,19 +131,19 @@
   bool PromptUserToChooseCredentials(
       std::vector<std::unique_ptr<autofill::PasswordForm>> local_forms,
       const url::Origin& origin,
-      const CredentialsCallback& callback) override {
+      CredentialsCallback callback) override {
     EXPECT_FALSE(local_forms.empty());
     const autofill::PasswordForm* form = local_forms[0].get();
     base::SequencedTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
-        base::BindOnce(callback,
+        base::BindOnce(std::move(callback),
                        base::Owned(new autofill::PasswordForm(*form))));
     std::vector<autofill::PasswordForm*> raw_forms(local_forms.size());
     std::transform(local_forms.begin(), local_forms.end(), raw_forms.begin(),
                    [](const std::unique_ptr<autofill::PasswordForm>& form) {
                      return form.get();
                    });
-    PromptUserToChooseCredentialsPtr(raw_forms, origin, callback);
+    PromptUserToChooseCredentialsPtr(raw_forms, origin, base::DoNothing());
     return true;
   }
 
diff --git a/components/password_manager/core/browser/credential_manager_pending_request_task.cc b/components/password_manager/core/browser/credential_manager_pending_request_task.cc
index d5f5c03..271bbd3 100644
--- a/components/password_manager/core/browser/credential_manager_pending_request_task.cc
+++ b/components/password_manager/core/browser/credential_manager_pending_request_task.cc
@@ -302,7 +302,7 @@
       base::AdaptCallbackForRepeating(std::move(send_callback_));
   if (!delegate_->client()->PromptUserToChooseCredentials(
           std::move(local_results), origin_,
-          base::Bind(
+          base::BindOnce(
               &CredentialManagerPendingRequestTaskDelegate::SendPasswordForm,
               base::Unretained(delegate_), repeating_send_callback,
               mediation_))) {
diff --git a/components/password_manager/core/browser/credential_manager_pending_request_task_unittest.cc b/components/password_manager/core/browser/credential_manager_pending_request_task_unittest.cc
index 618fdd9..ecafe67 100644
--- a/components/password_manager/core/browser/credential_manager_pending_request_task_unittest.cc
+++ b/components/password_manager/core/browser/credential_manager_pending_request_task_unittest.cc
@@ -32,7 +32,7 @@
   bool PromptUserToChooseCredentials(
       std::vector<std::unique_ptr<autofill::PasswordForm>> forms,
       const url::Origin& origin,
-      const CredentialsCallback& callback) override {
+      CredentialsCallback callback) override {
     forms_passed_to_ui_ = std::move(forms);
     return true;
   }
diff --git a/components/password_manager/core/browser/password_form_filling.cc b/components/password_manager/core/browser/password_form_filling.cc
index 2095ccb7c..5910626f 100644
--- a/components/password_manager/core/browser/password_form_filling.cc
+++ b/components/password_manager/core/browser/password_form_filling.cc
@@ -170,7 +170,9 @@
       PasswordFormMetricsRecorder::WaitForUsernameReason;
   WaitForUsernameReason wait_for_username_reason =
       WaitForUsernameReason::kDontWait;
-  if (client->IsIncognito()) {
+  if (client->RequiresReauthToFill()) {
+    wait_for_username_reason = WaitForUsernameReason::kReauthRequired;
+  } else if (client->IsIncognito()) {
     wait_for_username_reason = WaitForUsernameReason::kIncognitoMode;
   } else if (preferred_match->is_public_suffix_match) {
     wait_for_username_reason = WaitForUsernameReason::kPublicSuffixMatch;
diff --git a/components/password_manager/core/browser/password_form_metrics_recorder.h b/components/password_manager/core/browser/password_form_metrics_recorder.h
index 5c9e96c..341e540 100644
--- a/components/password_manager/core/browser/password_form_metrics_recorder.h
+++ b/components/password_manager/core/browser/password_form_metrics_recorder.h
@@ -204,6 +204,9 @@
   // credentials on page load but to wait for the user to confirm the credential
   // to be filled. This decision is only recorded for the first time, the
   // browser informs the renderer about credentials for a given form.
+  //
+  // Needs to stay in sync with PasswordManagerFirstWaitForUsernameReason in
+  // enums.xml.
   enum class WaitForUsernameReason {
     // Credentials may be filled on page load.
     kDontWait = 0,
@@ -221,7 +224,9 @@
     kTouchToFill = 5,
     // Show suggestion on account selection feature is enabled.
     kFoasFeature = 6,
-    kMaxValue = kFoasFeature,
+    // Re-authenticaion for filling passwords is required.
+    kReauthRequired = 7,
+    kMaxValue = kReauthRequired,
   };
 
   // This metric records the user experience with the passwords filling. The
diff --git a/components/password_manager/core/browser/password_manager_client.cc b/components/password_manager/core/browser/password_manager_client.cc
index efcefff..ffe7b0e 100644
--- a/components/password_manager/core/browser/password_manager_client.cc
+++ b/components/password_manager/core/browser/password_manager_client.cc
@@ -25,6 +25,10 @@
   return true;
 }
 
+bool PasswordManagerClient::RequiresReauthToFill() {
+  return false;
+}
+
 void PasswordManagerClient::ShowTouchToFill(PasswordManagerDriver* driver) {}
 
 BiometricAuthenticator* PasswordManagerClient::GetBiometricAuthenticator() {
diff --git a/components/password_manager/core/browser/password_manager_client.h b/components/password_manager/core/browser/password_manager_client.h
index ad1320f..165d8b5 100644
--- a/components/password_manager/core/browser/password_manager_client.h
+++ b/components/password_manager/core/browser/password_manager_client.h
@@ -91,7 +91,7 @@
 class PasswordManagerClient {
  public:
   using CredentialsCallback =
-      base::Callback<void(const autofill::PasswordForm*)>;
+      base::OnceCallback<void(const autofill::PasswordForm*)>;
   using ReauthSucceeded = util::StrongAlias<class ReauthSucceededTag, bool>;
 
   PasswordManagerClient() {}
@@ -171,7 +171,11 @@
   virtual bool PromptUserToChooseCredentials(
       std::vector<std::unique_ptr<autofill::PasswordForm>> local_forms,
       const url::Origin& origin,
-      const CredentialsCallback& callback) = 0;
+      CredentialsCallback callback) = 0;
+
+  // Indicates if re-auth with the device is needed before filling passwords.
+  // Currently only used by iOS.
+  virtual bool RequiresReauthToFill();
 
   // Instructs the client to show the Touch To Fill UI.
   virtual void ShowTouchToFill(PasswordManagerDriver* driver);
@@ -272,8 +276,9 @@
   virtual bool WasLastNavigationHTTPError() const;
 
   // Returns true if a credential leak dialog was shown. Used by Autofill
-  // Assistance to verify a password change intent. TODO(b/151391231): Remove
-  // when proper intent signing is implemented.
+  // Assistance to verify a password change intent. TODO(b/151391231): At the
+  // moment, password change scripts don't need validation, but it may change.
+  // If it doesn't change, remove this method and related code.
   virtual bool WasCredentialLeakDialogShown() const;
 
   // Obtains the cert status for the main frame.
diff --git a/components/password_manager/core/browser/password_manager_client_helper.cc b/components/password_manager/core/browser/password_manager_client_helper.cc
index 36f4b317..8de7a05a 100644
--- a/components/password_manager/core/browser/password_manager_client_helper.cc
+++ b/components/password_manager/core/browser/password_manager_client_helper.cc
@@ -67,10 +67,10 @@
 }
 
 void PasswordManagerClientHelper::OnCredentialsChosen(
-    const PasswordManagerClient::CredentialsCallback& callback,
+    PasswordManagerClient::CredentialsCallback callback,
     bool one_local_credential,
     const autofill::PasswordForm* form) {
-  callback.Run(form);
+  std::move(callback).Run(form);
   // If a site gets back a credential some navigations are likely to occur. They
   // shouldn't trigger the autofill password manager.
   if (form)
diff --git a/components/password_manager/core/browser/password_manager_client_helper.h b/components/password_manager/core/browser/password_manager_client_helper.h
index ff58880..b18c6fb 100644
--- a/components/password_manager/core/browser/password_manager_client_helper.h
+++ b/components/password_manager/core/browser/password_manager_client_helper.h
@@ -29,10 +29,9 @@
   // PasswordManagerClient::PromptUserToChooseCredentials. nullptr in |form|
   // means that nothing was chosen. |one_local_credential| is true if there was
   // just one local credential to be chosen from.
-  void OnCredentialsChosen(
-      const PasswordManagerClient::CredentialsCallback& callback,
-      bool one_local_credential,
-      const autofill::PasswordForm* form);
+  void OnCredentialsChosen(PasswordManagerClient::CredentialsCallback callback,
+                           bool one_local_credential,
+                           const autofill::PasswordForm* form);
 
   // Common logic for IOSChromePasswordManagerClient and
   // ChromePasswordManagerClient implementation of NotifyStorePasswordCalled.
diff --git a/components/password_manager/core/browser/stub_password_manager_client.cc b/components/password_manager/core/browser/stub_password_manager_client.cc
index 095ecae..f4a1683 100644
--- a/components/password_manager/core/browser/stub_password_manager_client.cc
+++ b/components/password_manager/core/browser/stub_password_manager_client.cc
@@ -45,7 +45,7 @@
 bool StubPasswordManagerClient::PromptUserToChooseCredentials(
     std::vector<std::unique_ptr<autofill::PasswordForm>> local_forms,
     const url::Origin& origin,
-    const CredentialsCallback& callback) {
+    CredentialsCallback callback) {
   return false;
 }
 
diff --git a/components/password_manager/core/browser/stub_password_manager_client.h b/components/password_manager/core/browser/stub_password_manager_client.h
index e130ccd4..129e34ee6 100644
--- a/components/password_manager/core/browser/stub_password_manager_client.h
+++ b/components/password_manager/core/browser/stub_password_manager_client.h
@@ -45,7 +45,7 @@
   bool PromptUserToChooseCredentials(
       std::vector<std::unique_ptr<autofill::PasswordForm>> local_forms,
       const url::Origin& origin,
-      const CredentialsCallback& callback) override;
+      CredentialsCallback callback) override;
   void NotifyUserAutoSignin(
       std::vector<std::unique_ptr<autofill::PasswordForm>> local_forms,
       const url::Origin& origin) override;
diff --git a/components/password_manager/ios/shared_password_controller.mm b/components/password_manager/ios/shared_password_controller.mm
index e5bdc07..05b50af8 100644
--- a/components/password_manager/ios/shared_password_controller.mm
+++ b/components/password_manager/ios/shared_password_controller.mm
@@ -381,7 +381,7 @@
       return;
     }
     case autofill::POPUP_ITEM_ID_GENERATE_PASSWORD_ENTRY: {
-      // Don't call completion because current siggestion state should remain
+      // Don't call completion because current suggestion state should remain
       // whether user injects a generated password or cancels.
       [self generatePasswordForFormId:uniqueFormID
                       fieldIdentifier:uniqueFieldID];
diff --git a/components/payments/core/features.cc b/components/payments/core/features.cc
index b129c3e..c4c9717 100644
--- a/components/payments/core/features.cc
+++ b/components/payments/core/features.cc
@@ -77,8 +77,8 @@
     "AllowJITInstallationWhenAppIconIsMissing",
     base::FEATURE_DISABLED_BY_DEFAULT};
 
-const base::Feature kPaymentHandlerLockIcon{"PaymentHandlerLockIcon",
-                                            base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kPaymentHandlerSecurityIcon{
+    "PaymentHandlerSecurityIcon", base::FEATURE_DISABLED_BY_DEFAULT};
 
 const base::Feature kEnforceFullDelegation{"EnforceFullDelegation",
                                            base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/components/payments/core/features.h b/components/payments/core/features.h
index 60b86bf..b7716bff 100644
--- a/components/payments/core/features.h
+++ b/components/payments/core/features.h
@@ -79,10 +79,10 @@
 // Used to test icon refetch for JIT installed apps with missing icons.
 extern const base::Feature kAllowJITInstallationWhenAppIconIsMissing;
 
-// Desktop only, if enabled the lock icon would be showed next to the
+// Desktop only, if enabled the security icon would be showed next to the
 // payment handler's URL bar. It indicate that only secure content is
 // allowed inside the payment handler.
-extern const base::Feature kPaymentHandlerLockIcon;
+extern const base::Feature kPaymentHandlerSecurityIcon;
 
 // Used to reject the apps with partial delegation.
 extern const base::Feature kEnforceFullDelegation;
diff --git a/components/performance_manager/v8_memory/v8_per_frame_memory_decorator.cc b/components/performance_manager/v8_memory/v8_per_frame_memory_decorator.cc
index 0659e70..2d69b36 100644
--- a/components/performance_manager/v8_memory/v8_per_frame_memory_decorator.cc
+++ b/components/performance_manager/v8_memory/v8_per_frame_memory_decorator.cc
@@ -237,6 +237,7 @@
   // NodeAttachedProcessData when the last V8PerFrameMemoryRequest is deleted,
   // which could happen at any time.
   resource_usage_reporter_->GetPerFrameV8MemoryUsageData(
+      blink::mojom::V8PerFrameMemoryReporter::Mode::DEFAULT,
       base::BindOnce(&NodeAttachedProcessData::OnPerFrameV8MemoryUsageData,
                      weak_factory_.GetWeakPtr()));
 }
@@ -274,20 +275,21 @@
       // No data for this node, clear any data associated with it.
       NodeAttachedFrameData::Destroy(frame_node);
     } else {
-      // There should always be data for the main isolated world for each frame.
-      DCHECK(base::Contains(it->second->associated_bytes, 0));
-
+      bool found_main_world = false;
       NodeAttachedFrameData* frame_data =
           NodeAttachedFrameData::GetOrCreate(frame_node);
-      for (const auto& kv : it->second->associated_bytes) {
-        if (kv.first == 0) {
+      for (const auto& entry : it->second->associated_bytes) {
+        if (entry->world_id ==
+            blink::mojom::V8IsolatedWorldMemoryUsage::kMainWorldId) {
           frame_data->data_available_ = true;
-          frame_data->data_.set_v8_bytes_used(kv.second->bytes_used);
+          frame_data->data_.set_v8_bytes_used(entry->bytes_used);
+          found_main_world = true;
         } else {
           // TODO(crbug.com/1080672): Where to stash the rest of the data?
         }
       }
-
+      // There should always be data for the main isolated world for each frame.
+      DCHECK(found_main_world);
       // Clear this datum as its usage has been consumed.
       associated_memory.erase(it);
     }
diff --git a/components/performance_manager/v8_memory/v8_per_frame_memory_decorator_unittest.cc b/components/performance_manager/v8_memory/v8_per_frame_memory_decorator_unittest.cc
index 13f7b09c..e11cc6a 100644
--- a/components/performance_manager/v8_memory/v8_per_frame_memory_decorator_unittest.cc
+++ b/components/performance_manager/v8_memory/v8_per_frame_memory_decorator_unittest.cc
@@ -51,7 +51,7 @@
 
   MOCK_METHOD(void,
               GetPerFrameV8MemoryUsageData,
-              (GetPerFrameV8MemoryUsageDataCallback callback),
+              (Mode mode, GetPerFrameV8MemoryUsageDataCallback callback),
               (override));
 
   void Bind(mojo::PendingReceiver<blink::mojom::V8PerFrameMemoryReporter>
@@ -142,8 +142,9 @@
       base::RepeatingCallback<void(
           MockV8PerFrameMemoryReporter::GetPerFrameV8MemoryUsageDataCallback
               callback)> responder) {
-    EXPECT_CALL(*mock_reporter, GetPerFrameV8MemoryUsageData(_))
+    EXPECT_CALL(*mock_reporter, GetPerFrameV8MemoryUsageData(_, _))
         .WillOnce([this, responder](
+                      MockV8PerFrameMemoryReporter::Mode mode,
                       MockV8PerFrameMemoryReporter::
                           GetPerFrameV8MemoryUsageDataCallback callback) {
           this->last_query_time_ = base::TimeTicks::Now();
@@ -230,11 +231,14 @@
     per_frame_data = datum.get();
     data->associated_memory.push_back(std::move(datum));
   }
-  ASSERT_FALSE(base::Contains(per_frame_data->associated_bytes, world_id));
+  for (const auto& entry : per_frame_data->associated_bytes) {
+    EXPECT_NE(world_id, entry->world_id);
+  }
 
   auto isolated_world_usage = blink::mojom::V8IsolatedWorldMemoryUsage::New();
   isolated_world_usage->bytes_used = bytes_used;
-  per_frame_data->associated_bytes[world_id] = std::move(isolated_world_usage);
+  isolated_world_usage->world_id = world_id;
+  per_frame_data->associated_bytes.push_back(std::move(isolated_world_usage));
 }
 
 }  // namespace
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 082a510..c84daf49 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -219,7 +219,7 @@
 #   Each policy has an 'owners' field. This field is a list of strings which
 #   describe the group of people responsible for maintaining the policy and can
 #   help answer questions or solve issues with the policy. The entries can be
-#   either emails of comitters or file:// references to OWNERS files in the
+#   either emails of committers or file:// references to OWNERS files in the
 #   Chromium repository.
 #
 # Placeholders:
@@ -6412,6 +6412,75 @@
           Note that patterns you list here are treated as domains, not URLs, so you should not specify a scheme or port.''',
     },
     {
+      'name': 'InsecurePrivateNetworkRequestsAllowed',
+      'owners': [
+        'titouan@chromium.org',
+        'clamy@chromium.org',
+        'mkwst@chromium.org',
+      ],
+      'type': 'main',
+      'schema': { 'type': 'boolean' },
+      'supported_on': [],
+      'future_on': [
+        'chrome.*',
+        'chrome_os',
+        'android',
+        'webview_android',
+      ],
+      'features': {
+        'dynamic_refresh': True,
+        'per_profile': True,
+      },
+      'example_value': False,
+      'id': 766,
+      'caption': '''Specifies whether to allow insecure websites to make requests to more-private network endpoints.''',
+      'tags': ['system-security'],
+      'desc': '''Controls whether insecure websites are allowed to make requests to more-private network endpoints. E.g. controls whether http://evil.com is allowed to make requests to both `localhost` and endpoints on the private network, neither of which are accessible from the public internet. See https://wicg.github.io/cors-rfc1918/#goals for more details.
+
+          When this policy is not set, the default behavior for requests from insecure contexts to more-private network endpoints will depend on the user's personal configuration for the <ph name="BLOCK_INSECURE_PRIVATE_NETWORK_REQUESTS_FEATURE_NAME">BlockInsecurePrivateNetworkRequests</ph> feature, which may be set by a field trial or on the command line.
+
+          When this policy is set to false, insecure websites are forbidden from making requests to more-private network endpoints. That is, insecure websites served from public IP addresses are forbidden from making requests to both localhost and private IP addresses. Insecure websites served from private IP addresses are forbidden from making requests to localhost.
+
+          When this policy is set to true, insecure websites are allowed to make requests to any network endpoint, subject to other cross-origin checks.''',
+    },
+    {
+      'name': 'InsecurePrivateNetworkRequestsAllowedForUrls',
+      'owners': [
+        'titouan@chromium.org',
+        'clamy@chromium.org',
+        'mkwst@chromium.org',
+      ],
+      'type': 'list',
+      'schema': {
+        'type': 'array',
+        'items': { 'type': 'string' },
+      },
+      'supported_on': [],
+      'future_on': [
+        'chrome.*',
+        'chrome_os',
+        'android',
+        'webview_android',
+      ],
+      'features': {
+        'dynamic_refresh': True,
+        'per_profile': True,
+      },
+      'example_value': ['http://www.example.com:8080', '[*.]example.edu'],
+      'id': 767,
+      'caption': '''Allow the listed sites to make requests to more-private network endpoints from insecure contexts.''',
+      'tags': ['system-security'],
+      'desc': '''List of URL patterns. Private network requests initiated from insecure websites served by matching origins are allowed.
+
+          If unset, this policy behaves as if set to the empty list.
+
+          For origins not covered by the patterns specified here, the global default value will be used either from the <ph name="INSECURE_PRIVATE_NETWORK_REQUESTS_ALLOWED_POLICY_NAME">InsecurePrivateNetworkRequestsAllowed</ph> policy, if it is set, or the user's personal configuration otherwise.
+
+          Note that this policy only affects insecure origins, so secure origins (e.g. https://example.com) included in this list will be ignored.
+
+          For detailed information on valid URL patterns, please see https://cloud.google.com/docs/chrome-enterprise/policies/url-patterns.''',
+    },
+    {
       'name': 'PluginsAllowedForUrls',
       'owners': ['file://components/policy/resources/OWNERS'],
       'type': 'list',
@@ -23715,9 +23784,18 @@
         'SensorsBlockedForUrls',
       ],
     },
+    {
+      'id': 40,
+      'name': 'PrivateNetworkRequestSettings',
+      'caption': '''Private network request settings''',
+      'policies': [
+        'InsecurePrivateNetworkRequestsAllowed',
+        'InsecurePrivateNetworkRequestsAllowedForUrls',
+      ],
+    },
   ],
   'placeholders': [],
   'deleted_policy_ids': [412, 476, 546, 562, 569, 578],
-  'highest_id_currently_used': 765,
-  'highest_atomic_group_id_currently_used': 39
+  'highest_id_currently_used': 767,
+  'highest_atomic_group_id_currently_used': 40
 }
diff --git a/components/signin/core/browser/chrome_connected_header_helper.h b/components/signin/core/browser/chrome_connected_header_helper.h
index e4f219b..6b53aeb4 100644
--- a/components/signin/core/browser/chrome_connected_header_helper.h
+++ b/components/signin/core/browser/chrome_connected_header_helper.h
@@ -49,6 +49,9 @@
       const GURL& url,
       const content_settings::CookieSettings* cookie_settings) override;
 
+  // SigninHeaderHelper implementation:
+  bool IsUrlEligibleForRequestHeader(const GURL& url) override;
+
  private:
   // Whether mirror account consistency should be used.
   AccountConsistencyMethod account_consistency_;
@@ -58,9 +61,6 @@
 
   // Returns whether the URL has a Google Drive origin.
   bool IsDriveOrigin(const GURL& url);
-
-  // SigninHeaderHelper implementation:
-  bool IsUrlEligibleForRequestHeader(const GURL& url) override;
 };
 
 }  // namespace signin
diff --git a/components/signin/core/browser/signin_header_helper.cc b/components/signin/core/browser/signin_header_helper.cc
index 34b1ebd..169f7b9 100644
--- a/components/signin/core/browser/signin_header_helper.cc
+++ b/components/signin/core/browser/signin_header_helper.cc
@@ -163,6 +163,12 @@
   return dictionary;
 }
 
+bool IsUrlEligibleForMirrorCookie(const GURL& url) {
+  ChromeConnectedHeaderHelper chrome_connected_helper(
+      AccountConsistencyMethod::kMirror);
+  return chrome_connected_helper.IsUrlEligibleForRequestHeader(url);
+}
+
 void AppendOrRemoveMirrorRequestHeader(
     RequestAdapter* request,
     const GURL& redirect_url,
diff --git a/components/signin/core/browser/signin_header_helper.h b/components/signin/core/browser/signin_header_helper.h
index 881b40b..a1199093 100644
--- a/components/signin/core/browser/signin_header_helper.h
+++ b/components/signin/core/browser/signin_header_helper.h
@@ -206,13 +206,16 @@
   static ResponseHeaderDictionary ParseAccountConsistencyResponseHeader(
       const std::string& header_value);
 
- private:
   // Returns whether the url is eligible for the request header.
   virtual bool IsUrlEligibleForRequestHeader(const GURL& url) = 0;
 
+ private:
   DISALLOW_COPY_AND_ASSIGN(SigninHeaderHelper);
 };
 
+// Returns whether the url is eligible for account consistency on Google
+// domains.
+bool IsUrlEligibleForMirrorCookie(const GURL& url);
 
 // Returns the CHROME_CONNECTED cookie, or an empty string if it should not be
 // added to the request to |url|.
diff --git a/components/signin/ios/browser/BUILD.gn b/components/signin/ios/browser/BUILD.gn
index dd87e0b6..2605ae9 100644
--- a/components/signin/ios/browser/BUILD.gn
+++ b/components/signin/ios/browser/BUILD.gn
@@ -20,6 +20,8 @@
     "//components/prefs",
     "//components/signin/core/browser",
     "//components/signin/public/base",
+    "//google_apis",
+    "//ios/net",
     "//ios/web/common:web_view_creation_util",
     "//ios/web/public",
     "//url",
diff --git a/components/signin/ios/browser/account_consistency_service.h b/components/signin/ios/browser/account_consistency_service.h
index d19a44a..0bd4ac03 100644
--- a/components/signin/ios/browser/account_consistency_service.h
+++ b/components/signin/ios/browser/account_consistency_service.h
@@ -6,7 +6,6 @@
 #define COMPONENTS_SIGNIN_IOS_BROWSER_ACCOUNT_CONSISTENCY_SERVICE_H_
 
 #include <map>
-#include <memory>
 #include <set>
 #include <string>
 
@@ -19,6 +18,7 @@
 #include "components/signin/ios/browser/active_state_manager.h"
 #import "components/signin/ios/browser/manage_accounts_delegate.h"
 #import "components/signin/public/identity_manager/identity_manager.h"
+#include "net/cookies/canonical_cookie.h"
 #include "net/cookies/cookie_access_result.h"
 
 namespace content_settings {
@@ -34,9 +34,11 @@
 class AccountReconcilor;
 class PrefService;
 
-// Handles actions necessary for Account Consistency to work on iOS. This
-// includes setting the Account Consistency cookie (informing Gaia that the
-// Account Consistency is on).
+// Handles actions necessary for keeping the list of Google accounts available
+// on the web and those available on the iOS device from first-party Google apps
+// consistent. This includes setting the Account Consistency cookie,
+// CHROME_CONNECTED, which informs Gaia that the user is signed in to Chrome
+// with Account Consistency on.
 class AccountConsistencyService : public KeyedService,
                                   public signin::IdentityManager::Observer,
                                   public ActiveStateManager::Observer {
@@ -46,6 +48,9 @@
   // Google authentication cookies are managed by |AccountReconcilor|).
   static const char kChromeConnectedCookieName[];
 
+  // Name of the Google authentication cookie.
+  static const char kGaiaCookieName[];
+
   // Name of the preference property that persists the domains that have a
   // CHROME_CONNECTED cookie set by this service.
   static const char kDomainsWithCookiePref[];
@@ -72,12 +77,17 @@
   // set. Calls callback once all cookies were removed.
   void RemoveChromeConnectedCookies(base::OnceClosure callback);
 
-  // Enqueues a request to add the CHROME_CONNECTED cookie to |domain|. If the
-  // cookie is already on |domain|, this function will do nothing unless
-  // |force_update_if_too_old| is true. In this case, the cookie will be
-  // refreshed if it is considered too old.
-  void AddChromeConnectedCookieToDomain(const std::string& domain,
-                                        bool force_update_if_too_old);
+  // Checks for the presence of Gaia cookies and if they have been deleted
+  // notifies the AccountReconcilor (the class responsible for rebuilding Gaia
+  // cookies if needed).
+  //
+  // Applies a one hour time restriction in between updates to avoid too many
+  // |GetAllCookies| calls on the cookie manager.
+  void SetGaiaCookiesIfDeleted();
+
+  // Enqueues a request to set the CHROME_CONNECTED cookie for |domain|.
+  // The cookie is set if it is not already on |domain|.
+  void SetChromeConnectedCookieWithDomain(const std::string& domain);
 
   // Enqueues a request to remove the CHROME_CONNECTED cookie to |domain|.
   // Does nothing if the cookie is not set on |domain|.
@@ -126,21 +136,39 @@
   // Applies the pending CHROME_CONNECTED cookie requests one by one.
   void ApplyCookieRequests();
 
-  void FinishedSetCookie(net::CookieAccessResult cookie_access_result);
+  // Called when the request to set CHROME_CONNECTED cookie is done.
+  void FinishedSetChromeConnectedCookie(
+      net::CookieAccessResult cookie_access_result);
 
   // Called when the current CHROME_CONNECTED cookie request is done.
-  void FinishedApplyingCookieRequest(bool success);
+  void FinishedApplyingChromeConnectedCookieRequest(bool success);
 
   // Returns whether the CHROME_CONNECTED cookie should be added to |domain|.
-  // If the cookie is already on |domain|, this function will return false
-  // unless |force_update_if_too_old| is true. In this case, it will return true
-  // if the cookie is considered to be too old.
-  bool ShouldAddChromeConnectedCookieToDomain(const std::string& domain,
-                                              bool force_update_if_too_old);
+  // If the cookie is not already on |domain|, it will return true. If the
+  // cookie is time constrained, |cookie_refresh_interval| is present, then a
+  // cookie older than |cookie_refresh_interval| returns true.
+  bool ShouldSetChromeConnectedCookieToDomain(
+      const std::string& domain,
+      const base::TimeDelta& cookie_refresh_interval);
+
+  // Enqueues a request to set the CHROME_CONNECTED cookie for |domain|.
+  // The cookie is set if it is not already on |domain| or if it is too old
+  // compared to the given |cookie_refresh_interval|.
+  void SetChromeConnectedCookieWithDomain(
+      const std::string& domain,
+      const base::TimeDelta& cookie_refresh_interval);
 
   // Adds CHROME_CONNECTED cookies on all the main Google domains.
   void AddChromeConnectedCookies();
 
+  // Triggers a Gaia cookie update on the Google domain.
+  void TriggerGaiaCookieChangeIfDeleted(
+      const net::CookieAccessResultList& cookie_list,
+      const net::CookieAccessResultList& excluded_cookies);
+
+  // Records whether Gaia cookies were present on navigation in UMA histogram.
+  static void LogIOSGaiaCookiesPresentOnNavigation(bool is_present);
+
   // IdentityManager::Observer implementation.
   void OnPrimaryAccountSet(const CoreAccountInfo& account_info) override;
   void OnPrimaryAccountCleared(
@@ -174,6 +202,9 @@
   // the time when the cookie was last updated.
   std::map<std::string, base::Time> last_cookie_update_map_;
 
+  // Last time Gaia cookie was updated for the Google domain.
+  base::Time last_gaia_cookie_verification_time_;
+
   // Handlers reacting on GAIA responses with the X-Chrome-Manage-Accounts
   // header set.
   std::map<web::WebState*, std::unique_ptr<web::WebStatePolicyDecider>>
diff --git a/components/signin/ios/browser/account_consistency_service.mm b/components/signin/ios/browser/account_consistency_service.mm
index b6ce342..55eefa5 100644
--- a/components/signin/ios/browser/account_consistency_service.mm
+++ b/components/signin/ios/browser/account_consistency_service.mm
@@ -10,6 +10,7 @@
 #include "base/logging.h"
 #import "base/mac/foundation_util.h"
 #include "base/macros.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/strings/sys_string_conversions.h"
 #include "components/content_settings/core/browser/cookie_settings.h"
 #include "components/google/core/common/google_util.h"
@@ -20,11 +21,13 @@
 #include "components/signin/core/browser/signin_header_helper.h"
 #include "components/signin/public/base/account_consistency_method.h"
 #include "components/signin/public/identity_manager/accounts_cookie_mutator.h"
+#include "google_apis/gaia/gaia_urls.h"
 #include "ios/web/common/web_view_creation_util.h"
 #include "ios/web/public/browser_state.h"
 #import "ios/web/public/navigation/web_state_policy_decider.h"
 #include "net/base/mac/url_conversions.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "net/cookies/canonical_cookie.h"
 #include "url/gurl.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -33,9 +36,20 @@
 
 namespace {
 
-// Threshold (in hours) used to control whether the CHROME_CONNECTED cookie
-// should be added again on a domain it was previously set.
-const int kHoursThresholdToReAddCookie = 24;
+// The validity of CHROME_CONNECTED cookies is one day maximum as a
+// precaution to ensure that the cookie is regenerated in the case that it
+// is removed or invalidated.
+constexpr base::TimeDelta kDelayThresholdToUpdateChromeConnectedCookie =
+    base::TimeDelta::FromHours(24);
+// The validity of the Gaia cookie on the Google domain is one hour to
+// ensure that Mirror account consistency is respected in light of the more
+// restrictive Intelligent Tracking Prevention (ITP) guidelines in iOS 14
+// that may remove or invalidate Gaia cookies on the Google domain.
+constexpr base::TimeDelta kDelayThresholdToUpdateGaiaCookie =
+    base::TimeDelta::FromHours(1);
+
+const char* kGoogleDomain = "google.com";
+const char* kYoutubeDomain = "youtube.com";
 
 // WebStatePolicyDecider that monitors the HTTP headers on Gaia responses,
 // reacting on the X-Chrome-Manage-Accounts header and notifying its delegate.
@@ -49,7 +63,9 @@
                             id<ManageAccountsDelegate> delegate);
 
  private:
-  // web::WebStatePolicyDecider override
+  // web::WebStatePolicyDecider override.
+  // Decides on navigation corresponding to |response| whether the navigation
+  // should continue and updates authentication cookies on Google domains.
   void ShouldAllowResponse(
       NSURLResponse* response,
       bool for_main_frame,
@@ -60,7 +76,7 @@
   AccountReconcilor* account_reconcilor_;                   // Weak.
   __weak id<ManageAccountsDelegate> delegate_;
 };
-}
+}  // namespace
 
 AccountConsistencyHandler::AccountConsistencyHandler(
     web::WebState* web_state,
@@ -84,17 +100,15 @@
   }
 
   GURL url = net::GURLWithNSURL(http_response.URL);
-  if (google_util::IsGoogleDomainUrl(
-          url, google_util::ALLOW_SUBDOMAIN,
-          google_util::DISALLOW_NON_STANDARD_PORTS)) {
-    // User is showing intent to navigate to a Google domain. Add the
-    // CHROME_CONNECTED cookie to the domain if necessary.
+  // Logged-in user is showing intent to navigate to a Google domain where we
+  // will need to set a CHROME_CONNECTED cookie if it is not already set.
+  if (signin::IsUrlEligibleForMirrorCookie(url)) {
     std::string domain = net::registry_controlled_domains::GetDomainAndRegistry(
         url, net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
-    account_consistency_service_->AddChromeConnectedCookieToDomain(
-        domain, true /* force_update_if_too_old */);
-    account_consistency_service_->AddChromeConnectedCookieToDomain(
-        "google.com", true /* force_update_if_too_old */);
+    account_consistency_service_->SetChromeConnectedCookieWithDomain(domain);
+    account_consistency_service_->SetChromeConnectedCookieWithDomain(
+        kGoogleDomain);
+    account_consistency_service_->SetGaiaCookiesIfDeleted();
   }
 
   if (!gaia::IsGaiaSignonRealm(url.GetOrigin())) {
@@ -150,6 +164,8 @@
 const char AccountConsistencyService::kChromeConnectedCookieName[] =
     "CHROME_CONNECTED";
 
+const char AccountConsistencyService::kGaiaCookieName[] = "SAPISID";
+
 const char AccountConsistencyService::kDomainsWithCookiePref[] =
     "signin.domains_with_cookie";
 
@@ -225,21 +241,45 @@
   web_state_handlers_.erase(web_state);
 }
 
-bool AccountConsistencyService::ShouldAddChromeConnectedCookieToDomain(
-    const std::string& domain,
-    bool force_update_if_too_old) {
-  auto it = last_cookie_update_map_.find(domain);
-  if (it == last_cookie_update_map_.end()) {
-    // |domain| isn't in the map, always add the cookie.
-    return true;
+void AccountConsistencyService::SetGaiaCookiesIfDeleted() {
+  // We currently enforce a time threshold to update the Gaia cookie
+  // to prevent calling the expensive call to the cookie manager's
+  // |GetAllCookies|.
+  if (base::Time::Now() - last_gaia_cookie_verification_time_ <
+      kDelayThresholdToUpdateGaiaCookie) {
+    return;
   }
-  if (!force_update_if_too_old) {
-    // |domain| is in the map and the cookie is considered valid. Don't add it
-    // again.
-    return false;
+  network::mojom::CookieManager* cookie_manager =
+      browser_state_->GetCookieManager();
+  cookie_manager->GetCookieList(
+      GaiaUrls::GetInstance()->secure_google_url(),
+      net::CookieOptions::MakeAllInclusive(),
+      base::BindOnce(
+          &AccountConsistencyService::TriggerGaiaCookieChangeIfDeleted,
+          base::Unretained(this)));
+  last_gaia_cookie_verification_time_ = base::Time::Now();
+}
+
+void AccountConsistencyService::TriggerGaiaCookieChangeIfDeleted(
+    const net::CookieAccessResultList& cookie_list,
+    const net::CookieAccessResultList& unused_excluded_cookies) {
+  for (const auto& cookie : cookie_list) {
+    if (cookie.cookie.Name() == kGaiaCookieName) {
+      LogIOSGaiaCookiesPresentOnNavigation(true);
+      return;
+    }
   }
-  return (base::Time::Now() - it->second) >
-         base::TimeDelta::FromHours(kHoursThresholdToReAddCookie);
+  // The SAPISID cookie may have been deleted previous to this update due to
+  // ITP restrictions marking Google domains as potential trackers.
+  // Re-generate cookie to ensure that the user is properly signed in.
+  LogIOSGaiaCookiesPresentOnNavigation(false);
+  identity_manager_->GetAccountsCookieMutator()->ForceTriggerOnCookieChange();
+}
+
+void AccountConsistencyService::LogIOSGaiaCookiesPresentOnNavigation(
+    bool is_present) {
+  base::UmaHistogramBoolean("Signin.IOSGaiaCookiePresentOnNavigation",
+                            is_present);
 }
 
 void AccountConsistencyService::RemoveChromeConnectedCookies(
@@ -261,11 +301,17 @@
                                         std::move(callback));
 }
 
-void AccountConsistencyService::AddChromeConnectedCookieToDomain(
+void AccountConsistencyService::SetChromeConnectedCookieWithDomain(
+    const std::string& domain) {
+  SetChromeConnectedCookieWithDomain(
+      domain, kDelayThresholdToUpdateChromeConnectedCookie);
+}
+
+void AccountConsistencyService::SetChromeConnectedCookieWithDomain(
     const std::string& domain,
-    bool force_update_if_too_old) {
-  if (!ShouldAddChromeConnectedCookieToDomain(domain,
-                                              force_update_if_too_old)) {
+    const base::TimeDelta& cookie_refresh_interval) {
+  if (!ShouldSetChromeConnectedCookieToDomain(domain,
+                                              cookie_refresh_interval)) {
     return;
   }
   last_cookie_update_map_[domain] = base::Time::Now();
@@ -273,6 +319,15 @@
   ApplyCookieRequests();
 }
 
+bool AccountConsistencyService::ShouldSetChromeConnectedCookieToDomain(
+    const std::string& domain,
+    const base::TimeDelta& cookie_refresh_interval) {
+  auto domain_iterator = last_cookie_update_map_.find(domain);
+  bool domain_not_found = domain_iterator == last_cookie_update_map_.end();
+  return domain_not_found || ((base::Time::Now() - domain_iterator->second) >
+                              cookie_refresh_interval);
+}
+
 void AccountConsistencyService::RemoveChromeConnectedCookieFromDomain(
     const std::string& domain,
     base::OnceClosure callback) {
@@ -325,7 +380,7 @@
       if (cookie_value.empty()) {
         // Don't add the cookie. Tentatively correct |last_cookie_update_map_|.
         last_cookie_update_map_.erase(cookie_requests_.front().domain);
-        FinishedApplyingCookieRequest(false);
+        FinishedApplyingChromeConnectedCookieRequest(false);
         return;
       }
       // Create expiration date of Now+2y to roughly follow the SAPISID cookie.
@@ -358,17 +413,19 @@
       browser_state_->GetCookieManager();
   cookie_manager->SetCanonicalCookie(
       *cookie, url, options,
-      base::BindOnce(&AccountConsistencyService::FinishedSetCookie,
-                     base::Unretained(this)));
+      base::BindOnce(
+          &AccountConsistencyService::FinishedSetChromeConnectedCookie,
+          base::Unretained(this)));
 }
 
-void AccountConsistencyService::FinishedSetCookie(
+void AccountConsistencyService::FinishedSetChromeConnectedCookie(
     net::CookieAccessResult cookie_access_result) {
   DCHECK(cookie_access_result.status.IsInclude());
-  FinishedApplyingCookieRequest(true);
+  FinishedApplyingChromeConnectedCookieRequest(true);
 }
 
-void AccountConsistencyService::FinishedApplyingCookieRequest(bool success) {
+void AccountConsistencyService::FinishedApplyingChromeConnectedCookieRequest(
+    bool success) {
   DCHECK(!cookie_requests_.empty());
   CookieRequest& request = cookie_requests_.front();
   if (success) {
@@ -399,10 +456,8 @@
   DCHECK(!browser_state_->IsOffTheRecord());
   // These cookie request are preventive and not a strong signal (unlike
   // navigation to a domain). Don't force update the old cookies in this case.
-  AddChromeConnectedCookieToDomain("google.com",
-                                   false /* force_update_if_too_old */);
-  AddChromeConnectedCookieToDomain("youtube.com",
-                                   false /* force_update_if_too_old */);
+  SetChromeConnectedCookieWithDomain(kGoogleDomain, base::TimeDelta::Max());
+  SetChromeConnectedCookieWithDomain(kYoutubeDomain, base::TimeDelta::Max());
 }
 
 void AccountConsistencyService::OnBrowsingDataRemoved() {
@@ -416,6 +471,7 @@
   }
   cookie_requests_.clear();
   last_cookie_update_map_.clear();
+  last_gaia_cookie_verification_time_ = base::Time();
   base::DictionaryValue dict;
   prefs_->Set(kDomainsWithCookiePref, dict);
 
diff --git a/components/signin/ios/browser/account_consistency_service_unittest.mm b/components/signin/ios/browser/account_consistency_service_unittest.mm
index a054686..431d363 100644
--- a/components/signin/ios/browser/account_consistency_service_unittest.mm
+++ b/components/signin/ios/browser/account_consistency_service_unittest.mm
@@ -141,6 +141,10 @@
 
 class AccountConsistencyServiceTest : public PlatformTest {
  public:
+  AccountConsistencyServiceTest()
+      : task_environment_(web::WebTaskEnvironment::Options::DEFAULT,
+                          base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
+
   void OnRemoveChromeConnectedCookieFinished() {
     EXPECT_FALSE(remove_cookie_callback_called_);
     remove_cookie_callback_called_ = true;
@@ -209,12 +213,6 @@
     WaitUntilAllCookieRequestsAreApplied();
   }
 
-  bool ShouldAddCookieToDomain(const std::string& domain,
-                               bool should_check_last_update_time) {
-    return account_consistency_service_->ShouldAddChromeConnectedCookieToDomain(
-        domain, should_check_last_update_time);
-  }
-
   std::vector<net::CanonicalCookie> GetCookiesInCookieJar() {
     std::vector<net::CanonicalCookie> cookies_out;
     base::RunLoop run_loop;
@@ -264,6 +262,31 @@
     run_loop.Run();
   }
 
+  // Simulates setting the CHROME_CONNECTED cookie for the Google domain at the
+  // designated time interval. Returns the time at which the cookie was updated.
+  base::Time SimulateSetChromeConnectedCookie() {
+    account_consistency_service_->SetChromeConnectedCookieWithDomain(
+        kGoogleDomain);
+    WaitUntilAllCookieRequestsAreApplied();
+
+    return account_consistency_service_->last_cookie_update_map_[kGoogleDomain];
+  }
+
+  // Simulates updating the Gaia cookie on the Google domain at the designated
+  // time interval. Returns the time at which the cookie was updated.
+  base::Time SimulateUpdateGaiaCookie() {
+    account_consistency_service_->SetGaiaCookiesIfDeleted();
+    WaitUntilAllCookieRequestsAreApplied();
+
+    return account_consistency_service_->last_gaia_cookie_verification_time_;
+  }
+
+  void CheckGoogleDomainHasGaiaCookie() {
+    EXPECT_TRUE(ContainsCookie(GetCookiesInCookieJar(),
+                               AccountConsistencyService::kGaiaCookieName,
+                               ".google.com"));
+  }
+
   // Creates test threads, necessary for ActiveStateManager that needs a UI
   // thread.
   web::WebTaskEnvironment task_environment_;
@@ -471,43 +494,46 @@
           ->size());
 }
 
-// Tests that cookie requests are correctly processed or ignored when the update
-// time isn't checked.
-TEST_F(AccountConsistencyServiceTest, ShouldAddCookieDontCheckUpdateTime) {
-  EXPECT_TRUE(ShouldAddCookieToDomain(kGoogleDomain, false));
-  EXPECT_TRUE(ShouldAddCookieToDomain(kYoutubeDomain, false));
-
+TEST_F(AccountConsistencyServiceTest, SetChromeConnectedCookieNotUpdateTime) {
   SignIn();
-  CheckDomainHasChromeConnectedCookie(kGoogleDomain);
-  CheckDomainHasChromeConnectedCookie(kYoutubeDomain);
-  EXPECT_FALSE(ShouldAddCookieToDomain(kGoogleDomain, false));
-  EXPECT_FALSE(ShouldAddCookieToDomain(kYoutubeDomain, false));
+  base::Time first_cookie_update = SimulateSetChromeConnectedCookie();
 
-  ResetAccountConsistencyService();
-
-  CheckDomainHasChromeConnectedCookie(kGoogleDomain);
-  CheckDomainHasChromeConnectedCookie(kYoutubeDomain);
-  EXPECT_FALSE(ShouldAddCookieToDomain(kGoogleDomain, false));
-  EXPECT_FALSE(ShouldAddCookieToDomain(kYoutubeDomain, false));
+  // The second update will not send a cookie request, since this call is made
+  // before update time.
+  base::Time second_cookie_update = SimulateSetChromeConnectedCookie();
+  EXPECT_EQ(first_cookie_update, second_cookie_update);
 }
 
-// Tests that cookie requests are correctly processed or ignored when the update
-// time is checked.
-TEST_F(AccountConsistencyServiceTest, ShouldAddCookieCheckUpdateTime) {
-  EXPECT_TRUE(ShouldAddCookieToDomain(kGoogleDomain, true));
-  EXPECT_TRUE(ShouldAddCookieToDomain(kYoutubeDomain, true));
-
+TEST_F(AccountConsistencyServiceTest, SetChromeConnectedCookieAtUpdateTime) {
   SignIn();
-  CheckDomainHasChromeConnectedCookie(kGoogleDomain);
-  CheckDomainHasChromeConnectedCookie(kYoutubeDomain);
+  base::Time first_cookie_update = SimulateSetChromeConnectedCookie();
 
-  EXPECT_FALSE(ShouldAddCookieToDomain(kGoogleDomain, true));
-  EXPECT_FALSE(ShouldAddCookieToDomain(kYoutubeDomain, true));
+  // Advance clock past 24-hour CHROME_CONNECTED update time.
+  task_environment_.FastForwardBy(base::TimeDelta::FromDays(2));
 
-  ResetAccountConsistencyService();
-  CheckDomainHasChromeConnectedCookie(kGoogleDomain);
-  CheckDomainHasChromeConnectedCookie(kYoutubeDomain);
+  // The second update will not send a cookie request, since CHROME_CONNECTED
+  // has already been set.
+  base::Time second_cookie_update = SimulateSetChromeConnectedCookie();
+  EXPECT_GT(second_cookie_update, first_cookie_update);
+}
 
-  EXPECT_TRUE(ShouldAddCookieToDomain(kGoogleDomain, true));
-  EXPECT_TRUE(ShouldAddCookieToDomain(kYoutubeDomain, true));
+TEST_F(AccountConsistencyServiceTest, SetGaiaCookieUpdateNotUpdateTime) {
+  base::Time first_gaia_cookie_update = SimulateUpdateGaiaCookie();
+
+  // The second update will not send a cookie request, since this call is made
+  // before update time.
+  base::Time second_gaia_cookie_update = SimulateUpdateGaiaCookie();
+  EXPECT_EQ(first_gaia_cookie_update, second_gaia_cookie_update);
+}
+
+TEST_F(AccountConsistencyServiceTest, SetGaiaCookieUpdateAtUpdateTime) {
+  base::Time first_gaia_cookie_update = SimulateUpdateGaiaCookie();
+
+  // Advance clock past one-hour Gaia update time.
+  task_environment_.FastForwardBy(base::TimeDelta::FromHours(2));
+
+  // The second update will send a cookie request, since update time is not
+  // considered for the call.
+  base::Time second_gaia_cookie_update = SimulateUpdateGaiaCookie();
+  EXPECT_GT(second_gaia_cookie_update, first_gaia_cookie_update);
 }
diff --git a/components/user_manager/known_user.cc b/components/user_manager/known_user.cc
index a92b89a..cb8fc18 100644
--- a/components/user_manager/known_user.cc
+++ b/components/user_manager/known_user.cc
@@ -91,6 +91,9 @@
 // Key for the PIN auto submit backfill needed indicator.
 const char kPinAutosubmitBackfillNeeded[] = "pin_autosubmit_backfill_needed";
 
+// Sync token for SAML password multi-device sync
+const char kPasswordSyncToken[] = "password_sync_token";
+
 // List containing all the known user preferences keys.
 const char* kReservedKeys[] = {kCanonicalEmail,
                                kGAIAIdKey,
@@ -111,7 +114,8 @@
                                kIsEnterpriseManaged,
                                kLastInputMethod,
                                kPinAutosubmitLength,
-                               kPinAutosubmitBackfillNeeded};
+                               kPinAutosubmitBackfillNeeded,
+                               kPasswordSyncToken};
 
 PrefService* GetLocalState() {
   if (!UserManager::IsInitialized())
@@ -712,6 +716,19 @@
   SetBooleanPref(account_id, kPinAutosubmitBackfillNeeded, true);
 }
 
+void SetPasswordSyncToken(const AccountId& account_id,
+                          const std::string& token) {
+  SetStringPref(account_id, kPasswordSyncToken, token);
+}
+
+std::string GetPasswordSyncToken(const AccountId& account_id) {
+  std::string token;
+  if (GetStringPref(account_id, kPasswordSyncToken, &token))
+    return token;
+  // Return empty string if sync token was not set for the account yet.
+  return std::string();
+}
+
 void RemovePrefs(const AccountId& account_id) {
   PrefService* local_state = GetLocalState();
 
diff --git a/components/user_manager/known_user.h b/components/user_manager/known_user.h
index 577dd6c..6e367ab 100644
--- a/components/user_manager/known_user.h
+++ b/components/user_manager/known_user.h
@@ -256,6 +256,14 @@
 void USER_MANAGER_EXPORT
 PinAutosubmitSetBackfillNeededForTests(const AccountId& account_id);
 
+// Setter and getter for password sync token used for syncing SAML passwords
+// across multiple user devices.
+void USER_MANAGER_EXPORT SetPasswordSyncToken(const AccountId& account_id,
+                                              const std::string& token);
+
+std::string USER_MANAGER_EXPORT
+GetPasswordSyncToken(const AccountId& account_id);
+
 // Removes all user preferences associated with |account_id|.
 // Not exported as code should not be calling this outside this component
 void RemovePrefs(const AccountId& account_id);
diff --git a/components/variations/synthetic_trial_registry.cc b/components/variations/synthetic_trial_registry.cc
index 12869e3..c0afd33c 100644
--- a/components/variations/synthetic_trial_registry.cc
+++ b/components/variations/synthetic_trial_registry.cc
@@ -16,7 +16,7 @@
 namespace internal {
 
 const base::Feature kExternalExperimentAllowlist{
-    "ExternalExperimentAllowlist", base::FEATURE_DISABLED_BY_DEFAULT};
+    "ExternalExperimentAllowlist", base::FEATURE_ENABLED_BY_DEFAULT};
 
 }  // namespace internal
 
diff --git a/components/viz/test/test_context_provider.cc b/components/viz/test/test_context_provider.cc
index e3d2515..aede008 100644
--- a/components/viz/test/test_context_provider.cc
+++ b/components/viz/test/test_context_provider.cc
@@ -8,7 +8,6 @@
 #include <stdint.h>
 
 #include <set>
-#include <string>
 #include <utility>
 #include <vector>
 
@@ -167,6 +166,16 @@
   return mailbox;
 }
 
+gpu::Mailbox TestSharedImageInterface::CreateSharedImageWithAHB(
+    const gpu::Mailbox& mailbox,
+    uint32_t usage,
+    const gpu::SyncToken& sync_token) {
+  base::AutoLock locked(lock_);
+  auto out_mailbox = gpu::Mailbox::GenerateForSharedImage();
+  shared_images_.insert(out_mailbox);
+  return out_mailbox;
+}
+
 void TestSharedImageInterface::UpdateSharedImage(
     const gpu::SyncToken& sync_token,
     const gpu::Mailbox& mailbox) {
diff --git a/components/viz/test/test_context_provider.h b/components/viz/test/test_context_provider.h
index 2c967601..1b895b4 100644
--- a/components/viz/test/test_context_provider.h
+++ b/components/viz/test/test_context_provider.h
@@ -65,6 +65,11 @@
       SkAlphaType alpha_type,
       uint32_t usage) override;
 
+  gpu::Mailbox CreateSharedImageWithAHB(
+      const gpu::Mailbox& mailbox,
+      uint32_t usage,
+      const gpu::SyncToken& sync_token) override;
+
   void UpdateSharedImage(const gpu::SyncToken& sync_token,
                          const gpu::Mailbox& mailbox) override;
   void UpdateSharedImage(const gpu::SyncToken& sync_token,
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index fa012c31..1207a4a7 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -1714,6 +1714,23 @@
     return;
   }
 
+  // If the main document hasn't specified any network report endpoint(s),
+  // then it is likely not interested in receiving:
+  // 1. Network reports (for obvious reasons).
+  // 2. ReportingObserver's reports.
+  // 3. Devtools warnings.
+  //
+  // Not creating a COOP reporter currently prevents all of these.
+  //
+  // TODO(arthursonzogni): Reconsider this decision later, developers might be
+  // interested in (2) and (3), despite not being interested in (1).
+  if (!render_frame_host_->cross_origin_opener_policy().reporting_endpoint &&
+      !render_frame_host_->cross_origin_opener_policy()
+           .report_only_reporting_endpoint) {
+    return;
+  }
+
+  DCHECK(IsInMainFrame());
   coop_reporter_ = std::make_unique<CrossOriginOpenerPolicyReporter>(
       storage_partition, frame_tree_node_->current_frame_host(),
       common_params_->url, render_frame_host_->cross_origin_opener_policy());
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 67e5f80..f5c8b483 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -5177,7 +5177,7 @@
 #endif
 
 void RenderProcessHostImpl::ProvideSwapFileForRenderer() {
-  if (!base::FeatureList::IsEnabled(blink::features::kParkableStringsToDisk))
+  if (!blink::features::IsParkableStringsToDiskEnabled())
     return;
 
   // In Incognito, nothing should be written to disk. Don't provide a file..
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
index 5366fe7..1e01f307 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -3845,7 +3845,7 @@
 // Tests that a fling in the opposite direction of the overscroll cancels the
 // overscroll instead of completing it.
 // Flaky on Fuchsia:  http://crbug.com/810690.
-#if defined(OS_FUCHSIA) || defined(OS_LINUX)
+#if defined(OS_FUCHSIA) || defined(OS_LINUX) || defined(OS_WIN)
 #define MAYBE_ReverseFlingCancelsOverscroll \
   DISABLED_ReverseFlingCancelsOverscroll
 #else
diff --git a/content/browser/service_worker/embedded_worker_instance_unittest.cc b/content/browser/service_worker/embedded_worker_instance_unittest.cc
index 7588ade7..302165f 100644
--- a/content/browser/service_worker/embedded_worker_instance_unittest.cc
+++ b/content/browser/service_worker/embedded_worker_instance_unittest.cc
@@ -115,8 +115,6 @@
   RegistrationAndVersionPair PrepareRegistrationAndVersion(
       const GURL& scope,
       const GURL& script_url) {
-    context()->storage()->LazyInitializeForTest();
-
     RegistrationAndVersionPair pair;
     blink::mojom::ServiceWorkerRegistrationOptions options;
     options.scope = scope;
diff --git a/content/browser/service_worker/service_worker_context_wrapper_unittest.cc b/content/browser/service_worker/service_worker_context_wrapper_unittest.cc
index 832631b9..7ea0897 100644
--- a/content/browser/service_worker/service_worker_context_wrapper_unittest.cc
+++ b/content/browser/service_worker/service_worker_context_wrapper_unittest.cc
@@ -56,13 +56,10 @@
                    url_loader_factory_getter_.get());
     // Init() posts a couple tasks to the IO thread. Let them finish.
     base::RunLoop().RunUntilIdle();
-
-    storage()->LazyInitializeForTest();
   }
 
   ServiceWorkerContextCore* context() { return wrapper_->context(); }
   ServiceWorkerRegistry* registry() { return context()->registry(); }
-  ServiceWorkerStorage* storage() { return context()->storage(); }
 
   blink::ServiceWorkerStatusCode StoreRegistration(
       scoped_refptr<ServiceWorkerRegistration> registration) {
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc b/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
index dfa6c691..16c9ae0 100644
--- a/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
+++ b/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
@@ -106,7 +106,6 @@
         registration_.get(), script_url_, blink::mojom::ScriptType::kClassic,
         1L, mojo::PendingRemote<storage::mojom::ServiceWorkerLiveVersionRef>(),
         context()->AsWeakPtr());
-    context()->storage()->LazyInitializeForTest();
 
     std::vector<storage::mojom::ServiceWorkerResourceRecordPtr> records;
     records.push_back(WriteToDiskCacheSync(
diff --git a/content/browser/service_worker/service_worker_installed_scripts_sender_unittest.cc b/content/browser/service_worker/service_worker_installed_scripts_sender_unittest.cc
index 4727e4c..3ad9ed56 100644
--- a/content/browser/service_worker/service_worker_installed_scripts_sender_unittest.cc
+++ b/content/browser/service_worker/service_worker_installed_scripts_sender_unittest.cc
@@ -126,8 +126,6 @@
   void SetUp() override {
     helper_ = std::make_unique<EmbeddedWorkerTestHelper>(base::FilePath());
 
-    context()->storage()->LazyInitializeForTest();
-
     scope_ = GURL("http://www.example.com/test/");
     blink::mojom::ServiceWorkerRegistrationOptions options;
     options.scope = scope_;
diff --git a/content/browser/service_worker/service_worker_job_unittest.cc b/content/browser/service_worker/service_worker_job_unittest.cc
index 413fc91c..e2fcce1 100644
--- a/content/browser/service_worker/service_worker_job_unittest.cc
+++ b/content/browser/service_worker/service_worker_job_unittest.cc
@@ -179,7 +179,6 @@
     return context()->job_coordinator();
   }
   ServiceWorkerRegistry* registry() const { return context()->registry(); }
-  ServiceWorkerStorage* storage() const { return context()->storage(); }
 
  protected:
   scoped_refptr<ServiceWorkerRegistration> RunRegisterJob(
@@ -1296,7 +1295,6 @@
     ScriptFailureEmbeddedWorkerInstanceClient* client_;
   };
 
-  ServiceWorkerStorage* storage() { return context()->storage(); }
   ServiceWorkerJobCoordinator* job_coordinator() {
     return context()->job_coordinator();
   }
diff --git a/content/browser/service_worker/service_worker_main_resource_loader_unittest.cc b/content/browser/service_worker/service_worker_main_resource_loader_unittest.cc
index 0bdd02c..7d774f39 100644
--- a/content/browser/service_worker/service_worker_main_resource_loader_unittest.cc
+++ b/content/browser/service_worker/service_worker_main_resource_loader_unittest.cc
@@ -398,7 +398,6 @@
     helper_ = std::make_unique<EmbeddedWorkerTestHelper>(base::FilePath());
 
     // Create an active service worker.
-    storage()->LazyInitializeForTest();
     blink::mojom::ServiceWorkerRegistrationOptions options;
     options.scope = GURL("https://example.com/");
     registration_ = CreateNewServiceWorkerRegistration(
@@ -453,7 +452,6 @@
   }
 
   ServiceWorkerRegistry* registry() { return helper_->context()->registry(); }
-  ServiceWorkerStorage* storage() { return helper_->context()->storage(); }
   mojo::Remote<storage::mojom::ServiceWorkerStorageControl>&
   GetStorageControl() {
     return helper_->context()->GetStorageControl();
diff --git a/content/browser/service_worker/service_worker_new_script_loader_unittest.cc b/content/browser/service_worker/service_worker_new_script_loader_unittest.cc
index a573e2ae..1a50c1e 100644
--- a/content/browser/service_worker/service_worker_new_script_loader_unittest.cc
+++ b/content/browser/service_worker/service_worker_new_script_loader_unittest.cc
@@ -153,8 +153,6 @@
   void SetUp() override {
     helper_ = std::make_unique<EmbeddedWorkerTestHelper>(base::FilePath());
 
-    context()->storage()->LazyInitializeForTest();
-
     mock_server_.Set(GURL(kNormalScriptURL),
                      MockHTTPServer::Response(
                          std::string("HTTP/1.1 200 OK\n"
diff --git a/content/browser/service_worker/service_worker_object_host_unittest.cc b/content/browser/service_worker/service_worker_object_host_unittest.cc
index 800a1ac..459691c7 100644
--- a/content/browser/service_worker/service_worker_object_host_unittest.cc
+++ b/content/browser/service_worker/service_worker_object_host_unittest.cc
@@ -112,8 +112,6 @@
   }
 
   void SetUpRegistration(const GURL& scope, const GURL& script_url) {
-    helper_->context()->storage()->LazyInitializeForTest();
-
     blink::mojom::ServiceWorkerRegistrationOptions options;
     options.scope = scope;
     registration_ = CreateNewServiceWorkerRegistration(
diff --git a/content/browser/service_worker/service_worker_registration_unittest.cc b/content/browser/service_worker/service_worker_registration_unittest.cc
index 35aca8b2..0d0c662d 100644
--- a/content/browser/service_worker/service_worker_registration_unittest.cc
+++ b/content/browser/service_worker/service_worker_registration_unittest.cc
@@ -186,13 +186,10 @@
     storage_partition_impl_->Initialize();
     helper_->context_wrapper()->set_storage_partition(
         storage_partition_impl_.get());
-
-    context()->storage()->LazyInitializeForTest();
   }
 
   ServiceWorkerContextCore* context() { return helper_->context(); }
   ServiceWorkerRegistry* registry() { return helper_->context()->registry(); }
-  ServiceWorkerStorage* storage() { return helper_->context()->storage(); }
 
   class RegistrationListener : public ServiceWorkerRegistration::Listener {
    public:
@@ -907,8 +904,6 @@
   }
 
   int64_t SetUpRegistration(const GURL& scope, const GURL& script_url) {
-    storage()->LazyInitializeForTest();
-
     // Prepare ServiceWorkerRegistration and ServiceWorkerVersion.
     scoped_refptr<ServiceWorkerRegistration> registration =
         CreateNewRegistration(scope);
diff --git a/content/browser/service_worker/service_worker_registry_unittest.cc b/content/browser/service_worker/service_worker_registry_unittest.cc
index f993393..a1f8d1a0 100644
--- a/content/browser/service_worker/service_worker_registry_unittest.cc
+++ b/content/browser/service_worker/service_worker_registry_unittest.cc
@@ -42,7 +42,6 @@
     special_storage_policy_ =
         base::MakeRefCounted<storage::MockSpecialStoragePolicy>();
     InitializeTestHelper();
-    LazyInitialize();
   }
 
   void TearDown() override {
@@ -63,8 +62,6 @@
         user_data_directory_path_, special_storage_policy_.get());
   }
 
-  void LazyInitialize() { registry()->storage()->LazyInitializeForTest(); }
-
   void SimulateRestart() {
     // Need to reset |helper_| then wait for scheduled tasks to be finished
     // because |helper_| has TestBrowserContext and the dtor schedules storage
@@ -72,7 +69,6 @@
     helper_.reset();
     base::RunLoop().RunUntilIdle();
     InitializeTestHelper();
-    LazyInitialize();
   }
 
   blink::ServiceWorkerStatusCode FindRegistrationForClientUrl(
@@ -129,7 +125,6 @@
 };
 
 TEST_F(ServiceWorkerRegistryTest, FindRegistration_LongestScopeMatch) {
-  LazyInitialize();
   const GURL kDocumentUrl("http://www.example.com/scope/foo");
   scoped_refptr<ServiceWorkerRegistration> found_registration;
 
diff --git a/content/browser/service_worker/service_worker_script_loader_factory_unittest.cc b/content/browser/service_worker/service_worker_script_loader_factory_unittest.cc
index 5f24dfc..d97e257b 100644
--- a/content/browser/service_worker/service_worker_script_loader_factory_unittest.cc
+++ b/content/browser/service_worker/service_worker_script_loader_factory_unittest.cc
@@ -32,7 +32,6 @@
   void SetUp() override {
     helper_ = std::make_unique<EmbeddedWorkerTestHelper>(base::FilePath());
     ServiceWorkerContextCore* context = helper_->context();
-    context->storage()->LazyInitializeForTest();
 
     scope_ = GURL("https://host/scope");
     script_url_ = GURL("https://host/script.js");
diff --git a/content/browser/service_worker/service_worker_storage.cc b/content/browser/service_worker/service_worker_storage.cc
index a759815..ca4bba5a 100644
--- a/content/browser/service_worker/service_worker_storage.cc
+++ b/content/browser/service_worker/service_worker_storage.cc
@@ -885,17 +885,63 @@
 
 void ServiceWorkerStorage::GetNewRegistrationId(
     base::OnceCallback<void(int64_t registration_id)> callback) {
-  std::move(callback).Run(NewRegistrationId());
+  switch (state_) {
+    case STORAGE_STATE_DISABLED:
+      std::move(callback).Run(
+          blink::mojom::kInvalidServiceWorkerRegistrationId);
+      return;
+    case STORAGE_STATE_INITIALIZING:  // Fall-through.
+    case STORAGE_STATE_UNINITIALIZED:
+      LazyInitialize(base::BindOnce(&ServiceWorkerStorage::GetNewRegistrationId,
+                                    weak_factory_.GetWeakPtr(),
+                                    std::move(callback)));
+      return;
+    case STORAGE_STATE_INITIALIZED:
+      break;
+  }
+  int64_t registration_id = next_registration_id_;
+  ++next_registration_id_;
+  std::move(callback).Run(registration_id);
 }
 
 void ServiceWorkerStorage::GetNewVersionId(
     base::OnceCallback<void(int64_t version_id)> callback) {
-  std::move(callback).Run(NewVersionId());
+  switch (state_) {
+    case STORAGE_STATE_DISABLED:
+      std::move(callback).Run(blink::mojom::kInvalidServiceWorkerVersionId);
+      return;
+    case STORAGE_STATE_INITIALIZING:  // Fall-through.
+    case STORAGE_STATE_UNINITIALIZED:
+      LazyInitialize(base::BindOnce(&ServiceWorkerStorage::GetNewVersionId,
+                                    weak_factory_.GetWeakPtr(),
+                                    std::move(callback)));
+      return;
+    case STORAGE_STATE_INITIALIZED:
+      break;
+  }
+  int64_t version_id = next_version_id_;
+  ++next_version_id_;
+  std::move(callback).Run(version_id);
 }
 
 void ServiceWorkerStorage::GetNewResourceId(
     base::OnceCallback<void(int64_t resource_id)> callback) {
-  std::move(callback).Run(NewResourceId());
+  switch (state_) {
+    case STORAGE_STATE_DISABLED:
+      std::move(callback).Run(blink::mojom::kInvalidServiceWorkerResourceId);
+      return;
+    case STORAGE_STATE_INITIALIZING:  // Fall-through.
+    case STORAGE_STATE_UNINITIALIZED:
+      LazyInitialize(base::BindOnce(&ServiceWorkerStorage::GetNewResourceId,
+                                    weak_factory_.GetWeakPtr(),
+                                    std::move(callback)));
+      return;
+    case STORAGE_STATE_INITIALIZED:
+      break;
+  }
+  int64_t resource_id = next_resource_id_;
+  ++next_resource_id_;
+  std::move(callback).Run(resource_id);
 }
 
 void ServiceWorkerStorage::Disable() {
@@ -1254,28 +1300,6 @@
                                 origins_to_purge_on_shutdown_));
 }
 
-int64_t ServiceWorkerStorage::NewRegistrationId() {
-  if (state_ == STORAGE_STATE_DISABLED) {
-    return blink::mojom::kInvalidServiceWorkerRegistrationId;
-  }
-  DCHECK_EQ(STORAGE_STATE_INITIALIZED, state_);
-  return next_registration_id_++;
-}
-
-int64_t ServiceWorkerStorage::NewVersionId() {
-  if (state_ == STORAGE_STATE_DISABLED)
-    return blink::mojom::kInvalidServiceWorkerVersionId;
-  DCHECK_EQ(STORAGE_STATE_INITIALIZED, state_);
-  return next_version_id_++;
-}
-
-int64_t ServiceWorkerStorage::NewResourceId() {
-  if (state_ == STORAGE_STATE_DISABLED)
-    return blink::mojom::kInvalidServiceWorkerResourceId;
-  DCHECK_EQ(STORAGE_STATE_INITIALIZED, state_);
-  return next_resource_id_++;
-}
-
 // static
 void ServiceWorkerStorage::CollectStaleResourcesFromDB(
     ServiceWorkerDatabase* database,
diff --git a/content/browser/service_worker/service_worker_storage.h b/content/browser/service_worker/service_worker_storage.h
index 6cb186e..e55a6d7d 100644
--- a/content/browser/service_worker/service_worker_storage.h
+++ b/content/browser/service_worker/service_worker_storage.h
@@ -430,10 +430,6 @@
 
   void ClearSessionOnlyOrigins();
 
-  int64_t NewRegistrationId();
-  int64_t NewVersionId();
-  int64_t NewResourceId();
-
   bool IsDisabled() const { return state_ == STORAGE_STATE_DISABLED; }
 
   // Static cross-thread helpers.
diff --git a/content/browser/service_worker/service_worker_storage_unittest.cc b/content/browser/service_worker/service_worker_storage_unittest.cc
index b2659ec0..2a64914 100644
--- a/content/browser/service_worker/service_worker_storage_unittest.cc
+++ b/content/browser/service_worker/service_worker_storage_unittest.cc
@@ -612,6 +612,39 @@
     return result.value();
   }
 
+  int64_t GetNewRegistrationId() {
+    int64_t result;
+    base::RunLoop loop;
+    storage()->GetNewRegistrationId(base::BindLambdaForTesting([&](int64_t id) {
+      result = id;
+      loop.Quit();
+    }));
+    loop.Run();
+    return result;
+  }
+
+  int64_t GetNewVersionId() {
+    int64_t result;
+    base::RunLoop loop;
+    storage()->GetNewVersionId(base::BindLambdaForTesting([&](int64_t id) {
+      result = id;
+      loop.Quit();
+    }));
+    loop.Run();
+    return result;
+  }
+
+  int64_t GetNewResourceId() {
+    int64_t result;
+    base::RunLoop loop;
+    storage()->GetNewResourceId(base::BindLambdaForTesting([&](int64_t id) {
+      result = id;
+      loop.Quit();
+    }));
+    loop.Run();
+    return result;
+  }
+
   base::circular_deque<int64_t> GetPurgingResources() {
     return storage()->purgeable_resource_ids_;
   }
@@ -752,11 +785,9 @@
 
   // Next available ids should be invalid.
   EXPECT_EQ(blink::mojom::kInvalidServiceWorkerRegistrationId,
-            storage()->NewRegistrationId());
-  EXPECT_EQ(blink::mojom::kInvalidServiceWorkerVersionId,
-            storage()->NewVersionId());
-  EXPECT_EQ(blink::mojom::kInvalidServiceWorkerResourceId,
-            storage()->NewRegistrationId());
+            GetNewRegistrationId());
+  EXPECT_EQ(blink::mojom::kInvalidServiceWorkerVersionId, GetNewVersionId());
+  EXPECT_EQ(blink::mojom::kInvalidServiceWorkerResourceId, GetNewResourceId());
 }
 
 TEST_F(ServiceWorkerStorageTest, StoreFindUpdateDeleteRegistration) {
diff --git a/content/browser/service_worker/service_worker_updated_script_loader_unittest.cc b/content/browser/service_worker/service_worker_updated_script_loader_unittest.cc
index 32e845a..f844e8a9 100644
--- a/content/browser/service_worker/service_worker_updated_script_loader_unittest.cc
+++ b/content/browser/service_worker/service_worker_updated_script_loader_unittest.cc
@@ -78,7 +78,6 @@
 
   void SetUp() override {
     helper_ = std::make_unique<EmbeddedWorkerTestHelper>(base::FilePath());
-    context()->storage()->LazyInitializeForTest();
     SetUpRegistration(kScriptURL);
 
     // Create the old script resource in storage.
diff --git a/content/browser/service_worker/service_worker_version_unittest.cc b/content/browser/service_worker/service_worker_version_unittest.cc
index 2ba0b28..052cbb95 100644
--- a/content/browser/service_worker/service_worker_version_unittest.cc
+++ b/content/browser/service_worker/service_worker_version_unittest.cc
@@ -88,7 +88,6 @@
 
   void SetUp() override {
     helper_ = GetHelper();
-    helper_->context()->storage()->LazyInitializeForTest();
 
     scope_ = GURL("https://www.example.com/test/");
     blink::mojom::ServiceWorkerRegistrationOptions options;
diff --git a/content/browser/worker_host/worker_script_loader_factory_unittest.cc b/content/browser/worker_host/worker_script_loader_factory_unittest.cc
index 0ac1f5a..1daba9d3 100644
--- a/content/browser/worker_host/worker_script_loader_factory_unittest.cc
+++ b/content/browser/worker_host/worker_script_loader_factory_unittest.cc
@@ -38,8 +38,6 @@
   void SetUp() override {
     // Set up the service worker system.
     helper_ = std::make_unique<EmbeddedWorkerTestHelper>(base::FilePath());
-    ServiceWorkerContextCore* context = helper_->context();
-    context->storage()->LazyInitializeForTest();
 
     browser_context_getter_ =
         base::BindRepeating(&ServiceWorkerContextWrapper::browser_context,
diff --git a/content/test/data/accessibility/html/input-file-expected-auralinux.txt b/content/test/data/accessibility/html/input-file-expected-auralinux.txt
index c765e17..0c1b255 100644
--- a/content/test/data/accessibility/html/input-file-expected-auralinux.txt
+++ b/content/test/data/accessibility/html/input-file-expected-auralinux.txt
@@ -1,4 +1,4 @@
 [document web]
 ++[section]
-++++[push button] name='No file chosen, Choose File'
-++++++[push button] name='Choose File'
\ No newline at end of file
+++++[push button] name='Choose File'
+++++++[push button] name='Choose File'
diff --git a/content/test/data/accessibility/html/input-file-expected-blink.txt b/content/test/data/accessibility/html/input-file-expected-blink.txt
index 565453a..26a674cf 100644
--- a/content/test/data/accessibility/html/input-file-expected-blink.txt
+++ b/content/test/data/accessibility/html/input-file-expected-blink.txt
@@ -1,7 +1,7 @@
 rootWebArea
 ++genericContainer ignored
 ++++genericContainer
-++++++button inputType='file' name='No file chosen, Choose File' value='No file chosen'
+++++++button inputType='file' name='Choose File' value='No file chosen'
 ++++++++button inputType='button' name='Choose File'
 ++++++++++staticText name='Choose File'
-++++++++++++inlineTextBox name='Choose File'
\ No newline at end of file
+++++++++++++inlineTextBox name='Choose File'
diff --git a/content/test/data/accessibility/html/input-file-expected-mac.txt b/content/test/data/accessibility/html/input-file-expected-mac.txt
index 90591b4..8ce79f7 100644
--- a/content/test/data/accessibility/html/input-file-expected-mac.txt
+++ b/content/test/data/accessibility/html/input-file-expected-mac.txt
@@ -1,4 +1,4 @@
 AXWebArea
 ++AXGroup
-++++AXButton AXTitle='No file chosen, Choose File'
-++++++AXButton AXTitle='Choose File'
\ No newline at end of file
+++++AXButton AXTitle='Choose File'
+++++++AXButton AXTitle='Choose File'
diff --git a/content/test/data/accessibility/html/input-file-expected-uia-win.txt b/content/test/data/accessibility/html/input-file-expected-uia-win.txt
index 864eb85c..4791dbd1 100644
--- a/content/test/data/accessibility/html/input-file-expected-uia-win.txt
+++ b/content/test/data/accessibility/html/input-file-expected-uia-win.txt
@@ -1,4 +1,4 @@
 Document
 ++Group IsControlElement=false
-++++Button Name='No file chosen, Choose File'
-++++++Button Name='Choose File'
\ No newline at end of file
+++++Button Name='Choose File'
+++++++Button Name='Choose File'
diff --git a/content/test/data/accessibility/html/input-file-expected-win.txt b/content/test/data/accessibility/html/input-file-expected-win.txt
index 32305241..3f98ef0 100644
--- a/content/test/data/accessibility/html/input-file-expected-win.txt
+++ b/content/test/data/accessibility/html/input-file-expected-win.txt
@@ -1,4 +1,4 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE ia2_hypertext='<obj0>'
 ++IA2_ROLE_SECTION ia2_hypertext='<obj0>'
-++++ROLE_SYSTEM_PUSHBUTTON name='No file chosen, Choose File' value='No file chosen' FOCUSABLE ia2_hypertext='<obj0>'
-++++++ROLE_SYSTEM_PUSHBUTTON name='Choose File' FOCUSABLE ia2_hypertext='Choose File'
\ No newline at end of file
+++++ROLE_SYSTEM_PUSHBUTTON name='Choose File' value='No file chosen' FOCUSABLE ia2_hypertext='<obj0>'
+++++++ROLE_SYSTEM_PUSHBUTTON name='Choose File' FOCUSABLE ia2_hypertext='Choose File'
diff --git a/content/test/data/accessibility/html/modal-dialog-opened-expected-blink.txt b/content/test/data/accessibility/html/modal-dialog-opened-expected-blink.txt
index 7aa8061..1976aea 100644
--- a/content/test/data/accessibility/html/modal-dialog-opened-expected-blink.txt
+++ b/content/test/data/accessibility/html/modal-dialog-opened-expected-blink.txt
@@ -11,5 +11,5 @@
 ++++++++popUpButton collapsed ignored invisible value='This should be pruned out of the tree.'
 ++++++++++menuListPopup invisible
 ++++++++++++menuListOption ignored name='This should be pruned out of the tree.' selected=true
-++++++button ignored invisible name='No file chosen, Choose File' value='No file chosen'
-++++++dialog ignored invisible
\ No newline at end of file
+++++++button ignored invisible name='Choose File' value='No file chosen'
+++++++dialog ignored invisible
diff --git a/gpu/command_buffer/client/shared_image_interface.cc b/gpu/command_buffer/client/shared_image_interface.cc
index 1830ef0..6f501c4 100644
--- a/gpu/command_buffer/client/shared_image_interface.cc
+++ b/gpu/command_buffer/client/shared_image_interface.cc
@@ -13,4 +13,12 @@
 void SharedImageInterface::NotifyMailboxAdded(const Mailbox& /*mailbox*/,
                                               uint32_t /*usage*/) {}
 
+Mailbox SharedImageInterface::CreateSharedImageWithAHB(
+    const Mailbox& mailbox,
+    uint32_t usage,
+    const SyncToken& sync_token) {
+  NOTREACHED();
+  return Mailbox();
+}
+
 }  // namespace gpu
diff --git a/gpu/command_buffer/client/shared_image_interface.h b/gpu/command_buffer/client/shared_image_interface.h
index 05db1d3..8c33e90 100644
--- a/gpu/command_buffer/client/shared_image_interface.h
+++ b/gpu/command_buffer/client/shared_image_interface.h
@@ -102,6 +102,18 @@
       SkAlphaType alpha_type,
       uint32_t usage) = 0;
 
+  // The primary purpose of this is API to use an AHB from media/AImageReader in
+  // a thread-safe way. The source mailbox passed to this API must be backed by
+  // a SharedImageVideo. The current AHB associated with the video is wrapped in
+  // a new shared image, associated with the returned mailbox. This shared image
+  // can then be used on any thread in the GPU service. So this API is meant to
+  // pull a buffer for the compositor from ImageReader on the GPU thread, before
+  // sharing it with the compositor. Its also wrapped in a new backing to ensure
+  // there is no cross-thread ImageReader usage.
+  virtual Mailbox CreateSharedImageWithAHB(const Mailbox& mailbox,
+                                           uint32_t usage,
+                                           const SyncToken& sync_token);
+
   // Updates a shared image after its GpuMemoryBuffer (if any) was modified on
   // the CPU or through external devices, after |sync_token| has been released.
   virtual void UpdateSharedImage(const SyncToken& sync_token,
diff --git a/gpu/command_buffer/service/image_reader_gl_owner.cc b/gpu/command_buffer/service/image_reader_gl_owner.cc
index 32e0536..bfc7f47 100644
--- a/gpu/command_buffer/service/image_reader_gl_owner.cc
+++ b/gpu/command_buffer/service/image_reader_gl_owner.cc
@@ -36,6 +36,7 @@
     case TextureOwner::Mode::kAImageReaderSecureSurfaceControl:
       return true;
     case TextureOwner::Mode::kAImageReaderInsecure:
+    case TextureOwner::Mode::kAImageReaderInsecureMultithreaded:
       return false;
     case TextureOwner::Mode::kSurfaceTextureInsecure:
       NOTREACHED();
@@ -51,13 +52,19 @@
 // smoothness. This is because in case an image is not acquired for some
 // reasons, last acquired image should be displayed which is only possible with
 // 2 images (1 previously acquired, 1 currently acquired/tried to acquire).
-// But some devices only support only 1 image. (see crbug.com/1051705).
-// For SurfaceControl we need 3 images instead of 2 since 1 frame (and hence
-// image associated with it) will be with system compositor and 2 frames will
-// be in flight.
+// But some devices supports only 1 image to be acquired. (see
+// crbug.com/1051705). For SurfaceControl we need 3 images instead of 2 since 1
+// frame (and hence image associated with it) will be with system compositor and
+// 2 frames will be in flight. For multi-threaded compositor, when AImageReader
+// is supported, we need 3 images in order to skip texture copy. 1 frame with
+// display compositor, 1 frame in flight and 1 frame being prepared by the
+// renderer.
 uint32_t NumRequiredMaxImages(TextureOwner::Mode mode) {
-  if (IsSurfaceControl(mode))
+  if (IsSurfaceControl(mode) ||
+      mode == TextureOwner::Mode::kAImageReaderInsecureMultithreaded) {
+    DCHECK(!media::MediaCodecUtil::LimitAImageReaderMaxSizeToOne());
     return 3;
+  }
   return media::MediaCodecUtil::LimitAImageReaderMaxSizeToOne() ? 1 : 2;
 }
 
diff --git a/gpu/command_buffer/service/shared_image_backing.cc b/gpu/command_buffer/service/shared_image_backing.cc
index c7ab7bdc..f624824 100644
--- a/gpu/command_buffer/service/shared_image_backing.cc
+++ b/gpu/command_buffer/service/shared_image_backing.cc
@@ -10,6 +10,10 @@
 #include "gpu/command_buffer/service/shared_image_representation.h"
 #include "gpu/command_buffer/service/texture_manager.h"
 
+#if defined(OS_ANDROID)
+#include "base/android/scoped_hardware_buffer_fence_sync.h"
+#endif
+
 namespace gpu {
 
 SharedImageBacking::SharedImageBacking(const Mailbox& mailbox,
@@ -224,4 +228,11 @@
   return nullptr;
 }
 
+#if defined(OS_ANDROID)
+std::unique_ptr<base::android::ScopedHardwareBufferFenceSync>
+SharedImageBacking::GetAHardwareBuffer() {
+  return nullptr;
+}
+#endif
+
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/shared_image_backing.h b/gpu/command_buffer/service/shared_image_backing.h
index 5121c28..f14f558 100644
--- a/gpu/command_buffer/service/shared_image_backing.h
+++ b/gpu/command_buffer/service/shared_image_backing.h
@@ -15,6 +15,7 @@
 #include "base/optional.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/thread_checker.h"
+#include "build/build_config.h"
 #include "components/viz/common/resources/resource_format.h"
 #include "gpu/command_buffer/common/mailbox.h"
 #include "gpu/gpu_gles2_export.h"
@@ -26,6 +27,10 @@
 #include "ui/gfx/native_pixmap.h"
 
 namespace base {
+namespace android {
+class ScopedHardwareBufferFenceSync;
+}  // namespace android
+
 namespace trace_event {
 class ProcessMemoryDump;
 class MemoryAllocatorDump;
@@ -129,6 +134,12 @@
   // the SharedImage is not backed by a NativePixmap.
   virtual scoped_refptr<gfx::NativePixmap> GetNativePixmap();
 
+#if defined(OS_ANDROID)
+  // Returns the AHardwareBuffer from backing if supported and available.
+  virtual std::unique_ptr<base::android::ScopedHardwareBufferFenceSync>
+  GetAHardwareBuffer();
+#endif
+
   // Helper to determine if the entire SharedImage is cleared.
   bool IsCleared() const { return ClearedRect() == gfx::Rect(size()); }
 
diff --git a/gpu/command_buffer/service/shared_image_factory.cc b/gpu/command_buffer/service/shared_image_factory.cc
index b91582a..45f7a5c 100644
--- a/gpu/command_buffer/service/shared_image_factory.cc
+++ b/gpu/command_buffer/service/shared_image_factory.cc
@@ -55,6 +55,11 @@
 #include "gpu/vulkan/vulkan_implementation.h"
 #endif  // defined(OS_FUCHSIA)
 
+#if defined(OS_ANDROID)
+#include "base/android/scoped_hardware_buffer_fence_sync.h"
+#include "gpu/command_buffer/service/shared_image_backing_scoped_hardware_buffer_fence_sync.h"
+#endif
+
 namespace gpu {
 
 // Overrides for flat_set lookups:
@@ -385,6 +390,30 @@
   return true;
 }
 
+#if defined(OS_ANDROID)
+bool SharedImageFactory::CreateSharedImageWithAHB(const Mailbox& out_mailbox,
+                                                  const Mailbox& in_mailbox,
+                                                  uint32_t usage) {
+  auto it = shared_images_.find(in_mailbox);
+  if (it == shared_images_.end()) {
+    LOG(ERROR)
+        << "CreateSharedImageWithAHB: Could not find shared image mailbox";
+    return false;
+  }
+  auto ahb = (*it)->GetAHardwareBuffer();
+  if (!ahb) {
+    LOG(ERROR) << "CreateSharedImageWithAHB: AHardwareBuffer is null";
+    return false;
+  }
+  auto backing =
+      std::make_unique<SharedImageBackingScopedHardwareBufferFenceSync>(
+          std::move(ahb), out_mailbox, (*it)->format(), (*it)->size(),
+          (*it)->color_space(), (*it)->surface_origin(), (*it)->alpha_type(),
+          usage, false);
+  return RegisterBacking(std::move(backing), false /* allow_legacy_mailbox */);
+}
+#endif
+
 void SharedImageFactory::RegisterSharedImageBackingFactoryForTesting(
     SharedImageBackingFactory* factory) {
   backing_factory_for_testing_ = factory;
diff --git a/gpu/command_buffer/service/shared_image_factory.h b/gpu/command_buffer/service/shared_image_factory.h
index b7586c56..6534c882 100644
--- a/gpu/command_buffer/service/shared_image_factory.h
+++ b/gpu/command_buffer/service/shared_image_factory.h
@@ -126,6 +126,12 @@
     return shared_context_state_;
   }
 
+#if defined(OS_ANDROID)
+  bool CreateSharedImageWithAHB(const Mailbox& out_mailbox,
+                                const Mailbox& in_mailbox,
+                                uint32_t usage);
+#endif
+
   void RegisterSharedImageBackingFactoryForTesting(
       SharedImageBackingFactory* factory);
 
diff --git a/gpu/command_buffer/service/shared_image_representation.cc b/gpu/command_buffer/service/shared_image_representation.cc
index 52206ad..55d76297 100644
--- a/gpu/command_buffer/service/shared_image_representation.cc
+++ b/gpu/command_buffer/service/shared_image_representation.cc
@@ -9,6 +9,10 @@
 #include "third_party/skia/include/core/SkPromiseImageTexture.h"
 #include "third_party/skia/include/gpu/GrDirectContext.h"
 
+#if defined(OS_ANDROID)
+#include "base/android/scoped_hardware_buffer_fence_sync.h"
+#endif
+
 namespace gpu {
 
 SharedImageRepresentation::SharedImageRepresentation(
@@ -284,6 +288,13 @@
   backing()->MarkForDestruction();
 }
 
+#if defined(OS_ANDROID)
+std::unique_ptr<base::android::ScopedHardwareBufferFenceSync>
+SharedImageRepresentationFactoryRef::GetAHardwareBuffer() {
+  return backing()->GetAHardwareBuffer();
+}
+#endif
+
 SharedImageRepresentationVaapi::SharedImageRepresentationVaapi(
     SharedImageManager* manager,
     SharedImageBacking* backing,
diff --git a/gpu/command_buffer/service/shared_image_representation.h b/gpu/command_buffer/service/shared_image_representation.h
index 48157da..626f610a 100644
--- a/gpu/command_buffer/service/shared_image_representation.h
+++ b/gpu/command_buffer/service/shared_image_representation.h
@@ -27,6 +27,12 @@
 typedef unsigned int GLenum;
 class SkPromiseImageTexture;
 
+namespace base {
+namespace android {
+class ScopedHardwareBufferFenceSync;
+}  // namespace android
+}  // namespace base
+
 namespace gl {
 class GLImage;
 }
@@ -148,6 +154,11 @@
   void RegisterImageFactory(SharedImageFactory* factory) {
     backing()->RegisterImageFactory(factory);
   }
+
+#if defined(OS_ANDROID)
+  std::unique_ptr<base::android::ScopedHardwareBufferFenceSync>
+  GetAHardwareBuffer();
+#endif
 };
 
 class GPU_GLES2_EXPORT SharedImageRepresentationGLTextureBase
diff --git a/gpu/command_buffer/service/shared_image_video.cc b/gpu/command_buffer/service/shared_image_video.cc
index cec6d99..6c5c680 100644
--- a/gpu/command_buffer/service/shared_image_video.cc
+++ b/gpu/command_buffer/service/shared_image_video.cc
@@ -138,6 +138,12 @@
   return base::Optional<VulkanYCbCrInfo>(ycbcr_info);
 }
 
+std::unique_ptr<base::android::ScopedHardwareBufferFenceSync>
+SharedImageVideo::GetAHardwareBuffer() {
+  DCHECK(stream_texture_sii_);
+  return stream_texture_sii_->GetAHardwareBuffer();
+}
+
 // Representation of SharedImageVideo as a GL Texture.
 class SharedImageRepresentationGLTextureVideo
     : public SharedImageRepresentationGLTexture {
diff --git a/gpu/command_buffer/service/shared_image_video.h b/gpu/command_buffer/service/shared_image_video.h
index 68e330aa..230fdfb 100644
--- a/gpu/command_buffer/service/shared_image_video.h
+++ b/gpu/command_buffer/service/shared_image_video.h
@@ -49,6 +49,8 @@
   void Update(std::unique_ptr<gfx::GpuFence> in_fence) override;
   bool ProduceLegacyMailbox(MailboxManager* mailbox_manager) override;
   size_t EstimatedSizeForMemTracking() const override;
+  std::unique_ptr<base::android::ScopedHardwareBufferFenceSync>
+  GetAHardwareBuffer() override;
 
   // SharedContextState::ContextLostObserver implementation.
   void OnContextLost() override;
diff --git a/gpu/command_buffer/service/texture_owner.cc b/gpu/command_buffer/service/texture_owner.cc
index 309b5b9..63ae331 100644
--- a/gpu/command_buffer/service/texture_owner.cc
+++ b/gpu/command_buffer/service/texture_owner.cc
@@ -45,6 +45,7 @@
     Mode mode) {
   switch (mode) {
     case Mode::kAImageReaderInsecure:
+    case Mode::kAImageReaderInsecureMultithreaded:
     case Mode::kAImageReaderInsecureSurfaceControl:
     case Mode::kAImageReaderSecureSurfaceControl:
       return new ImageReaderGLOwner(std::move(texture), mode);
diff --git a/gpu/command_buffer/service/texture_owner.h b/gpu/command_buffer/service/texture_owner.h
index 81bd88c1..81bf220 100644
--- a/gpu/command_buffer/service/texture_owner.h
+++ b/gpu/command_buffer/service/texture_owner.h
@@ -49,6 +49,11 @@
   // whether SurfaceControl is being used or not.
   enum class Mode {
     kAImageReaderInsecure,
+
+    // This mode indicates that the frame is going to be used in multi-threaded
+    // compositor where compositor is running on a different gpu thread and
+    // context than chrome's gpu main thread/context.
+    kAImageReaderInsecureMultithreaded,
     kAImageReaderInsecureSurfaceControl,
     kAImageReaderSecureSurfaceControl,
     kSurfaceTextureInsecure
diff --git a/gpu/ipc/client/client_shared_image_interface.cc b/gpu/ipc/client/client_shared_image_interface.cc
index c109a10..aea1335 100644
--- a/gpu/ipc/client/client_shared_image_interface.cc
+++ b/gpu/ipc/client/client_shared_image_interface.cc
@@ -112,6 +112,16 @@
       alpha_type, usage));
 }
 
+#if defined(OS_ANDROID)
+Mailbox ClientSharedImageInterface::CreateSharedImageWithAHB(
+    const Mailbox& mailbox,
+    uint32_t usage,
+    const SyncToken& sync_token) {
+  return AddMailbox(
+      proxy_->CreateSharedImageWithAHB(mailbox, usage, sync_token));
+}
+#endif
+
 ClientSharedImageInterface::SwapChainMailboxes
 ClientSharedImageInterface::CreateSwapChain(viz::ResourceFormat format,
                                             const gfx::Size& size,
diff --git a/gpu/ipc/client/client_shared_image_interface.h b/gpu/ipc/client/client_shared_image_interface.h
index 0792f71..5d0dd30 100644
--- a/gpu/ipc/client/client_shared_image_interface.h
+++ b/gpu/ipc/client/client_shared_image_interface.h
@@ -10,6 +10,7 @@
 #include "base/containers/flat_set.h"
 #include "base/synchronization/lock.h"
 #include "base/thread_annotations.h"
+#include "build/build_config.h"
 #include "gpu/ipc/common/surface_handle.h"
 
 namespace gpu {
@@ -63,6 +64,11 @@
                             GrSurfaceOrigin surface_origin,
                             SkAlphaType alpha_type,
                             uint32_t usage) override;
+#if defined(OS_ANDROID)
+  Mailbox CreateSharedImageWithAHB(const Mailbox& mailbox,
+                                   uint32_t usage,
+                                   const SyncToken& sync_token) override;
+#endif
   SwapChainMailboxes CreateSwapChain(viz::ResourceFormat format,
                                      const gfx::Size& size,
                                      const gfx::ColorSpace& color_space,
diff --git a/gpu/ipc/client/shared_image_interface_proxy.cc b/gpu/ipc/client/shared_image_interface_proxy.cc
index 0e8db63e..a95e8338 100644
--- a/gpu/ipc/client/shared_image_interface_proxy.cc
+++ b/gpu/ipc/client/shared_image_interface_proxy.cc
@@ -8,6 +8,7 @@
 #include "build/build_config.h"
 #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
 #include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
+#include "gpu/command_buffer/common/shared_image_usage.h"
 #include "gpu/ipc/client/gpu_channel_host.h"
 #include "gpu/ipc/common/command_buffer_id.h"
 #include "gpu/ipc/common/gpu_messages.h"
@@ -204,6 +205,27 @@
   return mailbox;
 }
 
+#if defined(OS_ANDROID)
+Mailbox SharedImageInterfaceProxy::CreateSharedImageWithAHB(
+    const Mailbox& mailbox,
+    uint32_t usage,
+    const SyncToken& sync_token) {
+  auto out_mailbox = Mailbox::GenerateForSharedImage();
+  std::vector<SyncToken> dependencies =
+      GenerateDependenciesFromSyncToken(std::move(sync_token), host_);
+  {
+    base::AutoLock lock(lock_);
+    AddMailbox(out_mailbox, usage);
+    gfx::GpuFenceHandle acquire_fence_handle;
+    last_flush_id_ = host_->EnqueueDeferredMessage(
+        GpuChannelMsg_CreateSharedImageWithAHB(route_id_, out_mailbox, mailbox,
+                                               usage, ++next_release_id_),
+        std::move(dependencies));
+  }
+  return out_mailbox;
+}
+#endif
+
 void SharedImageInterfaceProxy::UpdateSharedImage(const SyncToken& sync_token,
                                                   const Mailbox& mailbox) {
   UpdateSharedImage(sync_token, nullptr, mailbox);
diff --git a/gpu/ipc/client/shared_image_interface_proxy.h b/gpu/ipc/client/shared_image_interface_proxy.h
index d821350..4d0c8e3 100644
--- a/gpu/ipc/client/shared_image_interface_proxy.h
+++ b/gpu/ipc/client/shared_image_interface_proxy.h
@@ -39,6 +39,13 @@
                             GrSurfaceOrigin surface_origin,
                             SkAlphaType alpha_type,
                             uint32_t usage);
+
+#if defined(OS_ANDROID)
+  Mailbox CreateSharedImageWithAHB(const Mailbox& mailbox,
+                                   uint32_t usage,
+                                   const SyncToken& sync_token);
+#endif
+
   void UpdateSharedImage(const SyncToken& sync_token, const Mailbox& mailbox);
   void UpdateSharedImage(const SyncToken& sync_token,
                          std::unique_ptr<gfx::GpuFence> acquire_fence,
diff --git a/gpu/ipc/common/gpu_messages.h b/gpu/ipc/common/gpu_messages.h
index e01eb72..1acd3af 100644
--- a/gpu/ipc/common/gpu_messages.h
+++ b/gpu/ipc/common/gpu_messages.h
@@ -193,6 +193,13 @@
                     gpu::Mailbox /* id */,
                     uint32_t /* release_id */,
                     gfx::GpuFenceHandle /* in_fence_handle */)
+#if defined(OS_ANDROID)
+IPC_MESSAGE_ROUTED4(GpuChannelMsg_CreateSharedImageWithAHB,
+                    gpu::Mailbox /* out id */,
+                    gpu::Mailbox /* in id */,
+                    uint32_t /* usage */,
+                    uint32_t /* release_id */)
+#endif
 IPC_MESSAGE_ROUTED1(GpuChannelMsg_DestroySharedImage, gpu::Mailbox /* id */)
 #if defined(OS_WIN)
 IPC_MESSAGE_ROUTED1(GpuChannelMsg_CreateSwapChain,
diff --git a/gpu/ipc/service/shared_image_stub.cc b/gpu/ipc/service/shared_image_stub.cc
index a7655ed54..ac0bf33 100644
--- a/gpu/ipc/service/shared_image_stub.cc
+++ b/gpu/ipc/service/shared_image_stub.cc
@@ -74,6 +74,10 @@
     IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateGMBSharedImage,
                         OnCreateGMBSharedImage)
     IPC_MESSAGE_HANDLER(GpuChannelMsg_UpdateSharedImage, OnUpdateSharedImage)
+#if defined(OS_ANDROID)
+    IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateSharedImageWithAHB,
+                        OnCreateSharedImageWithAHB)
+#endif
     IPC_MESSAGE_HANDLER(GpuChannelMsg_DestroySharedImage, OnDestroySharedImage)
     IPC_MESSAGE_HANDLER(GpuChannelMsg_RegisterSharedImageUploadBuffer,
                         OnRegisterSharedImageUploadBuffer)
@@ -149,6 +153,30 @@
   return true;
 }
 
+#if defined(OS_ANDROID)
+bool SharedImageStub::CreateSharedImageWithAHB(const Mailbox& out_mailbox,
+                                               const Mailbox& in_mailbox,
+                                               uint32_t usage) {
+  TRACE_EVENT0("gpu", "SharedImageStub::CreateSharedImageWithAHB");
+  if (!out_mailbox.IsSharedImage() || !in_mailbox.IsSharedImage()) {
+    LOG(ERROR) << "SharedImageStub: Trying to access a SharedImage with a "
+                  "non-SharedImage mailbox.";
+    OnError();
+    return false;
+  }
+  if (!MakeContextCurrent()) {
+    OnError();
+    return false;
+  }
+  if (!factory_->CreateSharedImageWithAHB(out_mailbox, in_mailbox, usage)) {
+    LOG(ERROR) << "SharedImageStub: Unable to update shared image";
+    OnError();
+    return false;
+  }
+  return true;
+}
+#endif
+
 void SharedImageStub::OnCreateSharedImage(
     const GpuChannelMsg_CreateSharedImage_Params& params) {
   TRACE_EVENT2("gpu", "SharedImageStub::OnCreateSharedImage", "width",
@@ -280,6 +308,25 @@
   sync_point_client_state_->ReleaseFenceSync(release_id);
 }
 
+#if defined(OS_ANDROID)
+void SharedImageStub::OnCreateSharedImageWithAHB(const Mailbox& out_mailbox,
+                                                 const Mailbox& in_mailbox,
+                                                 uint32_t usage,
+                                                 uint32_t release_id) {
+  TRACE_EVENT0("gpu", "SharedImageStub::OnCreateSharedImageWithAHB");
+
+  if (!CreateSharedImageWithAHB(out_mailbox, in_mailbox, usage))
+    return;
+
+  SyncToken sync_token(sync_point_client_state_->namespace_id(),
+                       sync_point_client_state_->command_buffer_id(),
+                       release_id);
+  auto* mailbox_manager = channel_->gpu_channel_manager()->mailbox_manager();
+  mailbox_manager->PushTextureUpdates(sync_token);
+  sync_point_client_state_->ReleaseFenceSync(release_id);
+}
+#endif
+
 void SharedImageStub::OnDestroySharedImage(const Mailbox& mailbox) {
   TRACE_EVENT0("gpu", "SharedImageStub::OnDestroySharedImage");
   if (!mailbox.IsSharedImage()) {
diff --git a/gpu/ipc/service/shared_image_stub.h b/gpu/ipc/service/shared_image_stub.h
index c260f215..eb8102d 100644
--- a/gpu/ipc/service/shared_image_stub.h
+++ b/gpu/ipc/service/shared_image_stub.h
@@ -67,6 +67,13 @@
                          GrSurfaceOrigin surface_origin,
                          SkAlphaType alpha_type,
                          uint32_t usage);
+
+#if defined(OS_ANDROID)
+  bool CreateSharedImageWithAHB(const Mailbox& out_mailbox,
+                                const Mailbox& in_mailbox,
+                                uint32_t usage);
+#endif
+
   bool UpdateSharedImage(const Mailbox& mailbox,
                          const gfx::GpuFenceHandle& in_fence_handle);
 
@@ -81,6 +88,12 @@
   void OnUpdateSharedImage(const Mailbox& mailbox,
                            uint32_t release_id,
                            const gfx::GpuFenceHandle& in_fence_handle);
+#if defined(OS_ANDROID)
+  void OnCreateSharedImageWithAHB(const Mailbox& out_mailbox,
+                                  const Mailbox& in_mailbox,
+                                  uint32_t usage,
+                                  uint32_t release_id);
+#endif
   void OnDestroySharedImage(const Mailbox& mailbox);
   void OnRegisterSharedImageUploadBuffer(base::ReadOnlySharedMemoryRegion shm);
 #if defined(OS_WIN)
diff --git a/gpu/ipc/shared_image_interface_in_process.cc b/gpu/ipc/shared_image_interface_in_process.cc
index 2fb5642..5c9734a 100644
--- a/gpu/ipc/shared_image_interface_in_process.cc
+++ b/gpu/ipc/shared_image_interface_in_process.cc
@@ -308,6 +308,49 @@
   sync_point_client_state_->ReleaseFenceSync(sync_token.release_count());
 }
 
+#if defined(OS_ANDROID)
+Mailbox SharedImageInterfaceInProcess::CreateSharedImageWithAHB(
+    const Mailbox& in_mailbox,
+    uint32_t usage,
+    const SyncToken& sync_token) {
+  auto out_mailbox = Mailbox::GenerateForSharedImage();
+  {
+    base::AutoLock lock(lock_);
+    // Note: we enqueue the task under the lock to guarantee monotonicity of
+    // the release ids as seen by the service. Unretained is safe because
+    // SharedImageInterfaceInProcess synchronizes with the GPU thread at
+    // destruction time, cancelling tasks, before |this| is destroyed.
+    ScheduleGpuTask(
+        base::BindOnce(
+            &SharedImageInterfaceInProcess::CreateSharedImageWithAHBOnGpuThread,
+            base::Unretained(this), out_mailbox, in_mailbox, usage,
+            MakeSyncToken(next_fence_sync_release_++)),
+        {sync_token});
+  }
+  return out_mailbox;
+}
+
+void SharedImageInterfaceInProcess::CreateSharedImageWithAHBOnGpuThread(
+    const Mailbox& out_mailbox,
+    const Mailbox& in_mailbox,
+    uint32_t usage,
+    const SyncToken& sync_token) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
+  if (!MakeContextCurrent())
+    return;
+
+  if (!shared_image_factory_ ||
+      !shared_image_factory_->CreateSharedImageWithAHB(out_mailbox, in_mailbox,
+                                                       usage)) {
+    // Signal errors by losing the command buffer.
+    command_buffer_helper_->SetError();
+    return;
+  }
+  mailbox_manager_->PushTextureUpdates(sync_token);
+  sync_point_client_state_->ReleaseFenceSync(sync_token.release_count());
+}
+#endif
+
 SharedImageInterface::SwapChainMailboxes
 SharedImageInterfaceInProcess::CreateSwapChain(
     viz::ResourceFormat format,
diff --git a/gpu/ipc/shared_image_interface_in_process.h b/gpu/ipc/shared_image_interface_in_process.h
index 35d17b1..ed591fe6 100644
--- a/gpu/ipc/shared_image_interface_in_process.h
+++ b/gpu/ipc/shared_image_interface_in_process.h
@@ -83,6 +83,12 @@
                             SkAlphaType alpha_type,
                             uint32_t usage) override;
 
+#if defined(OS_ANDROID)
+  Mailbox CreateSharedImageWithAHB(const Mailbox& mailbox,
+                                   uint32_t usage,
+                                   const SyncToken& sync_token) override;
+#endif
+
   // Updates a shared image after its GpuMemoryBuffer (if any) was modified on
   // the CPU or through external devices, after |sync_token| has been released.
   void UpdateSharedImage(const SyncToken& sync_token,
@@ -196,6 +202,12 @@
   void DestroySharedImageOnGpuThread(const Mailbox& mailbox);
   void WaitSyncTokenOnGpuThread(const SyncToken& sync_token);
   void WrapTaskWithGpuUrl(base::OnceClosure task);
+#if defined(OS_ANDROID)
+  void CreateSharedImageWithAHBOnGpuThread(const Mailbox& out_mailbox,
+                                           const Mailbox& in_mailbox,
+                                           uint32_t usage,
+                                           const SyncToken& sync_token);
+#endif
 
   // Used to schedule work on the gpu thread. This is a raw pointer for now
   // since the ownership of SingleTaskSequence would be the same as the
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index 0b81d86..c3d8ad9 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -351,6 +351,12 @@
       <message name="IDS_IOS_AUTOFILL_ZIP" desc="Title of the field of a profile address representing the postal code of the address. [Length: 15em] [iOS only]">
         Zip Code
       </message>
+      <message name="IDS_IOS_AUTOFILL_REAUTH_REASON" desc="Message explaining that the reason why we are requiring the user to re-authenticate is to be able to use the password. This is shown by iOS in the Touch ID reauthentication system dialogue, right under the OS string 'Touch ID for $BROWSER_NAME'. [CHAR_LIMIT=22]">
+        Use password
+      </message>
+      <message name="IDS_IOS_AUTOFILL_SET_UP_SCREENLOCK_CONTENT" desc="Message informing the user that in order to use the password, a screen lock needs to be set up on the device. This is shown as an alert message after the user tries to view or copy the password from a settings page. [CHAR_LIMIT=100]">
+        To use passwords, you must first set a passcode on your device.
+      </message>
       <message name="IDS_IOS_COPY_ACTION_TITLE" desc="Title of the action used to copy the selected piece of content to the clipboard. Targeted content type includes URL or image. [iOS only]">
         Copy
       </message>
@@ -1684,6 +1690,9 @@
       <message name="IDS_IOS_DELETE_COMPROMISED_PASSWORD_DESCRIPTION" desc="Message on top of the confirmation alert when the user tapped delete password button. [iOS only]" meaning="Explaining to the user that deleting password locally won't delete account on a website.">
         Deleting this password will not delete your account on <ph name="WEBSITE">$1<ex>twitter.com</ex></ph>. Change your password on <ph name="WEBSITE">$1<ex>twitter.com</ex></ph> to keep it safe from others.
       </message>
+      <message name="IDS_IOS_EDIT_ACTION_TITLE" desc="Title of the action used to edit a selected item. [iOS only]">
+        Edit
+      </message>
       <message name="IDS_IOS_EDIT_PASSWORD_DESCRIPTION" desc="Message inside confirmation alert when the user is trying to edit password [iOS only]" meaning="Telling user to ensure provided password matches password on the website.">
         Make sure the password you are saving matches your password for <ph name="WEBSITE">$1<ex>twitter.com</ex></ph>
       </message>
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_AUTOFILL_REAUTH_REASON.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_AUTOFILL_REAUTH_REASON.png.sha1
new file mode 100644
index 0000000..a307fcb
--- /dev/null
+++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_AUTOFILL_REAUTH_REASON.png.sha1
@@ -0,0 +1 @@
+873e83499f6f3348880fa8e1a1f2fb7c53511dd7
\ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_AUTOFILL_SET_UP_SCREENLOCK_CONTENT.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_AUTOFILL_SET_UP_SCREENLOCK_CONTENT.png.sha1
new file mode 100644
index 0000000..30393b0
--- /dev/null
+++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_AUTOFILL_SET_UP_SCREENLOCK_CONTENT.png.sha1
@@ -0,0 +1 @@
+e24b94186b982962534b67f7fd9a6fe8f83bb333
\ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_EDIT_ACTION_TITLE.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_EDIT_ACTION_TITLE.png.sha1
new file mode 100644
index 0000000..ed7c0197
--- /dev/null
+++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_EDIT_ACTION_TITLE.png.sha1
@@ -0,0 +1 @@
+c8b5a1af10f45045d5c717ce565810e45217fdee
\ No newline at end of file
diff --git a/ios/chrome/browser/passwords/BUILD.gn b/ios/chrome/browser/passwords/BUILD.gn
index 727721e..7eee9fd 100644
--- a/ios/chrome/browser/passwords/BUILD.gn
+++ b/ios/chrome/browser/passwords/BUILD.gn
@@ -85,6 +85,7 @@
     "//ios/chrome/browser/ssl",
     "//ios/chrome/browser/sync/glue",
     "//ios/chrome/browser/translate:translate",
+    "//ios/chrome/browser/ui:feature_flags",
     "//ios/chrome/browser/ui/alert_coordinator",
     "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/ui/elements",
diff --git a/ios/chrome/browser/passwords/ios_chrome_password_manager_client.h b/ios/chrome/browser/passwords/ios_chrome_password_manager_client.h
index 2f8d43f..2211d513 100644
--- a/ios/chrome/browser/passwords/ios_chrome_password_manager_client.h
+++ b/ios/chrome/browser/passwords/ios_chrome_password_manager_client.h
@@ -58,6 +58,7 @@
   void PromptUserToMovePasswordToAccount(
       std::unique_ptr<password_manager::PasswordFormManagerForUI> form_to_move)
       override;
+  bool RequiresReauthToFill() override;
   bool ShowOnboarding(
       std::unique_ptr<password_manager::PasswordFormManagerForUI> form_to_save)
       override;
@@ -72,7 +73,7 @@
   bool PromptUserToChooseCredentials(
       std::vector<std::unique_ptr<autofill::PasswordForm>> local_forms,
       const url::Origin& origin,
-      const CredentialsCallback& callback) override;
+      CredentialsCallback callback) override;
   void AutomaticPasswordSave(
       std::unique_ptr<password_manager::PasswordFormManagerForUI>
           saved_form_manager) override;
diff --git a/ios/chrome/browser/passwords/ios_chrome_password_manager_client.mm b/ios/chrome/browser/passwords/ios_chrome_password_manager_client.mm
index a1401571..39feae4 100644
--- a/ios/chrome/browser/passwords/ios_chrome_password_manager_client.mm
+++ b/ios/chrome/browser/passwords/ios_chrome_password_manager_client.mm
@@ -34,6 +34,7 @@
 #include "ios/chrome/browser/sync/profile_sync_service_factory.h"
 #include "ios/chrome/browser/system_flags.h"
 #include "ios/chrome/browser/translate/chrome_ios_translate_client.h"
+#import "ios/chrome/browser/ui/ui_feature_flags.h"
 #include "net/cert/cert_status_flags.h"
 #include "services/metrics/public/cpp/ukm_recorder.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
@@ -87,7 +88,7 @@
 bool IOSChromePasswordManagerClient::PromptUserToChooseCredentials(
     std::vector<std::unique_ptr<autofill::PasswordForm>> local_forms,
     const url::Origin& origin,
-    const CredentialsCallback& callback) {
+    CredentialsCallback callback) {
   NOTIMPLEMENTED();
   return false;
 }
@@ -114,6 +115,10 @@
   NOTIMPLEMENTED();
 }
 
+bool IOSChromePasswordManagerClient::RequiresReauthToFill() {
+  return base::FeatureList::IsEnabled(kEnableAutofillPasswordReauthIOS);
+}
+
 bool IOSChromePasswordManagerClient::ShowOnboarding(
     std::unique_ptr<password_manager::PasswordFormManagerForUI> form_to_save) {
   return false;
diff --git a/ios/chrome/browser/passwords/test/test_password_manager_client.h b/ios/chrome/browser/passwords/test/test_password_manager_client.h
index eaf36b5..a852f92 100644
--- a/ios/chrome/browser/passwords/test/test_password_manager_client.h
+++ b/ios/chrome/browser/passwords/test/test_password_manager_client.h
@@ -35,7 +35,7 @@
   MOCK_METHOD3(PromptUserToChooseCredentialsPtr,
                bool(const std::vector<autofill::PasswordForm*>& local_forms,
                     const url::Origin& origin,
-                    const CredentialsCallback& callback));
+                    CredentialsCallback callback));
 
   scoped_refptr<TestPasswordStore> password_store() const;
   void set_password_store(scoped_refptr<TestPasswordStore> store);
@@ -61,7 +61,7 @@
   bool PromptUserToChooseCredentials(
       std::vector<std::unique_ptr<autofill::PasswordForm>> local_forms,
       const url::Origin& origin,
-      const CredentialsCallback& callback) override;
+      CredentialsCallback callback) override;
 
   std::unique_ptr<TestingPrefServiceSimple> prefs_;
   GURL last_committed_url_;
diff --git a/ios/chrome/browser/passwords/test/test_password_manager_client.mm b/ios/chrome/browser/passwords/test/test_password_manager_client.mm
index a139e49..6194ffca 100644
--- a/ios/chrome/browser/passwords/test/test_password_manager_client.mm
+++ b/ios/chrome/browser/passwords/test/test_password_manager_client.mm
@@ -85,17 +85,18 @@
 bool TestPasswordManagerClient::PromptUserToChooseCredentials(
     std::vector<std::unique_ptr<autofill::PasswordForm>> local_forms,
     const url::Origin& origin,
-    const CredentialsCallback& callback) {
+    CredentialsCallback callback) {
   EXPECT_FALSE(local_forms.empty());
   const autofill::PasswordForm* form = local_forms[0].get();
   base::SequencedTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
-      base::BindOnce(callback, base::Owned(new autofill::PasswordForm(*form))));
+      base::BindOnce(std::move(callback),
+                     base::Owned(new autofill::PasswordForm(*form))));
   std::vector<autofill::PasswordForm*> raw_forms(local_forms.size());
   std::transform(local_forms.begin(), local_forms.end(), raw_forms.begin(),
                  [](const std::unique_ptr<autofill::PasswordForm>& form) {
                    return form.get();
                  });
-  PromptUserToChooseCredentialsPtr(raw_forms, origin, callback);
+  PromptUserToChooseCredentialsPtr(raw_forms, origin, base::DoNothing());
   return true;
 }
diff --git a/ios/chrome/browser/translate/translate_egtest.mm b/ios/chrome/browser/translate/translate_egtest.mm
index 04a4fa7..67dbff28 100644
--- a/ios/chrome/browser/translate/translate_egtest.mm
+++ b/ios/chrome/browser/translate/translate_egtest.mm
@@ -1457,7 +1457,7 @@
   // Make sure the Translate manual trigger button is enabled and tap it.
   [ChromeEarlGreyUI openToolsMenu];
   [[[[EarlGrey selectElementWithMatcher:toolsMenuTranslateButton()]
-         usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, 200)
+         usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, 250)
       onElementWithMatcher:ToolsMenuView()]
       assertWithMatcher:grey_not(grey_accessibilityTrait(
                             UIAccessibilityTraitNotEnabled))]
@@ -1482,7 +1482,7 @@
   // Make sure the Translate manual trigger button is enabled and tap it.
   [ChromeEarlGreyUI openToolsMenu];
   [[[[EarlGrey selectElementWithMatcher:toolsMenuTranslateButton()]
-         usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, 200)
+         usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, 250)
       onElementWithMatcher:ToolsMenuView()]
       assertWithMatcher:grey_not(grey_accessibilityTrait(
                             UIAccessibilityTraitNotEnabled))]
@@ -1546,7 +1546,7 @@
   // Tap the Translate manual trigger button.
   [ChromeEarlGreyUI openToolsMenu];
   [[[EarlGrey selectElementWithMatcher:toolsMenuTranslateButton()]
-         usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, 200)
+         usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, 250)
       onElementWithMatcher:ToolsMenuView()] performAction:grey_tap()];
 
   // Make sure the infobar reappears.
@@ -1599,7 +1599,7 @@
   // Tap the Translate manual trigger button.
   [ChromeEarlGreyUI openToolsMenu];
   [[[EarlGrey selectElementWithMatcher:toolsMenuTranslateButton()]
-         usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, 200)
+         usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, 250)
       onElementWithMatcher:ToolsMenuView()] performAction:grey_tap()];
 
   // Make sure the infobar reappears.
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/BUILD.gn b/ios/chrome/browser/ui/autofill/manual_fill/BUILD.gn
index 3603d90..85e8c789 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/BUILD.gn
+++ b/ios/chrome/browser/ui/autofill/manual_fill/BUILD.gn
@@ -51,6 +51,7 @@
     "//ios/chrome/browser/favicon",
     "//ios/chrome/browser/main",
     "//ios/chrome/browser/passwords",
+    "//ios/chrome/browser/ui:feature_flags",
     "//ios/chrome/browser/ui/autofill/manual_fill:manual_fill_ui",
     "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/ui/coordinators:chrome_coordinators",
@@ -61,6 +62,7 @@
     "//ios/chrome/browser/ui/util",
     "//ios/chrome/browser/web_state_list:web_state_list",
     "//ios/chrome/common/ui/colors",
+    "//ios/chrome/common/ui/reauthentication",
     "//ios/web/public",
     "//ios/web/public/deprecated",
     "//ios/web/public/js_messaging",
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.h b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.h
index 5602e5a4..689bf398 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.h
+++ b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.h
@@ -17,8 +17,13 @@
 // autofill these a warning is displayed using the security alert presenter
 - (void)presentSecurityWarningAlertWithText:(NSString*)body;
 
+// Request the presented a dialog informing the user that a password must be set
+// to use the feature.
+- (void)showSetPasscodeDialog;
+
 @end
 
+@class ReauthenticationModule;
 class WebStateList;
 
 // Handler with the common logic for injecting data from manual fill.
@@ -28,7 +33,9 @@
 // state and |securityAlertPresenter| to present alerts.
 - (instancetype)initWithWebStateList:(WebStateList*)webStateList
               securityAlertPresenter:
-                  (id<AutofillSecurityAlertPresenter>)securityAlertPresenter;
+                  (id<AutofillSecurityAlertPresenter>)securityAlertPresenter
+              reauthenticationModule:
+                  (ReauthenticationModule*)reauthenticationModule;
 
 @end
 
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.mm b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.mm
index c760593..4404e8b9 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.mm
+++ b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.mm
@@ -20,7 +20,9 @@
 #import "ios/chrome/browser/autofill/form_input_accessory_view_handler.h"
 #import "ios/chrome/browser/passwords/password_tab_helper.h"
 #import "ios/chrome/browser/ui/autofill/manual_fill/form_observer_helper.h"
+#import "ios/chrome/browser/ui/ui_feature_flags.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
+#import "ios/chrome/common/ui/reauthentication/reauthentication_module.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/web/public/deprecated/crw_js_injection_receiver.h"
 #include "ios/web/public/js_messaging/web_frame.h"
@@ -50,6 +52,10 @@
 // Convenience getter for the current suggestion manager.
 @property(nonatomic, readonly) JsSuggestionManager* suggestionManager;
 
+// Interface for |reauthenticationModule|, handling mostly the case when no
+// hardware for authentication is available.
+@property(nonatomic, strong) ReauthenticationModule* reauthenticationModule;
+
 // The WebStateList with the relevant active web state for the injection.
 @property(nonatomic, assign) WebStateList* webStateList;
 
@@ -68,10 +74,6 @@
 // The last seen focused element identifier.
 @property(nonatomic, assign) std::string lastFocusedElementIdentifier;
 
-// The view controller this object was initialized with.
-@property(weak, nonatomic, nullable, readonly)
-    UIViewController* baseViewController;
-
 // Used to present alerts.
 @property(nonatomic, weak) id<AutofillSecurityAlertPresenter> alertPresenter;
 
@@ -81,7 +83,9 @@
 
 - (instancetype)initWithWebStateList:(WebStateList*)webStateList
               securityAlertPresenter:
-                  (id<AutofillSecurityAlertPresenter>)securityAlertPresenter {
+                  (id<AutofillSecurityAlertPresenter>)securityAlertPresenter
+              reauthenticationModule:
+                  (ReauthenticationModule*)reauthenticationModule {
   self = [super init];
   if (self) {
     _webStateList = webStateList;
@@ -89,6 +93,7 @@
     _formHelper =
         [[FormObserverHelper alloc] initWithWebStateList:webStateList];
     _formHelper.delegate = self;
+    _reauthenticationModule = reauthenticationModule;
   }
   return self;
 }
@@ -117,7 +122,32 @@
              requiresHTTPS:(BOOL)requiresHTTPS {
   if ([self canUserInjectInPasswordField:passwordField
                            requiresHTTPS:requiresHTTPS]) {
-    [self fillLastSelectedFieldWithString:content];
+    if (!base::FeatureList::IsEnabled(kEnableAutofillPasswordReauthIOS)) {
+      [self fillLastSelectedFieldWithString:content];
+    } else {
+      if (!passwordField) {
+        [self fillLastSelectedFieldWithString:content];
+        return;
+      }
+
+      if ([self.reauthenticationModule canAttemptReauth]) {
+        NSString* reason =
+            l10n_util::GetNSString(IDS_IOS_AUTOFILL_REAUTH_REASON);
+        __weak __typeof(self) weakSelf = self;
+        auto completionHandler = ^(ReauthenticationResult result) {
+          if (result != ReauthenticationResult::kFailure) {
+            [weakSelf fillLastSelectedFieldWithString:content];
+          }
+        };
+
+        [self.reauthenticationModule
+            attemptReauthWithLocalizedReason:reason
+                        canReusePreviousAuth:YES
+                                     handler:completionHandler];
+      } else {
+        [self.alertPresenter showSetPasscodeDialog];
+      }
+    }
   }
 }
 
diff --git a/ios/chrome/browser/ui/badges/badge_button_factory.mm b/ios/chrome/browser/ui/badges/badge_button_factory.mm
index 1a2378b..b0c29f6 100644
--- a/ios/chrome/browser/ui/badges/badge_button_factory.mm
+++ b/ios/chrome/browser/ui/badges/badge_button_factory.mm
@@ -113,7 +113,7 @@
       [UIColor colorNamed:kTextPrimaryColor], self.incognito,
       [UIColor colorNamed:kTextPrimaryDarkColor]);
   button.accessibilityTraits &= ~UIAccessibilityTraitButton;
-  button.enabled = NO;
+  button.userInteractionEnabled = NO;
   button.accessibilityIdentifier = kBadgeButtonIncognitoAccessibilityIdentifier;
   button.accessibilityLabel =
       l10n_util::GetNSString(IDS_IOS_BADGE_INCOGNITO_HINT);
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
index 10e2e34c..69066cc6 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
@@ -2188,9 +2188,49 @@
           [[ActionFactory alloc] initWithBrowser:self.browser
                                         scenario:MenuScenario::kBookmarkEntry];
 
-      UIAction* copyAction = [actionFactory actionToCopyURL:node->url()];
+      NSMutableArray<UIMenuElement*>* menuElements =
+          [[NSMutableArray alloc] init];
 
-      return [UIMenu menuWithTitle:@"" children:@[ copyAction ]];
+      [menuElements addObject:[actionFactory actionToOpenInNewTabWithBlock:^{
+                      std::vector<const BookmarkNode*> nodes = {node};
+                      [self openAllNodes:nodes inIncognito:NO newTab:YES];
+                    }]];
+
+      [menuElements
+          addObject:[actionFactory actionToOpenInNewIncognitoTabWithBlock:^{
+            std::vector<const BookmarkNode*> nodes = {node};
+            [self openAllNodes:nodes inIncognito:YES newTab:YES];
+          }]];
+
+      if (IsMultipleScenesSupported()) {
+        [menuElements
+            addObject:
+                [actionFactory
+                    actionToOpenInNewWindowWithURL:node->url()
+                                    activityOrigin:WindowActivityBookmarksOrigin
+                                        completion:^{
+                                          [self
+                                              dismissViewControllerAnimated:YES
+                                                                 completion:
+                                                                     nil];
+                                        }]];
+      }
+
+      [menuElements addObject:[actionFactory actionToCopyURL:node->url()]];
+
+      [menuElements addObject:[actionFactory actionToEditWithBlock:^{
+                      [self editNode:node];
+                    }]];
+
+      [menuElements addObject:[actionFactory actionToDeleteWithBlock:^{
+                      std::set<const BookmarkNode*> nodes;
+                      nodes.insert(node);
+                      [self handleSelectNodesForDeletion:nodes];
+                      base::RecordAction(base::UserMetricsAction(
+                          "MobileBookmarkManagerEntryDeleted"));
+                    }]];
+
+      return [UIMenu menuWithTitle:@"" children:menuElements];
     };
   }
 
diff --git a/ios/chrome/browser/ui/browser_view/BUILD.gn b/ios/chrome/browser/ui/browser_view/BUILD.gn
index ea48e91..0895551 100644
--- a/ios/chrome/browser/ui/browser_view/BUILD.gn
+++ b/ios/chrome/browser/ui/browser_view/BUILD.gn
@@ -171,6 +171,7 @@
     "//ios/chrome/browser/window_activities",
     "//ios/chrome/common",
     "//ios/chrome/common/ui/colors",
+    "//ios/chrome/common/ui/reauthentication",
     "//ios/chrome/common/ui/util",
     "//ios/components/security_interstitials",
     "//ios/components/webui:url_constants",
diff --git a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
index a3d3675..4019acb 100644
--- a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
@@ -8,6 +8,7 @@
 
 #include "base/scoped_observer.h"
 #include "base/strings/sys_string_conversions.h"
+#include "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/app_launcher/app_launcher_abuse_detector.h"
 #import "ios/chrome/browser/app_launcher/app_launcher_tab_helper.h"
 #import "ios/chrome/browser/autofill/autofill_tab_helper.h"
@@ -75,6 +76,7 @@
 #import "ios/chrome/browser/web/repost_form_tab_helper_delegate.h"
 #include "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h"
+#import "ios/chrome/common/ui/reauthentication/reauthentication_module.h"
 #include "ios/chrome/grit/ios_strings.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 
@@ -106,6 +108,9 @@
 // Mediator between OpenIn TabHelper and OpenIn UI.
 @property(nonatomic, strong) OpenInMediator* openInMediator;
 
+// Reauthentication Module used for re-authentication.
+@property(nonatomic, strong) ReauthenticationModule* reauthenticationModule;
+
 // =================================================
 // Child Coordinators, listed in alphabetical order.
 // =================================================
@@ -342,7 +347,8 @@
 
   self.injectionHandler = [[ManualFillInjectionHandler alloc]
         initWithWebStateList:self.browser->GetWebStateList()
-      securityAlertPresenter:self];
+      securityAlertPresenter:self
+      reauthenticationModule:self.reauthenticationModule];
   self.formInputAccessoryCoordinator = [[FormInputAccessoryCoordinator alloc]
       initWithBaseViewController:self.viewController
                          browser:self.browser
@@ -474,6 +480,15 @@
   self.infobarModalOverlayContainerCoordinator = nil;
 }
 
+#pragma mark - Properties
+
+- (ReauthenticationModule*)reauthenticationModule {
+  if (!_reauthenticationModule) {
+    _reauthenticationModule = [[ReauthenticationModule alloc] init];
+  }
+  return _reauthenticationModule;
+}
+
 #pragma mark - AutofillSecurityAlertPresenter
 
 - (void)presentSecurityWarningAlertWithText:(NSString*)body {
@@ -499,6 +514,39 @@
   [presenter presentViewController:alert animated:YES completion:nil];
 }
 
+- (void)showSetPasscodeDialog {
+  UIAlertController* alertController = [UIAlertController
+      alertControllerWithTitle:l10n_util::GetNSString(
+                                   IDS_IOS_SETTINGS_SET_UP_SCREENLOCK_TITLE)
+                       message:l10n_util::GetNSString(
+                                   IDS_IOS_AUTOFILL_SET_UP_SCREENLOCK_CONTENT)
+                preferredStyle:UIAlertControllerStyleAlert];
+
+  __weak id<ApplicationCommands> applicationCommandsHandler =
+      HandlerForProtocol(self.dispatcher, ApplicationCommands);
+  OpenNewTabCommand* command =
+      [OpenNewTabCommand commandWithURLFromChrome:GURL(kPasscodeArticleURL)];
+
+  UIAlertAction* learnAction = [UIAlertAction
+      actionWithTitle:l10n_util::GetNSString(
+                          IDS_IOS_SETTINGS_SET_UP_SCREENLOCK_LEARN_HOW)
+                style:UIAlertActionStyleDefault
+              handler:^(UIAlertAction*) {
+                [applicationCommandsHandler openURLInNewTab:command];
+              }];
+  [alertController addAction:learnAction];
+  UIAlertAction* okAction =
+      [UIAlertAction actionWithTitle:l10n_util::GetNSString(IDS_OK)
+                               style:UIAlertActionStyleDefault
+                             handler:nil];
+  [alertController addAction:okAction];
+  alertController.preferredAction = okAction;
+
+  [self.viewController presentViewController:alertController
+                                    animated:YES
+                                  completion:nil];
+}
+
 #pragma mark - ActivityServiceCommands
 
 - (void)sharePage {
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
index 7a9e20a2..7812447 100644
--- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -1600,6 +1600,7 @@
   // Update the tab strip visibility.
   if (self.tabStripView) {
     [self showTabStripView:self.tabStripView];
+    [self.tabStripView layoutSubviews];
     [self.tabStripCoordinator hideTabStrip:![self canShowTabStrip]];
     _fakeStatusBarView.hidden = ![self canShowTabStrip];
     [self addConstraintsToPrimaryToolbar];
@@ -1623,6 +1624,8 @@
   [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
   [self dismissPopups];
 
+  __weak BrowserViewController* weakSelf = self;
+
   [coordinator
       animateAlongsideTransition:^(
           id<UIViewControllerTransitionCoordinatorContext> context) {
@@ -1631,7 +1634,11 @@
         [_toolbarUIUpdater updateState];
       }
       completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
-        self.fullscreenController->ResizeViewport();
+        BrowserViewController* strongSelf = weakSelf;
+        weakSelf.fullscreenController->ResizeViewport();
+        if (strongSelf.tabStripView) {
+          [strongSelf.tabStripCoordinator tabStripSizeDidChange];
+        }
       }];
 }
 
diff --git a/ios/chrome/browser/ui/infobars/translate_infobar_egtest.mm b/ios/chrome/browser/ui/infobars/translate_infobar_egtest.mm
index 925c18e..845f7897 100644
--- a/ios/chrome/browser/ui/infobars/translate_infobar_egtest.mm
+++ b/ios/chrome/browser/ui/infobars/translate_infobar_egtest.mm
@@ -996,7 +996,7 @@
   [[[[EarlGrey selectElementWithMatcher:grey_allOf(grey_accessibilityID(
                                                        kToolsMenuTranslateId),
                                                    grey_interactable(), nil)]
-         usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, 200)
+         usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, 250)
       onElementWithMatcher:chrome_test_util::ToolsMenuView()]
       assertWithMatcher:grey_not(grey_accessibilityTrait(
                             UIAccessibilityTraitNotEnabled))]
diff --git a/ios/chrome/browser/ui/location_bar/BUILD.gn b/ios/chrome/browser/ui/location_bar/BUILD.gn
index 74d9f6a..de4490c9 100644
--- a/ios/chrome/browser/ui/location_bar/BUILD.gn
+++ b/ios/chrome/browser/ui/location_bar/BUILD.gn
@@ -26,7 +26,6 @@
     "resources:location_bar_share",
     "resources:location_bar_voice",
     "//base",
-    "//components/google/core/common",
     "//components/omnibox/browser",
     "//components/open_from_clipboard:",
     "//components/search_engines",
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm b/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm
index 185ccaf..22c02b95a 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm
+++ b/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm
@@ -9,7 +9,6 @@
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/sys_string_conversions.h"
-#include "components/google/core/common/google_util.h"
 #include "components/omnibox/browser/omnibox_edit_model.h"
 #include "components/omnibox/browser/omnibox_view.h"
 #include "components/search_engines/util.h"
@@ -66,14 +65,6 @@
 #error "This file requires ARC support."
 #endif
 
-namespace {
-// The histogram recording CLAuthorizationStatus for omnibox queries.
-const char* const kOmniboxQueryLocationAuthorizationStatusHistogram =
-    "Omnibox.QueryIosLocationAuthorizationStatus";
-// The number of possible CLAuthorizationStatus values to report.
-const int kLocationAuthorizationStatusCount = 5;
-}  // namespace
-
 @interface LocationBarCoordinator () <LoadQueryCommands,
                                       LocationBarDelegate,
                                       LocationBarViewControllerDelegate,
@@ -314,13 +305,6 @@
     UrlLoadParams params = UrlLoadParams::InCurrentTab(web_params);
     params.disposition = disposition;
     UrlLoadingBrowserAgent::FromBrowser(self.browser)->Load(params);
-
-    if (google_util::IsGoogleSearchUrl(url)) {
-      UMA_HISTOGRAM_ENUMERATION(
-          kOmniboxQueryLocationAuthorizationStatusHistogram,
-          [CLLocationManager authorizationStatus],
-          kLocationAuthorizationStatusCount);
-    }
   }
   [self cancelOmniboxEdit];
 }
diff --git a/ios/chrome/browser/ui/menu/action_factory.h b/ios/chrome/browser/ui/menu/action_factory.h
index 3eb9551..8b49b14 100644
--- a/ios/chrome/browser/ui/menu/action_factory.h
+++ b/ios/chrome/browser/ui/menu/action_factory.h
@@ -73,6 +73,10 @@
 // the given delete |block| when executed.
 - (UIAction*)actionToRemoveWithBlock:(ProceduralBlock)block;
 
+// Creates a UIAction instance whose title and icon are configured for editing
+// which will invoke the given edit |block| when executed.
+- (UIAction*)actionToEditWithBlock:(ProceduralBlock)block;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_MENU_ACTION_FACTORY_H_
diff --git a/ios/chrome/browser/ui/menu/action_factory.mm b/ios/chrome/browser/ui/menu/action_factory.mm
index 3a9e9b28..370d3ac 100644
--- a/ios/chrome/browser/ui/menu/action_factory.mm
+++ b/ios/chrome/browser/ui/menu/action_factory.mm
@@ -149,4 +149,11 @@
   return action;
 }
 
+- (UIAction*)actionToEditWithBlock:(ProceduralBlock)block {
+  return [self actionWithTitle:l10n_util::GetNSString(IDS_IOS_EDIT_ACTION_TITLE)
+                         image:nil
+                          type:MenuActionType::Edit
+                         block:block];
+}
+
 @end
diff --git a/ios/chrome/browser/ui/menu/action_factory_unittest.mm b/ios/chrome/browser/ui/menu/action_factory_unittest.mm
index e827677..2a19dc0a 100644
--- a/ios/chrome/browser/ui/menu/action_factory_unittest.mm
+++ b/ios/chrome/browser/ui/menu/action_factory_unittest.mm
@@ -199,4 +199,21 @@
   }
 }
 
+// Tests that the edit action has the right title and image.
+TEST_F(ActionFactoryTest, EditAction) {
+  if (@available(iOS 13.0, *)) {
+    ActionFactory* factory =
+        [[ActionFactory alloc] initWithBrowser:test_browser_.get()
+                                      scenario:kTestMenuScenario];
+
+    NSString* expectedTitle = l10n_util::GetNSString(IDS_IOS_EDIT_ACTION_TITLE);
+
+    UIAction* action = [factory actionToEditWithBlock:^{
+    }];
+
+    EXPECT_TRUE([expectedTitle isEqualToString:action.title]);
+    EXPECT_EQ(nil, action.image);
+  }
+}
+
 #endif  // defined(__IPHONE_13_0)
diff --git a/ios/chrome/browser/ui/menu/menu_action_type.h b/ios/chrome/browser/ui/menu/menu_action_type.h
index 05720d41..85abd5f5 100644
--- a/ios/chrome/browser/ui/menu/menu_action_type.h
+++ b/ios/chrome/browser/ui/menu/menu_action_type.h
@@ -15,7 +15,8 @@
   OpenInNewIncognitoTab = 3,
   OpenInNewWindow = 4,
   Remove = 5,
-  kMaxValue = Remove
+  Edit = 6,
+  kMaxValue = Edit
 };
 
 #endif  // IOS_CHROME_BROWSER_UI_MENU_MENU_ACTION_TYPE_H_
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm b/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm
index f7cae4fa..acc7fd0 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm
@@ -213,6 +213,19 @@
   [ChromeEarlGreyUI openToolsMenu];
   [ChromeEarlGreyUI
       tapToolsMenuButton:chrome_test_util::ReadingListMenuButton()];
+  // It seems that sometimes there is a delay before the ReadingList is
+  // displayed. See https://crbug.com/1109202 .
+  GREYAssert(base::test::ios::WaitUntilConditionOrTimeout(
+                 kWaitForUIElementTimeout,
+                 ^BOOL {
+                   NSError* error = nil;
+                   [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
+                                                           kReadingListViewID)]
+                       assertWithMatcher:grey_sufficientlyVisible()
+                                   error:&error];
+                   return error == nil;
+                 }),
+             @"Reading List didn't appear.");
 }
 
 // Adds 20 read and 20 unread entries to the model, opens the reading list menu
@@ -444,14 +457,7 @@
 }
 
 // Tests that the Reading List view is accessible.
-//
-// Disabled due to https://crbug.com/1109202.
-#if TARGET_IPHONE_SIMULATOR
-#define MAYBE_testAccessibility DISABLED_testAccessibility
-#else
-#define MAYBE_testAccessibility testAccessibility
-#endif
-- (void)MAYBE_testAccessibility {
+- (void)testAccessibility {
   AddEntriesAndEnterEdit();
   // In edit mode.
   [ChromeEarlGrey verifyAccessibilityForCurrentScreen];
diff --git a/ios/chrome/browser/ui/settings/language/BUILD.gn b/ios/chrome/browser/ui/settings/language/BUILD.gn
index 2b14c7e9..a6087b2 100644
--- a/ios/chrome/browser/ui/settings/language/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/language/BUILD.gn
@@ -42,20 +42,26 @@
     "language_settings_table_view_controller.mm",
   ]
   deps = [
+    "//components/prefs",
+    "//components/translate/core/browser:translate_pref_names",
     "//ios/chrome/app/strings:ios_strings_grit",
+    "//ios/chrome/browser",
     "//ios/chrome/browser/ui:feature_flags",
     "//ios/chrome/browser/ui/list_model",
     "//ios/chrome/browser/ui/settings:constants",
     "//ios/chrome/browser/ui/settings:settings_root",
     "//ios/chrome/browser/ui/settings/cells",
     "//ios/chrome/browser/ui/settings/cells:public",
+    "//ios/chrome/browser/ui/settings/elements:enterprise_info_popover_view_controller",
     "//ios/chrome/browser/ui/settings/language/cells",
     "//ios/chrome/browser/ui/table_view",
     "//ios/chrome/browser/ui/table_view/cells",
+    "//ios/chrome/browser/ui/table_view/cells",
     "//ios/chrome/browser/ui/table_view/cells:cells_constants",
     "//ios/chrome/browser/ui/util",
     "//ios/chrome/common/ui/colors",
     "//ios/chrome/common/ui/util",
+    "//net",
     "//ui/base",
   ]
   public_deps = [ ":language_ui_constants" ]
diff --git a/ios/chrome/browser/ui/settings/language/language_settings_data_source.h b/ios/chrome/browser/ui/settings/language/language_settings_data_source.h
index 1a78570..67e1537 100644
--- a/ios/chrome/browser/ui/settings/language/language_settings_data_source.h
+++ b/ios/chrome/browser/ui/settings/language/language_settings_data_source.h
@@ -25,6 +25,9 @@
 // Returns whether or not Translate is enabled.
 - (BOOL)translateEnabled;
 
+// Returns whether or not Translate is managed by enterprise policy.
+- (BOOL)translateManaged;
+
 // Stops observing the model. This is required during the shutdown.
 - (void)stopObservingModel;
 
diff --git a/ios/chrome/browser/ui/settings/language/language_settings_mediator.mm b/ios/chrome/browser/ui/settings/language/language_settings_mediator.mm
index aa8a0da6..be7260c 100644
--- a/ios/chrome/browser/ui/settings/language/language_settings_mediator.mm
+++ b/ios/chrome/browser/ui/settings/language/language_settings_mediator.mm
@@ -208,6 +208,11 @@
       prefs::kOfferTranslateEnabled);
 }
 
+- (BOOL)translateManaged {
+  return self.browserState->GetPrefs()->IsManagedPreference(
+      prefs::kOfferTranslateEnabled);
+}
+
 - (void)stopObservingModel {
   _offerTranslatePrefObserverBridge.reset();
   _acceptLanguagesPrefObserverBridge.reset();
diff --git a/ios/chrome/browser/ui/settings/language/language_settings_table_view_controller.mm b/ios/chrome/browser/ui/settings/language/language_settings_table_view_controller.mm
index 20ed7bc..38b236b2 100644
--- a/ios/chrome/browser/ui/settings/language/language_settings_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/language/language_settings_table_view_controller.mm
@@ -10,10 +10,14 @@
 #include "base/metrics/user_metrics.h"
 #include "base/metrics/user_metrics_action.h"
 #include "base/notreached.h"
+#include "components/prefs/pref_service.h"
+#include "components/translate/core/browser/translate_pref_names.h"
+#include "ios/chrome/browser/application_context.h"
 #import "ios/chrome/browser/ui/list_model/list_item+Controller.h"
 #import "ios/chrome/browser/ui/settings/cells/settings_cells_constants.h"
 #import "ios/chrome/browser/ui/settings/cells/settings_switch_cell.h"
 #import "ios/chrome/browser/ui/settings/cells/settings_switch_item.h"
+#import "ios/chrome/browser/ui/settings/elements/enterprise_info_popover_view_controller.h"
 #import "ios/chrome/browser/ui/settings/language/add_language_table_view_controller.h"
 #import "ios/chrome/browser/ui/settings/language/cells/language_item.h"
 #import "ios/chrome/browser/ui/settings/language/language_details_table_view_controller.h"
@@ -23,6 +27,8 @@
 #import "ios/chrome/browser/ui/settings/language/language_settings_ui_constants.h"
 #import "ios/chrome/browser/ui/settings/settings_table_view_controller_constants.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h"
+#import "ios/chrome/browser/ui/table_view/cells/table_view_info_button_cell.h"
+#import "ios/chrome/browser/ui/table_view/cells/table_view_info_button_item.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_link_header_footer_item.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_text_item.h"
 #include "ios/chrome/browser/ui/ui_feature_flags.h"
@@ -30,6 +36,7 @@
 #import "ios/chrome/common/ui/colors/UIColor+cr_semantic_colors.h"
 #import "ios/chrome/common/ui/colors/semantic_color_names.h"
 #include "ios/chrome/grit/ios_strings.h"
+#import "net/base/mac/url_conversions.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -47,14 +54,16 @@
   ItemTypeHeader = kItemTypeEnumZero,
   ItemTypeLanguage,  // This is a repeating type.
   ItemTypeAddLanguage,
-  ItemTypeTranslateSwitch
+  ItemTypeTranslateSwitch,
+  ItemTypeTranslateManaged,
 };
 
 }  // namespace
 
 @interface LanguageSettingsTableViewController () <
     AddLanguageTableViewControllerDelegate,
-    LanguageDetailsTableViewControllerDelegate>
+    LanguageDetailsTableViewControllerDelegate,
+    PopoverLabelViewControllerDelegate>
 
 // The data source passed to this instance.
 @property(nonatomic, strong) id<LanguageSettingsDataSource> dataSource;
@@ -68,6 +77,9 @@
 // A reference to the Translate switch item for quick access.
 @property(nonatomic, weak) SettingsSwitchItem* translateSwitchItem;
 
+// A reference to the Translate switch item for quick access.
+@property(nonatomic, weak) TableViewInfoButtonItem* translateManagedItem;
+
 // A reference to the presented AddLanguageTableViewController, if any.
 @property(nonatomic, weak)
     AddLanguageTableViewController* addLanguageTableViewController;
@@ -118,20 +130,40 @@
   [model addSectionWithIdentifier:SectionIdentifierLanguages];
   [self populateLanguagesSection];
 
-  // Translate switch item.
   [model addSectionWithIdentifier:SectionIdentifierTranslate];
-  SettingsSwitchItem* translateSwitchItem =
-      [[SettingsSwitchItem alloc] initWithType:ItemTypeTranslateSwitch];
-  self.translateSwitchItem = translateSwitchItem;
-  translateSwitchItem.accessibilityIdentifier =
-      kTranslateSwitchAccessibilityIdentifier;
-  translateSwitchItem.text =
-      l10n_util::GetNSString(IDS_IOS_LANGUAGE_SETTINGS_TRANSLATE_SWITCH_TITLE);
-  translateSwitchItem.detailText = l10n_util::GetNSString(
-      IDS_IOS_LANGUAGE_SETTINGS_TRANSLATE_SWITCH_SUBTITLE);
-  translateSwitchItem.on = [self.dataSource translateEnabled];
-  [model addItem:translateSwitchItem
-      toSectionWithIdentifier:SectionIdentifierTranslate];
+  if (base::FeatureList::IsEnabled(kEnableIOSManagedSettingsUI) &&
+      self.dataSource.translateManaged) {
+    // Translate managed item.
+    TableViewInfoButtonItem* translateManagedItem =
+        [[TableViewInfoButtonItem alloc] initWithType:ItemTypeTranslateManaged];
+    self.translateManagedItem = translateManagedItem;
+    translateManagedItem.accessibilityIdentifier =
+        kTranslateManagedAccessibilityIdentifier;
+    translateManagedItem.text = l10n_util::GetNSString(
+        IDS_IOS_LANGUAGE_SETTINGS_TRANSLATE_SWITCH_TITLE);
+    translateManagedItem.detailText = l10n_util::GetNSString(
+        IDS_IOS_LANGUAGE_SETTINGS_TRANSLATE_SWITCH_SUBTITLE);
+    translateManagedItem.statusText =
+        [self.dataSource translateEnabled]
+            ? l10n_util::GetNSString(IDS_IOS_SETTING_ON)
+            : l10n_util::GetNSString(IDS_IOS_SETTING_OFF);
+    [model addItem:translateManagedItem
+        toSectionWithIdentifier:SectionIdentifierTranslate];
+  } else {
+    // Translate switch item.
+    SettingsSwitchItem* translateSwitchItem =
+        [[SettingsSwitchItem alloc] initWithType:ItemTypeTranslateSwitch];
+    self.translateSwitchItem = translateSwitchItem;
+    translateSwitchItem.accessibilityIdentifier =
+        kTranslateSwitchAccessibilityIdentifier;
+    translateSwitchItem.text = l10n_util::GetNSString(
+        IDS_IOS_LANGUAGE_SETTINGS_TRANSLATE_SWITCH_TITLE);
+    translateSwitchItem.detailText = l10n_util::GetNSString(
+        IDS_IOS_LANGUAGE_SETTINGS_TRANSLATE_SWITCH_SUBTITLE);
+    translateSwitchItem.on = [self.dataSource translateEnabled];
+    [model addItem:translateSwitchItem
+        toSectionWithIdentifier:SectionIdentifierTranslate];
+  }
 }
 
 #pragma mark - SettingsRootTableViewController
@@ -155,7 +187,9 @@
   [self.tableView endUpdates];
 
   [self setAddLanguageItemEnabled:!self.isEditing];
-  [self setTranslateSwitchItemEnabled:!self.isEditing];
+  if (_translateSwitchItem) {
+    [self setTranslateSwitchItemEnabled:!self.isEditing];
+  }
 }
 
 #pragma mark - SettingsControllerProtocol
@@ -238,6 +272,7 @@
     }
     case ItemTypeHeader:
     case ItemTypeTranslateSwitch:
+    case ItemTypeTranslateManaged:
       // Not handled.
       break;
   }
@@ -344,6 +379,15 @@
                       forControlEvents:UIControlEventValueChanged];
       break;
     }
+    case ItemTypeTranslateManaged: {
+      TableViewInfoButtonCell* managedCell =
+          base::mac::ObjCCastStrict<TableViewInfoButtonCell>(cell);
+      [managedCell.trailingButton
+                 addTarget:self
+                    action:@selector(didTapManagedUIInfoButton:)
+          forControlEvents:UIControlEventTouchUpInside];
+      break;
+    }
     case ItemTypeHeader:
     case ItemTypeLanguage:
     case ItemTypeAddLanguage:
@@ -526,6 +570,26 @@
   [self translateEnabled:switchView.isOn];
 }
 
+// Called when the user clicks on the information button of the managed
+// setting's UI. Shows a textual bubble with the information of the enterprise.
+- (void)didTapManagedUIInfoButton:(UIButton*)buttonView {
+  EnterpriseInfoPopoverViewController* bubbleViewController =
+      [[EnterpriseInfoPopoverViewController alloc] initWithEnterpriseName:nil];
+
+  bubbleViewController.delegate = self;
+  // Disable the button when showing the bubble.
+  buttonView.enabled = NO;
+
+  // Set the anchor and arrow direction of the bubble.
+  bubbleViewController.popoverPresentationController.sourceView = buttonView;
+  bubbleViewController.popoverPresentationController.sourceRect =
+      buttonView.bounds;
+  bubbleViewController.popoverPresentationController.permittedArrowDirections =
+      UIPopoverArrowDirectionAny;
+
+  [self presentViewController:bubbleViewController animated:YES completion:nil];
+}
+
 #pragma mark - UIAdaptivePresentationControllerDelegate
 
 - (void)presentationControllerDidDismiss:
@@ -534,4 +598,11 @@
       base::UserMetricsAction("IOSLanguagesSettingsCloseWithSwipe"));
 }
 
+#pragma mark - PopoverLabelViewControllerDelegate
+
+- (void)didTapLinkURL:(NSURL*)URL {
+  GURL convertedURL = net::GURLWithNSURL(URL);
+  [self view:nil didTapLinkURL:convertedURL];
+}
+
 @end
diff --git a/ios/chrome/browser/ui/settings/language/language_settings_ui_constants.h b/ios/chrome/browser/ui/settings/language/language_settings_ui_constants.h
index bf97af2..b0b1994 100644
--- a/ios/chrome/browser/ui/settings/language/language_settings_ui_constants.h
+++ b/ios/chrome/browser/ui/settings/language/language_settings_ui_constants.h
@@ -19,5 +19,7 @@
 extern NSString* const kLanguageSettingsTableViewAccessibilityIdentifier;
 // Accessibility identifier of the Translate switch.
 extern NSString* const kTranslateSwitchAccessibilityIdentifier;
+// Accessibility identifier of the Managed Translate UI.
+extern NSString* const kTranslateManagedAccessibilityIdentifier;
 
 #endif  // IOS_CHROME_BROWSER_UI_SETTINGS_LANGUAGE_LANGUAGE_SETTINGS_UI_CONSTANTS_H_
diff --git a/ios/chrome/browser/ui/settings/language/language_settings_ui_constants.mm b/ios/chrome/browser/ui/settings/language/language_settings_ui_constants.mm
index af85012..5eb7c2b 100644
--- a/ios/chrome/browser/ui/settings/language/language_settings_ui_constants.mm
+++ b/ios/chrome/browser/ui/settings/language/language_settings_ui_constants.mm
@@ -20,3 +20,5 @@
     @"kLanguageSettingsTableViewAccessibilityIdentifier";
 NSString* const kTranslateSwitchAccessibilityIdentifier =
     @"kTranslateSwitchAccessibilityIdentifier";
+NSString* const kTranslateManagedAccessibilityIdentifier =
+    @"kTranslateManagedAccessibilityIdentifier";
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details_view_controller.h b/ios/chrome/browser/ui/settings/password/password_details/password_details_view_controller.h
index 608cf6ec..763ab1d0 100644
--- a/ios/chrome/browser/ui/settings/password/password_details/password_details_view_controller.h
+++ b/ios/chrome/browser/ui/settings/password/password_details/password_details_view_controller.h
@@ -26,7 +26,7 @@
 // Dispatcher for this ViewController.
 @property(nonatomic, weak) id<ApplicationCommands> commandsDispatcher;
 
-// Module containing the reauthentication mechanism for interections
+// Module containing the reauthentication mechanism for interactions
 // with password.
 @property(nonatomic, weak) id<ReauthenticationProtocol> reauthModule;
 
diff --git a/ios/chrome/browser/ui/settings/privacy/BUILD.gn b/ios/chrome/browser/ui/settings/privacy/BUILD.gn
index c36a909..4e60901 100644
--- a/ios/chrome/browser/ui/settings/privacy/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/privacy/BUILD.gn
@@ -73,6 +73,7 @@
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/content_settings",
     "//ios/chrome/browser/main:public",
+    "//ios/chrome/browser/ui:feature_flags",
     "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/ui/coordinators:chrome_coordinators",
     "//ios/chrome/browser/ui/settings:settings_root",
diff --git a/ios/chrome/browser/ui/settings/privacy/privacy_coordinator.mm b/ios/chrome/browser/ui/settings/privacy/privacy_coordinator.mm
index 222d9a15..2073a4b 100644
--- a/ios/chrome/browser/ui/settings/privacy/privacy_coordinator.mm
+++ b/ios/chrome/browser/ui/settings/privacy/privacy_coordinator.mm
@@ -5,6 +5,7 @@
 #import "ios/chrome/browser/ui/settings/privacy/privacy_coordinator.h"
 
 #import "base/mac/foundation_util.h"
+#include "components/content_settings/core/common/features.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "ios/chrome/browser/main/browser.h"
@@ -19,6 +20,7 @@
 #import "ios/chrome/browser/ui/settings/privacy/privacy_navigation_commands.h"
 #import "ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller.h"
 #import "ios/chrome/browser/ui/settings/settings_navigation_controller.h"
+#include "ios/chrome/browser/ui/ui_feature_flags.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -56,11 +58,13 @@
   self.handler = HandlerForProtocol(self.browser->GetCommandDispatcher(),
                                     ApplicationCommands);
 
-  self.cookiesStatusMediator = [[CookiesStatusMediator alloc]
-      initWithPrefService:self.browser->GetBrowserState()->GetPrefs()
-              settingsMap:ios::HostContentSettingsMapFactory::
-                              GetForBrowserState(
-                                  self.browser->GetBrowserState())];
+  if (base::FeatureList::IsEnabled(content_settings::kImprovedCookieControls)) {
+    self.cookiesStatusMediator = [[CookiesStatusMediator alloc]
+        initWithPrefService:self.browser->GetBrowserState()->GetPrefs()
+                settingsMap:ios::HostContentSettingsMapFactory::
+                                GetForBrowserState(
+                                    self.browser->GetBrowserState())];
+  }
 
   self.viewController = [[PrivacyTableViewController alloc]
          initWithBrowser:self.browser
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_empty_state_view.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_empty_state_view.mm
index a956c98..cfd3732 100644
--- a/ios/chrome/browser/ui/tab_grid/tab_grid_empty_state_view.mm
+++ b/ios/chrome/browser/ui/tab_grid/tab_grid_empty_state_view.mm
@@ -119,7 +119,12 @@
   bottomLabel.translatesAutoresizingMaskIntoConstraints = NO;
   bottomLabel.text = self.body;
   bottomLabel.textColor = UIColorFromRGB(kTabGridEmptyStateBodyTextColor);
-  bottomLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
+  if (base::FeatureList::IsEnabled(kIllustratedEmptyStates)) {
+    bottomLabel.font =
+        [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline];
+  } else {
+    bottomLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
+  }
   bottomLabel.adjustsFontForContentSizeCategory = YES;
   bottomLabel.numberOfLines = 0;
   bottomLabel.textAlignment = NSTextAlignmentCenter;
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_illustrated_item.mm b/ios/chrome/browser/ui/table_view/cells/table_view_illustrated_item.mm
index c383874..5d0b2be1 100644
--- a/ios/chrome/browser/ui/table_view/cells/table_view_illustrated_item.mm
+++ b/ios/chrome/browser/ui/table_view/cells/table_view_illustrated_item.mm
@@ -107,7 +107,7 @@
     _subtitleLabel = [[UILabel alloc] init];
     _subtitleLabel.textColor = [UIColor colorNamed:kTextSecondaryColor];
     _subtitleLabel.font =
-        [UIFont preferredFontForTextStyle:UIFontTextStyleFootnote];
+        [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline];
     _subtitleLabel.textAlignment = NSTextAlignmentCenter;
     _subtitleLabel.numberOfLines = 0;
     _subtitleLabel.translatesAutoresizingMaskIntoConstraints = NO;
diff --git a/ios/chrome/browser/ui/table_view/table_view_illustrated_empty_view.mm b/ios/chrome/browser/ui/table_view/table_view_illustrated_empty_view.mm
index ec06ddb..2e12419 100644
--- a/ios/chrome/browser/ui/table_view/table_view_illustrated_empty_view.mm
+++ b/ios/chrome/browser/ui/table_view/table_view_illustrated_empty_view.mm
@@ -124,7 +124,7 @@
     subtitleLabel.numberOfLines = 0;
     subtitleLabel.text = self.subtitle;
     subtitleLabel.font =
-        [UIFont preferredFontForTextStyle:UIFontTextStyleFootnote];
+        [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline];
     subtitleLabel.textColor = [UIColor colorNamed:kTextSecondaryColor];
     subtitleLabel.textAlignment = NSTextAlignmentCenter;
     [subviewsArray addObject:subtitleLabel];
diff --git a/ios/chrome/browser/ui/tabs/tab_strip_controller.h b/ios/chrome/browser/ui/tabs/tab_strip_controller.h
index 0153a6bf..7b295fd5 100644
--- a/ios/chrome/browser/ui/tabs/tab_strip_controller.h
+++ b/ios/chrome/browser/ui/tabs/tab_strip_controller.h
@@ -46,6 +46,9 @@
 // first.
 - (void)disconnect;
 
+// Notifies of a forced resizing layout of the tab strip.
+- (void)tabStripSizeDidChange;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_TABS_TAB_STRIP_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/tabs/tab_strip_controller.mm b/ios/chrome/browser/ui/tabs/tab_strip_controller.mm
index 0f82ae84..4114966 100644
--- a/ios/chrome/browser/ui/tabs/tab_strip_controller.mm
+++ b/ios/chrome/browser/ui/tabs/tab_strip_controller.mm
@@ -564,6 +564,11 @@
   [self updateTabSwitcherGuide];
 }
 
+- (void)tabStripSizeDidChange {
+  [self updateContentSizeAndRepositionViews];
+  [self layoutTabStripSubviews];
+}
+
 #pragma mark - Private
 
 - (void)initializeTabArray {
diff --git a/ios/chrome/browser/ui/tabs/tab_strip_legacy_coordinator.h b/ios/chrome/browser/ui/tabs/tab_strip_legacy_coordinator.h
index 08a2a2ae..a3076fb 100644
--- a/ios/chrome/browser/ui/tabs/tab_strip_legacy_coordinator.h
+++ b/ios/chrome/browser/ui/tabs/tab_strip_legacy_coordinator.h
@@ -31,6 +31,9 @@
 // Hides or shows the TabStrip.
 - (void)hideTabStrip:(BOOL)hidden;
 
+// Force resizing layout of the tab strip.
+- (void)tabStripSizeDidChange;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_TABS_TAB_STRIP_LEGACY_COORDINATOR_H_
diff --git a/ios/chrome/browser/ui/tabs/tab_strip_legacy_coordinator.mm b/ios/chrome/browser/ui/tabs/tab_strip_legacy_coordinator.mm
index bbc6ca1..d9ad1075 100644
--- a/ios/chrome/browser/ui/tabs/tab_strip_legacy_coordinator.mm
+++ b/ios/chrome/browser/ui/tabs/tab_strip_legacy_coordinator.mm
@@ -53,6 +53,10 @@
   [self.tabStripController hideTabStrip:hidden];
 }
 
+- (void)tabStripSizeDidChange {
+  [self.tabStripController tabStripSizeDidChange];
+}
+
 #pragma mark - ChromeCoordinator
 
 - (void)start {
diff --git a/ios/chrome/common/ui/reauthentication/reauthentication_module.h b/ios/chrome/common/ui/reauthentication/reauthentication_module.h
index 1f1a5fd8..f00d7dbb 100644
--- a/ios/chrome/common/ui/reauthentication/reauthentication_module.h
+++ b/ios/chrome/common/ui/reauthentication/reauthentication_module.h
@@ -31,12 +31,12 @@
 @interface ReauthenticationModule : NSObject <ReauthenticationProtocol>
 
 // The designated initializer. |successfulReauthTimeAccessor| must not be nil.
+// Use |init| to have ReauthenticationModule be it's own
+// |SuccessfulReauthTimeAccessor|.
 - (instancetype)initWithSuccessfulReauthTimeAccessor:
     (id<SuccessfulReauthTimeAccessor>)successfulReauthTimeAccessor
     NS_DESIGNATED_INITIALIZER;
 
-- (instancetype)init NS_UNAVAILABLE;
-
 @end
 
 #endif  // IOS_CHROME_COMMON_UI_REAUTHENTICATION_REAUTHENTICATION_MODULE_H_
diff --git a/ios/chrome/common/ui/reauthentication/reauthentication_module.mm b/ios/chrome/common/ui/reauthentication/reauthentication_module.mm
index a046e6174..b0b67e6 100644
--- a/ios/chrome/common/ui/reauthentication/reauthentication_module.mm
+++ b/ios/chrome/common/ui/reauthentication/reauthentication_module.mm
@@ -13,6 +13,14 @@
 
 constexpr char kPasscodeArticleURL[] = "https://support.apple.com/HT204060";
 
+@interface ReauthenticationModule () <SuccessfulReauthTimeAccessor>
+
+// Date kept to decide if last auth can be reused when
+// |lastSuccessfulReauthTime| is |self|.
+@property(nonatomic, strong) NSDate* lastSuccessfulReauthTime;
+
+@end
+
 @implementation ReauthenticationModule {
   // Block that creates a new |LAContext| object everytime one is required,
   // meant to make testing with a mock object possible.
@@ -24,6 +32,11 @@
   __weak id<SuccessfulReauthTimeAccessor> _successfulReauthTimeAccessor;
 }
 
+- (instancetype)init {
+  self = [self initWithSuccessfulReauthTimeAccessor:self];
+  return self;
+}
+
 - (instancetype)initWithSuccessfulReauthTimeAccessor:
     (id<SuccessfulReauthTimeAccessor>)successfulReauthTimeAccessor {
   DCHECK(successfulReauthTimeAccessor);
@@ -91,6 +104,12 @@
   return previousAuthValid;
 }
 
+#pragma mark - SuccessfulReauthTimeAccessor
+
+- (void)updateSuccessfulReauthTime {
+  self.lastSuccessfulReauthTime = [[NSDate alloc] init];
+}
+
 #pragma mark - ForTesting
 
 - (void)setCreateLAContext:(LAContext* (^)(void))createLAContext {
diff --git a/ios/web_view/internal/passwords/web_view_password_manager_client.h b/ios/web_view/internal/passwords/web_view_password_manager_client.h
index b53a8a18..072a08a9 100644
--- a/ios/web_view/internal/passwords/web_view_password_manager_client.h
+++ b/ios/web_view/internal/passwords/web_view_password_manager_client.h
@@ -71,7 +71,7 @@
   bool PromptUserToChooseCredentials(
       std::vector<std::unique_ptr<autofill::PasswordForm>> local_forms,
       const url::Origin& origin,
-      const CredentialsCallback& callback) override;
+      CredentialsCallback callback) override;
   void AutomaticPasswordSave(
       std::unique_ptr<password_manager::PasswordFormManagerForUI>
           saved_form_manager) override;
diff --git a/ios/web_view/internal/passwords/web_view_password_manager_client.mm b/ios/web_view/internal/passwords/web_view_password_manager_client.mm
index 4d32646..dd338c67 100644
--- a/ios/web_view/internal/passwords/web_view_password_manager_client.mm
+++ b/ios/web_view/internal/passwords/web_view_password_manager_client.mm
@@ -92,7 +92,7 @@
 bool WebViewPasswordManagerClient::PromptUserToChooseCredentials(
     std::vector<std::unique_ptr<autofill::PasswordForm>> local_forms,
     const url::Origin& origin,
-    const CredentialsCallback& callback) {
+    CredentialsCallback callback) {
   NOTIMPLEMENTED();
   return false;
 }
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index e3e83f9..d4de568 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -583,6 +583,9 @@
 const base::Feature kUsePooledSharedImageVideoProvider{
     "UsePooledSharedImageVideoProvider", base::FEATURE_ENABLED_BY_DEFAULT};
 
+// Used to enable/disable zero copy video path on webview for MCVD.
+const base::Feature kWebViewZeroCopyVideo{"EnableZeroCopyVideoOnWebview",
+                                          base::FEATURE_DISABLED_BY_DEFAULT};
 #endif  // defined(OS_ANDROID)
 
 #if defined(OS_CHROMEOS) && BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
diff --git a/media/base/media_switches.h b/media/base/media_switches.h
index 6462f78..7cdefcd8 100644
--- a/media/base/media_switches.h
+++ b/media/base/media_switches.h
@@ -195,6 +195,7 @@
 MEDIA_EXPORT extern const base::Feature kRequestSystemAudioFocus;
 MEDIA_EXPORT extern const base::Feature kUseAudioLatencyFromHAL;
 MEDIA_EXPORT extern const base::Feature kUsePooledSharedImageVideoProvider;
+MEDIA_EXPORT extern const base::Feature kWebViewZeroCopyVideo;
 #endif  // defined(OS_ANDROID)
 
 #if defined(OS_CHROMEOS) && BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
diff --git a/media/gpu/android/video_frame_factory_impl.cc b/media/gpu/android/video_frame_factory_impl.cc
index 7a6a55f..6686f09 100644
--- a/media/gpu/android/video_frame_factory_impl.cc
+++ b/media/gpu/android/video_frame_factory_impl.cc
@@ -19,6 +19,7 @@
 #include "gpu/command_buffer/service/abstract_texture.h"
 #include "gpu/command_buffer/service/shared_context_state.h"
 #include "gpu/command_buffer/service/texture_owner.h"
+#include "media/base/android/media_codec_util.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/media_switches.h"
 #include "media/base/video_frame.h"
@@ -33,10 +34,38 @@
 namespace media {
 namespace {
 
-gpu::TextureOwner::Mode GetTextureOwnerMode(
-    VideoFrameFactory::OverlayMode overlay_mode) {
+// The frames must be copied when threaded texture mailboxes are in use
+// (http://crbug.com/582170). This texture copy can be avoided if
+// AImageReader/AHardwareBuffer is supported and AImageReader
+// max size is not limited to 1 (crbug.com/1091945).
+base::Optional<VideoFrameMetadata::CopyMode> GetVideoFrameCopyMode(
+    bool enable_threaded_texture_mailboxes) {
+  if (!enable_threaded_texture_mailboxes)
+    return base::nullopt;
+
   const bool a_image_reader_supported =
       base::android::AndroidImageReader::GetInstance().IsSupported();
+  if (a_image_reader_supported &&
+      base::FeatureList::IsEnabled(media::kWebViewZeroCopyVideo) &&
+      !media::MediaCodecUtil::LimitAImageReaderMaxSizeToOne()) {
+    return VideoFrameMetadata::CopyMode::kCopyMailboxesOnly;
+  } else {
+    return VideoFrameMetadata::CopyMode::kCopyToNewTexture;
+  }
+}
+
+gpu::TextureOwner::Mode GetTextureOwnerMode(
+    VideoFrameFactory::OverlayMode overlay_mode,
+    const base::Optional<VideoFrameMetadata::CopyMode>& copy_mode) {
+  const bool a_image_reader_supported =
+      base::android::AndroidImageReader::GetInstance().IsSupported();
+
+  if (copy_mode == VideoFrameMetadata::kCopyMailboxesOnly) {
+    DCHECK(a_image_reader_supported &&
+           base::FeatureList::IsEnabled(media::kWebViewZeroCopyVideo) &&
+           !media::MediaCodecUtil::LimitAImageReaderMaxSizeToOne());
+    return gpu::TextureOwner::Mode::kAImageReaderInsecureMultithreaded;
+  }
 
   switch (overlay_mode) {
     case VideoFrameFactory::OverlayMode::kDontRequestPromotionHints:
@@ -61,6 +90,7 @@
 static void AllocateTextureOwnerOnGpuThread(
     VideoFrameFactory::InitCB init_cb,
     VideoFrameFactory::OverlayMode overlay_mode,
+    const base::Optional<VideoFrameMetadata::CopyMode>& copy_mode,
     scoped_refptr<gpu::SharedContextState> shared_context_state) {
   if (!shared_context_state) {
     std::move(init_cb).Run(nullptr);
@@ -69,7 +99,7 @@
 
   std::move(init_cb).Run(gpu::TextureOwner::Create(
       gpu::TextureOwner::CreateTexture(shared_context_state),
-      GetTextureOwnerMode(overlay_mode)));
+      GetTextureOwnerMode(overlay_mode, copy_mode)));
 }
 
 }  // namespace
@@ -84,8 +114,8 @@
     std::unique_ptr<FrameInfoHelper> frame_info_helper)
     : image_provider_(std::move(image_provider)),
       gpu_task_runner_(std::move(gpu_task_runner)),
-      enable_threaded_texture_mailboxes_(
-          gpu_preferences.enable_threaded_texture_mailboxes),
+      copy_mode_(GetVideoFrameCopyMode(
+          gpu_preferences.enable_threaded_texture_mailboxes)),
       mre_manager_(std::move(mre_manager)),
       frame_info_helper_(std::move(frame_info_helper)) {}
 
@@ -97,11 +127,12 @@
                                        InitCB init_cb) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   overlay_mode_ = overlay_mode;
+
   // On init success, create the TextureOwner and hop it back to this thread to
   // call |init_cb|.
-  auto gpu_init_cb =
-      base::BindOnce(&AllocateTextureOwnerOnGpuThread,
-                     BindToCurrentLoop(std::move(init_cb)), overlay_mode);
+  auto gpu_init_cb = base::BindOnce(&AllocateTextureOwnerOnGpuThread,
+                                    BindToCurrentLoop(std::move(init_cb)),
+                                    overlay_mode, copy_mode_);
   image_provider_->Initialize(std::move(gpu_init_cb));
 }
 
@@ -168,12 +199,11 @@
     return;
   }
 
-  auto image_ready_cb =
-      base::BindOnce(&VideoFrameFactoryImpl::CreateVideoFrame_OnImageReady,
-                     weak_factory_.GetWeakPtr(), std::move(output_cb),
-                     timestamp, natural_size, !!codec_buffer_wait_coordinator_,
-                     std::move(promotion_hint_cb), pixel_format, overlay_mode_,
-                     enable_threaded_texture_mailboxes_, gpu_task_runner_);
+  auto image_ready_cb = base::BindOnce(
+      &VideoFrameFactoryImpl::CreateVideoFrame_OnImageReady,
+      weak_factory_.GetWeakPtr(), std::move(output_cb), timestamp, natural_size,
+      !!codec_buffer_wait_coordinator_, std::move(promotion_hint_cb),
+      pixel_format, overlay_mode_, copy_mode_, gpu_task_runner_);
 
   RequestImage(std::move(output_buffer_renderer), std::move(image_ready_cb));
 }
@@ -235,7 +265,7 @@
     PromotionHintAggregator::NotifyPromotionHintCB promotion_hint_cb,
     VideoPixelFormat pixel_format,
     OverlayMode overlay_mode,
-    bool enable_threaded_texture_mailboxes,
+    const base::Optional<VideoFrameMetadata::CopyMode>& copy_mode,
     scoped_refptr<base::SequencedTaskRunner> gpu_task_runner,
     std::unique_ptr<CodecOutputBufferRenderer> output_buffer_renderer,
     FrameInfoHelper::FrameInfo frame_info,
@@ -282,14 +312,7 @@
     std::move(output_cb).Run(nullptr);
     return;
   }
-
-  // The frames must be copied when threaded texture mailboxes are in use
-  // (http://crbug.com/582170).
-  if (enable_threaded_texture_mailboxes) {
-    frame->metadata()->copy_mode =
-        VideoFrameMetadata::CopyMode::kCopyToNewTexture;
-  }
-
+  frame->metadata()->copy_mode = copy_mode;
   const bool is_surface_control =
       overlay_mode == OverlayMode::kSurfaceControlSecure ||
       overlay_mode == OverlayMode::kSurfaceControlInsecure;
diff --git a/media/gpu/android/video_frame_factory_impl.h b/media/gpu/android/video_frame_factory_impl.h
index 489149eb..6bf6ca6a 100644
--- a/media/gpu/android/video_frame_factory_impl.h
+++ b/media/gpu/android/video_frame_factory_impl.h
@@ -94,7 +94,7 @@
       PromotionHintAggregator::NotifyPromotionHintCB promotion_hint_cb,
       VideoPixelFormat pixel_format,
       OverlayMode overlay_mode,
-      bool enable_threaded_texture_mailboxes,
+      const base::Optional<VideoFrameMetadata::CopyMode>& copy_mode,
       scoped_refptr<base::SequencedTaskRunner> gpu_task_runner,
       std::unique_ptr<CodecOutputBufferRenderer> output_buffer_renderer,
       FrameInfoHelper::FrameInfo frame_info,
@@ -116,8 +116,8 @@
 
   OverlayMode overlay_mode_ = OverlayMode::kDontRequestPromotionHints;
 
-  // Is the sync mailbox manager enabled?
-  bool enable_threaded_texture_mailboxes_ = false;
+  // Indicates how video frame needs to be copied when required.
+  base::Optional<VideoFrameMetadata::CopyMode> copy_mode_;
 
   // Current group that new CodecImages should belong to.  Do not use this on
   // our thread; everything must be posted to the gpu main thread, including
diff --git a/media/renderers/video_resource_updater.cc b/media/renderers/video_resource_updater.cc
index fe95324..0cce682 100644
--- a/media/renderers/video_resource_updater.cc
+++ b/media/renderers/video_resource_updater.cc
@@ -841,12 +841,10 @@
   VideoFrameExternalResources external_resources;
   gfx::ColorSpace resource_color_space = video_frame->ColorSpace();
 
-  bool copy_to_new_texture = (video_frame->metadata()->copy_mode ==
-                              VideoFrameMetadata::CopyMode::kCopyToNewTexture);
-
+  const auto& copy_mode = video_frame->metadata()->copy_mode;
   GLuint target = video_frame->mailbox_holder(0).texture_target;
-  // If |copy_to_new_texture| then we will copy into a GL_TEXTURE_2D target.
-  if (copy_to_new_texture)
+  // If texture copy is required, then we will copy into a GL_TEXTURE_2D target.
+  if (copy_mode == VideoFrameMetadata::CopyMode::kCopyToNewTexture)
     target = GL_TEXTURE_2D;
 
   gfx::BufferFormat buffer_formats[VideoFrame::kMaxPlanes];
@@ -870,11 +868,25 @@
     const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(i);
     if (mailbox_holder.mailbox.IsZero())
       break;
-
-    if (copy_to_new_texture) {
+    if (copy_mode == VideoFrameMetadata::CopyMode::kCopyToNewTexture) {
       CopyHardwarePlane(video_frame.get(), resource_color_space, mailbox_holder,
                         &external_resources);
     } else {
+      gpu::SyncToken sync_token = mailbox_holder.sync_token;
+      gpu::Mailbox mailbox = mailbox_holder.mailbox;
+      if (copy_mode == VideoFrameMetadata::CopyMode::kCopyMailboxesOnly) {
+        auto* sii = SharedImageInterface();
+        uint32_t usage =
+            gpu::SHARED_IMAGE_USAGE_DISPLAY | gpu::SHARED_IMAGE_USAGE_GLES2;
+        mailbox = sii->CreateSharedImageWithAHB(mailbox_holder.mailbox, usage,
+                                                mailbox_holder.sync_token);
+        // Insert a sync token at this point and update video frame release sync
+        // token with it.
+        SyncTokenClientImpl client(nullptr /* GLES2Interface */, sii,
+                                   gpu::SyncToken());
+        sync_token = video_frame->UpdateReleaseSyncToken(&client);
+      }
+
       const gfx::Size& coded_size = video_frame->coded_size();
       const size_t width =
           VideoFrame::Columns(i, video_frame->format(), coded_size.width());
@@ -882,9 +894,8 @@
           VideoFrame::Rows(i, video_frame->format(), coded_size.height());
       const gfx::Size plane_size(width, height);
       auto transfer_resource = viz::TransferableResource::MakeGL(
-          mailbox_holder.mailbox, GL_LINEAR, mailbox_holder.texture_target,
-          mailbox_holder.sync_token, plane_size,
-          video_frame->metadata()->allow_overlay);
+          mailbox, GL_LINEAR, mailbox_holder.texture_target, sync_token,
+          plane_size, video_frame->metadata()->allow_overlay);
       transfer_resource.color_space = resource_color_space;
       transfer_resource.read_lock_fences_enabled =
           video_frame->metadata()->read_lock_fences_enabled;
@@ -898,9 +909,21 @@
           video_frame->metadata()->wants_promotion_hint;
 #endif
       external_resources.resources.push_back(std::move(transfer_resource));
-      external_resources.release_callbacks.push_back(
-          base::BindOnce(&VideoResourceUpdater::ReturnTexture,
-                         weak_ptr_factory_.GetWeakPtr(), video_frame));
+      if (copy_mode == VideoFrameMetadata::CopyMode::kCopyMailboxesOnly) {
+        // Adding a ref on |video_frame| to make sure lifetime of |video frame|
+        // is same as lifetime of this |mailbox|. Releasing |video_frame| before
+        // |mailbox| causes renderer to prepare more video frame which in turn
+        // causes holding onto multiple AHardwareBuffers by both |mailbox| and
+        // |video_frame| which in turn causes higher gpu memory usage and
+        // potential memory crashes.
+        external_resources.release_callbacks.push_back(base::BindOnce(
+            &VideoResourceUpdater::DestroyMailbox,
+            weak_ptr_factory_.GetWeakPtr(), mailbox, video_frame));
+      } else {
+        external_resources.release_callbacks.push_back(
+            base::BindOnce(&VideoResourceUpdater::ReturnTexture,
+                           weak_ptr_factory_.GetWeakPtr(), video_frame));
+      }
     }
   }
   return external_resources;
@@ -1265,6 +1288,19 @@
   video_frame->UpdateReleaseSyncToken(&client);
 }
 
+void VideoResourceUpdater::DestroyMailbox(gpu::Mailbox mailbox,
+                                          scoped_refptr<VideoFrame> video_frame,
+                                          const gpu::SyncToken& sync_token,
+                                          bool lost_resource) {
+  if (lost_resource)
+    return;
+
+  auto* sii = SharedImageInterface();
+  sii->DestroySharedImage(sync_token, mailbox);
+  SyncTokenClientImpl client(nullptr, sii, sync_token);
+  video_frame->UpdateReleaseSyncToken(&client);
+}
+
 void VideoResourceUpdater::RecycleResource(uint32_t plane_resource_id,
                                            const gpu::SyncToken& sync_token,
                                            bool lost_resource) {
@@ -1329,4 +1365,12 @@
   return true;
 }
 
+gpu::SharedImageInterface* VideoResourceUpdater::SharedImageInterface() const {
+  auto* sii = raster_context_provider_
+                  ? raster_context_provider_->SharedImageInterface()
+                  : context_provider_->SharedImageInterface();
+  DCHECK(sii);
+  return sii;
+}
+
 }  // namespace media
diff --git a/media/renderers/video_resource_updater.h b/media/renderers/video_resource_updater.h
index 1f83dd5..55b8353 100644
--- a/media/renderers/video_resource_updater.h
+++ b/media/renderers/video_resource_updater.h
@@ -32,6 +32,10 @@
 class Transform;
 }  // namespace gfx
 
+namespace gpu {
+class SharedImageInterface;
+}  // namespace gpu
+
 namespace viz {
 class ClientResourceProvider;
 class ContextProvider;
@@ -188,11 +192,15 @@
   void ReturnTexture(scoped_refptr<VideoFrame> video_frame,
                      const gpu::SyncToken& sync_token,
                      bool lost_resource);
+  void DestroyMailbox(gpu::Mailbox mailbox,
+                      scoped_refptr<VideoFrame> video_frame,
+                      const gpu::SyncToken& sync_token,
+                      bool lost_resource);
 
   // base::trace_event::MemoryDumpProvider implementation.
   bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
                     base::trace_event::ProcessMemoryDump* pmd) override;
-
+  gpu::SharedImageInterface* SharedImageInterface() const;
   viz::ContextProvider* const context_provider_;
   viz::RasterContextProvider* const raster_context_provider_;
   viz::SharedBitmapReporter* const shared_bitmap_reporter_;
diff --git a/media/renderers/video_resource_updater_unittest.cc b/media/renderers/video_resource_updater_unittest.cc
index 089c5fe..055a5de 100644
--- a/media/renderers/video_resource_updater_unittest.cc
+++ b/media/renderers/video_resource_updater_unittest.cc
@@ -201,13 +201,10 @@
   }
 
   scoped_refptr<media::VideoFrame> CreateTestStreamTextureHardwareVideoFrame(
-      bool needs_copy) {
+      base::Optional<media::VideoFrameMetadata::CopyMode> copy_mode) {
     scoped_refptr<media::VideoFrame> video_frame = CreateTestHardwareVideoFrame(
         media::PIXEL_FORMAT_ARGB, GL_TEXTURE_EXTERNAL_OES);
-    if (needs_copy) {
-      video_frame->metadata()->copy_mode =
-          VideoFrameMetadata::CopyMode::kCopyToNewTexture;
-    }
+    video_frame->metadata()->copy_mode = std::move(copy_mode);
     return video_frame;
   }
 
@@ -541,13 +538,14 @@
   EXPECT_TRUE(resources.resources[2].read_lock_fences_enabled);
 }
 
-TEST_F(VideoResourceUpdaterTest, CreateForHardwarePlanes_StreamTexture) {
+TEST_F(VideoResourceUpdaterTest,
+       CreateForHardwarePlanes_StreamTexture_CopyToNewTexture) {
   // Note that |use_stream_video_draw_quad| is true for this test.
   std::unique_ptr<VideoResourceUpdater> updater =
       CreateUpdaterForHardware(true);
   EXPECT_EQ(0u, GetSharedImageCount());
   scoped_refptr<media::VideoFrame> video_frame =
-      CreateTestStreamTextureHardwareVideoFrame(false);
+      CreateTestStreamTextureHardwareVideoFrame(base::nullopt);
 
   VideoFrameExternalResources resources =
       updater->CreateExternalResourcesFromVideoFrame(video_frame);
@@ -560,7 +558,8 @@
 
   // A copied stream texture should return an RGBA resource in a new
   // GL_TEXTURE_2D texture.
-  video_frame = CreateTestStreamTextureHardwareVideoFrame(true);
+  video_frame = CreateTestStreamTextureHardwareVideoFrame(
+      media::VideoFrameMetadata::CopyMode::kCopyToNewTexture);
   resources = updater->CreateExternalResourcesFromVideoFrame(video_frame);
   EXPECT_EQ(VideoFrameResourceType::RGBA_PREMULTIPLIED, resources.type);
   EXPECT_EQ(1u, resources.resources.size());
@@ -570,11 +569,43 @@
   EXPECT_EQ(1u, GetSharedImageCount());
 }
 
+TEST_F(VideoResourceUpdaterTest,
+       CreateForHardwarePlanes_StreamTexture_CopyMailboxesOnly) {
+  // Note that |use_stream_video_draw_quad| is true for this test.
+  std::unique_ptr<VideoResourceUpdater> updater =
+      CreateUpdaterForHardware(true);
+  EXPECT_EQ(0u, GetSharedImageCount());
+  scoped_refptr<media::VideoFrame> video_frame =
+      CreateTestStreamTextureHardwareVideoFrame(base::nullopt);
+  VideoFrameExternalResources resources =
+      updater->CreateExternalResourcesFromVideoFrame(video_frame);
+  EXPECT_EQ(VideoFrameResourceType::STREAM_TEXTURE, resources.type);
+  EXPECT_EQ(1u, resources.resources.size());
+  EXPECT_EQ((GLenum)GL_TEXTURE_EXTERNAL_OES,
+            resources.resources[0].mailbox_holder.texture_target);
+  EXPECT_EQ(1u, resources.release_callbacks.size());
+  EXPECT_EQ(0u, GetSharedImageCount());
+
+  // If mailbox is copied, the texture target should still be
+  // GL_TEXTURE_EXTERNAL_OES and resource type should be STREAM_TEXTURE.
+  video_frame = CreateTestStreamTextureHardwareVideoFrame(
+      media::VideoFrameMetadata::CopyMode::kCopyMailboxesOnly);
+  resources = updater->CreateExternalResourcesFromVideoFrame(video_frame);
+  EXPECT_EQ(VideoFrameResourceType::STREAM_TEXTURE, resources.type);
+  EXPECT_EQ(1u, resources.resources.size());
+  EXPECT_EQ((GLenum)GL_TEXTURE_EXTERNAL_OES,
+            resources.resources[0].mailbox_holder.texture_target);
+  EXPECT_EQ(1u, resources.release_callbacks.size());
+  // This count will be 1 since a new mailbox will be created when mailbox is
+  // being copied.
+  EXPECT_EQ(1u, GetSharedImageCount());
+}
+
 TEST_F(VideoResourceUpdaterTest, CreateForHardwarePlanes_TextureQuad) {
   std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
   EXPECT_EQ(0u, GetSharedImageCount());
   scoped_refptr<media::VideoFrame> video_frame =
-      CreateTestStreamTextureHardwareVideoFrame(false);
+      CreateTestStreamTextureHardwareVideoFrame(base::nullopt);
 
   VideoFrameExternalResources resources =
       updater->CreateExternalResourcesFromVideoFrame(video_frame);
@@ -663,7 +694,8 @@
   std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
 
   scoped_refptr<media::VideoFrame> video_frame =
-      CreateTestStreamTextureHardwareVideoFrame(true /* needs_copy */);
+      CreateTestStreamTextureHardwareVideoFrame(
+          media::VideoFrameMetadata::CopyMode::kCopyToNewTexture);
 
   VideoFrameExternalResources resources =
       updater->CreateExternalResourcesFromVideoFrame(video_frame);
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 1f7c339..bf71f1c 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -104,8 +104,8 @@
 #endif
 };
 
-const base::Feature kParentNodeReplaceChildren {
-  "ParentNodeReplaceChildren", base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kParentNodeReplaceChildren{
+    "ParentNodeReplaceChildren", base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Enable browser-initiated dedicated worker script loading
 // (PlzDedicatedWorker). https://crbug.com/906991
@@ -672,9 +672,21 @@
 const base::Feature kCSSMatchedPropertiesCacheDependencies{
     "CSSMatchedPropertiesCacheDependencies", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Disabling this will cause parkable strings to never be compressed.
+// This is useful for headless mode + virtual time. Since virtual time advances
+// quickly, strings may be parked too eagerly in that mode.
+const base::Feature kCompressParkableStrings{"CompressParkableStrings",
+                                             base::FEATURE_ENABLED_BY_DEFAULT};
+
 // Whether ParkableStrings can be written out to disk.
+// Depends on compression above.
 const base::Feature kParkableStringsToDisk{"ParkableStringsToDisk",
                                            base::FEATURE_DISABLED_BY_DEFAULT};
 
+bool IsParkableStringsToDiskEnabled() {
+  return base::FeatureList::IsEnabled(kParkableStringsToDisk) &&
+         base::FeatureList::IsEnabled(kCompressParkableStrings);
+}
+
 }  // namespace features
 }  // namespace blink
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn
index 3610a09..f64dca70 100644
--- a/third_party/blink/public/BUILD.gn
+++ b/third_party/blink/public/BUILD.gn
@@ -166,6 +166,7 @@
     "platform/web_audio_device.h",
     "platform/web_audio_latency_hint.h",
     "platform/web_audio_source_provider.h",
+    "platform/web_battery_savings.h",
     "platform/web_blob_info.h",
     "platform/web_cache.h",
     "platform/web_callbacks.h",
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index a250d76..5e42010 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -271,7 +271,9 @@
 BLINK_COMMON_EXPORT extern const base::Feature
     kCSSMatchedPropertiesCacheDependencies;
 
+BLINK_COMMON_EXPORT extern const base::Feature kCompressParkableStrings;
 BLINK_COMMON_EXPORT extern const base::Feature kParkableStringsToDisk;
+BLINK_COMMON_EXPORT bool IsParkableStringsToDiskEnabled();
 
 }  // namespace features
 }  // namespace blink
diff --git a/third_party/blink/public/common/loader/loading_behavior_flag.h b/third_party/blink/public/common/loader/loading_behavior_flag.h
index 845f7024..7cc3c69 100644
--- a/third_party/blink/public/common/loader/loading_behavior_flag.h
+++ b/third_party/blink/public/common/loader/loading_behavior_flag.h
@@ -41,6 +41,9 @@
   // occurred before the first rendering cycle begins. Used to study the
   // effects of delaying the first rendering cycle for web font loading.
   kLoadingBehaviorFontPreloadStartedBeforeRendering = 1 << 8,
+  // Indicates that the page uses the Next.js JavaScript framework (via a
+  // window variable)
+  kLoadingBehaviorNextJSFrameworkUsed = 1 << 9,
 };
 
 }  // namespace blink
diff --git a/third_party/blink/public/mojom/performance_manager/v8_per_frame_memory.mojom b/third_party/blink/public/mojom/performance_manager/v8_per_frame_memory.mojom
index f6088b5d..15114566 100644
--- a/third_party/blink/public/mojom/performance_manager/v8_per_frame_memory.mojom
+++ b/third_party/blink/public/mojom/performance_manager/v8_per_frame_memory.mojom
@@ -8,6 +8,9 @@
 
 // The amount of heap memory used by V8 in the context of a frame.
 struct V8IsolatedWorldMemoryUsage {
+  const int64 kMainWorldId = 0;
+  int64 world_id;
+
   // The number of v8 heap bytes used by a V8 isolated world.
   uint64 bytes_used = 0;
 
@@ -18,11 +21,11 @@
   // For example Chrome extensions use the host ID, as per
   // extensions::ScriptInjection::GetHostIdForIsolatedWorld. Some types of
   // isolated world will not have a suitable tag so will leave this empty.
-  string stable_id;
+  string? stable_id;
 
   // An optional human readable name for the world, for debugging. Unlike
   // stable_id this might not be unique.
-  string human_readable_name;
+  string? human_readable_name;
 };
 
 // Returns the number of bytes used by the v8 heap per frame.
@@ -30,9 +33,9 @@
   // The frame-unique token.
   mojo_base.mojom.UnguessableToken frame_token;
 
-  // The resources used by this frame, mapped on the isolated world ID.
-  // World ID 0 is the main world.
-  map<int64, V8IsolatedWorldMemoryUsage> associated_bytes;
+  // This should actually be a map with world ID keys, but due to limitations
+  // of WTF::HashMap around keys with value = 0, we have to use an array.
+  array<V8IsolatedWorldMemoryUsage> associated_bytes;
 };
 
 // Returns the number of bytes used by the v8 heap in a process.
@@ -54,9 +57,18 @@
 
 // Allows a browser to query the resource usage of sub-processes.
 interface V8PerFrameMemoryReporter {
+  // The mode for performing memory measurement.
+  enum Mode {
+    DEFAULT, // Perform memory measurement on the next garbage collection
+             // and force garbage collection after some timeout.
+
+    EAGER,   // Force immediate garbage collection and memory measurement.
+
+    LAZY,    // Perform memory measurement on the next garbage collection.
+  };
   // Requests a per-frame estimate of v8 heap byte usage on the next garbage
   // collection. Note that this causes extra cost for the next garbage
   // collection, which can be on the order of 10-20%.
-  GetPerFrameV8MemoryUsageData() => (PerProcessV8MemoryUsageData data);
+  GetPerFrameV8MemoryUsageData(Mode mode) => (PerProcessV8MemoryUsageData data);
 };
 
diff --git a/third_party/blink/public/platform/web_battery_savings.h b/third_party/blink/public/platform/web_battery_savings.h
new file mode 100644
index 0000000..b9c94ab
--- /dev/null
+++ b/third_party/blink/public/platform/web_battery_savings.h
@@ -0,0 +1,25 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_BATTERY_SAVINGS_H_
+#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_BATTERY_SAVINGS_H_
+
+namespace blink {
+
+// These are constants for the various keywords allowed for the battery-savings
+// meta element. For instance:
+//
+// <meta name="battery-savings" content="allow-reduced-frame-rate">
+//
+// These constants are bits which can be combined.
+enum WebBatterySavings {
+  kAllowReducedFrameRate = 1 << 0,
+  kAllowReducedScriptSpeed = 1 << 1,
+};
+
+using WebBatterySavingsFlags = unsigned;
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_BATTERY_SAVINGS_H_
diff --git a/third_party/blink/renderer/bindings/generated_in_core.gni b/third_party/blink/renderer/bindings/generated_in_core.gni
index a32f4087..df2259d 100644
--- a/third_party/blink/renderer/bindings/generated_in_core.gni
+++ b/third_party/blink/renderer/bindings/generated_in_core.gni
@@ -443,6 +443,8 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_composition_event.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_computed_accessible_node.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_computed_accessible_node.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_coop_access_violation_report_body.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_coop_access_violation_report_body.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_count_queuing_strategy.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_count_queuing_strategy.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_csp_violation_report_body.cc",
diff --git a/third_party/blink/renderer/bindings/generated_in_modules.gni b/third_party/blink/renderer/bindings/generated_in_modules.gni
index e3354b1..e5c40232 100644
--- a/third_party/blink/renderer/bindings/generated_in_modules.gni
+++ b/third_party/blink/renderer/bindings/generated_in_modules.gni
@@ -1567,8 +1567,6 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_media_recorder.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_media_session.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_media_session.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_media_settings_range.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_media_settings_range.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_media_source.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_media_source.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_media_stream.cc",
@@ -1709,8 +1707,6 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_permission_status.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_permissions.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_permissions.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_photo_capabilities.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_photo_capabilities.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_picture_in_picture_event.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_picture_in_picture_event.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_picture_in_picture_window.cc",
diff --git a/third_party/blink/renderer/bindings/idl_in_core.gni b/third_party/blink/renderer/bindings/idl_in_core.gni
index 06751b5..da5f137 100644
--- a/third_party/blink/renderer/bindings/idl_in_core.gni
+++ b/third_party/blink/renderer/bindings/idl_in_core.gni
@@ -247,6 +247,7 @@
           "//third_party/blink/renderer/core/fileapi/file_reader_sync.idl",
           "//third_party/blink/renderer/core/fileapi/url_file_api.idl",
           "//third_party/blink/renderer/core/frame/bar_prop.idl",
+          "//third_party/blink/renderer/core/frame/coop_access_violation_report_body.idl",
           "//third_party/blink/renderer/core/frame/csp/csp_violation_report_body.idl",
           "//third_party/blink/renderer/core/frame/deprecation_report_body.idl",
           "//third_party/blink/renderer/core/frame/document_policy_violation_report_body.idl",
diff --git a/third_party/blink/renderer/controller/BUILD.gn b/third_party/blink/renderer/controller/BUILD.gn
index 922f06e..6a63e4f 100644
--- a/third_party/blink/renderer/controller/BUILD.gn
+++ b/third_party/blink/renderer/controller/BUILD.gn
@@ -179,6 +179,9 @@
       "oom_intervention_impl_test.cc",
       "user_level_memory_pressure_signal_generator_test.cc",
     ]
+  } else {
+    sources +=
+        [ "performance_manager/v8_per_frame_memory_reporter_impl_test.cc" ]
   }
 
   if (is_linux || is_chromeos || is_android || is_mac || is_win) {
diff --git a/third_party/blink/renderer/controller/performance_manager/v8_per_frame_memory_reporter_impl.cc b/third_party/blink/renderer/controller/performance_manager/v8_per_frame_memory_reporter_impl.cc
index 200f48c..b35d956 100644
--- a/third_party/blink/renderer/controller/performance_manager/v8_per_frame_memory_reporter_impl.cc
+++ b/third_party/blink/renderer/controller/performance_manager/v8_per_frame_memory_reporter_impl.cc
@@ -21,6 +21,7 @@
   typedef const ::blink::mojom::blink::PerFrameV8MemoryUsageDataPtr&
       PeekOutType;
 };
+
 }  // namespace WTF
 
 namespace blink {
@@ -76,9 +77,11 @@
         ++(result->num_unassociated_contexts);
         result->unassociated_context_bytes_used += size;
       } else {
-        mojom::blink::PerFrameV8MemoryUsageData* per_frame_resources =
-            frames.at(frame).get();
-        if (!per_frame_resources) {
+        auto it = frames.find(frame);
+        mojom::blink::PerFrameV8MemoryUsageData* per_frame_resources;
+        if (it != frames.end()) {
+          per_frame_resources = it->value.get();
+        } else {
 #if DCHECK_IS_ON()
           // Check that the frame token didn't already occur.
           for (const auto& entry : frames) {
@@ -97,19 +100,29 @@
         mojom::blink::V8IsolatedWorldMemoryUsagePtr isolated_world_usage =
             mojom::blink::V8IsolatedWorldMemoryUsage::New();
         isolated_world_usage->bytes_used = size;
-        int32_t world_id = frame->GetScriptContextWorldId(context);
+        isolated_world_usage->world_id =
+            frame->GetScriptContextWorldId(context);
+        static_assert(
+            DOMWrapperWorld::WorldId::kMainWorldId ==
+                mojom::blink::V8IsolatedWorldMemoryUsage::kMainWorldId,
+            "The main world IDs must match.");
 
-        if (world_id != DOMWrapperWorld::WorldId::kMainWorldId) {
+        if (isolated_world_usage->world_id !=
+            DOMWrapperWorld::WorldId::kMainWorldId) {
           isolated_world_usage->stable_id =
               blink::GetIsolatedWorldStableId(context);
           isolated_world_usage->human_readable_name =
               blink::GetIsolatedWorldHumanReadableName(context);
         }
+#if DCHECK_IS_ON()
+        // Check that the world id didn't already occur.
+        for (const auto& entry : per_frame_resources->associated_bytes) {
+          DCHECK_NE(entry->world_id, isolated_world_usage->world_id);
+        }
+#endif
 
-        DCHECK(
-            !base::Contains(per_frame_resources->associated_bytes, world_id));
-        per_frame_resources->associated_bytes.Set(
-            world_id, std::move(isolated_world_usage));
+        per_frame_resources->associated_bytes.push_back(
+            std::move(isolated_world_usage));
       }
     }
     // Move the per-frame memory values to the result.
@@ -122,6 +135,19 @@
   GetPerFrameV8MemoryUsageDataCallback callback_;
 };
 
+v8::MeasureMemoryExecution ToV8MeasureMemoryExecution(
+    V8PerFrameMemoryReporterImpl::Mode mode) {
+  switch (mode) {
+    case V8PerFrameMemoryReporterImpl::Mode::DEFAULT:
+      return v8::MeasureMemoryExecution::kDefault;
+    case V8PerFrameMemoryReporterImpl::Mode::EAGER:
+      return v8::MeasureMemoryExecution::kEager;
+    case V8PerFrameMemoryReporterImpl::Mode::LAZY:
+      return v8::MeasureMemoryExecution::kLazy;
+  }
+  NOTREACHED();
+}
+
 }  // namespace
 
 // static
@@ -132,6 +158,7 @@
 }
 
 void V8PerFrameMemoryReporterImpl::GetPerFrameV8MemoryUsageData(
+    V8PerFrameMemoryReporterImpl::Mode mode,
     GetPerFrameV8MemoryUsageDataCallback callback) {
   v8::Isolate* isolate = v8::Isolate::GetCurrent();
   if (!isolate) {
@@ -141,7 +168,8 @@
         std::make_unique<FrameAssociatedMeasurementDelegate>(
             std::move(callback));
 
-    isolate->MeasureMemory(std::move(delegate));
+    isolate->MeasureMemory(std::move(delegate),
+                           ToV8MeasureMemoryExecution(mode));
   }
 }
 
diff --git a/third_party/blink/renderer/controller/performance_manager/v8_per_frame_memory_reporter_impl.h b/third_party/blink/renderer/controller/performance_manager/v8_per_frame_memory_reporter_impl.h
index 18cd9d1..442c3c05 100644
--- a/third_party/blink/renderer/controller/performance_manager/v8_per_frame_memory_reporter_impl.h
+++ b/third_party/blink/renderer/controller/performance_manager/v8_per_frame_memory_reporter_impl.h
@@ -6,17 +6,19 @@
 #define THIRD_PARTY_BLINK_RENDERER_CONTROLLER_PERFORMANCE_MANAGER_V8_PER_FRAME_MEMORY_REPORTER_IMPL_H_
 
 #include "third_party/blink/public/mojom/performance_manager/v8_per_frame_memory.mojom-blink.h"
+#include "third_party/blink/renderer/controller/controller_export.h"
 
 namespace blink {
 
 // Exposes V8 per-frame associated memory metrics to the browser.
-class V8PerFrameMemoryReporterImpl
+class CONTROLLER_EXPORT V8PerFrameMemoryReporterImpl
     : public mojom::blink::V8PerFrameMemoryReporter {
  public:
   static void Create(
       mojo::PendingReceiver<mojom::blink::V8PerFrameMemoryReporter> receiver);
 
   void GetPerFrameV8MemoryUsageData(
+      Mode mode,
       GetPerFrameV8MemoryUsageDataCallback callback) override;
 };
 
diff --git a/third_party/blink/renderer/controller/performance_manager/v8_per_frame_memory_reporter_impl_test.cc b/third_party/blink/renderer/controller/performance_manager/v8_per_frame_memory_reporter_impl_test.cc
new file mode 100644
index 0000000..8399e78
--- /dev/null
+++ b/third_party/blink/renderer/controller/performance_manager/v8_per_frame_memory_reporter_impl_test.cc
@@ -0,0 +1,87 @@
+// 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/controller/performance_manager/v8_per_frame_memory_reporter_impl.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/testing/sim/sim_compositor.h"
+#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
+#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
+#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
+#include "v8/include/v8.h"
+
+namespace blink {
+
+class V8PerFrameMemoryReporterImplTest : public SimTest {};
+
+namespace {
+
+class MemoryUsageChecker {
+ public:
+  void Callback(mojom::blink::PerProcessV8MemoryUsageDataPtr result) {
+    EXPECT_EQ(2u, result->associated_memory.size());
+    for (const auto& frame_memory : result->associated_memory) {
+      for (const auto& entry : frame_memory->associated_bytes) {
+        EXPECT_EQ(0u, entry->world_id);
+        EXPECT_LT(4000000u, entry->bytes_used);
+      }
+    }
+    called_ = true;
+  }
+  bool IsCalled() { return called_; }
+
+ private:
+  bool called_ = false;
+};
+
+}  // anonymous namespace
+
+TEST_F(V8PerFrameMemoryReporterImplTest, GetPerFrameV8MemoryUsageData) {
+  SimRequest main_resource("https://example.com/", "text/html");
+  SimRequest child_frame_resource("https://example.com/subframe.html",
+                                  "text/html");
+
+  LoadURL("https://example.com/");
+
+  main_resource.Complete(String::Format(R"HTML(
+      <script>
+        window.onload = function () {
+          globalThis.array = new Array(1000000).fill(0);
+          console.log("main loaded");
+        }
+      </script>
+      <body>
+        <iframe src='https://example.com/subframe.html'></iframe>
+      </body>)HTML"));
+
+  test::RunPendingTasks();
+
+  child_frame_resource.Complete(String::Format(R"HTML(
+      <script>
+        window.onload = function () {
+          globalThis.array = new Array(1000000).fill(0);
+          console.log("iframe loaded");
+        }
+      </script>
+      <body>
+      </body>)HTML"));
+
+  test::RunPendingTasks();
+
+  // Ensure that main frame and subframe are loaded before measuring memory
+  // usage.
+  EXPECT_TRUE(ConsoleMessages().Contains("main loaded"));
+  EXPECT_TRUE(ConsoleMessages().Contains("iframe loaded"));
+
+  V8PerFrameMemoryReporterImpl reporter;
+  MemoryUsageChecker checker;
+  reporter.GetPerFrameV8MemoryUsageData(
+      V8PerFrameMemoryReporterImpl::Mode::EAGER,
+      WTF::Bind(&MemoryUsageChecker::Callback, WTF::Unretained(&checker)));
+
+  test::RunPendingTasks();
+
+  EXPECT_TRUE(checker.IsCalled());
+}
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/core_idl_files.gni b/third_party/blink/renderer/core/core_idl_files.gni
index ca28a4236..d083114 100644
--- a/third_party/blink/renderer/core/core_idl_files.gni
+++ b/third_party/blink/renderer/core/core_idl_files.gni
@@ -182,6 +182,7 @@
                     "fileapi/file_reader.idl",
                     "fileapi/file_reader_sync.idl",
                     "frame/bar_prop.idl",
+                    "frame/coop_access_violation_report_body.idl",
                     "frame/csp/csp_violation_report_body.idl",
                     "frame/deprecation_report_body.idl",
                     "frame/document_policy_violation_report_body.idl",
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context.cc b/third_party/blink/renderer/core/display_lock/display_lock_context.cc
index 62e4d9b0..63c9b5df 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_context.cc
+++ b/third_party/blink/renderer/core/display_lock/display_lock_context.cc
@@ -737,6 +737,10 @@
       layout_box->Layer()->SetNeedsCompositingInputsUpdate();
     needs_compositing_dependent_flag_update_ = false;
 
+    if (needs_graphics_layer_rebuild_)
+      layout_box->Layer()->SetNeedsGraphicsLayerRebuild();
+    needs_graphics_layer_rebuild_ = false;
+
     return true;
   }
   return false;
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context.h b/third_party/blink/renderer/core/display_lock/display_lock_context.h
index 0af24aac..baa3223 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_context.h
+++ b/third_party/blink/renderer/core/display_lock/display_lock_context.h
@@ -162,6 +162,11 @@
     needs_compositing_dependent_flag_update_ = true;
   }
 
+  void NotifyGraphicsLayerRebuildBlocked() {
+    DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
+    needs_graphics_layer_rebuild_ = true;
+  }
+
   // Notify this element will be disconnected.
   void NotifyWillDisconnect();
 
@@ -363,6 +368,8 @@
   // again at the start of the lifecycle.
   bool keep_unlocked_until_lifecycle_ = false;
 
+  bool needs_graphics_layer_rebuild_ = false;
+
   enum class RenderAffectingState : int {
     kLockRequested,
     kIntersectsViewport,
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index dad778c..9094996 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -69,6 +69,7 @@
 #include "third_party/blink/public/mojom/ukm/ukm.mojom-blink.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/task_type.h"
+#include "third_party/blink/public/platform/web_battery_savings.h"
 #include "third_party/blink/public/platform/web_content_settings_client.h"
 #include "third_party/blink/public/platform/web_theme_engine.h"
 #include "third_party/blink/public/web/web_print_page_description.h"
@@ -283,6 +284,7 @@
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
 #include "third_party/blink/renderer/core/probe/core_probes.h"
 #include "third_party/blink/renderer/core/resize_observer/resize_observer_controller.h"
+#include "third_party/blink/renderer/core/script/detect_javascript_frameworks.h"
 #include "third_party/blink/renderer/core/script/script_runner.h"
 #include "third_party/blink/renderer/core/scroll/scrollbar_theme.h"
 #include "third_party/blink/renderer/core/svg/svg_document_extensions.h"
@@ -3936,6 +3938,7 @@
     GetFrame()->GetFrameScheduler()->OnLoad();
 
     AnchorElementMetrics::NotifyOnLoad(*this);
+    DetectJavascriptFrameworksOnLoad(*this);
 
     // If this is a document associated with a resource loading hints based
     // preview, then record the resource loading hints UKM now that the load is
@@ -7011,6 +7014,32 @@
   GetStyleEngine().SetColorSchemeFromMeta(color_scheme);
 }
 
+void Document::BatterySavingsMetaChanged() {
+  if (!RuntimeEnabledFeatures::BatterySavingsMetaEnabled())
+    return;
+
+  if (!IsInMainFrame())
+    return;
+
+  auto* root_element = documentElement();
+  if (!root_element)
+    return;
+  for (HTMLMetaElement& meta_element :
+       Traversal<HTMLMetaElement>::DescendantsOf(*root_element)) {
+    if (EqualIgnoringASCIICase(meta_element.GetName(), "battery-savings")) {
+      SpaceSplitString split_content(
+          AtomicString(meta_element.Content().GetString().LowerASCII()));
+      WebBatterySavingsFlags savings = 0;
+      if (split_content.Contains("allow-reduced-framerate"))
+        savings |= kAllowReducedFrameRate;
+      if (split_content.Contains("allow-reduced-script-speed"))
+        savings |= kAllowReducedScriptSpeed;
+      GetPage()->GetChromeClient().BatterySavingsChanged(*GetFrame(), savings);
+      return;
+    }
+  }
+}
+
 static HTMLLinkElement* GetLinkElement(const Document* doc,
                                        bool (*match_fn)(HTMLLinkElement&)) {
   HTMLHeadElement* head = doc->head();
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h
index 561700e8..a40b925 100644
--- a/third_party/blink/renderer/core/dom/document.h
+++ b/third_party/blink/renderer/core/dom/document.h
@@ -1545,6 +1545,10 @@
   // Update the presentation level color-scheme property for the root element.
   void ColorSchemeMetaChanged();
 
+  // A META element with name=battery-savings was added, removed, or modified.
+  // Re-collect the META values that apply and pass to LayerTreeHost.
+  void BatterySavingsMetaChanged();
+
   // Use counter related functions.
   void CountUse(mojom::WebFeature feature) final;
   void CountUse(mojom::WebFeature feature) const;
diff --git a/third_party/blink/renderer/core/editing/markers/document_marker_controller.cc b/third_party/blink/renderer/core/editing/markers/document_marker_controller.cc
index c6c939d6..33d6c674 100644
--- a/third_party/blink/renderer/core/editing/markers/document_marker_controller.cc
+++ b/third_party/blink/renderer/core/editing/markers/document_marker_controller.cc
@@ -445,9 +445,7 @@
   const PositionInFlatTree& end = SearchAroundPositionEnd(position);
 
   if (start > end) {
-    // TODO(crbug.com/778507): We shouldn't reach here, but currently do due to
-    // legacy implementation of StartOfWord(). Rewriting StartOfWord() with
-    // TextOffsetMapping should fix it.
+    // TODO(crbug/1114021): Investigate why this might happen.
     NOTREACHED() << "|start| should be before |end|.";
     return nullptr;
   }
@@ -555,6 +553,12 @@
   const PositionInFlatTree& start = SearchAroundPositionStart(position);
   const PositionInFlatTree& end = SearchAroundPositionEnd(position);
 
+  if (start > end) {
+    // TODO(crbug/1114021): Investigate why this might happen.
+    NOTREACHED() << "|start| should be before |end|.";
+    return result;
+  }
+
   const Node* const start_node = start.ComputeContainerNode();
   const unsigned start_offset = start.ComputeOffsetInContainerNode();
   const Node* const end_node = end.ComputeContainerNode();
diff --git a/third_party/blink/renderer/core/frame/BUILD.gn b/third_party/blink/renderer/core/frame/BUILD.gn
index c59e4c4d..d620770 100644
--- a/third_party/blink/renderer/core/frame/BUILD.gn
+++ b/third_party/blink/renderer/core/frame/BUILD.gn
@@ -13,6 +13,8 @@
     "bar_prop.h",
     "browser_controls.cc",
     "browser_controls.h",
+    "coop_access_violation_report_body.cc",
+    "coop_access_violation_report_body.h",
     "csp/content_security_policy.cc",
     "csp/content_security_policy.h",
     "csp/csp_directive.h",
diff --git a/third_party/blink/renderer/core/frame/coop_access_violation_report_body.cc b/third_party/blink/renderer/core/frame/coop_access_violation_report_body.cc
new file mode 100644
index 0000000..c730a35
--- /dev/null
+++ b/third_party/blink/renderer/core/frame/coop_access_violation_report_body.cc
@@ -0,0 +1,20 @@
+// 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/core/frame/coop_access_violation_report_body.h"
+
+namespace blink {
+
+CoopAccessViolationReportBody::CoopAccessViolationReportBody(
+    std::unique_ptr<SourceLocation> source_location,
+    const String& property)
+    : LocationReportBody(std::move(source_location)), property_(property) {}
+
+void CoopAccessViolationReportBody::BuildJSONValue(
+    V8ObjectBuilder& builder) const {
+  LocationReportBody::BuildJSONValue(builder);
+  builder.AddString("property", property());
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/frame/coop_access_violation_report_body.h b/third_party/blink/renderer/core/frame/coop_access_violation_report_body.h
new file mode 100644
index 0000000..cb8c18b
--- /dev/null
+++ b/third_party/blink/renderer/core/frame/coop_access_violation_report_body.h
@@ -0,0 +1,30 @@
+// 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_CORE_FRAME_COOP_ACCESS_VIOLATION_REPORT_BODY_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_COOP_ACCESS_VIOLATION_REPORT_BODY_H_
+
+#include "third_party/blink/renderer/bindings/core/v8/source_location.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_object_builder.h"
+#include "third_party/blink/renderer/core/frame/location_report_body.h"
+
+namespace blink {
+
+class CORE_EXPORT CoopAccessViolationReportBody : public LocationReportBody {
+  DEFINE_WRAPPERTYPEINFO();
+
+ public:
+  CoopAccessViolationReportBody(std::unique_ptr<SourceLocation> source_location,
+                                const String& property);
+  ~CoopAccessViolationReportBody() final = default;
+  const String& property() const { return property_; }
+  void BuildJSONValue(V8ObjectBuilder& builder) const final;
+
+ private:
+  const String property_;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_COOP_ACCESS_VIOLATION_REPORT_BODY_H_
diff --git a/third_party/blink/renderer/core/frame/coop_access_violation_report_body.idl b/third_party/blink/renderer/core/frame/coop_access_violation_report_body.idl
new file mode 100644
index 0000000..6c27971
--- /dev/null
+++ b/third_party/blink/renderer/core/frame/coop_access_violation_report_body.idl
@@ -0,0 +1,15 @@
+// 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.
+
+// https://html.spec.whatwg.org/#cross-origin-opener-policies
+
+[
+  NoInterfaceObject
+] interface CoopAccessViolationReportBody : ReportBody {
+  readonly attribute DOMString? sourceFile;
+  readonly attribute unsigned long? lineNumber;
+  readonly attribute unsigned long? columnNumber;
+  readonly attribute DOMString property;
+  [CallWith=ScriptState] object toJSON();
+};
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 e370394..bfc6638 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
@@ -1468,7 +1468,10 @@
                             ContentSecurityPolicyViolationType::kURLViolation ||
       violation_type ==
           blink::ContentSecurityPolicy::ContentSecurityPolicyViolationType::
-              kInlineViolation) {
+              kInlineViolation ||
+      violation_type ==
+          blink::ContentSecurityPolicy::ContentSecurityPolicyViolationType::
+              kEvalViolation) {
     if (frame_ancestor)
       frame_ancestor->AddInspectorIssue(std::move(info));
     else if (delegate_)
diff --git a/third_party/blink/renderer/core/frame/dom_window.cc b/third_party/blink/renderer/core/frame/dom_window.cc
index 800726b..32a28db5 100644
--- a/third_party/blink/renderer/core/frame/dom_window.cc
+++ b/third_party/blink/renderer/core/frame/dom_window.cc
@@ -17,12 +17,15 @@
 #include "third_party/blink/renderer/core/events/message_event.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/execution_context/security_context.h"
+#include "third_party/blink/renderer/core/frame/coop_access_violation_report_body.h"
 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
 #include "third_party/blink/renderer/core/frame/frame.h"
 #include "third_party/blink/renderer/core/frame/frame_client.h"
 #include "third_party/blink/renderer/core/frame/frame_console.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/frame/location.h"
+#include "third_party/blink/renderer/core/frame/report.h"
+#include "third_party/blink/renderer/core/frame/reporting_context.h"
 #include "third_party/blink/renderer/core/frame/settings.h"
 #include "third_party/blink/renderer/core/frame/user_activation.h"
 #include "third_party/blink/renderer/core/input/input_device_capabilities.h"
@@ -451,7 +454,7 @@
     return;
 
   LocalDOMWindow* accessing_window = IncumbentDOMWindow(isolate);
-  Frame* accessing_frame = accessing_window->GetFrame();
+  LocalFrame* accessing_frame = accessing_window->GetFrame();
 
   // A frame might be destroyed, but its context can still be able to execute
   // some code. Those accesses are ignored. See https://crbug.com/1108256.
@@ -463,12 +466,14 @@
   if (accessing_frame->IsCrossOriginToParentFrame())
     return;
 
-  const base::UnguessableToken& accessing_main_frame =
-      accessing_window->GetFrame()->Tree().Top().GetFrameToken();
+  LocalFrame& accessing_main_frame =
+      To<LocalFrame>(accessing_frame->Tree().Top());
+  const base::UnguessableToken& accessing_main_frame_token =
+      accessing_main_frame.GetFrameToken();
 
   auto* it = coop_access_monitor_.begin();
   while (it != coop_access_monitor_.end()) {
-    if (it->accessing_main_frame != accessing_main_frame) {
+    if (it->accessing_main_frame != accessing_main_frame_token) {
       ++it;
       continue;
     }
@@ -486,8 +491,18 @@
     it->reporter->QueueAccessReport(it->report_type, property_name,
                                     std::move(source_location));
 
-    // TODO(arthursonzogni): In the access-from-coop case, dispatch a
-    // reportingObserver event.
+    // TODO(arthursonzogni): Dispatch a console error/warning message.
+
+    // Send a coop-access-violation report.
+    if (it->report_type ==
+        network::mojom::CoopAccessReportType::kReportAccessFrom) {
+      ReportingContext::From(accessing_main_frame.DomWindow())
+          ->QueueReport(MakeGarbageCollected<Report>(
+              ReportType::kCoopAccessViolation,
+              accessing_main_frame.GetDocument()->Url().GetString(),
+              MakeGarbageCollected<CoopAccessViolationReportBody>(
+                  std::move(location), String(property_name))));
+    }
 
     // CoopAccessMonitor are used once and destroyed. This avoids sending
     // multiple reports for the same access.
diff --git a/third_party/blink/renderer/core/frame/report.cc b/third_party/blink/renderer/core/frame/report.cc
index 10c53d8..dc75628 100644
--- a/third_party/blink/renderer/core/frame/report.cc
+++ b/third_party/blink/renderer/core/frame/report.cc
@@ -6,11 +6,12 @@
 
 namespace blink {
 
-constexpr const char ReportType::kDeprecation[];
-constexpr const char ReportType::kFeaturePolicyViolation[];
-constexpr const char ReportType::kDocumentPolicyViolation[];
-constexpr const char ReportType::kIntervention[];
 constexpr const char ReportType::kCSPViolation[];
+constexpr const char ReportType::kCoopAccessViolation[];
+constexpr const char ReportType::kDeprecation[];
+constexpr const char ReportType::kDocumentPolicyViolation[];
+constexpr const char ReportType::kFeaturePolicyViolation[];
+constexpr const char ReportType::kIntervention[];
 
 ScriptValue Report::toJSON(ScriptState* script_state) const {
   V8ObjectBuilder builder(script_state);
diff --git a/third_party/blink/renderer/core/frame/report.h b/third_party/blink/renderer/core/frame/report.h
index aa8f5022..4049a6b 100644
--- a/third_party/blink/renderer/core/frame/report.h
+++ b/third_party/blink/renderer/core/frame/report.h
@@ -14,13 +14,14 @@
 // The constants are implemented as static members of a class to have an unique
 // address and not violate ODR.
 struct CORE_EXPORT ReportType {
+  static constexpr const char kCSPViolation[] = "csp-violation";
+  static constexpr const char kCoopAccessViolation[] = "coop-access-violation";
   static constexpr const char kDeprecation[] = "deprecation";
-  static constexpr const char kFeaturePolicyViolation[] =
-      "feature-policy-violation";
   static constexpr const char kDocumentPolicyViolation[] =
       "document-policy-violation";
+  static constexpr const char kFeaturePolicyViolation[] =
+      "feature-policy-violation";
   static constexpr const char kIntervention[] = "intervention";
-  static constexpr const char kCSPViolation[] = "csp-violation";
 };
 
 class CORE_EXPORT Report : public ScriptWrappable {
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_base.cc b/third_party/blink/renderer/core/frame/web_frame_widget_base.cc
index 4fcaae1..e1428ed 100644
--- a/third_party/blink/renderer/core/frame/web_frame_widget_base.cc
+++ b/third_party/blink/renderer/core/frame/web_frame_widget_base.cc
@@ -1885,4 +1885,9 @@
                                                callback);
 }
 
+void WebFrameWidgetBase::BatterySavingsChanged(WebBatterySavingsFlags savings) {
+  widget_base_->LayerTreeHost()->SetEnableFrameRateThrottling(
+      savings & kAllowReducedFrameRate);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_base.h b/third_party/blink/renderer/core/frame/web_frame_widget_base.h
index 22e3692..e1ff0ea 100644
--- a/third_party/blink/renderer/core/frame/web_frame_widget_base.h
+++ b/third_party/blink/renderer/core/frame/web_frame_widget_base.h
@@ -17,6 +17,7 @@
 #include "third_party/blink/public/mojom/manifest/display_mode.mojom-blink.h"
 #include "third_party/blink/public/mojom/page/widget.mojom-blink.h"
 #include "third_party/blink/public/platform/cross_variant_mojo_util.h"
+#include "third_party/blink/public/platform/web_battery_savings.h"
 #include "third_party/blink/public/platform/web_drag_data.h"
 #include "third_party/blink/public/web/web_frame_widget.h"
 #include "third_party/blink/renderer/core/clipboard/data_object.h"
@@ -490,6 +491,10 @@
   // level widget in a tab/window. E.g. a portal is activated or deactivated.
   void SetIsNestedMainFrameWidget(bool is_nested);
 
+  // The value of the applied battery-savings META element in the document
+  // changed.
+  void BatterySavingsChanged(WebBatterySavingsFlags savings);
+
  protected:
   enum DragAction { kDragEnter, kDragOver };
 
diff --git a/third_party/blink/renderer/core/html/html_meta_element.cc b/third_party/blink/renderer/core/html/html_meta_element.cc
index a0a6244..d851c90 100644
--- a/third_party/blink/renderer/core/html/html_meta_element.cc
+++ b/third_party/blink/renderer/core/html/html_meta_element.cc
@@ -484,6 +484,8 @@
     GetDocument().GetFrame()->DidChangeThemeColor();
   } else if (EqualIgnoringASCIICase(name_value, "color-scheme")) {
     GetDocument().ColorSchemeMetaChanged();
+  } else if (EqualIgnoringASCIICase(name_value, "battery-savings")) {
+    GetDocument().BatterySavingsMetaChanged();
   }
 }
 
@@ -565,6 +567,10 @@
     GetDocument().ColorSchemeMetaChanged();
     return;
   }
+  if (EqualIgnoringASCIICase(name_value, "battery-savings")) {
+    GetDocument().BatterySavingsMetaChanged();
+    return;
+  }
 
   // All situations below require a content attribute (which can be the empty
   // string).
diff --git a/third_party/blink/renderer/core/loader/empty_clients.h b/third_party/blink/renderer/core/loader/empty_clients.h
index 6744afc4..8c0451bf 100644
--- a/third_party/blink/renderer/core/loader/empty_clients.h
+++ b/third_party/blink/renderer/core/loader/empty_clients.h
@@ -217,6 +217,8 @@
   void SetCursorForPlugin(const ui::Cursor&, LocalFrame*) override {}
   void InstallSupplements(LocalFrame&) override {}
   void MainFrameScrollOffsetChanged(LocalFrame& main_frame) const override {}
+  void BatterySavingsChanged(LocalFrame& main_frame,
+                             WebBatterySavingsFlags savings) override {}
 };
 
 class CORE_EXPORT EmptyLocalFrameClient : public LocalFrameClient {
diff --git a/third_party/blink/renderer/core/page/chrome_client.h b/third_party/blink/renderer/core/page/chrome_client.h
index 3265f65..228ba34 100644
--- a/third_party/blink/renderer/core/page/chrome_client.h
+++ b/third_party/blink/renderer/core/page/chrome_client.h
@@ -39,6 +39,7 @@
 #include "third_party/blink/public/mojom/devtools/console_message.mojom-blink-forward.h"
 #include "third_party/blink/public/mojom/input/focus_type.mojom-blink-forward.h"
 #include "third_party/blink/public/platform/blame_context.h"
+#include "third_party/blink/public/platform/web_battery_savings.h"
 #include "third_party/blink/public/platform/web_float_rect.h"
 #include "third_party/blink/public/web/web_swap_result.h"
 #include "third_party/blink/public/web/web_widget_client.h"
@@ -519,6 +520,9 @@
       LocalFrame* frame,
       std::unique_ptr<viz::DelegatedInkMetadata> metadata) {}
 
+  virtual void BatterySavingsChanged(LocalFrame& main_frame,
+                                     WebBatterySavingsFlags savings) = 0;
+
  protected:
   ChromeClient() = default;
 
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 5f53cc8..263d668 100644
--- a/third_party/blink/renderer/core/page/chrome_client_impl.cc
+++ b/third_party/blink/renderer/core/page/chrome_client_impl.cc
@@ -1245,4 +1245,12 @@
   frame->GetWidgetForLocalRoot()->SetDelegatedInkMetadata(std::move(metadata));
 }
 
+void ChromeClientImpl::BatterySavingsChanged(LocalFrame& main_frame,
+                                             WebBatterySavingsFlags savings) {
+  DCHECK(main_frame.IsMainFrame());
+  WebLocalFrameImpl::FromFrame(main_frame)
+      ->FrameWidgetImpl()
+      ->BatterySavingsChanged(savings);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/page/chrome_client_impl.h b/third_party/blink/renderer/core/page/chrome_client_impl.h
index 9e1805d..b578c0a 100644
--- a/third_party/blink/renderer/core/page/chrome_client_impl.h
+++ b/third_party/blink/renderer/core/page/chrome_client_impl.h
@@ -290,6 +290,9 @@
 
   double UserZoomFactor() const override;
 
+  void BatterySavingsChanged(LocalFrame& main_frame,
+                             WebBatterySavingsFlags savings) override;
+
  private:
   bool IsChromeClientImpl() const override { return true; }
 
diff --git a/third_party/blink/renderer/core/paint/applied_decoration_painter.cc b/third_party/blink/renderer/core/paint/applied_decoration_painter.cc
index ec4fb71d..d1011602 100644
--- a/third_party/blink/renderer/core/paint/applied_decoration_painter.cc
+++ b/third_party/blink/renderer/core/paint/applied_decoration_painter.cc
@@ -10,7 +10,7 @@
 
 void AppliedDecorationPainter::Paint() {
   context_.SetStrokeStyle(decoration_info_.StrokeStyle());
-  context_.SetStrokeColor(decoration_info_.Color());
+  context_.SetStrokeColor(decoration_info_.LineColor());
 
   switch (decoration_info_.DecorationStyle()) {
     case ETextDecorationStyle::kWavy:
diff --git a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
index 5bd36b97..8539580 100644
--- a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
+++ b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
@@ -719,7 +719,6 @@
                              snapped_offset_from_composited_ancestor);
 
   UpdateMainGraphicsLayerGeometry(local_compositing_bounds);
-  UpdateOverflowControlsHostLayerGeometry(compositing_container);
   UpdateSquashingLayerGeometry(
       compositing_container, snapped_offset_from_composited_ancestor,
       non_scrolling_squashed_layers_, layers_needing_paint_invalidation);
@@ -790,20 +789,6 @@
   }
 }
 
-void CompositedLayerMapping::UpdateOverflowControlsHostLayerGeometry(
-    const PaintLayer* compositing_container) {
-  if (!overflow_controls_host_layer_)
-    return;
-
-  // To clip the scrollbars correctly, overflow_controls_host_layer_ should
-  // match our border box size.
-  const IntSize border_box_size =
-      owning_layer_.GetLayoutBox()->PixelSnappedBorderBoxSize(
-          PhysicalOffset(owning_layer_.SubpixelAccumulation() +
-                         owning_layer_.GetLayoutBox()->PhysicalLocation()));
-  overflow_controls_host_layer_->SetSize(gfx::Size(border_box_size));
-}
-
 void CompositedLayerMapping::UpdateMaskLayerGeometry() {
   if (!mask_layer_)
     return;
@@ -945,20 +930,12 @@
   if (scrolling_contents_layer_)
     graphics_layer_->AddChild(scrolling_contents_layer_.get());
 
-  // Now constructing the subtree for the overflow controls.
-  if (overflow_controls_host_layer_) {
-    graphics_layer_->AddChild(overflow_controls_host_layer_.get());
-    if (layer_for_horizontal_scrollbar_) {
-      overflow_controls_host_layer_->AddChild(
-          layer_for_horizontal_scrollbar_.get());
-    }
-    if (layer_for_vertical_scrollbar_) {
-      overflow_controls_host_layer_->AddChild(
-          layer_for_vertical_scrollbar_.get());
-    }
-    if (layer_for_scroll_corner_)
-      overflow_controls_host_layer_->AddChild(layer_for_scroll_corner_.get());
-  }
+  if (layer_for_horizontal_scrollbar_)
+    graphics_layer_->AddChild(layer_for_horizontal_scrollbar_.get());
+  if (layer_for_vertical_scrollbar_)
+    graphics_layer_->AddChild(layer_for_vertical_scrollbar_.get());
+  if (layer_for_scroll_corner_)
+    graphics_layer_->AddChild(layer_for_scroll_corner_.get());
 
   if (decoration_outline_layer_)
     graphics_layer_->AddChild(decoration_outline_layer_.get());
@@ -1136,13 +1113,6 @@
       layer_for_scroll_corner_, needs_scroll_corner_layer,
       CompositingReason::kLayerForScrollCorner);
 
-  bool needs_overflow_controls_host_layer = needs_horizontal_scrollbar_layer ||
-                                            needs_vertical_scrollbar_layer ||
-                                            needs_scroll_corner_layer;
-  ToggleScrollbarLayerIfNeeded(
-      overflow_controls_host_layer_, needs_overflow_controls_host_layer,
-      CompositingReason::kLayerForOverflowControlsHost);
-
   return horizontal_scrollbar_layer_changed ||
          vertical_scrollbar_layer_changed || scroll_corner_layer_changed;
 }
@@ -1524,10 +1494,21 @@
   return owning_layer_.NeedsReorderOverlayOverflowControls();
 }
 
-GraphicsLayer* CompositedLayerMapping::DetachLayerForOverflowControls() {
-  if (overflow_controls_host_layer_)
-    overflow_controls_host_layer_->RemoveFromParent();
-  return overflow_controls_host_layer_.get();
+wtf_size_t CompositedLayerMapping::MoveOverflowControlLayersInto(
+    GraphicsLayerVector& vector,
+    wtf_size_t position) {
+  wtf_size_t count = 0;
+  auto move_layer = [&](GraphicsLayer* layer) {
+    if (!layer)
+      return;
+    layer->RemoveFromParent();
+    vector.insert(position++, layer);
+    count++;
+  };
+  move_layer(layer_for_horizontal_scrollbar_.get());
+  move_layer(layer_for_vertical_scrollbar_.get());
+  move_layer(layer_for_scroll_corner_.get());
+  return count;
 }
 
 GraphicsLayer* CompositedLayerMapping::ParentForSublayers() const {
@@ -1552,7 +1533,9 @@
         if (layer && layer->Parent() == parent)
           layers_needing_reattachment.push_back(layer);
       };
-  add_layer_needing_reattachment(overflow_controls_host_layer_.get());
+  add_layer_needing_reattachment(layer_for_horizontal_scrollbar_.get());
+  add_layer_needing_reattachment(layer_for_vertical_scrollbar_.get());
+  add_layer_needing_reattachment(layer_for_scroll_corner_.get());
   add_layer_needing_reattachment(decoration_outline_layer_.get());
   add_layer_needing_reattachment(mask_layer_.get());
   add_layer_needing_reattachment(non_scrolling_squashing_layer_.get());
@@ -2326,8 +2309,6 @@
     name = "Vertical Scrollbar Layer";
   } else if (graphics_layer == layer_for_scroll_corner_.get()) {
     name = "Scroll Corner Layer";
-  } else if (graphics_layer == overflow_controls_host_layer_.get()) {
-    name = "Overflow Controls Host Layer";
   } else if (graphics_layer == scrolling_contents_layer_.get()) {
     name = "Scrolling Contents Layer";
   } else if (graphics_layer == decoration_outline_layer_.get()) {
diff --git a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h
index 5873234..88f9b21 100644
--- a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h
+++ b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h
@@ -210,10 +210,10 @@
   // scrolling content.
   bool NeedsToReparentOverflowControls() const;
 
-  // Removes the overflow controls host layer from its parent and positions it
-  // so that it can be inserted as a sibling to this CLM without changing
-  // position.
-  GraphicsLayer* DetachLayerForOverflowControls();
+  // Move overflow control layers from its parent into the vector.
+  // Returns the number of layers moved.
+  wtf_size_t MoveOverflowControlLayersInto(GraphicsLayerVector&,
+                                           wtf_size_t position);
 
   void SetBlendMode(BlendMode);
 
@@ -312,9 +312,6 @@
       Vector<GraphicsLayerPaintInfo>& layers,
       Vector<PaintLayer*>& layers_needing_paint_invalidation);
   void UpdateMainGraphicsLayerGeometry(const IntRect& local_compositing_bounds);
-  void UpdateOverflowControlsHostLayerGeometry(
-      const PaintLayer* compositing_container);
-  void UpdateChildTransformLayerGeometry();
   void UpdateMaskLayerGeometry();
   void UpdateForegroundLayerGeometry();
   void UpdateDecorationOutlineLayerGeometry(
@@ -412,10 +409,9 @@
   //
   //    + graphics_layer_
   //      + contents layers (or contents layers under scrolling_contents_layer_)
-  //      + overflow_controls_host_layer_ [OPTIONAL]
-  //      | + layer_for_vertical_scrollbar_ [OPTIONAL]
-  //      | + layer_for_horizontal_scrollbar_ [OPTIONAL]
-  //      | + layer_for_scroll_corner_ [OPTIONAL]
+  //      + layer_for_vertical_scrollbar_ [OPTIONAL]
+  //      + layer_for_horizontal_scrollbar_ [OPTIONAL]
+  //      + layer_for_scroll_corner_ [OPTIONAL]
   //      + decoration_outline_layer_ [OPTIONAL]
   //      + mask_layer_ [ OPTIONAL ]
   //      + non_scrolling_squashing_layer_ [ OPTIONAL ]
@@ -457,12 +453,6 @@
   std::unique_ptr<GraphicsLayer> layer_for_vertical_scrollbar_;
   std::unique_ptr<GraphicsLayer> layer_for_scroll_corner_;
 
-  // This layer contains the scrollbar and scroll corner layers and clips them
-  // to the border box bounds of our LayoutObject. It is usually added to
-  // graphics_layer_, but may be reparented by GraphicsLayerTreeBuilder to
-  // ensure that scrollbars appear above scrolling content.
-  std::unique_ptr<GraphicsLayer> overflow_controls_host_layer_;
-
   // DecorationLayer which paints outline.
   std::unique_ptr<GraphicsLayer> decoration_outline_layer_;
 
diff --git a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc
index a30b60ed..7c7f77e 100644
--- a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc
+++ b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc
@@ -1709,13 +1709,15 @@
   EXPECT_TRUE(mapping->MainGraphicsLayer()->ContentsOpaque());
 }
 
-TEST_F(CompositedLayerMappingTest, NullOverflowControlsHostLayer) {
+TEST_F(CompositedLayerMappingTest, NullOverflowControlLayers) {
   SetHtmlInnerHTML("<div id='target' style='will-change: transform'></div>");
   CompositedLayerMapping* mapping =
       ToLayoutBoxModelObject(GetLayoutObjectByElementId("target"))
           ->Layer()
           ->GetCompositedLayerMapping();
-  EXPECT_FALSE(mapping->DetachLayerForOverflowControls());
+  EXPECT_FALSE(mapping->LayerForHorizontalScrollbar());
+  EXPECT_FALSE(mapping->LayerForVerticalScrollbar());
+  EXPECT_FALSE(mapping->LayerForScrollCorner());
 }
 
 TEST_F(CompositedLayerMappingTest, CompositedHiddenAnimatingLayer) {
diff --git a/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_builder.cc b/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_builder.cc
index b3be822..35fa183 100644
--- a/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_builder.cc
+++ b/third_party/blink/renderer/core/paint/compositing/graphics_layer_tree_builder.cc
@@ -88,6 +88,15 @@
   bool recursion_blocked_by_display_lock =
       layer.GetLayoutObject().PrePaintBlockedByDisplayLock(
           DisplayLockLifecycleTarget::kChildren);
+  // If the recursion is blocked meaningfully (i.e. we would have recursed,
+  // since the layer has children), then we should inform the display-lock
+  // context that we blocked a graphics layer recursion, so that we can ensure
+  // to rebuild the tree once we're unlocked.
+  if (recursion_blocked_by_display_lock && layer.FirstChild()) {
+    auto* context = layer.GetLayoutObject().GetDisplayLockContext();
+    DCHECK(context);
+    context->NotifyGraphicsLayerRebuildBlocked();
+  }
 
   if (layer.IsStackingContextWithNegativeZOrderChildren()) {
     if (!recursion_blocked_by_display_lock) {
@@ -157,11 +166,9 @@
                 return a.second < b.second;
               });
     for (auto& item : pending) {
-      if (auto* layer = item.first->GetCompositedLayerMapping()
-                            ->DetachLayerForOverflowControls()) {
-        this_layer_children.insert(item.second + offset, layer);
-        offset++;
-      }
+      offset += item.first->GetCompositedLayerMapping()
+                    ->MoveOverflowControlLayersInto(this_layer_children,
+                                                    item.second + offset);
     }
 
     if (!this_layer_children.IsEmpty())
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc
index 00858ff3..6f1fb64 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -1055,6 +1055,11 @@
     MarkAncestorChainForFlagsUpdate(NeedsDescendantDependentUpdate);
 }
 
+void PaintLayer::SetNeedsGraphicsLayerRebuild() {
+  if (Compositor())
+    Compositor()->SetNeedsCompositingUpdate(kCompositingUpdateRebuildTree);
+}
+
 void PaintLayer::SetNeedsCheckRasterInvalidation() {
   DCHECK_EQ(GetLayoutObject().GetDocument().Lifecycle().GetState(),
             DocumentLifecycle::kInPrePaint);
diff --git a/third_party/blink/renderer/core/paint/paint_layer.h b/third_party/blink/renderer/core/paint/paint_layer.h
index 507d79d..9d57dc2 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.h
+++ b/third_party/blink/renderer/core/paint/paint_layer.h
@@ -821,6 +821,10 @@
   void SetNeedsVisualOverflowRecalc();
   void SetNeedsCompositingInputsUpdate(bool mark_ancestor_flags = true);
 
+  // Notifies the Compositor if one exists that it should rebuild the graphics
+  // layer tree.
+  void SetNeedsGraphicsLayerRebuild();
+
   // Mark this PaintLayer as needing raster invalidation checking after the
   // next compositing update step.
   void SetNeedsCheckRasterInvalidation();
diff --git a/third_party/blink/renderer/core/paint/text_decoration_info.cc b/third_party/blink/renderer/core/paint/text_decoration_info.cc
index c0f6afca..f54cdcd 100644
--- a/third_party/blink/renderer/core/paint/text_decoration_info.cc
+++ b/third_party/blink/renderer/core/paint/text_decoration_info.cc
@@ -200,7 +200,7 @@
   return style_.AppliedTextDecorations()[decoration_index_].Style();
 }
 
-Color TextDecorationInfo::Color() const {
+Color TextDecorationInfo::LineColor() const {
   return style_.AppliedTextDecorations()[decoration_index_].GetColor();
 }
 
diff --git a/third_party/blink/renderer/core/paint/text_decoration_info.h b/third_party/blink/renderer/core/paint/text_decoration_info.h
index 0be5eb54..41738f9 100644
--- a/third_party/blink/renderer/core/paint/text_decoration_info.h
+++ b/third_party/blink/renderer/core/paint/text_decoration_info.h
@@ -73,7 +73,7 @@
 
   // SetDecorationIndex must be called before using these methods.
   ETextDecorationStyle DecorationStyle() const;
-  Color Color() const;
+  Color LineColor() const;
   float ResolvedThickness() const {
     return applied_decorations_thickness_[decoration_index_];
   }
diff --git a/third_party/blink/renderer/core/script/BUILD.gn b/third_party/blink/renderer/core/script/BUILD.gn
index 7007485..09f93780 100644
--- a/third_party/blink/renderer/core/script/BUILD.gn
+++ b/third_party/blink/renderer/core/script/BUILD.gn
@@ -10,6 +10,8 @@
     "classic_pending_script.h",
     "classic_script.cc",
     "classic_script.h",
+    "detect_javascript_frameworks.cc",
+    "detect_javascript_frameworks.h",
     "document_modulator_impl.cc",
     "document_modulator_impl.h",
     "document_write_intervention.cc",
diff --git a/third_party/blink/renderer/core/script/detect_javascript_frameworks.cc b/third_party/blink/renderer/core/script/detect_javascript_frameworks.cc
new file mode 100644
index 0000000..0bc25d9
--- /dev/null
+++ b/third_party/blink/renderer/core/script/detect_javascript_frameworks.cc
@@ -0,0 +1,78 @@
+// 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/core/script/detect_javascript_frameworks.h"
+
+#include "third_party/blink/public/common/loader/loading_behavior_flag.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/local_frame_client.h"
+#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
+
+namespace blink {
+
+namespace {
+
+bool IsFrameworkVariableUsed(v8::Local<v8::Context> context,
+                             const String& framework_variable_name) {
+  v8::Isolate* isolate = context->GetIsolate();
+  v8::HandleScope handle_scope(isolate);
+
+  v8::Local<v8::Object> global = context->Global();
+  v8::TryCatch try_catch(isolate);
+
+  bool has_property;
+  bool succeeded =
+      global
+          ->HasRealNamedProperty(
+              context, V8AtomicString(isolate, framework_variable_name))
+          .To(&has_property);
+
+  DCHECK(succeeded && !try_catch.HasCaught());
+  return has_property;
+}
+
+bool IsFrameworkIDUsed(Document& document, const AtomicString& framework_id) {
+  if (document.getElementById(framework_id)) {
+    return true;
+  }
+  return false;
+}
+
+void CheckForNextJS(Document& document, v8::Local<v8::Context> context) {
+  if (IsFrameworkIDUsed(document, "__next") &&
+      IsFrameworkVariableUsed(context, "__NEXT_DATA__")) {
+    document.Loader()->DidObserveLoadingBehavior(
+        LoadingBehaviorFlag::kLoadingBehaviorNextJSFrameworkUsed);
+  }
+}
+
+}  // namespace
+
+void DetectJavascriptFrameworksOnLoad(Document& document) {
+  // Only detect Javascript frameworks on the main frame and if URL and BaseURL
+  // is HTTP. Note: Without these checks, ToScriptStateForMainWorld will
+  // initialize WindowProxy and trigger a second DidClearWindowObject() earlier
+  // than expected for Android WebView. The Gin Java Bridge has a race condition
+  // that relies on a second DidClearWindowObject() firing immediately before
+  // executing JavaScript. See the document that explains this in more detail:
+  // https://docs.google.com/document/d/1R5170is5vY425OO2Ru-HJBEraEKu0HjQEakcYldcSzM/edit?usp=sharing
+  if (!document.GetFrame() || !document.GetFrame()->IsMainFrame() ||
+      !document.Url().ProtocolIsInHTTPFamily() ||
+      !document.BaseURL().ProtocolIsInHTTPFamily()) {
+    return;
+  }
+
+  ScriptState* script_state = ToScriptStateForMainWorld(document.GetFrame());
+
+  if (!script_state || !script_state->ContextIsValid()) {
+    return;
+  }
+
+  ScriptState::Scope scope(script_state);
+  v8::Local<v8::Context> context = script_state->GetContext();
+
+  CheckForNextJS(document, context);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/script/detect_javascript_frameworks.h b/third_party/blink/renderer/core/script/detect_javascript_frameworks.h
new file mode 100644
index 0000000..fe15e764
--- /dev/null
+++ b/third_party/blink/renderer/core/script/detect_javascript_frameworks.h
@@ -0,0 +1,18 @@
+// 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_CORE_SCRIPT_DETECT_JAVASCRIPT_FRAMEWORKS_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_SCRIPT_DETECT_JAVASCRIPT_FRAMEWORKS_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+
+namespace blink {
+
+class Document;
+
+CORE_EXPORT void DetectJavascriptFrameworksOnLoad(Document&);
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_SCRIPT_DETECT_JAVASCRIPT_FRAMEWORKS_H_
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 4a7a526..b15e4092 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
@@ -3949,6 +3949,8 @@
   String text_alternative;
   AXRelatedObjectVector local_related_objects;
 
+  const auto* input_element = DynamicTo<HTMLInputElement>(GetNode());
+
   // 5.1/5.5 Text inputs, Other labelable Elements
   // If you change this logic, update AXNodeObject::nameFromLabelElement, too.
   auto* html_element = DynamicTo<HTMLElement>(GetNode());
@@ -3999,7 +4001,6 @@
   }
 
   // 5.2 input type="button", input type="submit" and input type="reset"
-  const auto* input_element = DynamicTo<HTMLInputElement>(GetNode());
   if (input_element && input_element->IsTextButton()) {
     // value attribute.
     name_from = ax::mojom::blink::NameFrom::kValue;
@@ -4145,31 +4146,6 @@
     }
   }
 
-  // Input type=file. Not part of the spec, but Blink implements it
-  // as a single control that has both a button ("Choose file...") and
-  // some text showing the filename, and we need to concatenate both into
-  // the name of the button.
-  if (input_element && input_element->type() == input_type_names::kFile) {
-    name_from = ax::mojom::blink::NameFrom::kValue;
-
-    String displayed_file_path = StringValue();
-    String upload_button_text = input_element->UploadButton()->value();
-    if (!displayed_file_path.IsEmpty()) {
-      text_alternative = displayed_file_path + ", " + upload_button_text;
-    } else {
-      text_alternative = upload_button_text;
-    }
-    *found_text_alternative = true;
-
-    if (name_sources) {
-      name_sources->push_back(NameSource(true, kValueAttr));
-      name_sources->back().type = name_from;
-      name_sources->back().text = text_alternative;
-    } else {
-      return text_alternative;
-    }
-  }
-
   // Also check for aria-placeholder.
   if (IsTextControl()) {
     name_from = ax::mojom::blink::NameFrom::kPlaceholder;
diff --git a/third_party/blink/renderer/modules/imagecapture/BUILD.gn b/third_party/blink/renderer/modules/imagecapture/BUILD.gn
index 76602d8..57f67a8 100644
--- a/third_party/blink/renderer/modules/imagecapture/BUILD.gn
+++ b/third_party/blink/renderer/modules/imagecapture/BUILD.gn
@@ -10,9 +10,6 @@
     "image_capture.h",
     "image_capture_frame_grabber.cc",
     "image_capture_frame_grabber.h",
-    "media_settings_range.h",
-    "photo_capabilities.cc",
-    "photo_capabilities.h",
   ]
 
   deps = [
diff --git a/third_party/blink/renderer/modules/imagecapture/idls.gni b/third_party/blink/renderer/modules/imagecapture/idls.gni
index f43e97793..88a06a7 100644
--- a/third_party/blink/renderer/modules/imagecapture/idls.gni
+++ b/third_party/blink/renderer/modules/imagecapture/idls.gni
@@ -2,14 +2,12 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-modules_idl_files = [
-  "image_capture.idl",
-  "media_settings_range.idl",
-  "photo_capabilities.idl",
-]
+modules_idl_files = [ "image_capture.idl" ]
 
 modules_dictionary_idl_files = [
   "constrain_point_2d_parameters.idl",
+  "media_settings_range.idl",
+  "photo_capabilities.idl",
   "photo_settings.idl",
   "point_2d.idl",
 ]
diff --git a/third_party/blink/renderer/modules/imagecapture/image_capture.cc b/third_party/blink/renderer/modules/imagecapture/image_capture.cc
index 125d1a9..6b0d71fe 100644
--- a/third_party/blink/renderer/modules/imagecapture/image_capture.cc
+++ b/third_party/blink/renderer/modules/imagecapture/image_capture.cc
@@ -13,16 +13,16 @@
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/bindings/core/v8/callback_promise_adapter.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_media_settings_range.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_media_track_capabilities.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_media_track_constraints.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_photo_capabilities.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/core/fileapi/blob.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
 #include "third_party/blink/renderer/modules/event_target_modules.h"
 #include "third_party/blink/renderer/modules/imagecapture/image_capture_frame_grabber.h"
-#include "third_party/blink/renderer/modules/imagecapture/media_settings_range.h"
-#include "third_party/blink/renderer/modules/imagecapture/photo_capabilities.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/permissions/permission_utils.h"
@@ -36,6 +36,7 @@
 
 using FillLightMode = media::mojom::blink::FillLightMode;
 using MeteringMode = media::mojom::blink::MeteringMode;
+using RedEyeReduction = media::mojom::blink::RedEyeReduction;
 
 namespace {
 
@@ -81,10 +82,38 @@
       return WebString::FromUTF8("single-shot");
     case MeteringMode::CONTINUOUS:
       return WebString::FromUTF8("continuous");
-    default:
-      NOTREACHED() << "Unknown MeteringMode";
   }
-  return WebString();
+}
+
+WebString ToString(FillLightMode value) {
+  switch (value) {
+    case FillLightMode::OFF:
+      return WebString::FromUTF8("off");
+    case FillLightMode::AUTO:
+      return WebString::FromUTF8("auto");
+    case FillLightMode::FLASH:
+      return WebString::FromUTF8("flash");
+  }
+}
+
+WebString ToString(RedEyeReduction value) {
+  switch (value) {
+    case RedEyeReduction::NEVER:
+      return WebString::FromUTF8("never");
+    case RedEyeReduction::ALWAYS:
+      return WebString::FromUTF8("always");
+    case RedEyeReduction::CONTROLLABLE:
+      return WebString::FromUTF8("controllable");
+  }
+}
+
+MediaSettingsRange* ToMediaSettingsRange(
+    const media::mojom::blink::Range& range) {
+  MediaSettingsRange* result = MediaSettingsRange::Create();
+  result->setMax(range.max);
+  result->setMin(range.min);
+  result->setStep(range.step);
+  return result;
 }
 
 }  // anonymous namespace
@@ -241,7 +270,7 @@
   settings->has_red_eye_reduction = photo_settings->hasRedEyeReduction();
   if (settings->has_red_eye_reduction) {
     if (photo_capabilities_ &&
-        !photo_capabilities_->IsRedEyeReductionControllable()) {
+        photo_capabilities_->redEyeReduction() != "controllable") {
       resolver->Reject(MakeGarbageCollected<DOMException>(
           DOMExceptionCode::kNotSupportedError,
           "redEyeReduction is not controllable."));
@@ -926,20 +955,22 @@
   // TODO(mcasas): collect the remaining two entries https://crbug.com/732521.
 
   photo_capabilities_ = MakeGarbageCollected<PhotoCapabilities>();
-  photo_capabilities_->SetRedEyeReduction(photo_state->red_eye_reduction);
-  // TODO(mcasas): Remove the explicit MediaSettingsRange::create() when
-  // mojo::StructTraits supports garbage-collected mappings,
-  // https://crbug.com/700180.
+  photo_capabilities_->setRedEyeReduction(
+      ToString(photo_state->red_eye_reduction));
   if (photo_state->height->min != 0 || photo_state->height->max != 0) {
-    photo_capabilities_->SetImageHeight(
-        MediaSettingsRange::Create(std::move(photo_state->height)));
+    photo_capabilities_->setImageHeight(
+        ToMediaSettingsRange(*photo_state->height));
   }
   if (photo_state->width->min != 0 || photo_state->width->max != 0) {
-    photo_capabilities_->SetImageWidth(
-        MediaSettingsRange::Create(std::move(photo_state->width)));
+    photo_capabilities_->setImageWidth(
+        ToMediaSettingsRange(*photo_state->width));
   }
-  if (!photo_state->fill_light_mode.IsEmpty())
-    photo_capabilities_->SetFillLightMode(photo_state->fill_light_mode);
+  WTF::Vector<WTF::String> fill_light_mode;
+  for (const auto& mode : photo_state->fill_light_mode) {
+    fill_light_mode.push_back(ToString(mode));
+  }
+  if (!fill_light_mode.IsEmpty())
+    photo_capabilities_->setFillLightMode(fill_light_mode);
 
   // Update the local track photo_state cache.
   UpdateMediaTrackCapabilities(base::DoNothing(), std::move(photo_state));
@@ -1051,72 +1082,67 @@
   }
   settings_->setPointsOfInterest(current_points_of_interest);
 
-  // TODO(mcasas): Remove the explicit MediaSettingsRange::create() when
-  // mojo::StructTraits supports garbage-collected mappings,
-  // https://crbug.com/700180.
   if (photo_state->exposure_compensation->max !=
       photo_state->exposure_compensation->min) {
     capabilities_->setExposureCompensation(
-        MediaSettingsRange::Create(*photo_state->exposure_compensation));
+        ToMediaSettingsRange(*photo_state->exposure_compensation));
     settings_->setExposureCompensation(
         photo_state->exposure_compensation->current);
   }
   if (photo_state->exposure_time->max != photo_state->exposure_time->min) {
     capabilities_->setExposureTime(
-        MediaSettingsRange::Create(*photo_state->exposure_time));
+        ToMediaSettingsRange(*photo_state->exposure_time));
     settings_->setExposureTime(photo_state->exposure_time->current);
   }
   if (photo_state->color_temperature->max !=
       photo_state->color_temperature->min) {
     capabilities_->setColorTemperature(
-        MediaSettingsRange::Create(*photo_state->color_temperature));
+        ToMediaSettingsRange(*photo_state->color_temperature));
     settings_->setColorTemperature(photo_state->color_temperature->current);
   }
   if (photo_state->iso->max != photo_state->iso->min) {
-    capabilities_->setIso(MediaSettingsRange::Create(*photo_state->iso));
+    capabilities_->setIso(ToMediaSettingsRange(*photo_state->iso));
     settings_->setIso(photo_state->iso->current);
   }
 
   if (photo_state->brightness->max != photo_state->brightness->min) {
     capabilities_->setBrightness(
-        MediaSettingsRange::Create(*photo_state->brightness));
+        ToMediaSettingsRange(*photo_state->brightness));
     settings_->setBrightness(photo_state->brightness->current);
   }
   if (photo_state->contrast->max != photo_state->contrast->min) {
-    capabilities_->setContrast(
-        MediaSettingsRange::Create(*photo_state->contrast));
+    capabilities_->setContrast(ToMediaSettingsRange(*photo_state->contrast));
     settings_->setContrast(photo_state->contrast->current);
   }
   if (photo_state->saturation->max != photo_state->saturation->min) {
     capabilities_->setSaturation(
-        MediaSettingsRange::Create(*photo_state->saturation));
+        ToMediaSettingsRange(*photo_state->saturation));
     settings_->setSaturation(photo_state->saturation->current);
   }
   if (photo_state->sharpness->max != photo_state->sharpness->min) {
-    capabilities_->setSharpness(
-        MediaSettingsRange::Create(*photo_state->sharpness));
+    capabilities_->setSharpness(ToMediaSettingsRange(*photo_state->sharpness));
     settings_->setSharpness(photo_state->sharpness->current);
   }
 
   if (photo_state->focus_distance->max != photo_state->focus_distance->min) {
     capabilities_->setFocusDistance(
-        MediaSettingsRange::Create(*photo_state->focus_distance));
+        ToMediaSettingsRange(*photo_state->focus_distance));
     settings_->setFocusDistance(photo_state->focus_distance->current);
   }
 
   if (HasPanTiltZoomPermissionGranted()) {
     if (photo_state->pan->max != photo_state->pan->min) {
-      capabilities_->setPan(MediaSettingsRange::Create(*photo_state->pan));
+      capabilities_->setPan(ToMediaSettingsRange(*photo_state->pan));
       settings_->setPan(photo_state->pan->current);
     }
     if (photo_state->tilt->max != photo_state->tilt->min) {
-      capabilities_->setTilt(MediaSettingsRange::Create(*photo_state->tilt));
+      capabilities_->setTilt(ToMediaSettingsRange(*photo_state->tilt));
       settings_->setTilt(photo_state->tilt->current);
     }
   }
   if (HasZoomPermissionGranted()) {
     if (photo_state->zoom->max != photo_state->zoom->min) {
-      capabilities_->setZoom(MediaSettingsRange::Create(*photo_state->zoom));
+      capabilities_->setZoom(ToMediaSettingsRange(*photo_state->zoom));
       settings_->setZoom(photo_state->zoom->current);
     }
   }
diff --git a/third_party/blink/renderer/modules/imagecapture/media_settings_range.h b/third_party/blink/renderer/modules/imagecapture/media_settings_range.h
deleted file mode 100644
index 5cc23e0..0000000
--- a/third_party/blink/renderer/modules/imagecapture/media_settings_range.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_IMAGECAPTURE_MEDIA_SETTINGS_RANGE_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_IMAGECAPTURE_MEDIA_SETTINGS_RANGE_H_
-
-#include "media/capture/mojom/image_capture.mojom-blink.h"
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-
-namespace blink {
-
-class MediaSettingsRange final : public ScriptWrappable {
-  DEFINE_WRAPPERTYPEINFO();
-
- public:
-  static MediaSettingsRange* Create(double max, double min, double step) {
-    return MakeGarbageCollected<MediaSettingsRange>(max, min, step);
-  }
-  static MediaSettingsRange* Create(media::mojom::blink::RangePtr range) {
-    return MediaSettingsRange::Create(*range);
-  }
-  static MediaSettingsRange* Create(const media::mojom::blink::Range& range) {
-    return MediaSettingsRange::Create(range.max, range.min, range.step);
-  }
-
-  MediaSettingsRange(double max, double min, double step)
-      : max_(max), min_(min), step_(step) {}
-
-  double max() const { return max_; }
-  double min() const { return min_; }
-  double step() const { return step_; }
-
- private:
-  double max_;
-  double min_;
-  double step_;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_IMAGECAPTURE_MEDIA_SETTINGS_RANGE_H_
diff --git a/third_party/blink/renderer/modules/imagecapture/media_settings_range.idl b/third_party/blink/renderer/modules/imagecapture/media_settings_range.idl
index 4ae579c..1c0f967 100644
--- a/third_party/blink/renderer/modules/imagecapture/media_settings_range.idl
+++ b/third_party/blink/renderer/modules/imagecapture/media_settings_range.idl
@@ -4,9 +4,8 @@
 
 // https://w3c.github.io/mediacapture-image/#mediasettingsrange
 
-[Exposed=Window]
-interface MediaSettingsRange {
-    readonly attribute double max;
-    readonly attribute double min;
-    readonly attribute double step;
+dictionary MediaSettingsRange {
+    double max;
+    double min;
+    double step;
 };
diff --git a/third_party/blink/renderer/modules/imagecapture/photo_capabilities.cc b/third_party/blink/renderer/modules/imagecapture/photo_capabilities.cc
deleted file mode 100644
index e3121991..0000000
--- a/third_party/blink/renderer/modules/imagecapture/photo_capabilities.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/modules/imagecapture/photo_capabilities.h"
-
-namespace blink {
-
-Vector<String> PhotoCapabilities::fillLightMode() const {
-  Vector<String> fill_light_modes;
-  for (const auto& mode : fill_light_modes_) {
-    switch (mode) {
-      case media::mojom::blink::FillLightMode::OFF:
-        fill_light_modes.push_back("off");
-        break;
-      case media::mojom::blink::FillLightMode::AUTO:
-        fill_light_modes.push_back("auto");
-        break;
-      case media::mojom::blink::FillLightMode::FLASH:
-        fill_light_modes.push_back("flash");
-        break;
-      default:
-        NOTREACHED();
-    }
-  }
-  return fill_light_modes;
-}
-
-String PhotoCapabilities::redEyeReduction() const {
-  switch (red_eye_reduction_) {
-    case media::mojom::blink::RedEyeReduction::NEVER:
-      return "never";
-    case media::mojom::blink::RedEyeReduction::ALWAYS:
-      return "always";
-    case media::mojom::blink::RedEyeReduction::CONTROLLABLE:
-      return "controllable";
-    default:
-      NOTREACHED();
-  }
-  return "";
-}
-
-bool PhotoCapabilities::IsRedEyeReductionControllable() const {
-  return red_eye_reduction_ ==
-         media::mojom::blink::RedEyeReduction::CONTROLLABLE;
-}
-
-void PhotoCapabilities::Trace(Visitor* visitor) const {
-  visitor->Trace(image_height_);
-  visitor->Trace(image_width_);
-  ScriptWrappable::Trace(visitor);
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/imagecapture/photo_capabilities.h b/third_party/blink/renderer/modules/imagecapture/photo_capabilities.h
deleted file mode 100644
index ec69a6f3..0000000
--- a/third_party/blink/renderer/modules/imagecapture/photo_capabilities.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_IMAGECAPTURE_PHOTO_CAPABILITIES_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_IMAGECAPTURE_PHOTO_CAPABILITIES_H_
-
-#include "media/capture/mojom/image_capture.mojom-blink-forward.h"
-#include "third_party/blink/renderer/modules/imagecapture/media_settings_range.h"
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
-
-namespace blink {
-
-class PhotoCapabilities final : public ScriptWrappable {
-  DEFINE_WRAPPERTYPEINFO();
-
- public:
-  PhotoCapabilities() = default;
-  ~PhotoCapabilities() override = default;
-
-  MediaSettingsRange* imageHeight() const { return image_height_; }
-  void SetImageHeight(MediaSettingsRange* value) { image_height_ = value; }
-
-  MediaSettingsRange* imageWidth() const { return image_width_; }
-  void SetImageWidth(MediaSettingsRange* value) { image_width_ = value; }
-
-  Vector<String> fillLightMode() const;
-  void SetFillLightMode(Vector<media::mojom::blink::FillLightMode> modes) {
-    fill_light_modes_ = modes;
-  }
-
-  String redEyeReduction() const;
-  void SetRedEyeReduction(
-      media::mojom::blink::RedEyeReduction red_eye_reduction) {
-    red_eye_reduction_ = red_eye_reduction;
-  }
-  bool IsRedEyeReductionControllable() const;
-
-  void Trace(Visitor*) const override;
-
- private:
-  Member<MediaSettingsRange> image_height_;
-  Member<MediaSettingsRange> image_width_;
-  Vector<media::mojom::blink::FillLightMode> fill_light_modes_;
-  media::mojom::blink::RedEyeReduction red_eye_reduction_;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_IMAGECAPTURE_PHOTO_CAPABILITIES_H_
diff --git a/third_party/blink/renderer/modules/imagecapture/photo_capabilities.idl b/third_party/blink/renderer/modules/imagecapture/photo_capabilities.idl
index 67051729..8788340f4 100644
--- a/third_party/blink/renderer/modules/imagecapture/photo_capabilities.idl
+++ b/third_party/blink/renderer/modules/imagecapture/photo_capabilities.idl
@@ -23,10 +23,9 @@
     "flash",
 };
 
-[Exposed=Window]
-interface PhotoCapabilities {
-  readonly attribute RedEyeReduction            redEyeReduction;
-  readonly attribute MediaSettingsRange         imageHeight;
-  readonly attribute MediaSettingsRange         imageWidth;
-  readonly attribute FrozenArray<FillLightMode> fillLightMode;
+dictionary PhotoCapabilities {
+  RedEyeReduction           redEyeReduction;
+  MediaSettingsRange        imageHeight;
+  MediaSettingsRange        imageWidth;
+  sequence<FillLightMode>   fillLightMode;
 };
diff --git a/third_party/blink/renderer/platform/bindings/parkable_string_manager.cc b/third_party/blink/renderer/platform/bindings/parkable_string_manager.cc
index 7881bdf..9ac6634e8 100644
--- a/third_party/blink/renderer/platform/bindings/parkable_string_manager.cc
+++ b/third_party/blink/renderer/platform/bindings/parkable_string_manager.cc
@@ -28,12 +28,6 @@
 
 namespace blink {
 
-// Disabling this will cause parkable strings to never be compressed.
-// This is useful for headless mode + virtual time. Since virtual time advances
-// quickly, strings may be parked too eagerly in that mode.
-const base::Feature kCompressParkableStrings{"CompressParkableStrings",
-                                             base::FEATURE_ENABLED_BY_DEFAULT};
-
 struct ParkableStringManager::Statistics {
   size_t original_size;
   size_t uncompressed_size;
@@ -49,7 +43,7 @@
 namespace {
 
 bool CompressionEnabled() {
-  return base::FeatureList::IsEnabled(kCompressParkableStrings);
+  return base::FeatureList::IsEnabled(features::kCompressParkableStrings);
 }
 
 class OnPurgeMemoryListener : public GarbageCollected<OnPurgeMemoryListener>,
@@ -339,7 +333,7 @@
   }
 
   // May not be usable, e.g. Incognito, permission or write failure.
-  if (base::FeatureList::IsEnabled(features::kParkableStringsToDisk)) {
+  if (features::IsParkableStringsToDiskEnabled()) {
     base::UmaHistogramBoolean("Memory.ParkableString.DiskIsUsable.5min",
                               data_allocator().may_write());
   }
diff --git a/third_party/blink/renderer/platform/bindings/parkable_string_manager.h b/third_party/blink/renderer/platform/bindings/parkable_string_manager.h
index f59aa50..d62d4ac 100644
--- a/third_party/blink/renderer/platform/bindings/parkable_string_manager.h
+++ b/third_party/blink/renderer/platform/bindings/parkable_string_manager.h
@@ -27,8 +27,6 @@
 class DiskDataAllocator;
 class ParkableString;
 
-PLATFORM_EXPORT extern const base::Feature kCompressParkableStrings;
-
 class PLATFORM_EXPORT ParkableStringManagerDumpProvider
     : public base::trace_event::MemoryDumpProvider {
   USING_FAST_MALLOC(ParkableStringManagerDumpProvider);
diff --git a/third_party/blink/renderer/platform/bindings/parkable_string_test.cc b/third_party/blink/renderer/platform/bindings/parkable_string_test.cc
index f46a56f..7972f0c9 100644
--- a/third_party/blink/renderer/platform/bindings/parkable_string_test.cc
+++ b/third_party/blink/renderer/platform/bindings/parkable_string_test.cc
@@ -64,7 +64,7 @@
   }
 
   void WaitForAging() {
-    if (base::FeatureList::IsEnabled(kCompressParkableStrings)) {
+    if (base::FeatureList::IsEnabled(features::kCompressParkableStrings)) {
       EXPECT_GT(task_environment_.GetPendingMainThreadTaskCount(), 0u);
     }
     task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(
@@ -854,7 +854,7 @@
 
 TEST_F(ParkableStringTest, CompressionDisabled) {
   base::test::ScopedFeatureList features;
-  features.InitAndDisableFeature(kCompressParkableStrings);
+  features.InitAndDisableFeature(features::kCompressParkableStrings);
 
   ParkableString parkable(MakeLargeString().ReleaseImpl());
   WaitForDelayedParking();
@@ -1056,7 +1056,10 @@
   base::ScopedMockElapsedTimersForTest mock_elapsed_timers;
   base::HistogramTester histogram_tester;
   base::test::ScopedFeatureList features;
-  features.InitAndEnableFeature(features::kParkableStringsToDisk);
+  features.InitWithFeatures(
+      {features::kCompressParkableStrings, features::kParkableStringsToDisk},
+      {});
+  ASSERT_TRUE(features::IsParkableStringsToDiskEnabled());
 
   ParkableString parkable(MakeLargeString().ReleaseImpl());
   ParkAndWait(parkable);
@@ -1116,10 +1119,10 @@
   WaitForAging();
   parkable.Impl()->Park(ParkableStringImpl::ParkingMode::kCompress);
 
-  // Advance the main thread until aging occurs. This uses RunLoop combined with
-  // ThreadPoolExecutionMode::QUEUED to force the 2-seconds-delayed aging task
-  // on the main thread to kick in before the immediate async compression task
-  // completes.
+  // Advance the main thread until aging occurs. This uses RunLoop combined
+  // with ThreadPoolExecutionMode::QUEUED to force the 2-seconds-delayed aging
+  // task on the main thread to kick in before the immediate async compression
+  // task completes.
   base::RunLoop run_loop;
   base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE, run_loop.QuitClosure(),
diff --git a/third_party/blink/renderer/platform/graphics/compositing_reasons.cc b/third_party/blink/renderer/platform/graphics/compositing_reasons.cc
index 17a6cfe..ff168ec2 100644
--- a/third_party/blink/renderer/platform/graphics/compositing_reasons.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing_reasons.cc
@@ -113,9 +113,6 @@
      "Secondary layer, the horizontal scrollbar layer"},
     {CompositingReason::kLayerForVerticalScrollbar, "layerForVerticalScrollbar",
      "Secondary layer, the vertical scrollbar layer"},
-    {CompositingReason::kLayerForOverflowControlsHost,
-     "layerForOverflowControlsHost",
-     "Secondary layer, the overflow controls host layer"},
     {CompositingReason::kLayerForScrollCorner, "layerForScrollCorner",
      "Secondary layer, the scroll corner layer"},
     {CompositingReason::kLayerForScrollingContents, "layerForScrollingContents",
diff --git a/third_party/blink/renderer/platform/graphics/compositing_reasons.h b/third_party/blink/renderer/platform/graphics/compositing_reasons.h
index 0528128..fe26bbc9 100644
--- a/third_party/blink/renderer/platform/graphics/compositing_reasons.h
+++ b/third_party/blink/renderer/platform/graphics/compositing_reasons.h
@@ -74,7 +74,6 @@
   used in CompositeAfterPaint. */                                             \
   V(LayerForHorizontalScrollbar)                                              \
   V(LayerForVerticalScrollbar)                                                \
-  V(LayerForOverflowControlsHost)                                             \
   V(LayerForScrollCorner)                                                     \
   V(LayerForScrollingContents)                                                \
   V(LayerForSquashingContents)                                                \
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 76a20a3..061359e 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -240,6 +240,10 @@
       status: "stable",
     },
     {
+      // https://github.com/chrishtr/battery-savings/blob/master/explainer.md
+      name: "BatterySavingsMeta",
+    },
+    {
       // https://github.com/WICG/display-locking/blob/master/explainer-beforematch.md
       name: "BeforeMatchEvent",
       status: "experimental",
diff --git a/third_party/blink/renderer/platform/scheduler/TaskSchedulingInBlink.md b/third_party/blink/renderer/platform/scheduler/TaskSchedulingInBlink.md
index 1e7ba82..d01926e 100644
--- a/third_party/blink/renderer/platform/scheduler/TaskSchedulingInBlink.md
+++ b/third_party/blink/renderer/platform/scheduler/TaskSchedulingInBlink.md
@@ -54,10 +54,8 @@
 Per-thread task runners include:
 - Compositor task runner
 - GC task runner
-- Cleanup task runner
 - Default (deprecated)
 - Input task runner (semi-deprecated)
-- IPC (semi-deprecated)
 
 New task runners might be added in the future; contact scheduler-dev@chromium.org
 if you think you need a new one.
diff --git a/third_party/blink/web_tests/FlagExpectations/composite-after-paint b/third_party/blink/web_tests/FlagExpectations/composite-after-paint
index 0dfdd341..2210584 100644
--- a/third_party/blink/web_tests/FlagExpectations/composite-after-paint
+++ b/third_party/blink/web_tests/FlagExpectations/composite-after-paint
@@ -41,7 +41,6 @@
 crbug.com/918155 virtual/prefer_compositing_to_lcd_text/scrollbars/overlay-scrollbar-over-child-layer-nested-2.html [ Pass ]
 crbug.com/918155 virtual/prefer_compositing_to_lcd_text/scrollbars/overlay-scrollbar-over-child-layer-nested.html [ Pass ]
 paint/invalidation/compositing/subpixel-offset-scaled-transform-composited.html [ Pass ]
-crbug.com/1113838 external/wpt/css/css-contain/content-visibility/content-visibility-074.html [ Pass ]
 
 # With CompositeAfterPaint and LayoutNGFragmentItem enabled
 crbug.com/1103138 paint/invalidation/compositing/float-under-composited-inline.html [ Pass Crash ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index dd883e57..5e98459e 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -270,9 +270,6 @@
 # Incorrect blending with foreignObject and svg descendants.
 crbug.com/1102803 external/wpt/svg/extensibility/foreignObject/isolation-with-svg.html [ Failure ]
 
-# Display locking failures
-crbug.com/1113838 external/wpt/css/css-contain/content-visibility/content-visibility-074.html [ Failure ]
-
 crbug.com/849459 fragmentation/repeating-thead-under-repeating-thead.html [ Failure ]
 
 # These fail when device_scale_factor is changed, but only for anti-aliasing:
@@ -1228,7 +1225,6 @@
 crbug.com/591099 virtual/layout_ng_block_frag/fragmentation/change-fragmentainer-height-inline-float.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_block_frag/fragmentation/content-preceding-first-fragmentainer.html [ Crash Failure ]
 crbug.com/591099 virtual/layout_ng_block_frag/fragmentation/float-after-forced-break.html [ Failure ]
-crbug.com/1066625 virtual/layout_ng_block_frag/fragmentation/outline-crossing-columns.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_block_frag/fragmentation/overflow-crossing-boundary.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_block_frag/fragmentation/relayout-abspos.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_block_frag/fragmentation/remove-unbreakable-block-in-line-float.html [ Failure ]
diff --git a/third_party/blink/web_tests/accessibility/file-upload-button-name.html b/third_party/blink/web_tests/accessibility/file-upload-button-name.html
deleted file mode 100644
index 5dfe34a..0000000
--- a/third_party/blink/web_tests/accessibility/file-upload-button-name.html
+++ /dev/null
@@ -1,45 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
-<script src="file:///gen/third_party/blink/public/mojom/choosers/file_chooser.mojom.js"></script>
-<script src="../fast/forms/resources/mock-file-chooser.js"></script>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-</head>
-<body>
-
-<input id="filetype" type="file">
-
-<script>
-async_test((t) => {
-    testRunner.waitUntilDone();
-
-    // Initially the name is just the button title.
-    var fileChooser = document.getElementById("filetype");
-    let axFileChooser = accessibilityController.accessibleElementById("filetype");
-    assert_equals(axFileChooser.name, "No file chosen, Choose File");
-    assert_equals(axFileChooser.stringValue, "AXValue: No file chosen");
-
-    // After a file is selected, the value should be the file chosen,
-    // and the name should concatenate both - because ATs think of this as a single
-    // control and they're only going to read the name.
-    axFileChooser.addNotificationListener((e) => {
-        assert_equals(axFileChooser.name, "cake.png, Choose File");
-        assert_equals(axFileChooser.stringValue, "AXValue: cake.png");
-        t.done();
-    });
-
-    // Simulate dragging a file to the file control.
-    eventSender.beginDragWithFiles(['resources/cake.png']);
-    var centerX = fileChooser.offsetLeft + fileChooser.offsetWidth / 2;
-    var centerY = fileChooser.offsetTop + fileChooser.offsetHeight / 2;
-    eventSender.mouseMoveTo(centerX, centerY);
-    eventSender.mouseUp();
-
-}, "Test that the accessible name of a file control changes when you choose a file.");
-
-</script>
-
-</body>
-</html>
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index 59c78d0..925dfc1 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -49715,6 +49715,19 @@
         ],
         {}
        ]
+      ],
+      "content-visibility-074.html": [
+       "ff6381ce3d0950c0b3c3822171c2b81d851ded15",
+       [
+        null,
+        [
+         [
+          "/css/css-contain/content-visibility/content-visibility-074-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
       ]
      },
      "counter-scoping-001.html": [
@@ -57997,6 +58010,19 @@
        {}
       ]
      ],
+     "scrollbars-no-margin.html": [
+      "092e4c5ea9ff6b47440f2556482f978b88f1a82e",
+      [
+       null,
+       [
+        [
+         "/css/css-flexbox/scrollbars-no-margin-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
      "scrollbars.html": [
       "0eca05bfc63f9522e6d624c35469ba69e7410968",
       [
@@ -168274,6 +168300,10 @@
        "b2232a4a72546b12a05f4ab84d41ef85c20959dc",
        []
       ],
+      "content-visibility-074-ref.html": [
+       "82a6c263fa906d70f76dc78fcd6d7b6c3b461b86",
+       []
+      ],
       "inline-container-with-child-ref.html": [
        "af51cbd5db8f3eff56411345860548e95fe4d354",
        []
@@ -170153,6 +170183,10 @@
       "590b533d8d25ac45dbeb1e7eab7cd02f3c1e8b5b",
       []
      ],
+     "scrollbars-no-margin-ref.html": [
+      "eaeb36e448dbef7d96881602fed38ca4d4ea10be",
+      []
+     ],
      "scrollbars-ref.html": [
       "911e7acba88333d4e2ddf0d0fec36fbcc4975825",
       []
@@ -236275,6 +236309,10 @@
       "604e765da46d85fe8ab85d3097fe7c2cbe00a930",
       []
      ],
+     "set-inner-html.js": [
+      "45053d43e362e223e0ce5e6dffb4da09c0ce3f34",
+      []
+     ],
      "worker.js": [
       "4079f7e9c7933cf9ee195fe0e7a54e0f56f184ab",
       []
@@ -358316,7 +358354,7 @@
      ]
     ],
     "MediaStreamTrack-getCapabilities.html": [
-     "4e0c933bc1ceae2e98ec702c4044cdde056790e4",
+     "d0b7c2a3f204f3a108d7dc15696df2904373292c",
      [
       null,
       {
@@ -358355,7 +358393,7 @@
      ]
     ],
     "getPhotoCapabilities.html": [
-     "663b43a6988af1d9b98466cd260ee29ec7d4e8d8",
+     "9e2392de04d478beefab3838b382a1ff21ea8715",
      [
       null,
       {}
@@ -392236,6 +392274,13 @@
       }
      ]
     ],
+    "trusted-types-source-file-path.tentative.html": [
+     "61adb2993431aef169a04afac27d3dcd36e267d6",
+     [
+      null,
+      {}
+     ]
+    ],
     "trusted-types-svg-script.tentative.html": [
      "946f825fa3eecd05247e1a2b16396ee4d3f7af11",
      [
diff --git a/third_party/blink/web_tests/external/wpt/css/css-animations/event-dispatch.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-animations/event-dispatch.tentative.html
index 770f9b00..d54031c 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-animations/event-dispatch.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-animations/event-dispatch.tentative.html
@@ -18,12 +18,14 @@
 
 const setupAnimation = (t, animationStyle) => {
   const div = addDiv(t, { style: 'animation: ' + animationStyle });
+  const animation = div.getAnimations()[0];
+  const timeoutPromise = armTimeoutWhenReady(animation, fastEventsTimeout);
+
   const watcher = new EventWatcher(t, div, [ 'animationstart',
                                              'animationiteration',
                                              'animationend',
                                              'animationcancel' ],
-                                   fastEventsTimeout);
-  const animation = div.getAnimations()[0];
+                                   timeoutPromise);
 
   return { animation, watcher, div };
 };
diff --git a/third_party/blink/web_tests/external/wpt/css/css-animations/support/testcommon.js b/third_party/blink/web_tests/external/wpt/css/css-animations/support/testcommon.js
index a7575b1..7d3392a5 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-animations/support/testcommon.js
+++ b/third_party/blink/web_tests/external/wpt/css/css-animations/support/testcommon.js
@@ -202,6 +202,21 @@
 };
 
 /**
+ * Timeout function used for tests with EventWatchers. The client agent has no
+ * strict requirement for how long it takes to resolve the ready promise. Once
+ * the promise is resolved a secondary timeout promise is armed that may have
+ * a tight deadline measured in animation frames.
+ */
+function armTimeoutWhenReady(animation, timeoutPromise) {
+  return () => {
+    if (animation.pending)
+      return animation.ready.then(() => { return timeoutPromise(); });
+    else
+      return timeoutPromise();
+  };
+}
+
+/**
  * Wrapper that takes a sequence of N animations and returns:
  *
  *   Promise.all([animations[0].ready, animations[1].ready, ... animations[N-1].ready]);
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/scrollbars-no-margin-ref.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/scrollbars-no-margin-ref.html
new file mode 100644
index 0000000..eaeb36e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/scrollbars-no-margin-ref.html
@@ -0,0 +1,118 @@
+<!DOCTYPE html>
+<head>
+
+<script src="support/scrollbars.js"></script>
+
+<style>
+.horizontal-header {
+  width: 120px;
+}
+.vertical-header {
+  width: 60px;
+}
+.container-row {
+  display: flex;
+  flex-direction: row;
+  align-items: flex-start;
+  justify-content: flex-start;
+}
+.container {
+  flex: none;
+  margin: 5px;
+}
+.ltr {
+  direction: ltr;
+}
+.rtl {
+  direction: rtl;
+}
+.horizontal {
+  writing-mode: horizontal-tb;
+}
+.flipped-blocks {
+  writing-mode: vertical-rl;
+}
+.flipped-lines {
+  writing-mode: vertical-lr;
+}
+.flex {
+  border: 2px solid red;
+  overflow: scroll;
+  max-width: 100px;
+  max-height: 100px;
+  white-space: nowrap;
+  font-size: 0;
+  scrollbar-width: thin;
+  scrollbar-color: black white;
+}
+.row > div, .row-reverse > div {
+  display: inline-flex;
+}
+.column > div, .column-reverse > div {
+  display: flex;
+}
+
+.flex > div {
+  width: 30px;
+  height: 30px;
+  border: 2px solid blue;
+  flex-direction: column;
+  justify-content: center;
+}
+.flex > div > div {
+  font-size: 20px;
+  text-align: center;
+  flex: none;
+}
+</style>
+
+</head>
+
+<div class="container-row">
+  <div class="vertical-header ltr horizontal"></div>
+  <div class="horizontal-header ltr horizontal">ltr<br>horizontal-tb</div>
+  <div class="vertical-header ltr flipped-blocks">ltr<br>vertical-rl</div>
+  <div class="vertical-header ltr flipped-blocks">ltr<br>vertical-lr</div>
+  <div class="horizontal-header rtl horizontal">rtl<br>horizontal-tb</div>
+  <div class="vertical-header rtl flipped-blocks">rtl<br>vertical-rl</div>
+  <div class="vertical-header rtl flipped-blocks">rtl<br>vertical-lr</div>
+</div>
+
+<script>
+// Override createContentNode to emulate reverse flow direction.
+createContentNode = (flexDirection, textDirection, writingMode) => {
+  var flexNode = document.createElement("div");
+  flexNode.className = "flex " + flexDirection;
+  flexNode.title = "flex-direction: " + flexDirection + "; direction: " + textDirection + "; writing-mode: " + writingMode;
+  for (var i = 1; i < 4; i++)
+    flexNode.appendChild(createLeafNode(flexDirection.endsWith("reverse") ? 4 - i : i));
+  return flexNode;
+}
+
+flexDirections.forEach((flexDirection) => {
+  var containerRow = createContainerRow(flexDirection);
+  document.body.appendChild(containerRow);
+});
+
+// Scroll all flex containers to the emulated beginning of flow.
+var nodes = document.querySelectorAll(".ltr > .row-reverse");
+for (var i = 0; i < nodes.length; i++) {
+  nodes[i].scrollLeft = 10000;
+  nodes[i].scrollTop = 10000;
+}
+nodes = document.querySelectorAll(".rtl > .row-reverse");
+for (var i = 0; i < nodes.length; i++) {
+  nodes[i].scrollLeft = -10000;
+  nodes[i].scrollTop = -10000;
+}
+nodes = document.querySelectorAll(".column-reverse");
+for (var i = 0; i < nodes.length; i++) {
+  nodes[i].scrollLeft = 10000;
+  nodes[i].scrollTop = 10000;
+}
+nodes = document.querySelectorAll(".flipped-blocks > .column-reverse");
+for (var i = 0; i < nodes.length; i++) {
+  nodes[i].scrollLeft = -10000;
+  nodes[i].scrollTop = 0;
+}
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/scrollbars-no-margin.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/scrollbars-no-margin.html
new file mode 100644
index 0000000..092e4c5e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/scrollbars-no-margin.html
@@ -0,0 +1,99 @@
+<!DOCTYPE html>
+<head>
+<title>Scrollbars inside flexbox with direction and writing-mode</title>
+<link rel="author" title="Google, Inc." href="http://www.google.com/">
+<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+<link rel="match" href="scrollbars-no-margin-ref.html">
+<link rel="help" href="https://drafts.csswg.org/css-flexbox/">
+
+<script src="support/scrollbars.js"></script>
+
+<style>
+.horizontal-header {
+  width: 120px;
+}
+.vertical-header {
+  width: 60px;
+}
+.container-row {
+  display: flex;
+  flex-direction: row;
+  align-items: flex-start;
+  justify-content: flex-start;
+}
+.container {
+  flex: none;
+  margin: 5px;
+}
+.ltr {
+  direction: ltr;
+}
+.rtl {
+  direction: rtl;
+}
+.horizontal {
+  writing-mode: horizontal-tb;
+}
+.flipped-blocks {
+  writing-mode: vertical-rl;
+}
+.flipped-lines {
+  writing-mode: vertical-lr;
+}
+.flex {
+  border: 2px solid red;
+  display: flex;
+  overflow: scroll;
+  max-width: 100px;
+  max-height: 100px;
+  font-size: 0;
+  scrollbar-width: thin;
+  scrollbar-color: black white;
+}
+.column {
+  flex-direction: column;
+}
+.column-reverse {
+  flex-direction: column-reverse;
+}
+.row {
+  flex-direction: row;
+}
+.row-reverse {
+  flex-direction: row-reverse;
+}
+.flex > .leaf1, .flex > .leaf2, .flex > .leaf3 {
+  flex: none;
+  width: 30px;
+  height: 30px;
+  border: 2px solid blue;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+}
+.flex > div > div {
+  font-size: 20px;
+  text-align: center;
+  flex: none;
+}
+</style>
+
+</head>
+
+<div class="container-row">
+  <div class="vertical-header ltr horizontal"></div>
+  <div class="horizontal-header ltr horizontal">ltr<br>horizontal-tb</div>
+  <div class="vertical-header ltr flipped-blocks">ltr<br>vertical-rl</div>
+  <div class="vertical-header ltr flipped-blocks">ltr<br>vertical-lr</div>
+  <div class="horizontal-header rtl horizontal">rtl<br>horizontal-tb</div>
+  <div class="vertical-header rtl flipped-blocks">rtl<br>vertical-rl</div>
+  <div class="vertical-header rtl flipped-blocks">rtl<br>vertical-lr</div>
+</div>
+
+<script>
+flexDirections.forEach((flexDirection) => {
+  var containerRow = createContainerRow(flexDirection);
+  document.body.appendChild(containerRow);
+});
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-redirect-same-origin-allow-popups.https-expected.txt b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-redirect-same-origin-allow-popups.https-expected.txt
new file mode 100644
index 0000000..2deb428
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-redirect-same-origin-allow-popups.https-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL Same origin popup redirects to same-origin with same-origin-allow-popups assert_equals: opener expected "false" but got "true"
+FAIL Cross origin popup redirects to same-origin with same-origin-allow-popups assert_equals: opener expected "false" but got "true"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-redirect-same-origin-allow-popups.https.html b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-redirect-same-origin-allow-popups.https.html
new file mode 100644
index 0000000..7690f23
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-redirect-same-origin-allow-popups.https.html
@@ -0,0 +1,96 @@
+<title>
+  Tests the interaction of COOP same-origin-allow-popups with redirects in a
+  newly opened popup.
+</title>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="./reporting/resources/dispatcher.js"></script>
+
+<div id=log></div>
+<script>
+
+const executor_path = "/html/cross-origin-opener-policy/reporting/resources/executor.html?pipe=";
+const same_origin = {
+  host: get_host_info().HTTPS_ORIGIN,
+  name: "Same origin"
+};
+const cross_origin = {
+  host: get_host_info().HTTPS_REMOTE_ORIGIN,
+  name: "Cross origin"
+};
+const coep_header = '|header(Cross-Origin-Embedder-Policy,unsafe-none)';
+
+// Tests the interaction of COOP same-origin-allow-popups with redirects in a
+// newly created popup.
+// 1- Creates a page with origin SAME_ORIGIN and COOP same-origin-allow-popups.
+// 2- This page opens a popup.
+// 3- The popup navigates and gets a redirect response with COOP unsafe none
+//    and origin either SAME_ORIGIN or CROSS_ORIGIN
+// 4- The popup follows the redirect and ends up on a final page with COOP
+//    same-origin-allow-popups and origin SAME_ORIGIN
+// 5- The popup and its opener should no longer be in the same browsing context
+//    group (ie the popup doesn't have an opener and the window that opened the
+//    popup sees it as closed).
+function redirect_test(popup_redirect_origin) {
+  promise_test(async t => {
+    // Identifies the test window.
+    const this_window_token = token();
+
+    // Identifies the first window that will open the popup. It has COOP
+    // same-origin-allow-popups.
+    const opener_token= token();
+    const same_origin_allow_popups_header =
+        `|header(Cross-Origin-Opener-Policy,same-origin-allow-popups)`;
+    const opener_url = same_origin.host + executor_path +
+        same_origin_allow_popups_header + `&uuid=${opener_token}`;
+
+    // Identifies the popup. It will initial try to navigate to
+    // popup_redirect_origin, which has COOP unsafe-none. The navigation is
+    // then redirected to a final response of SAME_ORIGIN and COOP
+    // same-origin-allow-popups.
+    const popup_token = token();
+    const popup_final_url = same_origin.host + executor_path +
+        same_origin_allow_popups_header + `&uuid=${popup_token}`;
+    const redirect_header = 'status(302)' +
+      `|header(Location,${encodeURIComponent(
+        popup_final_url
+          .replace(/,/g, "\\,")
+          .replace(/\\\\,/g, "\\\\\\,")
+          .replace(/\(/g, "%28")
+          .replace(/\)/g, "%29"))})`;
+    const popup_initial_url = popup_redirect_origin.host + executor_path +
+        redirect_header + `&uuid=${popup_token}`;
+
+    // 1. Create the initial window.
+    let opener_window_proxy = window.open(opener_url);
+    t.add_cleanup(() => send(opener_token, "window.close()"));
+
+    // 2. The initial window opens a popup.
+    send(opener_token, `
+      popup = window.open("${popup_initial_url}");
+    `);
+    t.add_cleanup(() => send(popup_token, "window.close()"));
+
+    // 3. Check the opener status on the popup.
+    send(popup_token, `
+      send("${this_window_token}", window.opener !== null);
+    `);
+    assert_equals(await receive(this_window_token), "false", "opener");
+
+    // 4. Check the status of the popup from the initial window.
+    send(opener_token, `
+      send("${this_window_token}", popup.closed);
+    `);
+    assert_equals(await receive(this_window_token), "true", "popup.closed");
+
+  }, `${popup_redirect_origin.name} popup redirects to same-origin with same-origin-allow-popups`);
+}
+
+redirect_test(same_origin);
+redirect_test(cross_origin);
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/reporting/access-reporting/reporting-observer-expected.txt b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/reporting/access-reporting/reporting-observer-expected.txt
deleted file mode 100644
index 036442d6..0000000
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/reporting/access-reporting/reporting-observer-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-This is a testharness.js-based test.
-FAIL Opener COOP assert_equals: No report received. expected 1 but got 0
-FAIL Openee COOP assert_equals: No report received. expected 1 but got 0
-FAIL Access from same-origin iframe assert_not_equals: No report received. got disallowed value "timeout"
-PASS Access from cross-site iframe
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-image/MediaStreamTrack-getCapabilities.html b/third_party/blink/web_tests/external/wpt/mediacapture-image/MediaStreamTrack-getCapabilities.html
index 4e0c933..d0b7c2a 100644
--- a/third_party/blink/web_tests/external/wpt/mediacapture-image/MediaStreamTrack-getCapabilities.html
+++ b/third_party/blink/web_tests/external/wpt/mediacapture-image/MediaStreamTrack-getCapabilities.html
@@ -77,8 +77,6 @@
           'focusMode');
     }
 
-    assert_true(capabilities.exposureCompensation instanceof
-                MediaSettingsRange);
     assert_equals(capabilities.exposureCompensation.max,
                   mockCapabilities.exposureCompensation.max);
     assert_equals(capabilities.exposureCompensation.min,
@@ -86,8 +84,6 @@
     assert_equals(capabilities.exposureCompensation.step,
                   mockCapabilities.exposureCompensation.step);
 
-    assert_true(capabilities.exposureTime instanceof
-                MediaSettingsRange);
     assert_equals(capabilities.exposureTime.max,
                   mockCapabilities.exposureTime.max);
     assert_equals(capabilities.exposureTime.min,
@@ -95,8 +91,6 @@
     assert_equals(capabilities.exposureTime.step,
                   mockCapabilities.exposureTime.step);
 
-    assert_true(capabilities.colorTemperature instanceof
-                MediaSettingsRange);
     assert_equals(capabilities.colorTemperature.max,
                   mockCapabilities.colorTemperature.max);
     assert_equals(capabilities.colorTemperature.min,
@@ -104,12 +98,10 @@
     assert_equals(capabilities.colorTemperature.step,
                   mockCapabilities.colorTemperature.step);
 
-    assert_true(capabilities.iso instanceof MediaSettingsRange);
     assert_equals(capabilities.iso.max, mockCapabilities.iso.max);
     assert_equals(capabilities.iso.min, mockCapabilities.iso.min);
     assert_equals(capabilities.iso.step, mockCapabilities.iso.step);
 
-    assert_true(capabilities.brightness instanceof MediaSettingsRange);
     assert_equals(capabilities.brightness.max,
                   mockCapabilities.brightness.max);
     assert_equals(capabilities.brightness.min,
@@ -117,7 +109,6 @@
     assert_equals(capabilities.brightness.step,
                   mockCapabilities.brightness.step);
 
-    assert_true(capabilities.contrast instanceof MediaSettingsRange);
     assert_equals(capabilities.contrast.max,
                   mockCapabilities.contrast.max);
     assert_equals(capabilities.contrast.min,
@@ -125,7 +116,6 @@
     assert_equals(capabilities.contrast.step,
                   mockCapabilities.contrast.step);
 
-    assert_true(capabilities.saturation instanceof MediaSettingsRange);
     assert_equals(capabilities.saturation.max,
                   mockCapabilities.saturation.max);
     assert_equals(capabilities.saturation.min,
@@ -133,7 +123,6 @@
     assert_equals(capabilities.saturation.step,
                   mockCapabilities.saturation.step);
 
-    assert_true(capabilities.sharpness instanceof MediaSettingsRange);
     assert_equals(capabilities.sharpness.max,
                   mockCapabilities.sharpness.max);
     assert_equals(capabilities.sharpness.min,
@@ -141,7 +130,6 @@
     assert_equals(capabilities.sharpness.step,
                   mockCapabilities.sharpness.step);
 
-    assert_true(capabilities.focusDistance instanceof MediaSettingsRange);
     assert_equals(capabilities.focusDistance.max,
                   mockCapabilities.focusDistance.max);
     assert_equals(capabilities.focusDistance.min,
@@ -150,17 +138,14 @@
                   mockCapabilities.focusDistance.step);
 
     if (ptzPermission === 'granted') {
-      assert_true(capabilities.pan instanceof MediaSettingsRange);
       assert_equals(capabilities.pan.max, mockCapabilities.pan.max);
       assert_equals(capabilities.pan.min, mockCapabilities.pan.min);
       assert_equals(capabilities.pan.step, mockCapabilities.pan.step);
 
-      assert_true(capabilities.tilt instanceof MediaSettingsRange);
       assert_equals(capabilities.tilt.max, mockCapabilities.tilt.max);
       assert_equals(capabilities.tilt.min, mockCapabilities.tilt.min);
       assert_equals(capabilities.tilt.step, mockCapabilities.tilt.step);
 
-      assert_true(capabilities.zoom instanceof MediaSettingsRange);
       assert_equals(capabilities.zoom.max, mockCapabilities.zoom.max);
       assert_equals(capabilities.zoom.min, mockCapabilities.zoom.min);
       assert_equals(capabilities.zoom.step, mockCapabilities.zoom.step);
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-image/getPhotoCapabilities.html b/third_party/blink/web_tests/external/wpt/mediacapture-image/getPhotoCapabilities.html
index 663b43a..9e2392d 100644
--- a/third_party/blink/web_tests/external/wpt/mediacapture-image/getPhotoCapabilities.html
+++ b/third_party/blink/web_tests/external/wpt/mediacapture-image/getPhotoCapabilities.html
@@ -22,17 +22,14 @@
   assert_true(typeof capturer.getPhotoCapabilities == 'function');
 
   let capabilities = await capturer.getPhotoCapabilities();
-  assert_true(capabilities instanceof PhotoCapabilities);
 
   assert_equals(capabilities.redEyeReduction, 'controllable',
                 'redEyeReduction');
 
-  assert_true(capabilities.imageHeight instanceof MediaSettingsRange);
   assert_equals(capabilities.imageHeight.max, mockCapabilities.height.max);
   assert_equals(capabilities.imageHeight.min, mockCapabilities.height.min);
   assert_equals(capabilities.imageHeight.step, mockCapabilities.height.step);
 
-  assert_true(capabilities.imageWidth instanceof MediaSettingsRange);
   assert_equals(capabilities.imageWidth.max, mockCapabilities.width.max);
   assert_equals(capabilities.imageWidth.min, mockCapabilities.width.min);
   assert_equals(capabilities.imageWidth.step, mockCapabilities.width.step);
diff --git a/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/force-load-at-top-target.html b/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/force-load-at-top-target.html
new file mode 100644
index 0000000..72feec8a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/force-load-at-top-target.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<title>Navigating to a text fragment anchor</title>
+<script src="stash.js"></script>
+<script src="force-load-at-top.js"></script>
+<style>
+  p#target {
+    margin: 2000px 0px 2000px 0px;
+  }
+</style>
+<!-- This page is loaded with the force-load-at-top Document-Policy header -->
+<body>
+  <p>Top of page</p>
+  <p id="target">target</p>
+  <p id="history">history</p>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/force-load-at-top-target.html.headers b/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/force-load-at-top-target.html.headers
new file mode 100644
index 0000000..33dcdbb01
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/force-load-at-top-target.html.headers
@@ -0,0 +1 @@
+Document-Policy: force-load-at-top
diff --git a/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/force-load-at-top.html b/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/force-load-at-top.html
new file mode 100644
index 0000000..1399de3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/force-load-at-top.html
@@ -0,0 +1,60 @@
+<!doctype html>
+<title>ForceLoadAtTop blocks scroll on load</title>
+<meta charset=utf-8>
+<link rel="help" href="https://wicg.github.io/ScrollToTextFragment/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/common/utils.js"></script>
+<script src="stash.js"></script>
+
+<!--See comment in scroll-to-text-fragment.html for why this test has the
+structure it has -->
+<script>
+
+let test_cases = [
+  {
+    fragment: '#:~:text=target',
+    type: 'text fragment'
+  },
+  {
+    fragment: '#target:~:text=target',
+    type: 'text fragment with element fallback'
+  },
+  {
+    fragment: '#target',
+    type: 'element fragment'
+  },
+  {
+    fragment: '#history',
+    type: 'history scroll restoration'
+  },
+];
+
+let document_policy_value = [
+  'force-load-at-top',
+  'no-force-load-at-top'
+];
+
+for (const value of document_policy_value) {
+  // If no-force-load-at-top is specified we expect to allow scrolling,
+  // otherwise scroll on load should be blocked.
+  const scroll_expected = value == 'no-force-load-at-top';
+  const block_verb = scroll_expected ? "must not" : "must";
+
+  for (const test_case of test_cases) {
+    promise_test(t => new Promise((resolve, reject) => {
+      let key = token();
+
+      test_driver.bless('Open a URL with a text fragment directive', () => {
+        window.open(`${value}-target.html?key=${key}${test_case.fragment}`, '_blank', 'noopener');
+      });
+
+      fetchResults(key, resolve, reject);
+    }).then(data => {
+      assert_equals(data.scrolled, scroll_expected);
+    }), `${value} ${block_verb} block scroll on load from ${test_case.type}.`);
+  }
+}
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/force-load-at-top.js b/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/force-load-at-top.js
new file mode 100644
index 0000000..223e3a4b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/force-load-at-top.js
@@ -0,0 +1,33 @@
+function checkScroll() {
+  // Ensure two animation frames on load to test the fallback to element
+  // anchor, which gets queued for the next frame if the text fragment is not
+  // found.
+  requestAnimationFrame(() => {
+    requestAnimationFrame(() => {
+      let results = {
+        scrolled: (window.pageYOffset != 0),
+      };
+
+      let key = (new URL(document.location)).searchParams.get("key");
+      stashResultsThenClose(key, results);
+    });
+  });
+}
+
+window.addEventListener('load', () => {
+  if (location.hash == "#history") {
+    // This is the "history" test - on the first load we'll navigate to a page
+    // that calls history.back(). When we load a second time (from the back
+    // navigation), record the scroll state at that point to check how history
+    // scroll restoration is handled.
+    if (history.state == null) {
+      history.pushState("test", "test", "");
+      requestAnimationFrame(() => {
+        location.href = "navigate-back.html";
+      });
+      return;
+    }
+  }
+
+  checkScroll();
+});
diff --git a/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/navigate-back.html b/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/navigate-back.html
new file mode 100644
index 0000000..4b4117f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/navigate-back.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<script>
+  onload = () => {
+    requestAnimationFrame(() => {
+      history.back();
+    });
+  };
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/no-force-load-at-top-target.html b/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/no-force-load-at-top-target.html
new file mode 100644
index 0000000..57e5f6d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/no-force-load-at-top-target.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<title>Navigating to a text fragment anchor</title>
+<script src="stash.js"></script>
+<script src="force-load-at-top.js"></script>
+<style>
+  p#target {
+    margin: 2000px 0px 2000px 0px;
+  }
+</style>
+<!-- This page is loaded with the no-force-load-at-top Document-Policy header -->
+<body>
+  <p>Top of page</p>
+  <p id="target">target</p>
+  <p id="history">history</p>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/no-force-load-at-top-target.html.headers b/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/no-force-load-at-top-target.html.headers
new file mode 100644
index 0000000..3a2c029
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/scroll-to-text-fragment/no-force-load-at-top-target.html.headers
@@ -0,0 +1 @@
+Document-Policy: no-force-load-at-top
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/issues/content-security-policy-issue-creation-eval-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/issues/content-security-policy-issue-creation-eval-expected.txt
new file mode 100644
index 0000000..23ebfd8
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/issues/content-security-policy-issue-creation-eval-expected.txt
@@ -0,0 +1,19 @@
+Verifies that CSP issue is created from a page with eval() usage.
+
+Inspector issue: {
+    issue : {
+        code : ContentSecurityPolicyIssue
+        details : {
+            contentSecurityPolicyIssueDetails : {
+                contentSecurityPolicyViolationType : kEvalViolation
+                sourceCodeLocation : {
+                    columnNumber : 13
+                    lineNumber : 7
+                    url : https://devtools.test:8443/inspector-protocol/resources/content-security-policy-issue-eval.html
+                }
+                violatedDirective : script-src
+            }
+        }
+    }
+}
+
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/issues/content-security-policy-issue-creation-eval.js b/third_party/blink/web_tests/http/tests/inspector-protocol/issues/content-security-policy-issue-creation-eval.js
new file mode 100644
index 0000000..c5061fa
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/issues/content-security-policy-issue-creation-eval.js
@@ -0,0 +1,12 @@
+(async function(testRunner) {
+    const {page, session, dp} = await testRunner.startBlank(
+      `Verifies that CSP issue is created from a page with eval() usage.\n`);
+
+    await dp.Network.enable();
+    await dp.Audits.enable();
+    page.navigate('https://devtools.test:8443/inspector-protocol/resources/content-security-policy-issue-eval.html');
+    const issue = await dp.Audits.onceIssueAdded();
+
+    testRunner.log(issue.params, "Inspector issue: ");
+    testRunner.completeTest();
+  })
\ No newline at end of file
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/resources/content-security-policy-issue-eval.html b/third_party/blink/web_tests/http/tests/inspector-protocol/resources/content-security-policy-issue-eval.html
new file mode 100644
index 0000000..da1c778
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/resources/content-security-policy-issue-eval.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';">
+
+<html>
+  <body>
+    <h2>Webpage with not allowed eval()</h2>
+
+    <script>alert(eval('7+10'))</script>
+  </body>
+</html>
diff --git a/third_party/blink/web_tests/platform/linux/virtual/layout_ng_block_frag/fragmentation/outline-crossing-columns-expected.png b/third_party/blink/web_tests/platform/linux/virtual/layout_ng_block_frag/fragmentation/outline-crossing-columns-expected.png
index f58f1aca..68ee6af 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/layout_ng_block_frag/fragmentation/outline-crossing-columns-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/layout_ng_block_frag/fragmentation/outline-crossing-columns-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/layout_ng_block_frag/fragmentation/outline-crossing-columns-expected.png b/third_party/blink/web_tests/platform/mac/virtual/layout_ng_block_frag/fragmentation/outline-crossing-columns-expected.png
index b25378f..70ca26e 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/layout_ng_block_frag/fragmentation/outline-crossing-columns-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/layout_ng_block_frag/fragmentation/outline-crossing-columns-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/layout_ng_block_frag/fragmentation/outline-crossing-columns-expected.png b/third_party/blink/web_tests/platform/win/virtual/layout_ng_block_frag/fragmentation/outline-crossing-columns-expected.png
new file mode 100644
index 0000000..23517bb
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/virtual/layout_ng_block_frag/fragmentation/outline-crossing-columns-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
index 19f47de1..66ebfbf1 100644
--- a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -4314,12 +4314,6 @@
     method setPositionState
     setter metadata
     setter playbackState
-interface MediaSettingsRange
-    attribute @@toStringTag
-    getter max
-    getter min
-    getter step
-    method constructor
 interface MediaSource : EventTarget
     static method isTypeSupported
     attribute @@toStringTag
@@ -5122,13 +5116,6 @@
     attribute @@toStringTag
     method constructor
     method query
-interface PhotoCapabilities
-    attribute @@toStringTag
-    getter fillLightMode
-    getter imageHeight
-    getter imageWidth
-    getter redEyeReduction
-    method constructor
 interface PictureInPictureEvent : Event
     attribute @@toStringTag
     getter pictureInPictureWindow
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 490d0e0..3b1b26a4 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
@@ -5155,12 +5155,6 @@
     method setPositionState
     setter metadata
     setter playbackState
-interface MediaSettingsRange
-    attribute @@toStringTag
-    getter max
-    getter min
-    getter step
-    method constructor
 interface MediaSource : EventTarget
     static method isTypeSupported
     attribute @@toStringTag
@@ -6105,13 +6099,6 @@
     method request
     method requestAll
     method revoke
-interface PhotoCapabilities
-    attribute @@toStringTag
-    getter fillLightMode
-    getter imageHeight
-    getter imageWidth
-    getter redEyeReduction
-    method constructor
 interface PictureInPictureEvent : Event
     attribute @@toStringTag
     getter pictureInPictureWindow
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 2bf88e7..d40ef828 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -20445,6 +20445,22 @@
   </description>
 </action>
 
+<action name="Settings.SafetyCheck.ChromeCleanerReboot">
+  <owner>rainhard@chromium.org</owner>
+  <owner>msramek@chromium.org</owner>
+  <description>
+    User clicks the safety check Chrome cleaner reboot button.
+  </description>
+</action>
+
+<action name="Settings.SafetyCheck.ChromeCleanerReviewInfectedState">
+  <owner>rainhard@chromium.org</owner>
+  <owner>msramek@chromium.org</owner>
+  <description>
+    User clicks the review button in an CCT infected state.
+  </description>
+</action>
+
 <action name="Settings.SafetyCheck.ManagePasswords">
   <owner>rainhard@chromium.org</owner>
   <owner>andzaytsev@google.com</owner>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 498716d..8efdfca 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -21366,6 +21366,8 @@
   <int value="763" label="DeviceShowLowDiskSpaceNotification"/>
   <int value="764" label="DeviceUserAllowlist"/>
   <int value="765" label="UsbDetachableAllowlist"/>
+  <int value="766" label="InsecurePrivateNetworkRequestsAllowed"/>
+  <int value="767" label="InsecurePrivateNetworkRequestsAllowedForUrls"/>
 </enum>
 
 <enum name="EnterprisePolicyDeviceIdValidity">
@@ -37199,6 +37201,7 @@
   <int value="3" label="Open in New Incognito Tab"/>
   <int value="4" label="Open in New Window"/>
   <int value="5" label="Remove"/>
+  <int value="6" label="Edit"/>
 </enum>
 
 <enum name="IOSMenuScenario">
@@ -54325,6 +54328,9 @@
   <int value="6" label="Fill On Select">
     User is browsing with the Fill On Select feature enabled.
   </int>
+  <int value="7" label="Reauth required">
+    Re-authenticaion for filling passwords is required.
+  </int>
 </enum>
 
 <enum name="PasswordManagerHttpCredentialType">
@@ -55952,6 +55958,7 @@
   <int value="37" label="ActiveDirectoryManagement"/>
   <int value="38" label="LegacySameSiteCookieBehaviorSettings"/>
   <int value="39" label="SensorsSettings"/>
+  <int value="40" label="PrivateNetworkRequestSettings"/>
 </enum>
 
 <enum name="PolicyLoadStatus">
@@ -61131,6 +61138,9 @@
 </enum>
 
 <enum name="RoamingUserDataDirectoryDeletionResult">
+  <obsolete>
+    Removed in 2020-08 (M86).
+  </obsolete>
   <int value="0" label="Error">
     An unexpected error occurred during processing.
   </int>
@@ -63685,6 +63695,8 @@
   <int value="2" label="Safety check, manage passwords"/>
   <int value="3" label="Safety check, manage safe browsing"/>
   <int value="4" label="Safety check, review extensions"/>
+  <int value="5" label="Safety check, reboot via Chrome cleaner"/>
+  <int value="6" label="Safety check, review Chrome cleaner infected state"/>
 </enum>
 
 <enum name="SettingsSections">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index a235b47a9..3ba740b8 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -73621,6 +73621,16 @@
   </summary>
 </histogram>
 
+<histogram name="IOS.NSString.stringByReplacingCharactersInRange.NilArgument"
+    enum="Boolean" expires_after="2021-07-31">
+  <owner>javierrobles@chromium.org</owner>
+  <owner>eugenebut@chromium.org</owner>
+  <summary>
+    NSString API: stringByReplacingCharactersInRange:withString: was invoked
+    with a nil argument.
+  </summary>
+</histogram>
+
 <histogram name="IOS.NTP.Impression" enum="IOSNTPImpression"
     expires_after="2021-01-03">
   <owner>gambard@chromium.org</owner>
@@ -117205,6 +117215,9 @@
 
 <histogram name="Omnibox.QueryIosLocationAuthorizationStatus"
     enum="IosLocationAuthorizationStatus" expires_after="M86">
+  <obsolete>
+    Removed in August 2020
+  </obsolete>
   <owner>mpearson@chromium.org</owner>
   <owner>jdonnelly@chromium.org</owner>
   <owner>stkhapugin@chromium.org</owner>
@@ -161416,7 +161429,7 @@
   <owner>anaudrey@chromium.org</owner>
   <summary>
     Which user actions were taken in safety check. Recorded every time a user
-    does an interaction in safety check.
+    does an interaction in safety check. Value 5 and 6 got added with M86.
   </summary>
 </histogram>
 
@@ -163990,6 +164003,20 @@
   </summary>
 </histogram>
 
+<histogram name="Signin.IOSGaiaCookiePresentOnNavigation" enum="BooleanPresent"
+    expires_after="2021-08-05">
+  <owner>fernandex@chromium.org</owner>
+  <owner>msarda@chromium.org</owner>
+  <owner>chrome-signin-team@google.com</owner>
+  <summary>
+    Records whether the Gaia cookie is present when a user navigates to a
+    Google-owned domain that is eligible for Mirror account consistency to track
+    authentication cookies that have been remove by an external force (e.g.
+    Apple's ITP). This logging is limited to once every hour due to performance
+    constraints.
+  </summary>
+</histogram>
+
 <histogram name="Signin.IOSLoginMethodAndSyncState"
     enum="SigninIOSLoginMethodAndSyncState" expires_after="2021-04-30">
   <owner>jebel@chromium.org</owner>
@@ -174358,6 +174385,9 @@
 
 <histogram name="Sync.DeleteRoamingUserDataDirectory"
     enum="RoamingUserDataDirectoryDeletionResult" expires_after="2020-08-04">
+  <obsolete>
+    Removed in 2020-08 (M86).
+  </obsolete>
   <owner>grt@chromium.org</owner>
   <owner>pastarmovj@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index c9c67db..63448d2 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -5282,6 +5282,16 @@
   </metric>
 </event>
 
+<event name="JavascriptFrameworkPageLoad" singular="True">
+  <owner>houssein@chromium.org</owner>
+  <metric name="NextJSPageLoad">
+    <summary>
+      True if the page loaded in the main frame uses the Next.js JavaScript
+      framework.
+    </summary>
+  </metric>
+</event>
+
 <event name="Layout.DisplayCutout.StateChanged">
   <owner>beccahughes@chromium.org</owner>
   <owner>media-dev@chromium.org</owner>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 56792ae..e6931c25 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -10,7 +10,7 @@
         },
         "linux": {
             "hash": "e6355871974e3232db70f33ff3ae6c8d6ee4dfa7",
-            "remote_path": "perfetto_binaries/trace_processor_shell/linux/e69d5b2de9433980adaa09301bae62b8d467b390/trace_processor_shell"
+            "remote_path": "perfetto_binaries/trace_processor_shell/linux/56f14dabfe991afdf09f35a56418657dbcb81791/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index 4927243..8ef2674 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -11,6 +11,9 @@
 # results: [ Skip ]
 # conflicts_allowed: True
 
+# Benchmark: blink_perf.accessibility
+crbug.com/1114112 [ android-nexus-5x android-webview ] blink_perf.accessibility/build-table.html [ Skip ]
+
 # Benchmark: blink_perf.bindings
 crbug.com/882881 [ android-nexus-5 ] blink_perf.bindings/structured-clone-json-deserialize.html [ Skip ]
 crbug.com/910207 [ android-nexus-5x ] blink_perf.bindings/structured-clone-json-deserialize.html [ Skip ]
@@ -342,6 +345,7 @@
 crbug.com/1097065 [ linux ] system_health.memory_desktop/browse:media:googleplaystore:2018 [ Skip ]
 crbug.com/1097065 [ linux ] system_health.memory_desktop/load:social:vk:2018 [ Skip ]
 crbug.com/1097065 [ linux ] system_health.memory_desktop/browse_accessibility:tech:codesearch:2018 [ Skip ]
+crbug.com/1114120 [ win ] system_health.memory_desktop/browse:social:twitter_infinite_scroll:2018 [ Skip ]
 crbug.com/1044682 [ desktop ] system_health.memory_desktop/browse:tools:gmail-labelclick:2020 [ Skip ]
 crbug.com/1044682 [ desktop ] system_health.memory_desktop/browse:tools:gmail-openconversation:2020 [ Skip ]
 crbug.com/1044682 [ desktop ] system_health.memory_desktop/browse:tools:gmail-search:2020 [ Skip ]
diff --git a/ui/webui/resources/js/i18n_template_no_process.js b/ui/webui/resources/js/i18n_template_no_process.js
index 9778a6f..5a3f9713 100644
--- a/ui/webui/resources/js/i18n_template_no_process.js
+++ b/ui/webui/resources/js/i18n_template_no_process.js
@@ -104,12 +104,6 @@
 
   const prefixes = [''];
 
-  // Only look through shadow DOM when it's supported. As of April 2015, iOS
-  // Chrome doesn't support shadow DOM.
-  if (Element.prototype.createShadowRoot) {
-    prefixes.push('* /deep/ ');
-  }
-
   const attributeNames = Object.keys(handlers);
   const selector = prefixes
                        .map(function(prefix) {
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/PageInfoControllerDelegateImpl.java b/weblayer/browser/java/org/chromium/weblayer_private/PageInfoControllerDelegateImpl.java
index a2d4f84..e0d6a04 100644
--- a/weblayer/browser/java/org/chromium/weblayer_private/PageInfoControllerDelegateImpl.java
+++ b/weblayer/browser/java/org/chromium/weblayer_private/PageInfoControllerDelegateImpl.java
@@ -94,6 +94,8 @@
         SingleWebsiteSettings fragment = (SingleWebsiteSettings) Fragment.instantiate(
                 mContext, SingleWebsiteSettings.class.getName(), fragmentArgs);
         fragment.setSiteSettingsClient(new WebLayerSiteSettingsClient(getBrowserContext()));
+        fragment.setHideNonPermissionPreferences(true);
+        fragment.setRefreshAfterReset(true);
         return fragment;
     }