diff --git a/AUTHORS b/AUTHORS
index 402af24..73ad432 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1172,6 +1172,7 @@
 Facebook, Inc. <*@oculus.com>
 Google Inc. <*@google.com>
 Hewlett-Packard Development Company, L.P. <*@hp.com>
+HyperConnect Inc. <*@hpcnt.com>
 IBM Inc. <*@*.ibm.com>
 IBM Inc. <*@ibm.com>
 Igalia S.L. <*@igalia.com>
diff --git a/DEPS b/DEPS
index 02bafcce..288a5671 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': '3d41d509a6a98c9d14a8e70e2b1c362e0e5498f1',
+  'skia_revision': '18f6a54fc3cea32dd92a28e8808e4525c5180782',
   # 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,11 +207,11 @@
   # 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': '29b1f07f4ab23475ca2ece790cd85affd6d774db',
+  'angle_revision': '65dcbe124508f9799348fd4828cbb0f76cf80671',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': 'b24900a1aa39721dc53824c01d4169c1d1a4a6e1',
+  'swiftshader_revision': '41974f57973ebcdab4cfde6cc60354f6b79a5901',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -258,7 +258,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': 'bdb38e31199e618c1cdab83900154872f43e06d6',
+  'catapult_revision': '13bf1254829136fb3df678699236ba9eb5d87587',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # 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': '88a5d76f5f629f70e73592f7a5f075dfa081bb05',
+  'devtools_frontend_revision': '2b117e76f5dc52b8cdcd7518790ce1892f140084',
   # 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.
@@ -318,7 +318,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.
-  'dawn_revision': '498d5ea20aed3b313cfc456d07a8003b95318764',
+  'dawn_revision': '9427c97d9c2917d66e79e49ffaa718aac2e7d6ad',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -334,7 +334,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling wuffs
   # and whatever else without interference from each other.
-  'wuffs_revision': '67503b5bda0274b637671e277ede1e34dd08b1d7',
+  'wuffs_revision': 'ba75ce9c5f224a646d92801b0b8ef74f555d490e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libgifcodec
   # and whatever else without interference from each other.
@@ -545,7 +545,7 @@
   },
 
   'src/ios/third_party/material_components_ios/src': {
-      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '959e66d5aea00e0aa124b5ac604c29856b6c4905',
+      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '58ae5f81390b44bd675a0694caaf4e385a6e39a1',
       'condition': 'checkout_ios',
   },
 
@@ -876,7 +876,7 @@
   # Tools used when building Chrome for Chrome OS. This affects both the Simple
   # Chrome workflow, as well as the chromeos-chrome ebuild.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'd281ff18627341a0ff2c33e19691159d504923f8',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '607aa13c8b9aa57ef1fa23cc044b969ae6757db2',
       'condition': 'checkout_chromeos',
   },
 
@@ -1249,7 +1249,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'e6cf9658552491bf5fdffd98d2e67aacb51661f4',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '625eb197594ebdc42f57db8d36837e5bb99ee41b',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1471,7 +1471,7 @@
   },
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '9e9c8b7155d49c2f38b82fe9c9707181c57073c9',
+    Var('webrtc_git') + '/src.git' + '@' + 'fc83cdc8198b0609f8986313ef48e565b558e8a7',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1543,7 +1543,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@2f11d877efaaa202ae38a26df97aca0685b57205',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@12e6ff85f6e21468f21f154acf81707805441e89',
     'condition': 'checkout_src_internal',
   },
 
@@ -1551,7 +1551,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/help_app/app',
-        'version': 'mluAO-o7A3mN4nCwt4x0R0SnXS6cuF3Fo--glimMpfkC',
+        'version': 'ewmYZK3dZxBbgR06k6qpzdRqlikpeAfsd40KuNLCOSYC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -1562,7 +1562,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'AsR6b9xlxrEC7Kxx3tzZ2Pn1DDftdw15hFUg0Q8B6ZoC',
+        'version': 'rr3VhMXsq7y_PFGfYuF4xO5k6h8d3dTyYtD20gc4jK8C',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index ffb230d..9afa0705 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -74,11 +74,15 @@
 
 _TEST_ONLY_WARNING = (
     'You might be calling functions intended only for testing from\n'
-    'production code.  It is OK to ignore this warning if you know what\n'
-    'you are doing, as the heuristics used to detect the situation are\n'
-    'not perfect.  The commit queue will not block on this warning,\n'
-    'however the android-binary-size trybot will block if the method\n'
-    'exists in the release apk.')
+    'production code.  If you are doing this from inside another method\n'
+    'named as *ForTesting(), then consider exposing things to have tests\n'
+    'make that same call directly.\n'
+    'If that is not possible, you may put a comment on the same line with\n'
+    '  // IN-TEST \n'
+    'to tell the PRESUBMIT script that the code is inside a *ForTesting()\n'
+    'method and can be ignored. Do not do this inside production code.\n'
+    'The android-binary-size trybot will block if the method exists in the\n'
+    'release apk.')
 
 
 _INCLUDE_ORDER_WARNING = (
diff --git a/WATCHLISTS b/WATCHLISTS
index cd6b005..2b0f4573 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -257,7 +257,7 @@
                   'device/battery/',
     },
     'bfcache': {
-      'filepath': 'content/browser/frame_host/back_forward_cache.*|'\
+      'filepath': 'content/browser/renderer_host/back_forward_cache.*|'\
                   'content/browser/back_forward_cache_browsertest.cc|'\
                   'content/test/data/back_forward_cache/|'\
                   'content/public/browser/back_forward_cache.*|'\
@@ -1326,7 +1326,7 @@
       'filepath': '^native_client_sdk/',
     },
     'navigation': {
-      'filepath': 'content/browser/frame_host|'\
+      'filepath': 'content/browser/renderer_host|'\
                   'content/browser/renderer_host/render_process_host.*|'\
                   'content/browser/renderer_host/render_view_host.*|'\
                   'content/browser/web_contents/web_contents_impl.*|'\
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentCaptureTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentCaptureTest.java
index 2bdaaba..ad98a3c4 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentCaptureTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentCaptureTest.java
@@ -21,6 +21,7 @@
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Feature;
+import org.chromium.base.test.util.FlakyTest;
 import org.chromium.components.content_capture.ContentCaptureConsumer;
 import org.chromium.components.content_capture.ContentCaptureController;
 import org.chromium.components.content_capture.ContentCaptureData;
@@ -608,6 +609,7 @@
 
     @Test
     @SmallTest
+    @FlakyTest(message = "https://crbug.com/1126950")
     @Feature({"AndroidWebView"})
     public void testMultipleConsumers() throws Throwable {
         TestThreadUtils.runOnUiThreadBlocking(() -> {
diff --git a/android_webview/tools/run_cts.py b/android_webview/tools/run_cts.py
index 41731e5..d78242d 100755
--- a/android_webview/tools/run_cts.py
+++ b/android_webview/tools/run_cts.py
@@ -310,8 +310,8 @@
   if known_args.devices:
     # test_runner.py parses --device as nargs instead of append args
     forwarded_args.extend(['--device'] + known_args.devices)
-  if known_args.blacklist_file:
-    forwarded_args.extend(['--blacklist-file', known_args.blacklist_file])
+  if known_args.denylist_file:
+    forwarded_args.extend(['--denylist-file', known_args.denylist_file])
 
   if known_args.verbose:
     forwarded_args.extend(['-' + 'v' * known_args.verbose])
@@ -332,7 +332,7 @@
       emulator_instance.Start(writable_system=True)
       device_utils.DeviceUtils(emulator_instance.serial).WaitUntilFullyBooted()
 
-    devices = script_common.GetDevices(args.devices, args.blacklist_file)
+    devices = script_common.GetDevices(args.devices, args.denylist_file)
     device = devices[0]
     if len(devices) > 1:
       logging.warning('Detection of arch and cts-release will use 1st of %d '
diff --git a/android_webview/tools/run_simpleperf.py b/android_webview/tools/run_simpleperf.py
index 8c892bb..af7bea0 100755
--- a/android_webview/tools/run_simpleperf.py
+++ b/android_webview/tools/run_simpleperf.py
@@ -321,7 +321,7 @@
   logging_common.InitializeLogging(args)
   devil_chromium.Initialize(adb_path=args.adb_path)
 
-  devices = script_common.GetDevices(args.devices, args.blacklist_file)
+  devices = script_common.GetDevices(args.devices, args.denylist_file)
   device = devices[0]
 
   if len(devices) > 1:
diff --git a/ash/app_list/views/assistant/assistant_privacy_info_view.h b/ash/app_list/views/assistant/assistant_privacy_info_view.h
index 68bca5a..514dcbf 100644
--- a/ash/app_list/views/assistant/assistant_privacy_info_view.h
+++ b/ash/app_list/views/assistant/assistant_privacy_info_view.h
@@ -7,7 +7,6 @@
 
 #include "ash/app_list/views/privacy_info_view.h"
 #include "ui/views/controls/button/button.h"
-#include "ui/views/controls/styled_label_listener.h"
 
 namespace ash {
 
diff --git a/ash/app_list/views/search_result_view.cc b/ash/app_list/views/search_result_view.cc
index 42c02c26..21828bc 100644
--- a/ash/app_list/views/search_result_view.cc
+++ b/ash/app_list/views/search_result_view.cc
@@ -81,7 +81,7 @@
   badge_icon_->set_can_process_events_within_subtree(false);
 
   set_context_menu_controller(this);
-  set_notify_enter_exit_on_child(true);
+  SetNotifyEnterExitOnChild(true);
 }
 
 SearchResultView::~SearchResultView() = default;
diff --git a/ash/app_list/views/suggested_content_info_view.h b/ash/app_list/views/suggested_content_info_view.h
index 4b5e80e..045ab07 100644
--- a/ash/app_list/views/suggested_content_info_view.h
+++ b/ash/app_list/views/suggested_content_info_view.h
@@ -7,7 +7,6 @@
 
 #include "ash/app_list/views/privacy_info_view.h"
 #include "ui/views/controls/button/button.h"
-#include "ui/views/controls/styled_label_listener.h"
 
 namespace ash {
 
diff --git a/ash/login/ui/lock_contents_view.cc b/ash/login/ui/lock_contents_view.cc
index 909b05e0..e2e04805 100644
--- a/ash/login/ui/lock_contents_view.cc
+++ b/ash/login/ui/lock_contents_view.cc
@@ -1979,7 +1979,7 @@
     *bold_start += shortcut_offset_in_string;
   }
 
-  auto label = std::make_unique<views::StyledLabel>(this);
+  auto label = std::make_unique<views::StyledLabel>();
   label->SetText(error_text);
   MakeSectionBold(label.get(), error_text, bold_start, bold_length);
   label->SetAutoColorReadabilityEnabled(false);
diff --git a/ash/login/ui/lock_contents_view.h b/ash/login/ui/lock_contents_view.h
index 750e493c..b7c3491 100644
--- a/ash/login/ui/lock_contents_view.h
+++ b/ash/login/ui/lock_contents_view.h
@@ -32,7 +32,6 @@
 #include "chromeos/dbus/power_manager/power_supply_properties.pb.h"
 #include "ui/display/display_observer.h"
 #include "ui/display/screen.h"
-#include "ui/views/controls/styled_label_listener.h"
 #include "ui/views/metadata/metadata_header_macros.h"
 #include "ui/views/view.h"
 
@@ -42,7 +41,6 @@
 
 namespace views {
 class BoxLayout;
-class StyledLabel;
 }  // namespace views
 
 namespace ash {
@@ -69,7 +67,6 @@
       public LoginDataDispatcher::Observer,
       public SystemTrayFocusObserver,
       public display::DisplayObserver,
-      public views::StyledLabelListener,
       public KeyboardControllerObserver,
       public chromeos::PowerManagerClient::Observer {
  public:
@@ -213,11 +210,6 @@
   void OnDisplayMetricsChanged(const display::Display& display,
                                uint32_t changed_metrics) override;
 
-  // views::StyledLabelListener:
-  void StyledLabelLinkClicked(views::StyledLabel* label,
-                              const gfx::Range& range,
-                              int event_flags) override {}
-
   // KeyboardControllerObserver:
   void OnKeyboardVisibilityChanged(bool is_visible) override;
 
diff --git a/ash/login/ui/lock_screen_media_controls_view.cc b/ash/login/ui/lock_screen_media_controls_view.cc
index 18bbd39..12552b9 100644
--- a/ash/login/ui/lock_screen_media_controls_view.cc
+++ b/ash/login/ui/lock_screen_media_controls_view.cc
@@ -227,7 +227,7 @@
   // Media controls have not been dismissed initially.
   Shell::Get()->media_controller()->SetMediaControlsDismissed(false);
 
-  set_notify_enter_exit_on_child(true);
+  SetNotifyEnterExitOnChild(true);
 
   contents_view_ = AddChildView(std::make_unique<views::View>());
   contents_view_->SetLayoutManager(std::make_unique<views::BoxLayout>(
diff --git a/ash/login/ui/login_expanded_public_account_view.cc b/ash/login/ui/login_expanded_public_account_view.cc
index 8a191e0f..2f3e73a 100644
--- a/ash/login/ui/login_expanded_public_account_view.cc
+++ b/ash/login/ui/login_expanded_public_account_view.cc
@@ -35,6 +35,7 @@
 #include "ui/views/controls/styled_label_listener.h"
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/fill_layout.h"
+
 namespace ash {
 
 namespace {
diff --git a/ash/public/cpp/external_arc/message_center/arc_notification_content_view.cc b/ash/public/cpp/external_arc/message_center/arc_notification_content_view.cc
index 55c2fe6..134f978 100644
--- a/ash/public/cpp/external_arc/message_center/arc_notification_content_view.cc
+++ b/ash/public/cpp/external_arc/message_center/arc_notification_content_view.cc
@@ -254,7 +254,7 @@
   DCHECK_EQ(360, message_center::kNotificationWidth);
 
   SetFocusBehavior(FocusBehavior::ALWAYS);
-  set_notify_enter_exit_on_child(true);
+  SetNotifyEnterExitOnChild(true);
 
   item_->IncrementWindowRefCount();
   item_->AddObserver(this);
diff --git a/ash/shelf/shelf_tooltip_preview_bubble.cc b/ash/shelf/shelf_tooltip_preview_bubble.cc
index ed05d35..c2f70356 100644
--- a/ash/shelf/shelf_tooltip_preview_bubble.cc
+++ b/ash/shelf/shelf_tooltip_preview_bubble.cc
@@ -49,7 +49,7 @@
   set_margins(gfx::Insets());
   // We hide this tooltip on mouse exit, so we want to get enter/exit events
   // at this level, even for subviews.
-  set_notify_enter_exit_on_child(true);
+  SetNotifyEnterExitOnChild(true);
 
   SetLayoutManager(std::make_unique<views::BoxLayout>(
       views::BoxLayout::Orientation::kHorizontal,
diff --git a/ash/strings/ash_strings_mk.xtb b/ash/strings/ash_strings_mk.xtb
index add8efaf..4997110 100644
--- a/ash/strings/ash_strings_mk.xtb
+++ b/ash/strings/ash_strings_mk.xtb
@@ -603,7 +603,7 @@
 <translation id="7654687942625752712">Притиснете ги и задржете ги двете копчиња за јачина на звук пет секунди за да оневозможите говорни повратни информации.</translation>
 <translation id="7658239707568436148">Откажи</translation>
 <translation id="7705524343798198388">VPN</translation>
-<translation id="7705822912736783206">Извршете проверка со отпечаток</translation>
+<translation id="7705822912736783206">Автентицирајте со отпечаток</translation>
 <translation id="7723389094756330927">{NUM_NOTIFICATIONS,plural, =1{1 известување}one{# известување}other{# известувања}}</translation>
 <translation id="7724603315864178912">Исечи</translation>
 <translation id="7749443890790263709">Достигнат е максималниот број работни простори.</translation>
@@ -621,7 +621,7 @@
 <translation id="7886277072580235377">Сесијата на интернет ќе се исчисти кога ќе се одјавите. <ph name="LEARN_MORE" /></translation>
 <translation id="788781083998633524">Испрати е-порака</translation>
 <translation id="7897375687985782769">Ја притиснавте кратенката од тастатура за ротација на екранот. Дали сакате да го ротирате екранот?</translation>
-<translation id="7901405293566323524">Телефонски комутатор</translation>
+<translation id="7901405293566323524">Phone Hub</translation>
 <translation id="7904094684485781019">Администраторот за оваа сметка не дозволува повеќекратно пријавување.</translation>
 <translation id="7933084174919150729">„Помошникот на Google“ е достапен само за примарниот профил.</translation>
 <translation id="79341161159229895"><ph name="FIRST_PARENT_EMAIL" /> и <ph name="SECOND_PARENT_EMAIL" /> управуваат со сметката</translation>
diff --git a/ash/strings/ash_strings_or.xtb b/ash/strings/ash_strings_or.xtb
index a22aaff5..93726be 100644
--- a/ash/strings/ash_strings_or.xtb
+++ b/ash/strings/ash_strings_or.xtb
@@ -116,6 +116,7 @@
 <translation id="2127372758936585790">କମ୍-ଶକ୍ତି ବିଶିଷ୍ଟ ଚାର୍ଜର୍</translation>
 <translation id="2135456203358955318">ଡକ୍‌ଡ ମ୍ୟାଗ୍ନିଫାୟର୍</translation>
 <translation id="2144487987174258011">Adobe ଫ୍ଲାସ୍ ପ୍ଲେୟାର୍‌କୁ ଅପ୍‌ଡେଟ୍ କରିବା ପାଇଁ ରିଷ୍ଟାର୍ଟ କରନ୍ତୁ</translation>
+<translation id="2180011262286780504">ସ୍କ୍ରିନ୍ କ୍ୟାପଚର୍ କରିବାର କ୍ଷମତା ଆପଣଙ୍କ ଆଡମିନିଷ୍ଟ୍ରେଟରଙ୍କ ଦ୍ୱାରା ଅକ୍ଷମ କରାଯାଇଛି।</translation>
 <translation id="2208323208084708176">ଏକୀକୃତ ଡେସ୍କଟପ୍ ମୋଡ୍</translation>
 <translation id="2220572644011485463">ପିନ୍‌ କିମ୍ବା ପାସ୍‌ୱର୍ଡ</translation>
 <translation id="2222338659135520253">ସାଇନ୍ ଇନ୍ କରିବା ଆବଶ୍ୟକ</translation>
@@ -239,6 +240,7 @@
 <translation id="3428447136709161042"><ph name="NETWORK_NAME" />ରୁ ବିଚ୍ଛିନ୍ନ କରନ୍ତୁ</translation>
 <translation id="3430396595145920809">ପଛକୁ ଫେରିବାକୁ ଡାହାଣ ପାର୍ଶ୍ୱରୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ</translation>
 <translation id="343571671045587506">ରିମାଇଣ୍ଡର୍ ଏଡିଟ୍ କରନ୍ତୁ</translation>
+<translation id="3435967511775410570">ଟିପଚିହ୍ନ ଚିହ୍ନଟ କରାଯାଇଛି</translation>
 <translation id="3445925074670675829">USB-C ଡିଭାଇସ୍</translation>
 <translation id="3454224730401036106">ଆପଣଙ୍କର ସଂଯୋଗକୁ ଏକ ଅଧିକ ସୁରକ୍ଷିତ ନେଟ୍‌ୱର୍କକୁ ସ୍ୱିଚ୍ କରିଦିଆଯାଇଛି</translation>
 <translation id="3465223694362104965">ଆପଣ ଗତଥର ପାଇଁ ସାଇନ୍ ଇନ୍ କରିବା ପରେ ଅନ୍ୟ ଏକ କୀ'ବୋର୍ଡ ଏହି ଡିଭାଇସ୍‍‍ରେ ସଂଯୁକ୍ତ ହୋଇଛି। ଆପଣ ଏହି କୀ'ବୋର୍ଡକୁ ବ୍ୟବହାର କରିବା ପୂର୍ବରୁ ଏହା ଭରସାଯୋଗ୍ୟ ବୋଲି ସୁନିଶ୍ଚିତ କରନ୍ତୁ।</translation>
@@ -600,6 +602,7 @@
 <translation id="7654687942625752712">କୁହାଯାଇଥିବା ମତାମତ ଅକ୍ଷମ କରିବାକୁ ଉଭୟ ଭଲ୍ୟୁମ୍‍ କୀ ଦବାଇ ରଖନ୍ତୁ।</translation>
 <translation id="7658239707568436148">ବାତିଲ୍</translation>
 <translation id="7705524343798198388">VPN</translation>
+<translation id="7705822912736783206">ଟିପଚିହ୍ନ ସାହାଯ୍ୟରେ ପ୍ରମାଣିତ କରନ୍ତୁ</translation>
 <translation id="7723389094756330927">{NUM_NOTIFICATIONS,plural, =1{1ଟି ବିଜ୍ଞପ୍ତି}other{#ଟି ବିଜ୍ଞପ୍ତି}}</translation>
 <translation id="7724603315864178912">Cut</translation>
 <translation id="7749443890790263709">ସର୍ବାଧିକ ସଂଖ୍ୟକ ଡେସ୍କରେ ପହଞ୍ଚିଯାଇଛି।</translation>
@@ -617,6 +620,7 @@
 <translation id="7886277072580235377">ଯେତେବେଳେ ଆପଣ ସାଇନ୍ ଆଉଟ୍ କରିବେ ସେତେବେଳେ ଆପଣଙ୍କ ଇଣ୍ଟର୍ନେଟ୍ ଅବଧି ଖାଲି ହୋଇଯିବ। <ph name="LEARN_MORE" /></translation>
 <translation id="788781083998633524">ଏକ ଇମେଲ୍ ପଠାନ୍ତୁ</translation>
 <translation id="7897375687985782769">ଆପଣ ସ୍କ୍ରିନ୍‍ର ଘୂର୍ଣ୍ଣନ ପାଇଁ କୀବୋର୍ଡ ସର୍ଟକଟ୍ ଦବାଇଛନ୍ତି। ଆପଣ କ'ଣ ସ୍କ୍ରିନ୍‍କୁ ଘୂରାଇବାକୁ ଚାହୁଁଛନ୍ତି?</translation>
+<translation id="7901405293566323524">ଫୋନ୍ ହବ୍</translation>
 <translation id="7904094684485781019">ଏହି ଆକାଉଣ୍ଟର ବ୍ୟବସ୍ଥାପକ ଏକାଧିକ ସାଇନ୍‌ ଇନ୍‌ ପାଇଁ ଅନୁମତି ଦେଇନାହାନ୍ତି।</translation>
 <translation id="7933084174919150729">Google Assistant କେବଳ ପ୍ରାଥମିକ ପ୍ରୋଫାଇଲ୍ ପାଇଁ ଉପଲବ୍ଧ ଅଟେ।</translation>
 <translation id="79341161159229895"><ph name="FIRST_PARENT_EMAIL" /> ଏବଂ <ph name="SECOND_PARENT_EMAIL" /> ଦ୍ୱାରା ଆକାଉଣ୍ଟ ପରିଚାଳିତ ହେଉଛି</translation>
@@ -627,6 +631,7 @@
 <translation id="7982789257301363584">ନେଟୱାର୍କ</translation>
 <translation id="7984197416080286869">ଅନେକ ଟିପଚିହ୍ନ ପ୍ରଚେଷ୍ଟା</translation>
 <translation id="7994370417837006925">ଏକାଧିକ ସାଇନ୍-ଇନ୍</translation>
+<translation id="7995804128062002838">ସ୍କ୍ରିନ୍ କ୍ୟାପଚର୍ କରିବା ବିଫଳ ହୋଇଛି</translation>
 <translation id="8000066093800657092">କୌଣସି ନେଟ୍‌ୱର୍କ ନାହିଁ</translation>
 <translation id="8004512796067398576">ବୃଦ୍ଧି</translation>
 <translation id="8029629653277878342">ଅଧିକ ସୁରକ୍ଷା ପାଇଁ PIN କିମ୍ବା ପାସୱାର୍ଡ ଆବଶ୍ୟକ</translation>
@@ -714,6 +719,7 @@
 <translation id="8843682306134542540">ଘୂର୍ଣ୍ଣନ ଲକ୍ ଟୋଗଲ୍ କରନ୍ତୁ। <ph name="STATE_TEXT" /></translation>
 <translation id="8850991929411075241">Search+Esc</translation>
 <translation id="8853703225951107899">ଆପଣଙ୍କ PIN କିମ୍ବା ପାସୱାର୍ଡକୁ ଏବେ ବି ଯାଞ୍ଚ କରାଯାଇପାରିଲା ନାହିଁ। ଧ୍ୟାନ ଦିଅନ୍ତୁ: ଯଦି ଆପଣ ଆପଣଙ୍କ ପାସୱାର୍ଡକୁ ବର୍ତ୍ତମାନ ପରିବର୍ତ୍ତନ କରିଛନ୍ତି, ତେବେ ପୁରୁଣା ପାସୱାର୍ଡ ବ୍ୟବହାର କରନ୍ତୁ। ଆପଣ ସାଇନ୍ ଆଉଟ୍ କରିବା ପରେ ଆପଣଙ୍କ ନୂଆ ପାସୱାର୍ଡ ଲାଗୁ ହେବ।</translation>
+<translation id="885387440427703469">ସ୍କ୍ରିନ୍ କ୍ୟାପଚର୍ ଅକ୍ଷମ କରାଯାଇଛି</translation>
 <translation id="8870509716567206129">ଆପ୍‍ ସ୍ପ୍ଲିଟ୍‍-ସ୍କ୍ରୀନକୁ ସମର୍ଥନ କରେନାହିଁ।</translation>
 <translation id="8874184842967597500">ସଂଯୁକ୍ତ ନାହିଁ</translation>
 <translation id="8877788021141246043">ଗୋଟିଏ ରିମାଇଣ୍ଡର୍‌କୁ ସେଟ୍ କରନ୍ତୁ</translation>
diff --git a/ash/system/holding_space/holding_space_item_chip_view.cc b/ash/system/holding_space/holding_space_item_chip_view.cc
index 6b9d576e..d109c3b7 100644
--- a/ash/system/holding_space/holding_space_item_chip_view.cc
+++ b/ash/system/holding_space/holding_space_item_chip_view.cc
@@ -60,7 +60,7 @@
   SetFocusBehavior(FocusBehavior::ALWAYS);
   SetInkDropMode(InkDropMode::ON_NO_GESTURE_HANDLER);
   set_ink_drop_visible_opacity(ShelfConfig::Get()->GetInkDropVisibleOpacity());
-  set_notify_enter_exit_on_child(true);
+  SetNotifyEnterExitOnChild(true);
 
   // Ink drop layers should be clipped to match the corner radius of this view.
   views::InstallRoundRectHighlightPathGenerator(this, gfx::Insets(),
diff --git a/ash/system/network/network_state_list_detailed_view.cc b/ash/system/network/network_state_list_detailed_view.cc
index 25efb6d..0ba5a8409 100644
--- a/ash/system/network/network_state_list_detailed_view.cc
+++ b/ash/system/network/network_state_list_detailed_view.cc
@@ -115,7 +115,7 @@
     SetArrow(views::BubbleBorder::NONE);
     set_shadow(views::BubbleBorder::NO_ASSETS);
     set_anchor_view_insets(gfx::Insets(0, 0, kBubbleMargin, 0));
-    set_notify_enter_exit_on_child(true);
+    SetNotifyEnterExitOnChild(true);
     SetLayoutManager(std::make_unique<views::FillLayout>());
     AddChildView(content);
   }
diff --git a/ash/system/tray/actionable_view.cc b/ash/system/tray/actionable_view.cc
index 3870df2..a4627c5 100644
--- a/ash/system/tray/actionable_view.cc
+++ b/ash/system/tray/actionable_view.cc
@@ -27,7 +27,7 @@
       ink_drop_style_(ink_drop_style) {
   SetFocusBehavior(FocusBehavior::ALWAYS);
   set_has_ink_drop_action_on_click(false);
-  set_notify_enter_exit_on_child(true);
+  SetNotifyEnterExitOnChild(true);
   // TODO(pbos): Replace the use of FocusPainter with the FocusRing (using the
   // below HighlightPathGenerator).
   SetInstallFocusRingOnFocus(false);
diff --git a/ash/system/tray/hover_highlight_view.cc b/ash/system/tray/hover_highlight_view.cc
index 72970f8..4690422d 100644
--- a/ash/system/tray/hover_highlight_view.cc
+++ b/ash/system/tray/hover_highlight_view.cc
@@ -32,7 +32,7 @@
     : ActionableView(TrayPopupInkDropStyle::FILL_BOUNDS),
       listener_(listener),
       use_unified_theme_(use_unified_theme) {
-  set_notify_enter_exit_on_child(true);
+  SetNotifyEnterExitOnChild(true);
   SetInkDropMode(InkDropMode::ON);
 }
 
diff --git a/ash/system/tray/tray_background_view.cc b/ash/system/tray/tray_background_view.cc
index b22d7d2..149d4f66 100644
--- a/ash/system/tray/tray_background_view.cc
+++ b/ash/system/tray/tray_background_view.cc
@@ -159,7 +159,7 @@
       show_when_collapsed_(true),
       widget_observer_(new TrayWidgetObserver(this)) {
   DCHECK(shelf_);
-  set_notify_enter_exit_on_child(true);
+  SetNotifyEnterExitOnChild(true);
   set_ink_drop_base_color(ShelfConfig::Get()->GetInkDropBaseColor());
   set_ink_drop_visible_opacity(ShelfConfig::Get()->GetInkDropVisibleOpacity());
 
diff --git a/ash/system/tray/tray_bubble_view.cc b/ash/system/tray/tray_bubble_view.cc
index 37810db..4017715e 100644
--- a/ash/system/tray/tray_bubble_view.cc
+++ b/ash/system/tray/tray_bubble_view.cc
@@ -236,7 +236,7 @@
   bubble_border_->set_avoid_shadow_overlap(true);
   set_parent_window(params_.parent_window);
   SetCanActivate(false);
-  set_notify_enter_exit_on_child(true);
+  SetNotifyEnterExitOnChild(true);
   set_close_on_deactivate(init_params.close_on_deactivate);
   set_margins(gfx::Insets());
 
diff --git a/ash/wm/window_cycle_list.cc b/ash/wm/window_cycle_list.cc
index a9565ed..222eee14 100644
--- a/ash/wm/window_cycle_list.cc
+++ b/ash/wm/window_cycle_list.cc
@@ -122,7 +122,7 @@
  public:
   explicit WindowCycleItemView(aura::Window* window) : WindowMiniView(window) {
     SetFocusBehavior(FocusBehavior::ALWAYS);
-    set_notify_enter_exit_on_child(true);
+    SetNotifyEnterExitOnChild(true);
   }
   WindowCycleItemView(const WindowCycleItemView&) = delete;
   WindowCycleItemView& operator=(const WindowCycleItemView&) = delete;
diff --git a/base/BUILD.gn b/base/BUILD.gn
index ce8ed11..7bdb379 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -1304,38 +1304,47 @@
       "allocator/allocator_shim_override_cpp_symbols.h",
       "allocator/allocator_shim_override_libc_symbols.h",
     ]
+    if (is_android) {
+      sources +=
+          [ "allocator/allocator_shim_override_linker_wrapped_symbols.h" ]
+      all_dependent_configs += [ "//base/allocator:wrap_malloc_symbols" ]
+    }
+    if (is_apple) {
+      sources += [ "allocator/allocator_shim_override_mac_symbols.h" ]
+    }
+    if (is_chromeos || is_linux) {
+      sources += [ "allocator/allocator_shim_override_glibc_weak_symbols.h" ]
+    }
     if (is_win) {
       sources += [
-        "allocator/allocator_shim_default_dispatch_to_winheap.cc",
         "allocator/allocator_shim_override_ucrt_symbols_win.h",
         "allocator/winheap_stubs_win.cc",
         "allocator/winheap_stubs_win.h",
       ]
-    } else if ((is_linux || is_chromeos) && use_allocator == "tcmalloc") {
-      sources += [
-        "allocator/allocator_shim_default_dispatch_to_tcmalloc.cc",
-        "allocator/allocator_shim_override_glibc_weak_symbols.h",
-      ]
-      deps += [ "//base/allocator:tcmalloc" ]
-    } else if ((is_linux || is_chromeos) && use_allocator == "none") {
-      sources += [ "allocator/allocator_shim_default_dispatch_to_glibc.cc" ]
-    } else if ((is_linux || is_chromeos || is_android) &&
-               use_allocator == "partition") {
+    }
+
+    if (use_allocator == "partition") {
       sources +=
           [ "allocator/allocator_shim_default_dispatch_to_partition_alloc.cc" ]
-    } else if (is_android) {
-      sources +=
-          [ "allocator/allocator_shim_override_linker_wrapped_symbols.h" ]
-      all_dependent_configs += [ "//base/allocator:wrap_malloc_symbols" ]
-      if (use_allocator == "none") {
+    } else if (use_allocator == "tcmalloc") {
+      sources += [ "allocator/allocator_shim_default_dispatch_to_tcmalloc.cc" ]
+      deps += [ "//base/allocator:tcmalloc" ]
+    } else if (use_allocator == "none") {
+      if (is_android) {
         sources += [ "allocator/allocator_shim_default_dispatch_to_linker_wrapped_symbols.cc" ]
       }
-    } else if (is_apple) {
-      sources += [
-        "allocator/allocator_shim_default_dispatch_to_mac_zoned_malloc.cc",
-        "allocator/allocator_shim_default_dispatch_to_mac_zoned_malloc.h",
-        "allocator/allocator_shim_override_mac_symbols.h",
-      ]
+      if (is_apple) {
+        sources += [
+          "allocator/allocator_shim_default_dispatch_to_mac_zoned_malloc.cc",
+          "allocator/allocator_shim_default_dispatch_to_mac_zoned_malloc.h",
+        ]
+      }
+      if (is_chromeos || is_linux) {
+        sources += [ "allocator/allocator_shim_default_dispatch_to_glibc.cc" ]
+      }
+      if (is_win) {
+        sources += [ "allocator/allocator_shim_default_dispatch_to_winheap.cc" ]
+      }
     }
   }
 
@@ -1767,6 +1776,7 @@
         "allocator/partition_allocator/partition_cookie.h",
         "allocator/partition_allocator/partition_direct_map_extent.h",
         "allocator/partition_allocator/partition_freelist_entry.h",
+        "allocator/partition_allocator/partition_lock.cc",
         "allocator/partition_allocator/partition_lock.h",
         "allocator/partition_allocator/partition_oom.cc",
         "allocator/partition_allocator/partition_oom.h",
@@ -1778,8 +1788,6 @@
         "allocator/partition_allocator/partition_tag_bitmap.h",
         "allocator/partition_allocator/random.cc",
         "allocator/partition_allocator/random.h",
-        "allocator/partition_allocator/thread_cache.cc",
-        "allocator/partition_allocator/thread_cache.h",
       ]
       if (is_win) {
         sources +=
@@ -3201,7 +3209,6 @@
       "allocator/partition_allocator/memory_reclaimer_unittest.cc",
       "allocator/partition_allocator/page_allocator_unittest.cc",
       "allocator/partition_allocator/partition_alloc_unittest.cc",
-      "allocator/partition_allocator/thread_cache_unittest.cc",
     ]
   }
 
diff --git a/base/allocator/allocator_interception_mac.h b/base/allocator/allocator_interception_mac.h
index 68f1d53..c206c656 100644
--- a/base/allocator/allocator_interception_mac.h
+++ b/base/allocator/allocator_interception_mac.h
@@ -15,6 +15,11 @@
 
 struct MallocZoneFunctions;
 
+// This initializes AllocatorDispatch::default_dispatch by saving pointers to
+// the functions in the current default malloc zone. This must be called before
+// the default malloc zone is changed to have its intended effect.
+void InitializeDefaultDispatchToMacAllocator();
+
 // Saves the function pointers currently used by the default zone.
 void StoreFunctionsForDefaultZone();
 
diff --git a/base/allocator/allocator_interception_mac.mm b/base/allocator/allocator_interception_mac.mm
index 10f2b97..3d7299c 100644
--- a/base/allocator/allocator_interception_mac.mm
+++ b/base/allocator/allocator_interception_mac.mm
@@ -310,6 +310,10 @@
   return *result != NULL;
 }
 
+void InitializeDefaultDispatchToMacAllocator() {
+  StoreFunctionsForAllZones();
+}
+
 void StoreFunctionsForDefaultZone() {
   ChromeMallocZone* default_zone = reinterpret_cast<ChromeMallocZone*>(
       malloc_default_zone());
diff --git a/base/allocator/allocator_shim.cc b/base/allocator/allocator_shim.cc
index b1518ec..216337b 100644
--- a/base/allocator/allocator_shim.cc
+++ b/base/allocator/allocator_shim.cc
@@ -329,7 +329,6 @@
 // On Windows we use plain link-time overriding of the CRT symbols.
 #include "base/allocator/allocator_shim_override_ucrt_symbols_win.h"
 #elif defined(OS_APPLE)
-#include "base/allocator/allocator_shim_default_dispatch_to_mac_zoned_malloc.h"
 #include "base/allocator/allocator_shim_override_mac_symbols.h"
 #else
 #include "base/allocator/allocator_shim_override_libc_symbols.h"
diff --git a/base/allocator/allocator_shim_default_dispatch_to_mac_zoned_malloc.cc b/base/allocator/allocator_shim_default_dispatch_to_mac_zoned_malloc.cc
index 55e17bb..9e3cedc 100644
--- a/base/allocator/allocator_shim_default_dispatch_to_mac_zoned_malloc.cc
+++ b/base/allocator/allocator_shim_default_dispatch_to_mac_zoned_malloc.cc
@@ -88,10 +88,6 @@
 
 }  // namespace
 
-void InitializeDefaultDispatchToMacAllocator() {
-  StoreFunctionsForAllZones();
-}
-
 const AllocatorDispatch AllocatorDispatch::default_dispatch = {
     &MallocImpl,           /* alloc_function */
     &CallocImpl,           /* alloc_zero_initialized_function */
diff --git a/base/allocator/allocator_shim_default_dispatch_to_mac_zoned_malloc.h b/base/allocator/allocator_shim_default_dispatch_to_mac_zoned_malloc.h
index 77d533c1..c248203 100644
--- a/base/allocator/allocator_shim_default_dispatch_to_mac_zoned_malloc.h
+++ b/base/allocator/allocator_shim_default_dispatch_to_mac_zoned_malloc.h
@@ -8,11 +8,6 @@
 namespace base {
 namespace allocator {
 
-// This initializes AllocatorDispatch::default_dispatch by saving pointers to
-// the functions in the current default malloc zone. This must be called before
-// the default malloc zone is changed to have its intended effect.
-void InitializeDefaultDispatchToMacAllocator();
-
 }  // namespace allocator
 }  // namespace base
 
diff --git a/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc b/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc
index 92b2a8d4..85fbbca 100644
--- a/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc
+++ b/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc
@@ -5,9 +5,9 @@
 #include "base/allocator/allocator_shim.h"
 #include "base/allocator/allocator_shim_internals.h"
 #include "base/allocator/partition_allocator/partition_alloc.h"
-#include "base/allocator/partition_allocator/partition_alloc_constants.h"
 #include "base/bits.h"
 #include "base/no_destructor.h"
+#include "build/build_config.h"
 
 namespace {
 
@@ -74,8 +74,8 @@
     return *root;
   }
 
-  auto* new_root = new (g_allocator_buffer) base::ThreadSafePartitionRoot(
-      false /* enforce_alignment */, true /* enable_thread_cache */);
+  auto* new_root = new (g_allocator_buffer)
+      base::ThreadSafePartitionRoot(false /* enforce_alignment */);
   g_root_.store(new_root, std::memory_order_release);
 
   // Semantically equivalent to base::Lock::Release().
@@ -100,9 +100,8 @@
                         size_t alignment,
                         size_t size,
                         void* context) {
-  // Since the general-purpose allocator uses the thread cache, this one cannot.
   static base::NoDestructor<base::ThreadSafePartitionRoot> aligned_allocator{
-      true /* enforce_alignment */, false /* enable_thread_cache */};
+      true /* enforce_alignment */};
   return aligned_allocator->AlignedAllocFlags(base::PartitionAllocNoHooks,
                                               alignment, size);
 }
@@ -151,12 +150,16 @@
 
 extern "C" {
 
+#if !defined(OS_APPLE)
+
 SHIM_ALWAYS_EXPORT void malloc_stats(void) __THROW {}
 
 SHIM_ALWAYS_EXPORT int mallopt(int cmd, int value) __THROW {
   return 0;
 }
 
+#endif  // !defined(OS_APPLE)
+
 #ifdef HAVE_STRUCT_MALLINFO
 SHIM_ALWAYS_EXPORT struct mallinfo mallinfo(void) __THROW {
   return {};
diff --git a/base/allocator/allocator_shim_internals.h b/base/allocator/allocator_shim_internals.h
index 0196f89..da1e5a6 100644
--- a/base/allocator/allocator_shim_internals.h
+++ b/base/allocator/allocator_shim_internals.h
@@ -5,6 +5,8 @@
 #ifndef BASE_ALLOCATOR_ALLOCATOR_SHIM_INTERNALS_H_
 #define BASE_ALLOCATOR_ALLOCATOR_SHIM_INTERNALS_H_
 
+#include "build/build_config.h"
+
 #if defined(__GNUC__)
 
 #include <sys/cdefs.h>  // for __THROW
@@ -39,6 +41,11 @@
 // impression that they can hook the allocator.
 #define SHIM_ALWAYS_EXPORT __attribute__((visibility("default"), noinline))
 
+#elif defined(OS_WIN)  // __GNUC__
+
+#define __THROW
+#define SHIM_ALWAYS_EXPORT __declspec(noinline)
+
 #endif  // __GNUC__
 
 #endif  // BASE_ALLOCATOR_ALLOCATOR_SHIM_INTERNALS_H_
diff --git a/base/allocator/partition_allocator/partition_alloc.cc b/base/allocator/partition_allocator/partition_alloc.cc
index 6fd2622..869efdcc 100644
--- a/base/allocator/partition_allocator/partition_alloc.cc
+++ b/base/allocator/partition_allocator/partition_alloc.cc
@@ -203,8 +203,7 @@
 }
 
 template <bool thread_safe>
-void PartitionRoot<thread_safe>::Init(bool enforce_alignment,
-                                      bool enable_thread_cache) {
+void PartitionRoot<thread_safe>::Init(bool enforce_alignment) {
   ScopedGuard guard{lock_};
   if (initialized)
     return;
@@ -218,10 +217,6 @@
   // If alignment needs to be enforced, disallow adding cookies and/or tags at
   // the beginning of the slot.
   allow_extras = !enforce_alignment;
-  with_thread_cache = enable_thread_cache;
-
-  if (with_thread_cache)
-    internal::ThreadCache::ClaimThreadCacheAndCheck();
 
   // We mark the sentinel bucket/page as free to make sure it is skipped by our
   // logic to find a new active page.
@@ -288,9 +283,6 @@
 }
 
 template <bool thread_safe>
-PartitionRoot<thread_safe>::~PartitionRoot() = default;
-
-template <bool thread_safe>
 bool PartitionRoot<thread_safe>::ReallocDirectMappedInPlace(
     internal::PartitionPage<thread_safe>* page,
     size_t raw_size) {
@@ -629,10 +621,6 @@
         PartitionPurgeBucket(bucket);
     }
   }
-
-  // Purges only this thread's cache.
-  if (with_thread_cache && internal::g_thread_cache)
-    internal::g_thread_cache->Purge();
 }
 
 template <bool thread_safe>
@@ -820,8 +808,7 @@
     PartitionAllocatorAlignment alignment) {
   partition_root_.Init(
       alignment ==
-          PartitionAllocatorAlignment::kAlignedAlloc /* enforce_alignment */,
-      false);
+      PartitionAllocatorAlignment::kAlignedAlloc /* enforce_alignment */);
   PartitionAllocMemoryReclaimer::Instance()->RegisterPartition(
       &partition_root_);
 }
diff --git a/base/allocator/partition_allocator/partition_alloc.h b/base/allocator/partition_allocator/partition_alloc.h
index 7b8f0c31..1f335d9 100644
--- a/base/allocator/partition_allocator/partition_alloc.h
+++ b/base/allocator/partition_allocator/partition_alloc.h
@@ -53,7 +53,6 @@
 
 #include <limits.h>
 #include <string.h>
-#include <memory>
 
 #include <atomic>
 
@@ -69,7 +68,6 @@
 #include "base/allocator/partition_allocator/partition_page.h"
 #include "base/allocator/partition_allocator/partition_ref_count.h"
 #include "base/allocator/partition_allocator/partition_tag.h"
-#include "base/allocator/partition_allocator/thread_cache.h"
 #include "base/base_export.h"
 #include "base/bits.h"
 #include "base/check_op.h"
@@ -373,8 +371,6 @@
   using DirectMapExtent = internal::PartitionDirectMapExtent<thread_safe>;
   using ScopedGuard = internal::ScopedGuard<thread_safe>;
 
-  bool with_thread_cache = false;
-
   internal::MaybeSpinLock<thread_safe> lock_;
   // Invariant: total_size_of_committed_pages <=
   //                total_size_of_super_pages +
@@ -413,10 +409,10 @@
   Bucket buckets[kNumBuckets] = {};
 
   PartitionRoot() = default;
-  PartitionRoot(bool enable_tag_pointers, bool enable_thread_cache) {
-    Init(enable_tag_pointers, enable_thread_cache);
+  explicit PartitionRoot(bool enable_tag_pointers) {
+    Init(enable_tag_pointers);
   }
-  ~PartitionRoot();
+  ~PartitionRoot() = default;
 
   // Public API
   //
@@ -428,7 +424,7 @@
   //
   // Moving it a layer lower couples PartitionRoot and PartitionBucket, but
   // preserves the layering of the includes.
-  void Init(bool enforce_alignment, bool enable_thread_cache);
+  void Init(bool enforce_alignment);
 
   ALWAYS_INLINE static bool IsValidPage(Page* page);
   ALWAYS_INLINE static PartitionRoot* FromPage(Page* page);
@@ -466,7 +462,9 @@
   // this is marked |ALWAYS_INLINE|.
   ALWAYS_INLINE void* AllocFlagsNoHooks(int flags, size_t size);
 
-  ALWAYS_INLINE void* Realloc(void* ptr, size_t newize, const char* type_name);
+  ALWAYS_INLINE void* Realloc(void* ptr,
+                              size_t new_size,
+                              const char* type_name);
   // Overload that may return nullptr if reallocation isn't possible. In this
   // case, |ptr| remains valid.
   ALWAYS_INLINE void* TryRealloc(void* ptr,
@@ -497,18 +495,13 @@
   // Frees memory, with |ptr| as returned by |RawAlloc()|.
   ALWAYS_INLINE void RawFree(void* ptr, Page* page);
 
-  internal::ThreadCache* thread_cache_for_testing() const {
-    return with_thread_cache ? internal::g_thread_cache.get() : nullptr;
-  }
-
  private:
   // Allocates memory, without any cookies / tags.
   //
   // |flags| and |size| are as in AllocFlags(). |allocated_size| and
   // is_already_zeroed| are output only. |allocated_size| is guaranteed to be
   // larger or equal to |size|.
-  ALWAYS_INLINE void* RawAlloc(Bucket* bucket,
-                               int flags,
+  ALWAYS_INLINE void* RawAlloc(int flags,
                                size_t size,
                                size_t* allocated_size,
                                bool* is_already_zeroed);
@@ -530,13 +523,13 @@
 #endif
   }
 
+ private:
+  ALWAYS_INLINE void* AllocFromBucket(Bucket* bucket, int flags, size_t size)
+      EXCLUSIVE_LOCKS_REQUIRED(lock_);
   bool ReallocDirectMappedInPlace(internal::PartitionPage<thread_safe>* page,
                                   size_t raw_size)
       EXCLUSIVE_LOCKS_REQUIRED(lock_);
   void DecommitEmptyPages() EXCLUSIVE_LOCKS_REQUIRED(lock_);
-  static void RawFreeStatic(void* ptr);
-
-  friend class internal::ThreadCache;
 };
 
 static_assert(sizeof(PartitionRoot<internal::ThreadSafe>) ==
@@ -619,15 +612,6 @@
 // static
 template <bool thread_safe>
 ALWAYS_INLINE void PartitionRoot<thread_safe>::FreeNoHooks(void* ptr) {
-  // The thread cache is added "in the middle" of the main allocator, that is:
-  // - After all the cookie/tag management
-  // - Before the "raw" allocator.
-  //
-  // On the deallocation side:
-  // 1. Check cookies / tags, adjust the pointer
-  // 2. Deallocation
-  //   a. Return to the thread cache of possible. If it succeeds, return.
-  //   b. Otherwise, call the "raw" allocator <-- Locking
   if (UNLIKELY(!ptr))
     return;
 
@@ -694,19 +678,6 @@
   memset(ptr, kFreedByte, page->GetAllocatedSize());
 #endif
 
-  // TLS access can be expensive, do a cheap local check first.
-  //
-  // Also the thread-unsafe variant doesn't have a use for a thread cache, so
-  // make it statically known to the compiler.
-  if (thread_safe && root->with_thread_cache &&
-      LIKELY(!page->bucket->is_direct_mapped())) {
-    PA_DCHECK(page->bucket >= root->buckets);
-    size_t bucket_index = page->bucket - root->buckets;
-    internal::ThreadCache* thread_cache = internal::g_thread_cache.get();
-    if (thread_cache && thread_cache->MaybePutInCache(ptr, bucket_index))
-      return;
-  }
-
   root->RawFree(ptr, page);
 }
 
@@ -722,14 +693,6 @@
 
 // static
 template <bool thread_safe>
-void PartitionRoot<thread_safe>::RawFreeStatic(void* ptr) {
-  Page* page = Page::FromPointerNoAlignmentCheck(ptr);
-  auto* root = PartitionRoot<thread_safe>::FromPage(page);
-  root->RawFree(ptr, page);
-}
-
-// static
-template <bool thread_safe>
 ALWAYS_INLINE bool PartitionRoot<thread_safe>::IsValidPage(Page* page) {
   PartitionRoot* root = FromPage(page);
   return root->inverted_self == ~reinterpret_cast<uintptr_t>(root);
@@ -848,6 +811,7 @@
   size_t sub_order_index = size & kOrderSubIndexMask[order];
   Bucket* bucket = bucket_lookups[(order << kNumBucketsPerOrderBits) +
                                   order_index + !!sub_order_index];
+  PA_CHECK(bucket);
   PA_DCHECK(!bucket->slot_size || bucket->slot_size >= size);
   PA_DCHECK(!(bucket->slot_size % kSmallestBucket));
   return bucket;
@@ -870,7 +834,7 @@
   return result;
 #else
   PA_DCHECK(initialized);
-  void* ret = nullptr;
+  void* ret;
   const bool hooks_enabled = PartitionAllocHooks::AreHooksEnabled();
   if (UNLIKELY(hooks_enabled)) {
     if (PartitionAllocHooks::AllocationOverrideHookIfEnabled(&ret, flags, size,
@@ -894,63 +858,13 @@
 template <bool thread_safe>
 ALWAYS_INLINE void* PartitionRoot<thread_safe>::AllocFlagsNoHooks(int flags,
                                                                   size_t size) {
-  // The thread cache is added "in the middle" of the main allocator, that is:
-  // - After all the cookie/tag management
-  // - Before the "raw" allocator.
-  //
-  // That is, the general allocation flow is:
-  // 1. Adjustment of requested size to make room for tags / cookies
-  // 2. Allocation:
-  //   a. Call to the thread cache, if it succeeds, go to step 3.
-  //   b. Otherwise, call the "raw" allocator <-- Locking
-  // 3. Handle cookies/tags, zero allocation if required
   size_t requested_size = size;
   size = internal::PartitionSizeAdjustAdd(allow_extras, size);
   PA_CHECK(size >= requested_size);  // check for overflows
 
-  auto* bucket = SizeToBucket(size);
   size_t allocated_size;
   bool is_already_zeroed;
-  void* ret = nullptr;
-
-  // !thread_safe => !with_thread_cache, but adding the condition allows the
-  // compiler to statically remove this branch for the thread-unsafe variant.
-  if (thread_safe && with_thread_cache) {
-    if (UNLIKELY(!internal::g_thread_cache))
-      internal::g_thread_cache = internal::ThreadCache::Create(this);
-    // bucket->slot_size is 0 for direct-mapped allocations, as their bucket is
-    // the sentinel one. However, since we are touching *bucket, we may as well
-    // check it directly, rather than fetching the sentinel one, and comparing
-    // the addresses. Since the sentinel bucket is *not* part of the the buckets
-    // array, |bucket_index| is not valid for the sentinel one.
-    //
-    // TODO(lizeb): Consider making Bucket::sentinel per-PartitionRoot, at the
-    // end of the |buckets| array. This would remove this branch.
-    if (LIKELY(bucket->slot_size)) {
-      PA_DCHECK(bucket != Bucket::get_sentinel_bucket());
-      PA_DCHECK(bucket >= buckets && bucket < (buckets + kNumBuckets));
-      size_t bucket_index = bucket - buckets;
-      ret = internal::g_thread_cache->GetFromCache(bucket_index);
-      is_already_zeroed = false;
-      allocated_size = bucket->slot_size;
-
-#if DCHECK_IS_ON()
-      // Make sure that the allocated pointer comes from the same place it would
-      // for a non-thread cache allocation.
-      if (ret) {
-        Page* page = Page::FromPointerNoAlignmentCheck(ret);
-        PA_DCHECK(IsValidPage(page));
-        PA_DCHECK(page->bucket == &buckets[bucket_index]);
-      }
-#endif
-    } else {
-      PA_DCHECK(bucket == Bucket::get_sentinel_bucket());
-    }
-  }
-
-  if (!ret)
-    ret = RawAlloc(bucket, flags, size, &allocated_size, &is_already_zeroed);
-
+  void* ret = RawAlloc(flags, size, &allocated_size, &is_already_zeroed);
   if (UNLIKELY(!ret))
     return nullptr;
 
@@ -1011,14 +925,18 @@
 
 template <bool thread_safe>
 ALWAYS_INLINE void* PartitionRoot<thread_safe>::RawAlloc(
-    Bucket* bucket,
     int flags,
     size_t size,
     size_t* allocated_size,
     bool* is_already_zeroed) {
-  internal::ScopedGuard<thread_safe> guard{lock_};
-  return AllocFromBucket(bucket, flags, size, allocated_size,
-                         is_already_zeroed);
+  auto* bucket = SizeToBucket(size);
+  PA_DCHECK(bucket);
+
+  {
+    internal::ScopedGuard<thread_safe> guard{lock_};
+    return AllocFromBucket(bucket, flags, size, allocated_size,
+                           is_already_zeroed);
+  }
 }
 
 template <bool thread_safe>
diff --git a/base/allocator/partition_allocator/partition_alloc_perftest.cc b/base/allocator/partition_allocator/partition_alloc_perftest.cc
index 9f73792b..18ce987 100644
--- a/base/allocator/partition_allocator/partition_alloc_perftest.cc
+++ b/base/allocator/partition_allocator/partition_alloc_perftest.cc
@@ -2,10 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <algorithm>
 #include <atomic>
-#include <limits>
-#include <memory>
 #include <vector>
 
 #include "base/allocator/partition_allocator/partition_alloc.h"
@@ -33,7 +30,7 @@
 // Change kTimeLimit to something higher if you need more time to capture a
 // trace.
 constexpr base::TimeDelta kTimeLimit = base::TimeDelta::FromSeconds(2);
-constexpr int kWarmupRuns = 10000;
+constexpr int kWarmupRuns = 5;
 constexpr int kTimeCheckInterval = 100000;
 
 // Size constants are mostly arbitrary, but try to simulate something like CSS
@@ -81,10 +78,12 @@
   void* Alloc(size_t size) override {
     return alloc_.AllocFlagsNoHooks(0, size);
   }
-  void Free(void* data) override { ThreadSafePartitionRoot::FreeNoHooks(data); }
+  void Free(void* data) override {
+    base::ThreadSafePartitionRoot::FreeNoHooks(data);
+  }
 
  private:
-  ThreadSafePartitionRoot alloc_{false, false};
+  base::ThreadSafePartitionRoot alloc_{false};
 };
 
 class TestLoopThread : public PlatformThread::Delegate {
diff --git a/base/allocator/partition_allocator/partition_lock.cc b/base/allocator/partition_allocator/partition_lock.cc
new file mode 100644
index 0000000..1af9089
--- /dev/null
+++ b/base/allocator/partition_allocator/partition_lock.cc
@@ -0,0 +1,106 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/allocator/partition_allocator/partition_lock.h"
+
+#if !DCHECK_IS_ON()
+
+#include "base/threading/platform_thread.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+#include <sched.h>
+#endif
+
+// The YIELD_PROCESSOR macro wraps an architecture specific-instruction that
+// informs the processor we're in a busy wait, so it can handle the branch more
+// intelligently and e.g. reduce power to our core or give more resources to the
+// other hyper-thread on this core. See the following for context:
+// https://software.intel.com/en-us/articles/benefitting-power-and-performance-sleep-loops
+//
+// The YIELD_THREAD macro tells the OS to relinquish our quantum. This is
+// basically a worst-case fallback, and if you're hitting it with any frequency
+// you really should be using a proper lock (such as |base::Lock|)rather than
+// these spinlocks.
+#if defined(OS_WIN)
+
+#define YIELD_PROCESSOR YieldProcessor()
+#define YIELD_THREAD SwitchToThread()
+
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+
+#if defined(ARCH_CPU_X86_64) || defined(ARCH_CPU_X86)
+#define YIELD_PROCESSOR __asm__ __volatile__("pause")
+#elif (defined(ARCH_CPU_ARMEL) && __ARM_ARCH >= 6) || defined(ARCH_CPU_ARM64)
+#define YIELD_PROCESSOR __asm__ __volatile__("yield")
+#elif defined(ARCH_CPU_MIPSEL)
+// The MIPS32 docs state that the PAUSE instruction is a no-op on older
+// architectures (first added in MIPS32r2). To avoid assembler errors when
+// targeting pre-r2, we must encode the instruction manually.
+#define YIELD_PROCESSOR __asm__ __volatile__(".word 0x00000140")
+#elif defined(ARCH_CPU_MIPS64EL) && __mips_isa_rev >= 2
+// Don't bother doing using .word here since r2 is the lowest supported mips64
+// that Chromium supports.
+#define YIELD_PROCESSOR __asm__ __volatile__("pause")
+#elif defined(ARCH_CPU_PPC64_FAMILY)
+#define YIELD_PROCESSOR __asm__ __volatile__("or 31,31,31")
+#elif defined(ARCH_CPU_S390_FAMILY)
+// just do nothing
+#define YIELD_PROCESSOR ((void)0)
+#endif  // ARCH
+
+#ifndef YIELD_PROCESSOR
+#warning "Processor yield not supported on this architecture."
+#define YIELD_PROCESSOR ((void)0)
+#endif
+
+#define YIELD_THREAD sched_yield()
+
+#else  // Other OS
+
+#warning "Thread yield not supported on this OS."
+#define YIELD_THREAD ((void)0)
+
+#endif  // OS_WIN
+
+namespace base {
+namespace internal {
+
+void SpinLock::AcquireSlow() {
+  // The value of |kYieldProcessorTries| is cargo culted from TCMalloc, Windows
+  // critical section defaults, and various other recommendations.
+  static const int kYieldProcessorTries = 1000;
+  // The value of |kYieldThreadTries| is completely made up.
+  static const int kYieldThreadTries = 10;
+  int yield_thread_count = 0;
+  do {
+    do {
+      for (int count = 0; count < kYieldProcessorTries; ++count) {
+        // Let the processor know we're spinning.
+        YIELD_PROCESSOR;
+        if (!lock_.load(std::memory_order_relaxed) &&
+            LIKELY(!lock_.exchange(true, std::memory_order_acquire)))
+          return;
+      }
+
+      if (yield_thread_count < kYieldThreadTries) {
+        ++yield_thread_count;
+        // Give the OS a chance to schedule something on this core.
+        YIELD_THREAD;
+      } else {
+        // At this point, it's likely that the lock is held by a lower priority
+        // thread that is unavailable to finish its work because of higher
+        // priority threads spinning here. Sleeping should ensure that they make
+        // progress.
+        PlatformThread::Sleep(TimeDelta::FromMilliseconds(1));
+      }
+    } while (lock_.load(std::memory_order_relaxed));
+  } while (UNLIKELY(lock_.exchange(true, std::memory_order_acquire)));
+}
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // !DCHECK_IS_ON()
diff --git a/base/allocator/partition_allocator/partition_lock.h b/base/allocator/partition_allocator/partition_lock.h
index 60f0456..9167697 100644
--- a/base/allocator/partition_allocator/partition_lock.h
+++ b/base/allocator/partition_allocator/partition_lock.h
@@ -6,9 +6,10 @@
 #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_LOCK_H_
 
 #include <atomic>
+#include <type_traits>
 
+#include "base/allocator/buildflags.h"
 #include "base/no_destructor.h"
-#include "base/partition_alloc_buildflags.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/platform_thread.h"
 #include "build/build_config.h"
@@ -38,6 +39,35 @@
   MaybeSpinLock<thread_safe>& lock_;
 };
 
+#if !DCHECK_IS_ON()
+// Spinlock. Do not use, to be removed. crbug.com/1061437.
+class BASE_EXPORT SpinLock {
+ public:
+  SpinLock() = default;
+  ~SpinLock() = default;
+
+  ALWAYS_INLINE void Acquire() {
+    if (LIKELY(!lock_.exchange(true, std::memory_order_acquire)))
+      return;
+    AcquireSlow();
+  }
+
+  ALWAYS_INLINE void Release() {
+    lock_.store(false, std::memory_order_release);
+  }
+
+  // Not supported.
+  void AssertAcquired() const {}
+
+ private:
+  // This is called if the initial attempt to acquire the lock fails. It's
+  // slower, but has a much better scheduling and power consumption behavior.
+  void AcquireSlow();
+
+  std::atomic_int lock_{0};
+};
+#endif  // !DCHECK_IS_ON()
+
 template <>
 class LOCKABLE MaybeSpinLock<true> {
  public:
@@ -90,14 +120,22 @@
   }
 
  private:
+#if DCHECK_IS_ON()
   // NoDestructor to avoid issues with the "static destruction order fiasco".
   //
-  // This also means that for DCHECK_IS_ON() builds we leak a lock when a
-  // partition is destructed. This will in practice only show in some tests, as
-  // partitions are not destructed in regular use. In addition, on most
-  // platforms, base::Lock doesn't allocate memory and neither does the OS
-  // library, and the destructor is a no-op.
+  // This also means that we leak a lock when a partition is destructed. This
+  // will in practice only show in some tests, as partitions are not destructed
+  // in regular use. In addition, on most platforms, base::Lock doesn't allocate
+  // memory and neither does the OS library, and the destructor is a no-op.
   base::NoDestructor<base::Lock> lock_;
+#else
+  // base::Lock is slower on the fast path than SpinLock, hence we still use it
+  // on non-DCHECK() builds. crbug.com/1125999
+  base::NoDestructor<SpinLock> lock_;
+  // base::NoDestructor is here to use the same code elsewhere, we are not
+  // leaking anything.
+  static_assert(std::is_trivially_destructible<SpinLock>::value, "");
+#endif
 
 #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && DCHECK_IS_ON()
   std::atomic<PlatformThreadRef> owning_thread_ref_ GUARDED_BY(lock_);
diff --git a/base/allocator/partition_allocator/thread_cache.cc b/base/allocator/partition_allocator/thread_cache.cc
deleted file mode 100644
index 0f170b2..0000000
--- a/base/allocator/partition_allocator/thread_cache.cc
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/allocator/partition_allocator/thread_cache.h"
-
-#include <sys/types.h>
-#include <atomic>
-#include <vector>
-
-#include "base/allocator/partition_allocator/partition_alloc.h"
-
-namespace base {
-
-namespace internal {
-
-// static
-std::unique_ptr<ThreadCache> ThreadCache::Create(
-    PartitionRoot<internal::ThreadSafe>* root) {
-  PA_CHECK(root);
-
-  // Placement new and RawAlloc() are used, as otherwise when this partition is
-  // the malloc() implementation, the memory allocated for the new thread cache
-  // would make this code reentrant.
-  //
-  // This also means that deallocation must use RawFreeStatic(), hence the
-  // operator delete() implementation below.
-  size_t allocated_size;
-  bool already_zeroed;
-
-  auto* bucket = root->SizeToBucket(sizeof(ThreadCache));
-  void* buffer =
-      root->RawAlloc(bucket, PartitionAllocZeroFill, sizeof(ThreadCache),
-                     &allocated_size, &already_zeroed);
-  ThreadCache* tcache = new (buffer) ThreadCache();
-  return std::unique_ptr<ThreadCache>(tcache);
-}
-
-void ThreadCache::operator delete(void* ptr) {
-  PartitionRoot<internal::ThreadSafe>::RawFreeStatic(ptr);
-}
-
-void ThreadCache::Purge() {
-  for (Bucket& bucket : buckets_) {
-    size_t count = bucket.count;
-
-    while (bucket.freelist_head) {
-      auto* entry = bucket.freelist_head;
-      bucket.freelist_head = EncodedPartitionFreelistEntry::Decode(entry->next);
-
-      PartitionRoot<ThreadSafe>::RawFreeStatic(entry);
-      count--;
-    }
-    CHECK_EQ(0u, count);
-    bucket.count = 0;
-  }
-}
-
-// Since |g_thread_cache| is shared, make sure that no more than one
-// PartitionRoot can use it.
-static std::atomic<bool> g_has_instance;
-
-// static
-void ThreadCache::ClaimThreadCacheAndCheck() {
-  bool expected = false;
-  if (!g_has_instance.compare_exchange_strong(expected, true,
-                                              std::memory_order_seq_cst,
-                                              std::memory_order_seq_cst)) {
-    PA_CHECK(false)
-        << "Only one PartitionRoot is allowed to have a thread cache";
-  }
-}
-
-}  // namespace internal
-
-}  // namespace base
diff --git a/base/allocator/partition_allocator/thread_cache.h b/base/allocator/partition_allocator/thread_cache.h
deleted file mode 100644
index 9c238b3d..0000000
--- a/base/allocator/partition_allocator/thread_cache.h
+++ /dev/null
@@ -1,165 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_THREAD_CACHE_H_
-#define BASE_ALLOCATOR_PARTITION_ALLOCATOR_THREAD_CACHE_H_
-
-#include <cstdint>
-#include <memory>
-
-#include "base/allocator/partition_allocator/partition_alloc_forward.h"
-#include "base/allocator/partition_allocator/partition_cookie.h"
-#include "base/allocator/partition_allocator/partition_freelist_entry.h"
-#include "base/base_export.h"
-#include "base/gtest_prod_util.h"
-#include "base/partition_alloc_buildflags.h"
-
-namespace base {
-
-namespace internal {
-
-class ThreadCache;
-#pragma clang diagnostic push
-// Silences the global destructor warning, as the name does not imply.
-#pragma clang diagnostic ignored "-Wglobal-constructors"
-#pragma clang diagnostic ignored "-Wexit-time-destructors"
-// This is *not* using base::NoDestructor<> as we do want the destructor to be
-// called when a thread is destroyed.
-//
-// Cannot be a static member of ThreadCache, as it is "dllexport" (BASE_EXPORT),
-// and that is not supported by the Windows linker.
-static thread_local std::unique_ptr<ThreadCache> g_thread_cache;
-#pragma clang diagnostic pop
-
-// Per-thread cache. *Not* threadsafe, must only be accessed from a single
-// thread.
-//
-// In practice, this is easily enforced as long as only |instance| is
-// manipulated, as it is a thread_local member. As such, any
-// |ThreadCache::instance->*()| call will necessarily be done from a single
-// thread.
-class BASE_EXPORT ThreadCache {
- public:
-  // Create a new ThreadCache associated with |root|.
-  static std::unique_ptr<ThreadCache> Create(PartitionRoot<ThreadSafe>* root);
-  static std::unique_ptr<ThreadCache> Create(
-      PartitionRoot<NotThreadSafe>* root) {
-    IMMEDIATE_CRASH();
-  }
-
-  ~ThreadCache();
-  void operator delete(void* ptr);
-  ThreadCache(const ThreadCache&) = delete;
-  ThreadCache(const ThreadCache&&) = delete;
-  ThreadCache& operator=(const ThreadCache&) = delete;
-
-  // CHECK()s that the thread cache has not been claimed by another
-  // PartitionRoot, and mark it as claimed.
-  static void ClaimThreadCacheAndCheck();
-
-  // Tries to put a memory block at |address| into the cache.
-  // The block comes from the bucket at index |bucket_index| from the partition
-  // this cache is for.
-  //
-  // Returns true if the memory was put in the cache, and false otherwise. This
-  // can happen either because the cache is full or the allocation was too
-  // large.
-  ALWAYS_INLINE bool MaybePutInCache(void* address, size_t bucket_index);
-
-  // Tries to allocate memory from the cache.
-  // Returns nullptr for failure.
-  //
-  // Has the same behavior as RawAlloc(), that is: no cookie nor tag handling.
-  ALWAYS_INLINE void* GetFromCache(size_t bucket_index);
-
-  // Empties the cache.
-  void Purge();
-
-  size_t bucket_count_for_testing(size_t index) const {
-    return buckets_[index].count;
-  }
-
- private:
-  ThreadCache() = default;
-
-  struct Bucket {
-    size_t count;
-    PartitionFreelistEntry* freelist_head;
-  };
-
-  // TODO(lizeb): Optimize the threshold, and define it as an allocation size
-  // rather than a bucket index.
-  static constexpr size_t kBucketCount = 40;
-  static_assert(
-      kBucketCount < kNumBuckets,
-      "Cannot have more cached buckets than what the allocator supports");
-  // TODO(lizeb): Tune this constant, and adapt it to the bucket size /
-  // allocation patterns.
-  static constexpr size_t kMaxCountPerBucket = 100;
-
-  Bucket buckets_[kBucketCount];
-
-  FRIEND_TEST_ALL_PREFIXES(ThreadCacheTest, LargeAllocationsAreNotCached);
-  FRIEND_TEST_ALL_PREFIXES(ThreadCacheTest, MultipleThreadCaches);
-};
-
-// Some platforms which don't build PartitionAlloc (iOS for instance) still end
-// up including partition_alloc.h, and then this file as a side-effect. The
-// proper fix is to fix these dependencies, and make partition_alloc.h inclusion
-// require USE_PARTITION_ALLOC.
-inline ThreadCache::~ThreadCache() {
-#if !BUILDFLAG(USE_PARTITION_ALLOC)
-  IMMEDIATE_CRASH();
-#else
-  Purge();
-#endif  // !BUILDFLAG(USE_PARTITION_ALLOC)
-}
-
-#if !BUILDFLAG(USE_PARTITION_ALLOC)
-inline void ThreadCache::operator delete(void* ptr) {}
-#endif  // !BUILDFLAG(USE_PARTITION_ALLOC)
-
-ALWAYS_INLINE bool ThreadCache::MaybePutInCache(void* address,
-                                                size_t bucket_index) {
-  if (bucket_index >= kBucketCount)
-    return false;
-
-  auto& bucket = buckets_[bucket_index];
-
-  if (bucket.count >= kMaxCountPerBucket)
-    return false;
-
-  PA_DCHECK(bucket.count != 0 || bucket.freelist_head == nullptr);
-
-  auto* entry = reinterpret_cast<PartitionFreelistEntry*>(address);
-  entry->next = PartitionFreelistEntry::Encode(bucket.freelist_head);
-  bucket.freelist_head = entry;
-  bucket.count++;
-  return true;
-}
-
-ALWAYS_INLINE void* ThreadCache::GetFromCache(size_t bucket_index) {
-  // Only handle "small" allocations.
-  if (bucket_index >= kBucketCount)
-    return nullptr;
-
-  auto& bucket = buckets_[bucket_index];
-  auto* result = bucket.freelist_head;
-  if (!result) {
-    PA_DCHECK(bucket.count == 0);
-    return nullptr;
-  }
-  PA_DCHECK(bucket.count != 0);
-  auto* next = EncodedPartitionFreelistEntry::Decode(result->next);
-  PA_DCHECK(result != next);
-  bucket.count--;
-  PA_DCHECK(bucket.count != 0 || !next);
-  bucket.freelist_head = next;
-  return result;
-}
-
-}  // namespace internal
-}  // namespace base
-
-#endif  // BASE_ALLOCATOR_PARTITION_ALLOCATOR_THREAD_CACHE_H_
diff --git a/base/allocator/partition_allocator/thread_cache_unittest.cc b/base/allocator/partition_allocator/thread_cache_unittest.cc
deleted file mode 100644
index 411d7ff6..0000000
--- a/base/allocator/partition_allocator/thread_cache_unittest.cc
+++ /dev/null
@@ -1,218 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/allocator/partition_allocator/thread_cache.h"
-
-#include <vector>
-
-#include "base/allocator/buildflags.h"
-#include "base/allocator/partition_allocator/partition_alloc.h"
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/synchronization/lock.h"
-#include "base/test/bind_test_util.h"
-#include "base/threading/platform_thread.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-// Only a single partition can have a thread cache at a time. When
-// PartitionAlloc is malloc(), it is already in use.
-//
-// With *SAN, PartitionAlloc is replaced in partition_alloc.h by ASAN, so we
-// cannot test the thread cache.
-#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && \
-    !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
-
-namespace base {
-namespace internal {
-
-namespace {
-
-class LambdaThreadDelegate : public PlatformThread::Delegate {
- public:
-  explicit LambdaThreadDelegate(OnceClosure f) : f_(std::move(f)) {}
-  void ThreadMain() override { std::move(f_).Run(); }
-
- private:
-  OnceClosure f_;
-};
-
-// Need to be a global object without a destructor, because the cache is a
-// global object with a destructor (to handle thread destruction), and the
-// PartitionRoot has to outlive it.
-//
-// Forbid extras, since they make finding out which bucket is used harder.
-NoDestructor<ThreadSafePartitionRoot> g_root{true, true};
-
-size_t BucketIndexForSize(size_t size) {
-  auto* bucket = g_root->SizeToBucket(size);
-  return bucket - g_root->buckets;
-}
-
-size_t FillThreadCacheAndReturnIndex(size_t size, size_t count = 1) {
-  size_t bucket_index = BucketIndexForSize(size);
-  std::vector<void*> allocated_data;
-
-  for (size_t i = 0; i < count; ++i) {
-    allocated_data.push_back(g_root->Alloc(size, ""));
-  }
-  for (void* ptr : allocated_data) {
-    g_root->Free(ptr);
-  }
-
-  return bucket_index;
-}
-
-}  // namespace
-
-class ThreadCacheTest : public ::testing::Test {
- protected:
-  void SetUp() override {
-    auto* tcache = g_root->thread_cache_for_testing();
-    if (tcache)
-      tcache->Purge();
-  }
-  void TearDown() override {}
-};
-
-TEST_F(ThreadCacheTest, Simple) {
-  const size_t kTestSize = 12;
-  void* ptr = g_root->Alloc(kTestSize, "");
-  ASSERT_TRUE(ptr);
-
-  // There is a cache.
-  auto* tcache = g_root->thread_cache_for_testing();
-  EXPECT_TRUE(tcache);
-
-  size_t index = BucketIndexForSize(kTestSize);
-  EXPECT_EQ(0u, tcache->bucket_count_for_testing(index));
-
-  g_root->Free(ptr);
-  // Freeing fills the thread cache.
-  EXPECT_EQ(1u, tcache->bucket_count_for_testing(index));
-
-  void* ptr2 = g_root->Alloc(kTestSize, "");
-  EXPECT_EQ(ptr, ptr2);
-  // Allocated from the thread cache.
-  EXPECT_EQ(0u, tcache->bucket_count_for_testing(index));
-}
-
-TEST_F(ThreadCacheTest, InexactSizeMatch) {
-  const size_t kTestSize = 12;
-  void* ptr = g_root->Alloc(kTestSize, "");
-  ASSERT_TRUE(ptr);
-
-  // There is a cache.
-  auto* tcache = g_root->thread_cache_for_testing();
-  EXPECT_TRUE(tcache);
-
-  size_t index = BucketIndexForSize(kTestSize);
-  EXPECT_EQ(0u, tcache->bucket_count_for_testing(index));
-
-  g_root->Free(ptr);
-  // Freeing fills the thread cache.
-  EXPECT_EQ(1u, tcache->bucket_count_for_testing(index));
-
-  void* ptr2 = g_root->Alloc(kTestSize + 1, "");
-  EXPECT_EQ(ptr, ptr2);
-  // Allocated from the thread cache.
-  EXPECT_EQ(0u, tcache->bucket_count_for_testing(index));
-}
-
-TEST_F(ThreadCacheTest, MultipleObjectsCachedPerBucket) {
-  size_t bucket_index = FillThreadCacheAndReturnIndex(100, 10);
-  auto* tcache = g_root->thread_cache_for_testing();
-  EXPECT_EQ(10u, tcache->bucket_count_for_testing(bucket_index));
-}
-
-TEST_F(ThreadCacheTest, ObjectsCachedCountIsLimited) {
-  size_t bucket_index = FillThreadCacheAndReturnIndex(100, 1000);
-  auto* tcache = g_root->thread_cache_for_testing();
-  EXPECT_LT(tcache->bucket_count_for_testing(bucket_index), 1000u);
-}
-
-TEST_F(ThreadCacheTest, Purge) {
-  size_t bucket_index = FillThreadCacheAndReturnIndex(100, 10);
-  auto* tcache = g_root->thread_cache_for_testing();
-  EXPECT_EQ(10u, tcache->bucket_count_for_testing(bucket_index));
-  tcache->Purge();
-  EXPECT_EQ(0u, tcache->bucket_count_for_testing(bucket_index));
-}
-
-TEST_F(ThreadCacheTest, NoCrossPartitionCache) {
-  const size_t kTestSize = 12;
-  ThreadSafePartitionRoot root{true, false};
-
-  size_t bucket_index = FillThreadCacheAndReturnIndex(kTestSize);
-  void* ptr = root.Alloc(kTestSize, "");
-  ASSERT_TRUE(ptr);
-
-  auto* tcache = g_root->thread_cache_for_testing();
-  EXPECT_EQ(1u, tcache->bucket_count_for_testing(bucket_index));
-
-  ThreadSafePartitionRoot::Free(ptr);
-  EXPECT_EQ(1u, tcache->bucket_count_for_testing(bucket_index));
-}
-
-#if ENABLE_THREAD_CACHE_STATISTICS  // Required to record hits and misses.
-TEST_F(ThreadCacheTest, LargeAllocationsAreNotCached) {
-  auto* tcache = g_root->thread_cache_for_testing();
-  size_t hits_before = tcache ? tcache->hits_ : 0;
-
-  FillThreadCacheAndReturnIndex(100 * 1024);
-  tcache = g_root->thread_cache_for_testing();
-  EXPECT_EQ(hits_before, tcache->hits_);
-}
-#endif
-
-TEST_F(ThreadCacheTest, MultipleThreadCaches) {
-  const size_t kTestSize = 100;
-  FillThreadCacheAndReturnIndex(kTestSize);
-  auto* parent_thread_tcache = g_root->thread_cache_for_testing();
-  ASSERT_TRUE(parent_thread_tcache);
-
-  LambdaThreadDelegate delegate{BindLambdaForTesting([&]() {
-    EXPECT_FALSE(g_root->thread_cache_for_testing());  // No allocations yet.
-    FillThreadCacheAndReturnIndex(kTestSize);
-    auto* tcache = g_root->thread_cache_for_testing();
-    EXPECT_TRUE(tcache);
-
-    EXPECT_NE(parent_thread_tcache, tcache);
-  })};
-
-  PlatformThreadHandle thread_handle;
-  PlatformThread::Create(0, &delegate, &thread_handle);
-  PlatformThread::Join(thread_handle);
-}
-
-TEST_F(ThreadCacheTest, ThreadCacheReclaimedWhenThreadExits) {
-  const size_t kTestSize = 100;
-  // Make sure that there is always at least one object allocated in the test
-  // bucket, so that the PartitionPage is no reclaimed.
-  void* tmp = g_root->Alloc(kTestSize, "");
-  void* other_thread_ptr;
-
-  LambdaThreadDelegate delegate{BindLambdaForTesting([&]() {
-    EXPECT_FALSE(g_root->thread_cache_for_testing());  // No allocations yet.
-    other_thread_ptr = g_root->Alloc(kTestSize, "");
-    g_root->Free(other_thread_ptr);
-    // |other_thread_ptr| is now in the thread cache.
-  })};
-
-  PlatformThreadHandle thread_handle;
-  PlatformThread::Create(0, &delegate, &thread_handle);
-  PlatformThread::Join(thread_handle);
-
-  void* this_thread_ptr = g_root->Alloc(kTestSize, "");
-  // |other_thread_ptr| was returned to the central allocator, and is returned
-  // |here, as is comes from the freelist.
-  EXPECT_EQ(this_thread_ptr, other_thread_ptr);
-  g_root->Free(other_thread_ptr);
-  g_root->Free(tmp);
-}
-
-}  // namespace internal
-}  // namespace base
-
-#endif  // !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) &&
-        // !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
diff --git a/base/strings/string_split.h b/base/strings/string_split.h
index 73c15d7..d8b218ef 100644
--- a/base/strings/string_split.h
+++ b/base/strings/string_split.h
@@ -45,8 +45,7 @@
 // To split on either commas or semicolons, keeping all whitespace:
 //
 //   std::vector<std::string> tokens = base::SplitString(
-//       input, ", WARN_UNUSED_RESULT;", base::KEEP_WHITESPACE,
-//       base::SPLIT_WANT_ALL) WARN_UNUSED_RESULT;
+//       input, ",;", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
 BASE_EXPORT std::vector<std::string> SplitString(StringPiece input,
                                                  StringPiece separators,
                                                  WhitespaceHandling whitespace,
diff --git a/base/threading/sequence_bound.h b/base/threading/sequence_bound.h
index 217a1d53..b7299ed 100644
--- a/base/threading/sequence_bound.h
+++ b/base/threading/sequence_bound.h
@@ -509,10 +509,10 @@
   // Note: this doesn't handle a void return type, which has an explicit
   // specialization below.
   template <typename ReturnType>
-  class AsyncCallWithBoundArgsBuilder
+  class AsyncCallWithBoundArgsBuilderDefault
       : public AsyncCallWithBoundArgsBuilderBase<ReturnType> {
    public:
-    ~AsyncCallWithBoundArgsBuilder() {
+    ~AsyncCallWithBoundArgsBuilderDefault() {
       // Must use Then() since the method's return type is not void.
       // Should be optimized out if the code is bug-free.
       CHECK(!this->sequence_bound_);
@@ -535,13 +535,13 @@
    private:
     friend SequenceBound;
 
-    AsyncCallWithBoundArgsBuilder(AsyncCallWithBoundArgsBuilder&&) = default;
-    AsyncCallWithBoundArgsBuilder& operator=(AsyncCallWithBoundArgsBuilder&&) =
-        default;
+    AsyncCallWithBoundArgsBuilderDefault(
+        AsyncCallWithBoundArgsBuilderDefault&&) = default;
+    AsyncCallWithBoundArgsBuilderDefault& operator=(
+        AsyncCallWithBoundArgsBuilderDefault&&) = default;
   };
 
-  template <>
-  class AsyncCallWithBoundArgsBuilder<void>
+  class AsyncCallWithBoundArgsBuilderVoid
       : public AsyncCallWithBoundArgsBuilderBase<void> {
    public:
     // Note: despite being here, this is actually still protected, since it is
@@ -549,7 +549,7 @@
     using AsyncCallWithBoundArgsBuilderBase<
         void>::AsyncCallWithBoundArgsBuilderBase;
 
-    ~AsyncCallWithBoundArgsBuilder() {
+    ~AsyncCallWithBoundArgsBuilderVoid() {
       if (this->sequence_bound_) {
         this->sequence_bound_->impl_task_runner_->PostTask(
             *this->location_, std::move(this->callback_));
@@ -566,11 +566,18 @@
    private:
     friend SequenceBound;
 
-    AsyncCallWithBoundArgsBuilder(AsyncCallWithBoundArgsBuilder&&) = default;
-    AsyncCallWithBoundArgsBuilder& operator=(AsyncCallWithBoundArgsBuilder&&) =
+    AsyncCallWithBoundArgsBuilderVoid(AsyncCallWithBoundArgsBuilderVoid&&) =
         default;
+    AsyncCallWithBoundArgsBuilderVoid& operator=(
+        AsyncCallWithBoundArgsBuilderVoid&&) = default;
   };
 
+  template <typename ReturnType>
+  using AsyncCallWithBoundArgsBuilder = typename std::conditional<
+      std::is_void<ReturnType>::value,
+      AsyncCallWithBoundArgsBuilderVoid,
+      AsyncCallWithBoundArgsBuilderDefault<ReturnType>>::type;
+
   void PostTaskAndThenHelper(const Location& location,
                              OnceCallback<void()> callback,
                              OnceClosure then_callback) {
diff --git a/build/apple/tweak_info_plist.py b/build/apple/tweak_info_plist.py
index ff11acbf..7f47e762 100755
--- a/build/apple/tweak_info_plist.py
+++ b/build/apple/tweak_info_plist.py
@@ -43,22 +43,8 @@
   """Runs a subprocess and waits for termination. Returns (stdout, returncode)
   of the process. stderr is attached to the parent."""
   proc = subprocess.Popen(args, stdout=subprocess.PIPE)
-  (stdout, stderr) = proc.communicate()
-  return (stdout, proc.returncode)
-
-
-def _GetOutputNoError(args):
-  """Similar to _GetOutput() but ignores stderr. If there's an error launching
-  the child (like file not found), the exception will be caught and (None, 1)
-  will be returned to mimic quiet failure."""
-  try:
-    proc = subprocess.Popen(args,
-                            stdout=subprocess.PIPE,
-                            stderr=subprocess.PIPE)
-  except OSError:
-    return (None, 1)
-  (stdout, stderr) = proc.communicate()
-  return (stdout, proc.returncode)
+  stdout, _ = proc.communicate()
+  return stdout.decode('UTF-8'), proc.returncode
 
 
 def _RemoveKeys(plist, *keys):
@@ -194,9 +180,9 @@
   components_len = len(components)
   combinations = 1 << components_len
   tag_suffixes = []
-  for combination in xrange(0, combinations):
+  for combination in range(0, combinations):
     tag_suffix = ''
-    for component_index in xrange(0, components_len):
+    for component_index in range(0, components_len):
       if combination & (1 << component_index):
         tag_suffix += '-' + components[component_index]
     tag_suffixes.append(tag_suffix)
diff --git a/build/config/ios/codesign.py b/build/config/ios/codesign.py
index 994981e..1c6e3ce 100644
--- a/build/config/ios/codesign.py
+++ b/build/config/ios/codesign.py
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from __future__ import print_function
+
 import argparse
 import codecs
 import datetime
@@ -15,6 +17,11 @@
 import sys
 import tempfile
 
+if sys.version_info.major < 3:
+  basestring_compat = basestring
+else:
+  basestring_compat = str
+
 
 def GetProvisioningProfilesDir():
   """Returns the location of the installed mobile provisioning profiles.
@@ -27,6 +34,21 @@
       os.environ['HOME'], 'Library', 'MobileDevice', 'Provisioning Profiles')
 
 
+def ReadPlistFromString(plist_bytes):
+  """Parse property list from given |plist_bytes|.
+
+    Args:
+      plist_bytes: contents of property list to load. Must be bytes in python 3.
+
+    Returns:
+      The contents of property list as a python object.
+    """
+  if sys.version_info.major == 2:
+    return plistlib.readPlistFromString(plist_bytes)
+  else:
+    return plistlib.loads(plist_bytes)
+
+
 def LoadPlistFile(plist_path):
   """Loads property list file at |plist_path|.
 
@@ -36,8 +58,9 @@
   Returns:
     The content of the property list file as a python object.
   """
-  return plistlib.readPlistFromString(subprocess.check_output([
-      'xcrun', 'plutil', '-convert', 'xml1', '-o', '-', plist_path]))
+  return ReadPlistFromString(
+      subprocess.check_output(
+          ['xcrun', 'plutil', '-convert', 'xml1', '-o', '-', plist_path]))
 
 
 class Bundle(object):
@@ -74,7 +97,7 @@
       error message. The dictionary will be empty if there are no errors.
     """
     errors = {}
-    for key, expected_value in expected_mappings.iteritems():
+    for key, expected_value in expected_mappings.items():
       if key in self._data:
         value = self._data[key]
         if value != expected_value:
@@ -88,9 +111,11 @@
   def __init__(self, provisioning_profile_path):
     """Initializes the ProvisioningProfile with data from profile file."""
     self._path = provisioning_profile_path
-    self._data = plistlib.readPlistFromString(subprocess.check_output([
-        'xcrun', 'security', 'cms', '-D', '-u', 'certUsageAnyCA',
-        '-i', provisioning_profile_path]))
+    self._data = ReadPlistFromString(
+        subprocess.check_output([
+            'xcrun', 'security', 'cms', '-D', '-u', 'certUsageAnyCA', '-i',
+            provisioning_profile_path
+        ]))
 
   @property
   def path(self):
@@ -155,13 +180,13 @@
     self._data = self._ExpandVariables(self._data, substitutions)
 
   def _ExpandVariables(self, data, substitutions):
-    if isinstance(data, str):
-      for key, substitution in substitutions.iteritems():
+    if isinstance(data, basestring_compat):
+      for key, substitution in substitutions.items():
         data = data.replace('$(%s)' % (key,), substitution)
       return data
 
     if isinstance(data, dict):
-      for key, value in data.iteritems():
+      for key, value in data.items():
         data[key] = self._ExpandVariables(value, substitutions)
       return data
 
@@ -172,7 +197,7 @@
     return data
 
   def LoadDefaults(self, defaults):
-    for key, value in defaults.iteritems():
+    for key, value in defaults.items():
       if key not in self._data:
         self._data[key] = value
 
diff --git a/build/config/ios/compile_xcassets.py b/build/config/ios/compile_xcassets.py
index c1f4680b..5ed43e8b 100644
--- a/build/config/ios/compile_xcassets.py
+++ b/build/config/ios/compile_xcassets.py
@@ -32,16 +32,18 @@
 # Regular expressions matching spurious messages from actool that should be
 # ignored (as they are bogus). Generally a bug should be filed with Apple
 # when adding a pattern here.
-SPURIOUS_PATTERNS = map(re.compile, [
-    # crbug.com/770634, likely a bug in Xcode 9.1 beta, remove once build
-    # requires a version of Xcode with a fix.
-    r'\[\]\[ipad\]\[76x76\]\[\]\[\]\[1x\]\[\]\[\]: notice: \(null\)',
+SPURIOUS_PATTERNS = [
+    re.compile(v) for v in [
+        # crbug.com/770634, likely a bug in Xcode 9.1 beta, remove once build
+        # requires a version of Xcode with a fix.
+        r'\[\]\[ipad\]\[76x76\]\[\]\[\]\[1x\]\[\]\[\]: notice: \(null\)',
 
-    # crbug.com/770634, likely a bug in Xcode 9.2 beta, remove once build
-    # requires a version of Xcode with a fix.
-    r'\[\]\[ipad\]\[76x76\]\[\]\[\]\[1x\]\[\]\[\]: notice: 76x76@1x app icons'
-    ' only apply to iPad apps targeting releases of iOS prior to 10.0.',
-])
+        # crbug.com/770634, likely a bug in Xcode 9.2 beta, remove once build
+        # requires a version of Xcode with a fix.
+        r'\[\]\[ipad\]\[76x76\]\[\]\[\]\[1x\]\[\]\[\]: notice: 76x76@1x app icons'
+        ' only apply to iPad apps targeting releases of iOS prior to 10.0.',
+    ]
+]
 
 # Map special type of asset catalog to the corresponding command-line
 # parameter that need to be passed to actool.
@@ -193,7 +195,7 @@
     stdout, _ = process.communicate()
 
     # Filter the output to remove all garbarge and to fix the paths.
-    stdout = FilterCompilerOutput(stdout, relative_paths)
+    stdout = FilterCompilerOutput(stdout.decode('UTF-8'), relative_paths)
 
     if process.returncode or stdout:
       sys.stderr.write(stdout)
diff --git a/build/config/ios/strip_arm64e.py b/build/config/ios/strip_arm64e.py
index 53a1a573..f21baf423 100644
--- a/build/config/ios/strip_arm64e.py
+++ b/build/config/ios/strip_arm64e.py
@@ -18,9 +18,9 @@
   if process.returncode:
     sys.stderr.write('error: command failed with retcode %d: %s\n\n' %
                      (process.returncode, ' '.join(map(repr, command))))
-    sys.stderr.write(errs)
+    sys.stderr.write(errs.decode('UTF-8', errors='ignore'))
     sys.exit(process.returncode)
-  return outs
+  return outs.decode('UTF-8')
 
 
 def check_call(command):
diff --git a/build/config/ios/write_framework_hmap.py b/build/config/ios/write_framework_hmap.py
index 08ea9e9e..ac467ee9 100644
--- a/build/config/ios/write_framework_hmap.py
+++ b/build/config/ios/write_framework_hmap.py
@@ -50,7 +50,7 @@
   count = len(filelist)
   capacity = NextGreaterPowerOf2(count)
   strings_offset = 24 + (12 * capacity)
-  max_value_length = len(max(filelist.items(), key=lambda (k,v):len(v))[1])
+  max_value_length = len(max(filelist.values(), key=lambda v: len(v)))
 
   out = open(output_name, 'wb')
   out.write(struct.pack('<LHHLLLL', magic, version, _reserved, strings_offset,
@@ -86,14 +86,17 @@
   for bucket in buckets:
     if bucket is not None:
       (file, path) = bucket
-      out.write(struct.pack('<%ds' % len(file), file))
-      out.write(struct.pack('<s', '\0'))
       base = os.path.dirname(path) + os.sep
-      out.write(struct.pack('<%ds' % len(base), base))
-      out.write(struct.pack('<s', '\0'))
       path = os.path.basename(path)
+      file = file.encode('UTF-8')
+      base = base.encode('UTF-8')
+      path = path.encode('UTF-8')
+      out.write(struct.pack('<%ds' % len(file), file))
+      out.write(struct.pack('<s', b'\0'))
+      out.write(struct.pack('<%ds' % len(base), base))
+      out.write(struct.pack('<s', b'\0'))
       out.write(struct.pack('<%ds' % len(path), path))
-      out.write(struct.pack('<s', '\0'))
+      out.write(struct.pack('<s', b'\0'))
 
 
 if __name__ == '__main__':
diff --git a/build/config/mac/package_framework.py b/build/config/mac/package_framework.py
index 7560409..0026f46 100644
--- a/build/config/mac/package_framework.py
+++ b/build/config/mac/package_framework.py
@@ -23,7 +23,7 @@
   # Foo.framework/Versions/Current symlink to it.
   if args.version:
     try:
-      os.makedirs(os.path.join(args.framework, VERSIONS, args.version), 0755)
+      os.makedirs(os.path.join(args.framework, VERSIONS, args.version), 0o755)
     except OSError as e:
       if e.errno != errno.EEXIST:
         raise e
diff --git a/build/config/mac/plist_util.py b/build/config/mac/plist_util.py
index 56e74e6..d89b4188 100644
--- a/build/config/mac/plist_util.py
+++ b/build/config/mac/plist_util.py
@@ -12,6 +12,10 @@
 import tempfile
 import shlex
 
+if sys.version_info.major < 3:
+  basestring_compat = basestring
+else:
+  basestring_compat = str
 
 # Xcode substitutes variables like ${PRODUCT_NAME} or $(PRODUCT_NAME) when
 # compiling Info.plist. It also supports supports modifiers like :identifier
@@ -80,10 +84,10 @@
     substitution.
   """
   if isinstance(value, dict):
-    return {k: Interpolate(v, substitutions) for k, v in value.iteritems()}
+    return {k: Interpolate(v, substitutions) for k, v in value.items()}
   if isinstance(value, list):
     return [Interpolate(v, substitutions) for v in value]
-  if isinstance(value, str):
+  if isinstance(value, basestring_compat):
     return InterpolateString(value, substitutions)
   return value
 
@@ -93,7 +97,7 @@
   fd, name = tempfile.mkstemp()
   try:
     subprocess.check_call(['plutil', '-convert', 'xml1', '-o', name, path])
-    with os.fdopen(fd, 'r') as f:
+    with os.fdopen(fd, 'rb') as f:
       return plistlib.readPlist(f)
   finally:
     os.unlink(name)
@@ -109,7 +113,7 @@
     # it does exist.
     if os.path.exists(path):
       os.unlink(path)
-    with os.fdopen(fd, 'w') as f:
+    with os.fdopen(fd, 'wb') as f:
       plistlib.writePlist(data, f)
     subprocess.check_call(['plutil', '-convert', format, '-o', path, name])
   finally:
@@ -134,7 +138,7 @@
     are concatenated.
   """
   result = plist1.copy()
-  for key, value in plist2.iteritems():
+  for key, value in plist2.items():
     if isinstance(value, dict):
       old_value = result.get(key)
       if isinstance(old_value, dict):
diff --git a/build/config/mac/sdk_info.py b/build/config/mac/sdk_info.py
index 1ad11d3..46f3435 100644
--- a/build/config/mac/sdk_info.py
+++ b/build/config/mac/sdk_info.py
@@ -13,6 +13,11 @@
 import subprocess
 import sys
 
+if sys.version_info.major < 3:
+  basestring_compat = basestring
+else:
+  basestring_compat = str
+
 # src directory
 ROOT_SRC_DIR = os.path.dirname(
     os.path.dirname(
@@ -61,7 +66,8 @@
     settings['xcode_build'] = version_plist['ProductBuildVersion']
     return
 
-  lines = subprocess.check_output(['xcodebuild', '-version']).splitlines()
+  lines = subprocess.check_output(['xcodebuild',
+                                   '-version']).decode('UTF-8').splitlines()
   settings['xcode_version'] = FormatVersion(lines[0].split()[-1])
   settings['xcode_version_int'] = int(settings['xcode_version'], 10)
   settings['xcode_build'] = lines[-1].split()[-1]
@@ -69,8 +75,8 @@
 
 def FillMachineOSBuild(settings):
   """Fills OS build number into |settings|."""
-  machine_os_build = subprocess.check_output(['sw_vers', '-buildVersion'],
-                                             universal_newlines=True).strip()
+  machine_os_build = subprocess.check_output(['sw_vers', '-buildVersion'
+                                              ]).decode('UTF-8').strip()
   settings['machine_os_build'] = machine_os_build
 
   # The reported build number is made up from the kernel major version number,
@@ -91,14 +97,17 @@
 
 def FillSDKPathAndVersion(settings, platform, xcode_version):
   """Fills the SDK path and version for |platform| into |settings|."""
-  settings['sdk_path'] = subprocess.check_output([
-      'xcrun', '-sdk', platform, '--show-sdk-path']).strip()
-  settings['sdk_version'] = subprocess.check_output([
-      'xcrun', '-sdk', platform, '--show-sdk-version']).strip()
-  settings['sdk_platform_path'] = subprocess.check_output([
-      'xcrun', '-sdk', platform, '--show-sdk-platform-path']).strip()
+  settings['sdk_path'] = subprocess.check_output(
+      ['xcrun', '-sdk', platform, '--show-sdk-path']).decode('UTF-8').strip()
+  settings['sdk_version'] = subprocess.check_output(
+      ['xcrun', '-sdk', platform,
+       '--show-sdk-version']).decode('UTF-8').strip()
+  settings['sdk_platform_path'] = subprocess.check_output(
+      ['xcrun', '-sdk', platform,
+       '--show-sdk-platform-path']).decode('UTF-8').strip()
   settings['sdk_build'] = subprocess.check_output(
-      ['xcrun', '-sdk', platform, '--show-sdk-build-version']).strip()
+      ['xcrun', '-sdk', platform,
+       '--show-sdk-build-version']).decode('UTF-8').strip()
 
 
 def CreateXcodeSymlinkAt(src, dst):
@@ -157,6 +166,6 @@
     value = settings[key]
     if args.create_symlink_at and '_path' in key:
       value = CreateXcodeSymlinkAt(value, args.create_symlink_at)
-    if isinstance(value, str):
+    if isinstance(value, basestring_compat):
       value = '"%s"' % value
     print('%s=%s' % (key, value))
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index b4bfd20..21c0165 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-0.20200910.0.1
+0.20200910.1.1
diff --git a/build/mac/find_sdk.py b/build/mac/find_sdk.py
index 58362bf..d86f310 100755
--- a/build/mac/find_sdk.py
+++ b/build/mac/find_sdk.py
@@ -65,7 +65,7 @@
     print(out, file=sys.stderr)
     print(err, file=sys.stderr)
     raise Exception('Error %d running xcode-select' % job.returncode)
-  dev_dir = out.rstrip()
+  dev_dir = out.decode('UTF-8').rstrip()
   sdk_dir = os.path.join(
       dev_dir, 'Platforms/MacOSX.platform/Developer/SDKs')
 
diff --git a/build/toolchain/mac/filter_libtool.py b/build/toolchain/mac/filter_libtool.py
index cbde5c65..8be2679 100644
--- a/build/toolchain/mac/filter_libtool.py
+++ b/build/toolchain/mac/filter_libtool.py
@@ -12,14 +12,16 @@
 # This script executes libool and filters out logspam lines like:
 #    '/path/to/libtool: file: foo.o has no symbols'
 
-BLACKLIST_PATTERNS = map(re.compile, [
-    r'^.*libtool: (?:for architecture: \S* )?file: .* has no symbols$',
-    r'^.*libtool: warning for library: .* the table of contents is empty '
+BLACKLIST_PATTERNS = [
+    re.compile(v) for v in [
+        r'^.*libtool: (?:for architecture: \S* )?file: .* has no symbols$',
+        r'^.*libtool: warning for library: .* the table of contents is empty '
         r'\(no object file members in the library define global symbols\)$',
-    r'^.*libtool: warning same member name \(\S*\) in output file used for '
+        r'^.*libtool: warning same member name \(\S*\) in output file used for '
         r'input files: \S* and: \S* \(due to use of basename, truncation, '
         r'blank padding or duplicate input files\)$',
-])
+    ]
+]
 
 
 def IsBlacklistedLine(line):
@@ -34,7 +36,7 @@
   env = os.environ.copy()
   libtoolout = subprocess.Popen(cmd_list, stderr=subprocess.PIPE, env=env)
   _, err = libtoolout.communicate()
-  for line in err.splitlines():
+  for line in err.decode('UTF-8').splitlines():
     if not IsBlacklistedLine(line):
       print(line, file=sys.stderr)
   return libtoolout.returncode
diff --git a/cc/metrics/compositor_frame_reporter.cc b/cc/metrics/compositor_frame_reporter.cc
index 872b81a..8aa63e34 100644
--- a/cc/metrics/compositor_frame_reporter.cc
+++ b/cc/metrics/compositor_frame_reporter.cc
@@ -214,18 +214,11 @@
     base::TimeDelta::FromSeconds(5);
 constexpr int kEventLatencyHistogramBucketCount = 100;
 
-bool ShouldReportLatencyMetricsForSequenceType(
-    FrameSequenceTrackerType sequence_type) {
-  return sequence_type != FrameSequenceTrackerType::kUniversal;
-}
-
 std::string GetCompositorLatencyHistogramName(
     const int report_type_index,
     FrameSequenceTrackerType frame_sequence_tracker_type,
     const int stage_type_index) {
   DCHECK_LE(frame_sequence_tracker_type, FrameSequenceTrackerType::kMaxType);
-  DCHECK(
-      ShouldReportLatencyMetricsForSequenceType(frame_sequence_tracker_type));
   const char* tracker_type_name =
       FrameSequenceTracker::GetFrameSequenceTrackerTypeName(
           frame_sequence_tracker_type);
@@ -538,7 +531,6 @@
     for (size_t fst_type = 0; fst_type < active_trackers_.size(); ++fst_type) {
       const auto tracker_type = static_cast<FrameSequenceTrackerType>(fst_type);
       if (!active_trackers_.test(fst_type) ||
-          tracker_type == FrameSequenceTrackerType::kUniversal ||
           tracker_type == FrameSequenceTrackerType::kCustom ||
           tracker_type == FrameSequenceTrackerType::kMaxType) {
         continue;
@@ -576,7 +568,6 @@
           UMA_HISTOGRAM_ENUMERATION("CompositorLatency.Type.ScrollbarScroll",
                                     report_type);
           break;
-        case FrameSequenceTrackerType::kUniversal:
         case FrameSequenceTrackerType::kCustom:
         case FrameSequenceTrackerType::kMaxType:
           NOTREACHED();
@@ -596,8 +587,6 @@
 void CompositorFrameReporter::ReportStageHistogramWithBreakdown(
     const CompositorFrameReporter::StageData& stage,
     FrameSequenceTrackerType frame_sequence_tracker_type) const {
-  if (!ShouldReportLatencyMetricsForSequenceType(frame_sequence_tracker_type))
-    return;
   base::TimeDelta stage_delta = stage.end_time - stage.start_time;
   ReportCompositorLatencyHistogram(frame_sequence_tracker_type,
                                    static_cast<int>(stage.stage_type),
diff --git a/cc/metrics/frame_sequence_metrics.cc b/cc/metrics/frame_sequence_metrics.cc
index 56c6157..0a688f5 100644
--- a/cc/metrics/frame_sequence_metrics.cc
+++ b/cc/metrics/frame_sequence_metrics.cc
@@ -105,7 +105,6 @@
   // SetScrollingThread().
   if ((thread_type == ThreadType::kCompositor ||
        thread_type == ThreadType::kMain) &&
-      type != FrameSequenceTrackerType::kUniversal &&
       type != FrameSequenceTrackerType::kCustom)
     jank_reporter_ = std::make_unique<JankMetrics>(type, thread_type);
 }
@@ -113,17 +112,8 @@
 FrameSequenceMetrics::~FrameSequenceMetrics() = default;
 
 void FrameSequenceMetrics::ReportLeftoverData() {
-  if (HasDataLeftForReporting()) {
-    // Do this before ReportMetrics() which clears the throughput data.
-    // TODO(xidachen): Find a way to make ThroughputUkmReporter to directly talk
-    // to LayerTreeHostClient, and submit throughput data. Instead of storing
-    // the values in ThroughputUkmReporter.
-    if (type_ == FrameSequenceTrackerType::kUniversal &&
-        HasEnoughDataForReporting()) {
-      throughput_ukm_reporter_->ComputeUniversalThroughput(this);
-    }
+  if (HasDataLeftForReporting())
     ReportMetrics();
-  }
 }
 
 void FrameSequenceMetrics::SetScrollingThread(ThreadType scrolling_thread) {
@@ -161,9 +151,6 @@
     case FrameSequenceTrackerType::kWheelScroll:
       return scrolling_thread_;
 
-    case FrameSequenceTrackerType::kUniversal:
-      return ThreadType::kSlower;
-
     case FrameSequenceTrackerType::kCustom:
       return ThreadType::kMain;
 
@@ -246,16 +233,14 @@
       main_throughput_);
 
   // Report for the 'slower thread' for the metrics where it makes sense.
-  bool should_report_slower_thread =
-      IsInteractionType(type_) || type_ == FrameSequenceTrackerType::kUniversal;
+  bool should_report_slower_thread = IsInteractionType(type_);
   base::Optional<int> aggregated_throughput_percent;
   if (should_report_slower_thread) {
     aggregated_throughput_percent = ThroughputData::ReportHistogram(
         this, ThreadType::kSlower,
         GetIndexForMetric(FrameSequenceMetrics::ThreadType::kSlower, type_),
         aggregated_throughput_);
-    if (aggregated_throughput_percent.has_value() && throughput_ukm_reporter_ &&
-        type_ != FrameSequenceTrackerType::kUniversal) {
+    if (aggregated_throughput_percent.has_value() && throughput_ukm_reporter_) {
       throughput_ukm_reporter_->ReportThroughputUkm(
           aggregated_throughput_percent, impl_throughput_percent,
           main_throughput_percent, type_);
@@ -426,7 +411,6 @@
   }
 
   if (!is_animation && !IsInteractionType(sequence_type) &&
-      sequence_type != FrameSequenceTrackerType::kUniversal &&
       sequence_type != FrameSequenceTrackerType::kVideo) {
     return base::nullopt;
   }
diff --git a/cc/metrics/frame_sequence_metrics.h b/cc/metrics/frame_sequence_metrics.h
index 8b0d56b..323dec4 100644
--- a/cc/metrics/frame_sequence_metrics.h
+++ b/cc/metrics/frame_sequence_metrics.h
@@ -24,7 +24,6 @@
   kPinchZoom = 2,
   kRAF = 3,
   kTouchScroll = 4,
-  kUniversal = 5,
   kVideo = 6,
   kWheelScroll = 7,
   kScrollbarScroll = 8,
diff --git a/cc/metrics/frame_sequence_metrics_unittest.cc b/cc/metrics/frame_sequence_metrics_unittest.cc
index e99209a7..6f514d1 100644
--- a/cc/metrics/frame_sequence_metrics_unittest.cc
+++ b/cc/metrics/frame_sequence_metrics_unittest.cc
@@ -27,28 +27,6 @@
   EXPECT_EQ(first.aggregated_throughput().frames_produced, 0u);
 }
 
-// Test that ThroughputUkmReporter::ReportThroughputUkm isn't called for the
-// kUniversal tracker.
-TEST(FrameSequenceMetricsTest, UniversalNotReportUkmAtRenderer) {
-  auto recorder = std::make_unique<ukm::TestUkmRecorder>();
-  auto ukm_manager = std::make_unique<UkmManager>(std::move(recorder));
-  ThroughputUkmReporter reporter(ukm_manager.get());
-  auto metric = std::make_unique<FrameSequenceMetrics>(
-      FrameSequenceTrackerType::kUniversal, &reporter);
-
-  metric->impl_throughput().frames_expected = 200u;
-  metric->impl_throughput().frames_produced = 190u;
-  metric->aggregated_throughput().frames_expected = 170u;
-  metric->aggregated_throughput().frames_produced = 150u;
-  metric->ReportMetrics();
-
-  // The corresponding |samples_to_next_event_| element is 0 if the
-  // ReportThroughputUkm isn't called.
-  EXPECT_EQ(reporter.GetSamplesToNextEventForTesting(
-                static_cast<int>(FrameSequenceTrackerType::kUniversal)),
-            1u);
-}
-
 TEST(FrameSequenceMetricsTest, MergeMetrics) {
   // Create a metric with only a small number of frames. It shouldn't report any
   // metrics.
@@ -139,20 +117,6 @@
       "Graphics.Smoothness.PercentDroppedFrames.MainThread.TouchScroll", 1u);
   // All the metrics have now been reported. No data should be left over.
   EXPECT_FALSE(first.HasDataLeftForReporting());
-
-  FrameSequenceMetrics third(FrameSequenceTrackerType::kUniversal, nullptr);
-  third.impl_throughput().frames_expected = 120;
-  third.impl_throughput().frames_produced = 80;
-  third.main_throughput().frames_expected = 120;
-  third.main_throughput().frames_produced = 80;
-  EXPECT_TRUE(third.HasEnoughDataForReporting());
-  third.ReportMetrics();
-
-  histograms.ExpectTotalCount(
-      "Graphics.Smoothness.PercentDroppedFrames.CompositorThread.Universal",
-      1u);
-  histograms.ExpectTotalCount(
-      "Graphics.Smoothness.PercentDroppedFrames.MainThread.Universal", 1u);
 }
 
 TEST(FrameSequenceMetricsTest, IrrelevantMetricsNotReported) {
diff --git a/cc/metrics/frame_sequence_tracker.cc b/cc/metrics/frame_sequence_tracker.cc
index 3d2f484c..56019f9 100644
--- a/cc/metrics/frame_sequence_tracker.cc
+++ b/cc/metrics/frame_sequence_tracker.cc
@@ -52,8 +52,6 @@
       return "RAF";
     case FrameSequenceTrackerType::kTouchScroll:
       return "TouchScroll";
-    case FrameSequenceTrackerType::kUniversal:
-      return "Universal";
     case FrameSequenceTrackerType::kVideo:
       return "Video";
     case FrameSequenceTrackerType::kWheelScroll:
diff --git a/cc/metrics/frame_sequence_tracker_collection.cc b/cc/metrics/frame_sequence_tracker_collection.cc
index bd5d684..1519c456 100644
--- a/cc/metrics/frame_sequence_tracker_collection.cc
+++ b/cc/metrics/frame_sequence_tracker_collection.cc
@@ -67,7 +67,6 @@
     metrics->SetScrollingThread(scrolling_thread);
   }
 
-  if (type != FrameSequenceTrackerType::kUniversal) {
     if (metrics->GetEffectiveThread() == ThreadType::kCompositor) {
       if (compositor_frame_reporting_controller_ &&
           compositor_thread_driving_smoothness_ == 0) {
@@ -84,7 +83,6 @@
       }
       ++main_thread_driving_smoothness_;
     }
-  }
   return frame_trackers_[key].get();
 }
 
@@ -133,7 +131,6 @@
         tracker->type());
   }
 
-  if (type != FrameSequenceTrackerType::kUniversal) {
     if (tracker->metrics()->GetEffectiveThread() == ThreadType::kCompositor) {
       DCHECK_GT(compositor_thread_driving_smoothness_, 0u);
       --compositor_thread_driving_smoothness_;
@@ -151,7 +148,6 @@
             ThreadType::kMain, false);
       }
     }
-  }
 
   frame_trackers_.erase(key);
   tracker->ScheduleTerminate();
@@ -298,35 +294,6 @@
   DestroyTrackers();
 }
 
-bool FrameSequenceTrackerCollection::HasThroughputData() const {
-  return throughput_ukm_reporter_ &&
-         throughput_ukm_reporter_->HasThroughputData();
-}
-
-int FrameSequenceTrackerCollection::TakeLastAggregatedPercent() {
-  DCHECK(throughput_ukm_reporter_);
-  return throughput_ukm_reporter_->TakeLastAggregatedPercent();
-}
-
-int FrameSequenceTrackerCollection::TakeLastImplPercent() {
-  DCHECK(throughput_ukm_reporter_);
-  return throughput_ukm_reporter_->TakeLastImplPercent();
-}
-
-base::Optional<int> FrameSequenceTrackerCollection::TakeLastMainPercent() {
-  DCHECK(throughput_ukm_reporter_);
-  return throughput_ukm_reporter_->TakeLastMainPercent();
-}
-
-void FrameSequenceTrackerCollection::ComputeUniversalThroughputForTesting() {
-  DCHECK(throughput_ukm_reporter_);
-  const auto type = FrameSequenceTrackerType::kUniversal;
-  auto key = std::make_pair(type, ThreadType::kUnknown);
-  DCHECK(frame_trackers_.contains(key));
-  throughput_ukm_reporter_->ComputeUniversalThroughput(
-      frame_trackers_[key]->metrics());
-}
-
 void FrameSequenceTrackerCollection::DestroyTrackers() {
   for (auto& tracker : removal_trackers_) {
     if (tracker->termination_status() ==
@@ -351,15 +318,10 @@
         accumulated_metrics_.erase(key);
       }
 
-      if (metrics->HasEnoughDataForReporting()) {
-        // Do this before ReportMetrics() which clears the throughput data.
-        if (metrics->type() == FrameSequenceTrackerType::kUniversal)
-          throughput_ukm_reporter_->ComputeUniversalThroughput(metrics.get());
+      if (metrics->HasEnoughDataForReporting())
         metrics->ReportMetrics();
-      }
-      if (metrics->HasDataLeftForReporting()) {
+      if (metrics->HasDataLeftForReporting())
         accumulated_metrics_[key] = std::move(metrics);
-      }
     }
   }
 
diff --git a/cc/metrics/frame_sequence_tracker_collection.h b/cc/metrics/frame_sequence_tracker_collection.h
index 9bb8566..e54f39f 100644
--- a/cc/metrics/frame_sequence_tracker_collection.h
+++ b/cc/metrics/frame_sequence_tracker_collection.h
@@ -112,15 +112,6 @@
 
   void SetUkmManager(UkmManager* manager);
 
-  // These methods directly calls corresponding APIs in ThroughputUkmReporter,
-  // please refer to the ThroughputUkmReporter for details.
-  bool HasThroughputData() const;
-  int TakeLastAggregatedPercent();
-  int TakeLastImplPercent();
-  base::Optional<int> TakeLastMainPercent();
-
-  void ComputeUniversalThroughputForTesting();
-
   using NotifyCustomerTrackerResutlsCallback =
       base::RepeatingCallback<void(CustomTrackerResults)>;
   void set_custom_tracker_results_added_callback(
diff --git a/cc/metrics/frame_sequence_tracker_unittest.cc b/cc/metrics/frame_sequence_tracker_unittest.cc
index d9e343e..0c044df5 100644
--- a/cc/metrics/frame_sequence_tracker_unittest.cc
+++ b/cc/metrics/frame_sequence_tracker_unittest.cc
@@ -347,35 +347,13 @@
                                 viz::BeginFrameAck(args_2, true), args_1);
 }
 
-TEST_F(FrameSequenceTrackerTest, UniversalTrackerCreation) {
-  // The universal tracker should be explicitly created by the object that
-  // manages the |collection_|
-  EXPECT_FALSE(TrackerExists(FrameSequenceTrackerType::kUniversal));
-}
-
-TEST_F(FrameSequenceTrackerTest, UniversalTrackerRestartableAfterClearAll) {
-  collection_.StartSequence(FrameSequenceTrackerType::kUniversal);
-  EXPECT_TRUE(TrackerExists(FrameSequenceTrackerType::kUniversal));
-
-  collection_.ClearAll();
-  EXPECT_FALSE(TrackerExists(FrameSequenceTrackerType::kUniversal));
-
-  collection_.StartSequence(FrameSequenceTrackerType::kUniversal);
-  EXPECT_TRUE(TrackerExists(FrameSequenceTrackerType::kUniversal));
-}
-
 TEST_F(FrameSequenceTrackerTest, TestNotifyFramePresented) {
   collection_.StartSequence(FrameSequenceTrackerType::kCompositorAnimation);
   collection_.StartSequence(FrameSequenceTrackerType::kMainThreadAnimation);
-  // The kTouchScroll tracker is created in the test constructor, and the
-  // kUniversal tracker is created in the FrameSequenceTrackerCollection
-  // constructor.
   EXPECT_EQ(NumberOfTrackers(), 3u);
-  collection_.StartSequence(FrameSequenceTrackerType::kUniversal);
-  EXPECT_EQ(NumberOfTrackers(), 4u);
 
   collection_.StopSequence(FrameSequenceTrackerType::kCompositorAnimation);
-  EXPECT_EQ(NumberOfTrackers(), 3u);
+  EXPECT_EQ(NumberOfTrackers(), 2u);
   EXPECT_TRUE(TrackerExists(FrameSequenceTrackerType::kMainThreadAnimation));
   EXPECT_TRUE(TrackerExists(FrameSequenceTrackerType::kTouchScroll));
   // StopSequence should have destroyed all trackers because there is no frame
@@ -1904,29 +1882,6 @@
   EXPECT_EQ(active_encoded, 16);  // 1 << 4
 }
 
-TEST_F(FrameSequenceTrackerTest, UniversalTrackerSubmitThroughput) {
-  auto recorder = std::make_unique<ukm::TestUkmRecorder>();
-  auto ukm_manager = std::make_unique<UkmManager>(std::move(recorder));
-
-  collection_.ClearAll();
-  collection_.SetUkmManager(ukm_manager.get());
-  auto* tracker =
-      collection_.StartSequence(FrameSequenceTrackerType::kUniversal);
-  ImplThroughput(tracker).frames_expected = 200u;
-  ImplThroughput(tracker).frames_produced = 190u;
-  MainThroughput(tracker).frames_expected = 100u;
-  MainThroughput(tracker).frames_produced = 50u;
-  AggregatedThroughput(tracker).frames_expected = 200u;
-  AggregatedThroughput(tracker).frames_produced = 150u;
-
-  collection_.ComputeUniversalThroughputForTesting();
-  DCHECK(collection_.HasThroughputData());
-  EXPECT_EQ(collection_.TakeLastAggregatedPercent(), 25);
-  EXPECT_EQ(collection_.TakeLastImplPercent(), 5);
-  EXPECT_EQ(collection_.TakeLastMainPercent().value(), 50);
-  EXPECT_FALSE(collection_.HasThroughputData());
-}
-
 // Test that when an impl frame caused no damage is due to waiting on main, the
 // computation of aggregated throughput is correct.
 TEST_F(FrameSequenceTrackerTest, ImplFrameNoDamageWaitingOnMain1) {
diff --git a/cc/metrics/jank_metrics.cc b/cc/metrics/jank_metrics.cc
index fba24b1..1164269c 100644
--- a/cc/metrics/jank_metrics.cc
+++ b/cc/metrics/jank_metrics.cc
@@ -99,8 +99,7 @@
 }
 
 void JankMetrics::ReportJankMetrics(int frames_expected) {
-  if (tracker_type_ == FrameSequenceTrackerType::kUniversal ||
-      tracker_type_ == FrameSequenceTrackerType::kCustom)
+  if (tracker_type_ == FrameSequenceTrackerType::kCustom)
     return;
 
   int jank_percent = static_cast<int>(100 * jank_count_ / frames_expected);
diff --git a/cc/metrics/jank_metrics_unittest.cc b/cc/metrics/jank_metrics_unittest.cc
index 687a835..e96e7dd 100644
--- a/cc/metrics/jank_metrics_unittest.cc
+++ b/cc/metrics/jank_metrics_unittest.cc
@@ -228,28 +228,6 @@
   histogram_tester.ExpectTotalCount(invalid_metric, 0u);
 }
 
-// Test if jank reporting is correctly disabled for Universal trackers.
-TEST_F(JankMetricsTest, UniversalNotReported) {
-  base::HistogramTester histogram_tester;
-  FrameSequenceTrackerType tracker_type = FrameSequenceTrackerType::kUniversal;
-  FrameSequenceMetrics::ThreadType thread_type =
-      FrameSequenceMetrics::ThreadType::kCompositor;
-  JankMetrics jank_reporter{tracker_type, thread_type};
-
-  // There should be 4 janks, but the jank reporter does not track or report
-  // them.
-  auto feedbacks = CreateFeedbackSequence({16, +33, +48, 16, +33, +48}, 16.67);
-
-  AddPresentedFramesToJankReporter(&jank_reporter, feedbacks);
-  jank_reporter.ReportJankMetrics(100u);
-
-  // Expect no jank reports even though the sequence contains jank
-  histogram_tester.ExpectTotalCount("Graphics.Smoothness.Jank.Main.Universal",
-                                    0u);
-  histogram_tester.ExpectTotalCount(
-      "Graphics.Smoothness.Jank.Compositor.Universal", 0u);
-}
-
 // Test if jank reporting is correctly disabled for Custom trackers.
 TEST_F(JankMetricsTest, CustomNotReported) {
   base::HistogramTester histogram_tester;
diff --git a/cc/metrics/throughput_ukm_reporter.cc b/cc/metrics/throughput_ukm_reporter.cc
index 39f1a33..e384da5 100644
--- a/cc/metrics/throughput_ukm_reporter.cc
+++ b/cc/metrics/throughput_ukm_reporter.cc
@@ -16,11 +16,6 @@
 ThroughputUkmReporter::ThroughputUkmReporter(UkmManager* ukm_manager)
     : ukm_manager_(ukm_manager) {
   DCHECK(ukm_manager_);
-  // TODO(crbug.com/1040634): Setting it to 1 such that the first sample is
-  // ignored. TThis is because the universal tracker is active during the page
-  // load and the first sample is heavily biased by loading as a result.
-  samples_to_next_event_[static_cast<int>(
-      FrameSequenceTrackerType::kUniversal)] = 1;
 }
 
 ThroughputUkmReporter::~ThroughputUkmReporter() = default;
@@ -36,10 +31,9 @@
   if (!ukm_manager_)
     return;
   if (samples_to_next_event_[static_cast<int>(type)] == 0) {
-    // Sample every 100 events. Using the Universal tracker as an example
-    // which reports UMA every 5s, then the system collects UKM once per
-    // 100*5 = 500 seconds. This number may need to be tuned to not throttle
-    // the UKM system.
+    // Sample every 100 events. If a tracker reports UMA every 5s, then the
+    // system collects UKM once per 100*5 = 500 seconds. This number may need to
+    // be tuned to not throttle the UKM system.
     samples_to_next_event_[static_cast<int>(type)] = kNumberOfSamplesToReport;
     if (impl_throughput_percent) {
       ukm_manager_->RecordThroughputUKM(
@@ -70,39 +64,6 @@
   --samples_for_aggregated_report_;
 }
 
-void ThroughputUkmReporter::ComputeUniversalThroughput(
-    FrameSequenceMetrics* metrics) {
-  last_impl_percent_ = metrics->impl_throughput().DroppedFramePercent();
-  last_main_percent_ = metrics->main_throughput().DroppedFramePercent();
-  last_aggregated_percent_ =
-      metrics->aggregated_throughput().DroppedFramePercent();
-}
-
-bool ThroughputUkmReporter::HasThroughputData() const {
-  return last_aggregated_percent_.has_value();
-}
-
-int ThroughputUkmReporter::TakeLastAggregatedPercent() {
-  int ret_value = last_aggregated_percent_.value();
-  DCHECK(ret_value >= 0 && ret_value <= 100);
-  last_aggregated_percent_ = base::nullopt;
-  return ret_value;
-}
-
-int ThroughputUkmReporter::TakeLastImplPercent() {
-  int ret_value = last_impl_percent_.value();
-  DCHECK(ret_value >= 0 && ret_value <= 100);
-  last_impl_percent_ = base::nullopt;
-  return ret_value;
-}
-
-base::Optional<int> ThroughputUkmReporter::TakeLastMainPercent() {
-  base::Optional<int> ret_value = last_main_percent_;
-  DCHECK(!ret_value || (ret_value.value() >= 0 && ret_value.value() <= 100));
-  last_main_percent_ = base::nullopt;
-  return ret_value;
-}
-
 uint32_t ThroughputUkmReporter::GetSamplesToNextEventForTesting(int index) {
   DCHECK_LT(index, static_cast<int>(FrameSequenceTrackerType::kMaxType));
   return samples_to_next_event_[index];
diff --git a/cc/metrics/throughput_ukm_reporter.h b/cc/metrics/throughput_ukm_reporter.h
index c92fdfe..ba8581a5 100644
--- a/cc/metrics/throughput_ukm_reporter.h
+++ b/cc/metrics/throughput_ukm_reporter.h
@@ -36,21 +36,6 @@
   void ReportAggregateThroughput(AggregationType aggregation_type,
                                  int throughput);
 
-  void ComputeUniversalThroughput(FrameSequenceMetrics* metrics);
-
-  // Once the kUniversal tracker reported its throughput to UMA, this returns
-  // true. In this case, the |last_aggregated_percent_| and |last_impl_percent_|
-  // must have value.
-  bool HasThroughputData() const;
-  // These functions are called only when HasThroughputData is true. They return
-  // the throughput value of the corresponding thread, and reset them to nullopt
-  // to indicate the value has been reported.
-  int TakeLastAggregatedPercent();
-  int TakeLastImplPercent();
-  // This could be nullopt even if the HasThroughputData() is true, because it
-  // could happen that all the frames are generated from the compositor thread.
-  base::Optional<int> TakeLastMainPercent();
-
   uint32_t GetSamplesToNextEventForTesting(int index);
 
  private:
@@ -65,18 +50,6 @@
   // initialized right after the LayerTreeHostImpl is created. So when this
   // pointer is initialized, there should be no trackers yet.
   UkmManager* const ukm_manager_;
-
-  // The last "PercentDroppedFrames" reported to UMA. LayerTreeHostImpl will
-  // read this number and send to the GPU process. When this page is done, we
-  // will report to UKM using these numbers. Currently only meaningful to the
-  // kUniversal tracker.
-  // Possible values:
-  //   1. A non-negative int value which is the percent of frames dropped.
-  //   2. base::nullopt: when they are fetched by LayerTreeHostImpl, so that it
-  //      knows that the last value has been reported.
-  base::Optional<int> last_aggregated_percent_;
-  base::Optional<int> last_main_percent_;
-  base::Optional<int> last_impl_percent_;
 };
 
 }  // namespace cc
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index f160222..04e6025 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -2315,19 +2315,6 @@
       std::move(compositor_frame),
       /*hit_test_data_changed=*/false, debug_state_.show_hit_test_borders);
 
-  // This is expected to be true roughly every 5 seconds.
-  if (frame_trackers_.HasThroughputData()) {
-    ukm::SourceId source_id = ukm_manager_->source_id();
-    // source_id can be invalid in tests.
-    if (source_id != ukm::kInvalidSourceId) {
-      int aggregated_percent = frame_trackers_.TakeLastAggregatedPercent();
-      int impl_percent = frame_trackers_.TakeLastImplPercent();
-      base::Optional<int> main_percent = frame_trackers_.TakeLastMainPercent();
-      client_->SubmitThroughputData(source_id, aggregated_percent, impl_percent,
-                                    main_percent);
-    }
-  }
-
 #if DCHECK_IS_ON()
   if (!doing_sync_draw_) {
     // The throughput computation (in |FrameSequenceTracker|) depends on the
@@ -3602,7 +3589,6 @@
   has_valid_layer_tree_frame_sink_ = true;
 
   auto* context_provider = layer_tree_frame_sink_->context_provider();
-  frame_trackers_.StartSequence(FrameSequenceTrackerType::kUniversal);
 
   if (context_provider) {
     max_texture_size_ =
diff --git a/cc/trees/ukm_manager.cc b/cc/trees/ukm_manager.cc
index 5b014c0..a41e299a 100644
--- a/cc/trees/ukm_manager.cc
+++ b/cc/trees/ukm_manager.cc
@@ -114,7 +114,6 @@
         CASE_FOR_MAIN_THREAD_TRACKER(RAF);
         CASE_FOR_MAIN_THREAD_TRACKER(ScrollbarScroll);
         CASE_FOR_MAIN_THREAD_TRACKER(TouchScroll);
-        CASE_FOR_MAIN_THREAD_TRACKER(Universal);
         CASE_FOR_MAIN_THREAD_TRACKER(Video);
         CASE_FOR_MAIN_THREAD_TRACKER(WheelScroll);
 #undef CASE_FOR_MAIN_THREAD_TRACKER
@@ -138,7 +137,6 @@
         CASE_FOR_COMPOSITOR_THREAD_TRACKER(RAF);
         CASE_FOR_COMPOSITOR_THREAD_TRACKER(ScrollbarScroll);
         CASE_FOR_COMPOSITOR_THREAD_TRACKER(TouchScroll);
-        CASE_FOR_COMPOSITOR_THREAD_TRACKER(Universal);
         CASE_FOR_COMPOSITOR_THREAD_TRACKER(Video);
         CASE_FOR_COMPOSITOR_THREAD_TRACKER(WheelScroll);
 #undef CASE_FOR_COMPOSITOR_THREAD_TRACKER
@@ -161,7 +159,6 @@
         CASE_FOR_SLOWER_THREAD_TRACKER(RAF);
         CASE_FOR_SLOWER_THREAD_TRACKER(ScrollbarScroll);
         CASE_FOR_SLOWER_THREAD_TRACKER(TouchScroll);
-        CASE_FOR_SLOWER_THREAD_TRACKER(Universal);
         CASE_FOR_SLOWER_THREAD_TRACKER(Video);
         CASE_FOR_SLOWER_THREAD_TRACKER(WheelScroll);
 #undef CASE_FOR_SLOWER_THREAD_TRACKER
@@ -272,8 +269,6 @@
       continue;
     const auto frame_sequence_tracker_type =
         static_cast<FrameSequenceTrackerType>(type);
-    if (frame_sequence_tracker_type == FrameSequenceTrackerType::kUniversal)
-      continue;
     switch (frame_sequence_tracker_type) {
 #define CASE_FOR_TRACKER(name)            \
   case FrameSequenceTrackerType::k##name: \
diff --git a/cc/trees/ukm_manager_unittest.cc b/cc/trees/ukm_manager_unittest.cc
index e8cf3a6..a00d682 100644
--- a/cc/trees/ukm_manager_unittest.cc
+++ b/cc/trees/ukm_manager_unittest.cc
@@ -77,7 +77,6 @@
 const char kRAF[] = "RAF";
 const char kScrollbarScroll[] = "ScrollbarScroll";
 const char kTouchScroll[] = "TouchScroll";
-const char kUniversal[] = "Universal";
 const char kVideo[] = "Video";
 const char kWheelScroll[] = "WheelScroll";
 
@@ -268,8 +267,6 @@
       static_cast<size_t>(FrameSequenceTrackerType::kTouchScroll));
   active_trackers.set(
       static_cast<size_t>(FrameSequenceTrackerType::kCompositorAnimation));
-  active_trackers.set(
-      static_cast<size_t>(FrameSequenceTrackerType::kUniversal));
 
   manager_->RecordCompositorLatencyUKM(report_type(), stage_history,
                                        active_trackers, viz_breakdown);
@@ -344,7 +341,6 @@
   EXPECT_FALSE(test_ukm_recorder_->EntryHasMetric(entry, kMainThreadAnimation));
   EXPECT_FALSE(test_ukm_recorder_->EntryHasMetric(entry, kPinchZoom));
   EXPECT_FALSE(test_ukm_recorder_->EntryHasMetric(entry, kRAF));
-  EXPECT_FALSE(test_ukm_recorder_->EntryHasMetric(entry, kUniversal));
   EXPECT_FALSE(test_ukm_recorder_->EntryHasMetric(entry, kVideo));
   EXPECT_FALSE(test_ukm_recorder_->EntryHasMetric(entry, kWheelScroll));
 }
diff --git a/chrome/android/features/media_router/java/res/layout/caf_controller_media_route_button.xml b/chrome/android/features/media_router/java/res/layout/caf_controller_media_route_button.xml
index b168fd96..9801fece 100644
--- a/chrome/android/features/media_router/java/res/layout/caf_controller_media_route_button.xml
+++ b/chrome/android/features/media_router/java/res/layout/caf_controller_media_route_button.xml
@@ -3,7 +3,7 @@
      Use of this source code is governed by a BSD-style license that can be
      found in the LICENSE file.
 -->
-<androidx.appcompat.app.MediaRouteButton
+<androidx.mediarouter.app.MediaRouteButton
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/cast_controller_media_route_button"
     android:layout_width="wrap_content"
diff --git a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
index 5db0330..7a72412 100644
--- a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
+++ b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
@@ -531,10 +531,10 @@
             mIsIncognito = mTabModelSelector.isIncognitoSelected();
             mPropertyModel.set(IS_INCOGNITO, mIsIncognito);
 
-            // if OvervieModeState is NOT_SHOWN, default to SHOWING_HOMEPAGE. This should only
+            // if OvervieModeState is NOT_SHOWN, default to SHOWING_TABSWITCHER. This should only
             // happen when entering Start through SwipeDown gesture on URL bar.
             if (mOverviewModeState == OverviewModeState.NOT_SHOWN) {
-                mOverviewModeState = OverviewModeState.SHOWING_HOMEPAGE;
+                mOverviewModeState = OverviewModeState.SHOWING_TABSWITCHER;
             }
 
             // set OverviewModeState
@@ -744,9 +744,11 @@
             if (mSecondaryTasksSurfacePropertyModel == null) {
                 mSecondaryTasksSurfaceController = mSecondaryTasksSurfaceInitializer.initialize();
             }
-            mSecondaryTasksSurfacePropertyModel.set(IS_FAKE_SEARCH_BOX_VISIBLE,
-                    mIsIncognito && mOverviewModeState == OverviewModeState.SHOWN_HOMEPAGE);
-            mSecondaryTasksSurfacePropertyModel.set(IS_INCOGNITO, mIsIncognito);
+            if (mSecondaryTasksSurfacePropertyModel != null) {
+                mSecondaryTasksSurfacePropertyModel.set(IS_FAKE_SEARCH_BOX_VISIBLE,
+                        mIsIncognito && mOverviewModeState == OverviewModeState.SHOWN_HOMEPAGE);
+                mSecondaryTasksSurfacePropertyModel.set(IS_INCOGNITO, mIsIncognito);
+            }
             if (mSecondaryTasksSurfaceController != null) {
                 mSecondaryTasksSurfaceController.showOverview(false);
             }
diff --git a/chrome/android/features/start_surface/internal/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java b/chrome/android/features/start_surface/internal/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java
index 7348a4c11..de9ed76 100644
--- a/chrome/android/features/start_surface/internal/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java
+++ b/chrome/android/features/start_surface/internal/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java
@@ -323,6 +323,11 @@
                 .addOverviewModeObserver(mOverviewModeObserverCaptor.capture());
 
         assertThat(mediator.getOverviewState(), equalTo(OverviewModeState.NOT_SHOWN));
+        // Sets the current OvervieModeState to SHOWING_START before calling the
+        // {@link StartSurfaceMediator#showOverview()}. This is because if the current
+        // OvervieModeState is NOT_SHOWN, the state will be set default to SHOWING_TABSWITCHER in
+        // {@link StartSurfaceMediator#showOverview()}.
+        mediator.setOverviewState(OverviewModeState.SHOWING_START);
 
         mediator.showOverview(false);
         verify(mMainTabGridController).showOverview(eq(false));
@@ -368,6 +373,11 @@
                 .addOverviewModeObserver(mOverviewModeObserverCaptor.capture());
 
         assertThat(mediator.getOverviewState(), equalTo(OverviewModeState.NOT_SHOWN));
+        // Sets the current OvervieModeState to SHOWING_START before calling the
+        // {@link StartSurfaceMediator#showOverview()}. This is because if the current
+        // OvervieModeState is NOT_SHOWN, the state will be set default to SHOWING_TABSWITCHER in
+        // {@link StartSurfaceMediator#showOverview()}.
+        mediator.setOverviewState(OverviewModeState.SHOWING_START);
 
         mediator.showOverview(false);
         verify(mMainTabGridController).showOverview(eq(false));
@@ -414,6 +424,11 @@
                 .addOverviewModeObserver(mOverviewModeObserverCaptor.capture());
 
         assertThat(mediator.getOverviewState(), equalTo(OverviewModeState.NOT_SHOWN));
+        // Sets the current OvervieModeState to SHOWING_START before calling the
+        // {@link StartSurfaceMediator#showOverview()}. This is because if the current
+        // OvervieModeState is NOT_SHOWN, the state will be set default to SHOWING_TABSWITCHER in
+        // {@link StartSurfaceMediator#showOverview()}.
+        mediator.setOverviewState(OverviewModeState.SHOWING_START);
 
         mediator.showOverview(false);
         verify(mMainTabGridController).showOverview(eq(false));
@@ -1364,7 +1379,7 @@
 
         assertThat(mediator.getOverviewState(), equalTo(OverviewModeState.NOT_SHOWN));
         mediator.showOverview(false);
-        assertThat(mediator.getOverviewState(), equalTo(OverviewModeState.SHOWN_HOMEPAGE));
+        assertThat(mediator.getOverviewState(), equalTo(OverviewModeState.SHOWN_TABSWITCHER));
     }
 
     @Test
@@ -1500,6 +1515,11 @@
                 .when(mBrowserControlsStateProvider)
                 .addObserver(mBrowserControlsStateProviderCaptor.capture());
         StartSurfaceMediator mediator = createStartSurfaceMediator(SurfaceMode.SINGLE_PANE, false);
+        // Sets the current OvervieModeState to SHOWING_START before calling the
+        // {@link StartSurfaceMediator#showOverview()}. This is because if the current
+        // OvervieModeState is NOT_SHOWN, the state will be set default to SHOWING_TABSWITCHER in
+        // {@link StartSurfaceMediator#showOverview()}.
+        mediator.setOverviewState(OverviewModeState.SHOWING_START);
         mediator.showOverview(false);
 
         verify(mBrowserControlsStateProvider).addObserver(ArgumentMatchers.any());
@@ -1527,6 +1547,11 @@
                 .addOverviewModeObserver(mOverviewModeObserverCaptor.capture());
 
         assertThat(mediator.getOverviewState(), equalTo(OverviewModeState.NOT_SHOWN));
+        // Sets the current OvervieModeState to SHOWING_START before calling the
+        // {@link StartSurfaceMediator#showOverview()}. This is because if the current
+        // OvervieModeState is NOT_SHOWN, the state will be set default to SHOWING_TABSWITCHER in
+        // {@link StartSurfaceMediator#showOverview()}.
+        mediator.setOverviewState(OverviewModeState.SHOWING_START);
         mediator.showOverview(false);
         assertThat(mediator.getOverviewState(), equalTo(OverviewModeState.SHOWN_HOMEPAGE));
         assertThat(mPropertyModel.get(IS_EXPLORE_SURFACE_VISIBLE), equalTo(false));
diff --git a/chrome/android/java/res/layout/personalized_signin_promo_view_body.xml b/chrome/android/java/res/layout/personalized_signin_promo_view_body.xml
index 71ee8a7..98aa62f 100644
--- a/chrome/android/java/res/layout/personalized_signin_promo_view_body.xml
+++ b/chrome/android/java/res/layout/personalized_signin_promo_view_body.xml
@@ -16,7 +16,7 @@
         android:layout_marginBottom="8dp"
         android:gravity="center"
         android:textAppearance="@style/TextAppearance.TextMediumThick.Primary"
-        android:text="@string/signin_promo_status_message"
+        android:text="@string/sync_error_card_title"
         android:visibility="gone"/>
 
     <TextView
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/paint_preview/PaintPreviewHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/paint_preview/PaintPreviewHelper.java
index b9694e7..bb47d2c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/paint_preview/PaintPreviewHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/paint_preview/PaintPreviewHelper.java
@@ -13,7 +13,6 @@
 import org.chromium.chrome.browser.metrics.UmaUtils;
 import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
 import org.chromium.chrome.browser.paint_preview.services.PaintPreviewTabServiceFactory;
-import org.chromium.chrome.browser.paint_preview.services.PaintPreviewTabServiceNativeInitObserver;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
@@ -50,9 +49,6 @@
         }
         sActivityCreationTimeMs = activity.getOnCreateTimestampMs();
 
-        activity.getLifecycleDispatcher().register(
-                new PaintPreviewTabServiceNativeInitObserver(activity.getLifecycleDispatcher()));
-
         // TODO(crbug/1074428): verify this doesn't cause a memory leak if the user exits Chrome
         // prior to onTabStateInitialized being called.
         tabModelSelector.addObserver(new EmptyTabModelSelectorObserver() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentAppFactoryInterface.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentAppFactoryInterface.java
index b0bff6a..7fe761a5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentAppFactoryInterface.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentAppFactoryInterface.java
@@ -13,6 +13,10 @@
      * 3) Call delegate.onPaymentAppCreated(app) for apps that match the method data.
      * 4) Call delegate.onDoneCreatingPaymentApps(this) exactly once.
      *
+     * If called while the RenderFrameHost object is still available in Java, but its counterparts
+     * has been deleted in C++, then none of the `delegate` methods are expected to be called,
+     * because the frame is being unloaded.
+     *
      * @param delegate Provides information about payment request and receives a list of payment
      * apps.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestFactory.java
index 816df05..def0a8f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestFactory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestFactory.java
@@ -132,6 +132,7 @@
         @Override
         public String getInvalidSslCertificateErrorMessage() {
             WebContents webContents = getWebContents();
+            if (webContents == null || webContents.isDestroyed()) return null;
             if (!OriginSecurityChecker.isSchemeCryptographic(webContents.getLastCommittedUrl())) {
                 return null;
             }
@@ -146,8 +147,10 @@
 
         @Override
         public boolean prefsCanMakePayment() {
-            return UserPrefs.get(Profile.fromWebContents(getWebContents()))
-                    .getBoolean(Pref.CAN_MAKE_PAYMENT_ENABLED);
+            WebContents webContents = getWebContents();
+            return webContents != null && !webContents.isDestroyed()
+                    && UserPrefs.get(Profile.fromWebContents(webContents))
+                               .getBoolean(Pref.CAN_MAKE_PAYMENT_ENABLED);
         }
 
         @Override
@@ -161,6 +164,7 @@
             return activity != null ? mPackageManager.getTwaPackageName(activity) : null;
         }
 
+        @Nullable
         private WebContents getWebContents() {
             return WebContentsStatics.fromRenderFrameHost(mRenderFrameHost);
         }
@@ -196,6 +200,8 @@
         }
 
         WebContents webContents = WebContentsStatics.fromRenderFrameHost(mRenderFrameHost);
+        if (webContents == null || webContents.isDestroyed()) return new InvalidPaymentRequest();
+
         return ComponentPaymentRequestImpl.createPaymentRequest(mRenderFrameHost,
                 /*isOffTheRecord=*/delegate.isOffTheRecord(webContents),
                 /*skipUiForBasicCard=*/delegate.skipUiForBasicCard(),
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java
index 916dd78..63764e7b3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java
@@ -141,10 +141,10 @@
     /**
      * Notify closing the opened payment app window.
      *
-     * @param webContents The web contents in the opened window.
+     * @param webContents The web contents in the opened window. Can be null.
      */
-    public static void onClosingPaymentAppWindow(WebContents webContents) {
-        if (webContents.isDestroyed()) return;
+    public static void onClosingPaymentAppWindow(@Nullable WebContents webContents) {
+        if (webContents == null || webContents.isDestroyed()) return;
         ServiceWorkerPaymentAppBridgeJni.get().onClosingPaymentAppWindow(
                 webContents, PaymentEventResponseType.PAYMENT_HANDLER_WINDOW_CLOSING);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/AndroidSyncSettings.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/AndroidSyncSettings.java
index 0e12ac3d..3160cd7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/AndroidSyncSettings.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/AndroidSyncSettings.java
@@ -118,8 +118,18 @@
         updateSyncability(callback);
 
         mSyncContentResolverDelegate.addStatusChangeListener(
-                ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS,
-                new AndroidSyncSettingsChangedObserver());
+                ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS, new SyncStatusObserver() {
+                    @Override
+                    public void onStatusChanged(int which) {
+                        if (which == ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS) {
+                            // Sync settings have changed; update our cached values.
+                            if (updateCachedSettings()) {
+                                // If something actually changed, tell our observers.
+                                notifyObservers();
+                            }
+                        }
+                    }
+                });
     }
 
     /**
@@ -287,24 +297,6 @@
     }
 
     /**
-     * Helper class to be used by observers whenever sync settings change.
-     *
-     * To register the observer, call AndroidSyncSettings.registerObserver(...).
-     */
-    private class AndroidSyncSettingsChangedObserver implements SyncStatusObserver {
-        @Override
-        public void onStatusChanged(int which) {
-            if (which == ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS) {
-                // Sync settings have changed; update our cached values.
-                if (updateCachedSettings()) {
-                    // If something actually changed, tell our observers.
-                    notifyObservers();
-                }
-            }
-        }
-    }
-
-    /**
      * Update the three cached settings from the content resolver.
      *
      * @return Whether either chromeSyncEnabled or masterSyncEnabled changed.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/ProfileSyncService.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/ProfileSyncService.java
index 7d6a21c..ae05364 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/ProfileSyncService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/ProfileSyncService.java
@@ -195,6 +195,16 @@
                 mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
     }
 
+    public void setDecoupledFromAndroidMasterSync() {
+        ProfileSyncServiceJni.get().setDecoupledFromAndroidMasterSync(
+                mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
+    }
+
+    public boolean getDecoupledFromAndroidMasterSync() {
+        return ProfileSyncServiceJni.get().getDecoupledFromAndroidMasterSync(
+                mNativeProfileSyncServiceAndroid, ProfileSyncService.this);
+    }
+
     /**
      * Gets the set of data types that are "preferred" in sync. Those are the
      * chosen ones (see getChosenDataTypes), plus any that are implied by them.
@@ -652,6 +662,10 @@
         int getAuthError(long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
         boolean requiresClientUpgrade(
                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
+        void setDecoupledFromAndroidMasterSync(
+                long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
+        boolean getDecoupledFromAndroidMasterSync(
+                long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
         boolean isEngineInitialized(
                 long nativeProfileSyncServiceAndroid, ProfileSyncService caller);
         boolean isEncryptEverythingAllowed(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/SyncErrorCardPreference.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/SyncErrorCardPreference.java
index 448b36a..645aa5f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/SyncErrorCardPreference.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/SyncErrorCardPreference.java
@@ -127,7 +127,6 @@
 
         errorCardView.getDismissButton().setVisibility(View.GONE);
         errorCardView.getStatusMessage().setVisibility(View.VISIBLE);
-        errorCardView.getStatusMessage().setText(R.string.sync_error_card_title);
         errorCardView.getDescription().setText(
                 SyncSettingsUtils.getSyncErrorHint(getContext(), mSyncError));
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoControllerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoControllerTest.java
index f42af4e7..8878341 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoControllerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoControllerTest.java
@@ -104,7 +104,7 @@
                     new PageInfoController(tab.getWebContents(), ConnectionSecurityLevel.NONE,
                             /*publisher=*/null, chromePageInfoControllerDelegate,
                             chromePermissionParamsListBuilderDelegate);
-            PageInfoView pageInfoView = pageInfo.getPageInfoViewForTesting();
+            PageInfoView pageInfoView = (PageInfoView) pageInfo.getPageInfoViewForTesting();
             // Test that the title contains the Unicode hostname rather than strict equality, as
             // the test server will be bound to a random port.
             Assert.assertTrue(
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 c9b4524..beaeb48 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
@@ -41,7 +41,6 @@
 import org.chromium.components.location.LocationUtils;
 import org.chromium.components.page_info.PageInfoController;
 import org.chromium.components.page_info.PageInfoFeatureList;
-import org.chromium.components.page_info.PageInfoView;
 import org.chromium.components.user_prefs.UserPrefs;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.content_public.common.ContentSwitches;
@@ -90,10 +89,10 @@
         onView(withId(R.id.location_bar_status_icon)).perform(click());
     }
 
-    private PageInfoView getPageInfoView() {
+    private View getPageInfoView() {
         PageInfoController controller = PageInfoController.getLastPageInfoControllerForTesting();
         assertNotNull(controller);
-        PageInfoView view = controller.getPageInfoViewForTesting();
+        View view = controller.getPageInfoViewForTesting();
         assertNotNull(view);
         return view;
     }
@@ -266,9 +265,8 @@
     @Features.EnableFeatures(PageInfoFeatureList.PAGE_INFO_V2)
     public void testShowConnectionInfoSubpage() throws IOException {
         loadUrlAndOpenPageInfo(mTestServerRule.getServer().getURL(mPath));
-        View dialog = (View) getPageInfoView().getParent();
         onView(withId(R.id.page_info_connection_row)).perform(click());
-        mRenderTestRule.render(dialog, "PageInfo_ConnectionInfoSubpage");
+        mRenderTestRule.render(getPageInfoView(), "PageInfo_ConnectionInfoSubpage");
     }
 
     /**
@@ -280,9 +278,8 @@
     @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");
+        mRenderTestRule.render(getPageInfoView(), "PageInfo_PermissionsSubpage");
     }
 
     /**
@@ -295,9 +292,8 @@
     public void testShowCookiesSubpage() throws IOException {
         setThirdPartyCookieBlocking(CookieControlsMode.BLOCK_THIRD_PARTY);
         loadUrlAndOpenPageInfo(mTestServerRule.getServer().getURL(mPath));
-        View dialog = (View) getPageInfoView().getParent();
         onView(withId(R.id.page_info_cookies_row)).perform(click());
-        mRenderTestRule.render(dialog, "PageInfo_CookiesSubpage");
+        mRenderTestRule.render(getPageInfoView(), "PageInfo_CookiesSubpage");
     }
 
     // TODO(1071762): Add tests for preview pages, offline pages, offline state and other states.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/paint_preview/services/PaintPreviewTabServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/paint_preview/services/PaintPreviewTabServiceTest.java
index b80f138..1d0dfd6 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/paint_preview/services/PaintPreviewTabServiceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/paint_preview/services/PaintPreviewTabServiceTest.java
@@ -151,6 +151,44 @@
     }
 
     /**
+     * Tests that capturing and deleting via an audit works as expected.
+     */
+    @Test
+    @MediumTest
+    @Feature({"PaintPreview"})
+    public void testCapturedAndDeleteViaAudit() throws Exception {
+        EmbeddedTestServer testServer = mActivityTestRule.getTestServer();
+        final String url = testServer.getURL("/chrome/test/data/android/about.html");
+
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mPaintPreviewTabService = PaintPreviewTabServiceFactory.getServiceInstance();
+            // Use capture on switch mode.
+            mPaintPreviewTabService.onRestoreCompleted(mTabModelSelector, true, true);
+            mTab.loadUrl(new LoadUrlParams(url));
+        });
+        // Give the tab time to complete layout before hiding.
+        TimeUnit.SECONDS.sleep(1);
+
+        // This will hide mTab so that a capture occurs.
+        mActivityTestRule.loadUrlInNewTab(url);
+
+        int tabId = mTab.getId();
+        CriteriaHelper.pollUiThread(() -> {
+            return mPaintPreviewTabService.hasCaptureForTab(tabId);
+        }, "Paint Preview didn't get captured.", TIMEOUT_MS, POLLING_INTERVAL_MS);
+
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            // Use the incognito tab model as the normal tab model will still have the tab ids
+            // active.
+            mPaintPreviewTabService.auditOnStart(mTabModelSelector.getModel(/*incognito=*/true));
+        });
+
+        CriteriaHelper.pollUiThread(() -> {
+            return !mPaintPreviewTabService.hasCaptureForTab(tabId);
+        }, "Paint Preview didn't get deleted.", TIMEOUT_MS, POLLING_INTERVAL_MS);
+    }
+
+    /**
      * Verifies the early cache is created correctly.
      */
     @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTestRule.java
index f4c940ef..cfa8c63 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTestRule.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTestRule.java
@@ -202,8 +202,10 @@
      * @return the test account that is signed in.
      */
     public Account setUpAccountAndSignInForTesting() {
-        Account account = addTestAccount();
-        signinAndEnableSync(account);
+        Account account = mAccountManagerTestRule.addAndSignInTestAccount(mProfileSyncService);
+        enableUKM();
+        SyncTestUtil.waitForSyncActive();
+        SyncTestUtil.triggerSyncAndWaitForCompletion();
         return account;
     }
 
@@ -429,10 +431,8 @@
                                     Assert.fail("Sign-in was aborted");
                                 }
                             });
-            // Outside of tests, URL-keyed anonymized data collection is enabled by sign-in UI.
-            UnifiedConsentServiceBridge.setUrlKeyedAnonymizedDataCollectionEnabled(
-                    Profile.getLastUsedRegularProfile(), true);
         });
+        enableUKM();
         if (setFirstSetupComplete) {
             SyncTestUtil.waitForSyncActive();
             SyncTestUtil.triggerSyncAndWaitForCompletion();
@@ -441,4 +441,12 @@
         }
         Assert.assertEquals(account, mAccountManagerTestRule.getCurrentSignedInAccount());
     }
+
+    private static void enableUKM() {
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            // Outside of tests, URL-keyed anonymized data collection is enabled by sign-in UI.
+            UnifiedConsentServiceBridge.setUrlKeyedAnonymizedDataCollectionEnabled(
+                    Profile.getLastUsedRegularProfile(), true);
+        });
+    }
 }
diff --git a/chrome/app/resources/generated_resources_bn.xtb b/chrome/app/resources/generated_resources_bn.xtb
index 497ee88b..51b3760 100644
--- a/chrome/app/resources/generated_resources_bn.xtb
+++ b/chrome/app/resources/generated_resources_bn.xtb
@@ -4478,6 +4478,7 @@
 <translation id="6415900369006735853">আপনার ফোনের মাধ্যমে ইন্টারনেটে কানেক্ট করুন</translation>
 <translation id="6416743254476733475">আপনার কম্পিউটারে অনুমতি দিন বা ব্লক করুন।</translation>
 <translation id="6417265370957905582">Google Assistant</translation>
+<translation id="6417468503703810114">ডিফল্ট মোড</translation>
 <translation id="6418160186546245112"><ph name="IDS_SHORT_PRODUCT_NAME" /> এর পূর্বে ইনস্টল করা সংস্করণে ফিরিয়ে নিয়ে যাওয়া হচ্ছে</translation>
 <translation id="6418481728190846787">সমস্ত অ্যাপ্লিকেশানের অ্যাক্সেস স্থায়ীভাবে সরান</translation>
 <translation id="6418511932144861495">জরুরী আপডেট ইনস্টল করুন</translation>
@@ -5553,6 +5554,7 @@
 <translation id="7766082757934713382">অ্যাপ ও সিস্টেমের অটোমেটিক আপডেট পজ করে নেটওয়ার্ক ডেটার ব্যবহার কম করতে সাহায্য করে</translation>
 <translation id="7766807826975222231">একবার ঘুরে দেখুন</translation>
 <translation id="7766838926148951335">অনুমতিগুলি স্বীকার করুন</translation>
+<translation id="7768507955883790804">আপনি সাইট খুললে সেটি অটোমেটিক এই সেটিংস মেনে কাজ করবে</translation>
 <translation id="7768770796815395237">পরিবর্তন করুন</translation>
 <translation id="7768784765476638775">বাছুন ও শুনুন</translation>
 <translation id="7769672763586021400">মডেল আইডি</translation>
diff --git a/chrome/app/resources/generated_resources_or.xtb b/chrome/app/resources/generated_resources_or.xtb
index f0b0aa6..c1abbc13 100644
--- a/chrome/app/resources/generated_resources_or.xtb
+++ b/chrome/app/resources/generated_resources_or.xtb
@@ -506,6 +506,7 @@
 <translation id="158849752021629804">ହୋମ୍‌ ନେଟ୍‌ୱର୍କ ଦରକାର</translation>
 <translation id="1588870296199743671">ଏହା ମାଧ୍ୟମରେ ଲିଙ୍କ ଖୋଲନ୍ତୁ...</translation>
 <translation id="1589055389569595240">'ବନାନ ଏବଂ ବ୍ୟାକରଣ' ବିକଳ୍ପ ଦେଖାନ୍ତୁ</translation>
+<translation id="1591679663873027990">Parallels Desktopକୁ USB ଡିଭାଇସଗୁଡ଼ିକୁ ଆକ୍ସେସ୍ କରିବାକୁ ଅନୁମତି ଦିଅନ୍ତୁ। କୌଣସି USB ଡିଭାଇସକୁ କାଢ଼ି ଦିଆଯିବା ପରେ Parallels Desktop ଏହାକୁ ମନେ ରଖିବ ନାହିଁ।</translation>
 <translation id="1593594475886691512">ଫର୍ମାଟ୍‍ କରାଯାଉଛି…</translation>
 <translation id="159359590073980872">ଛବି କେଚ୍‍</translation>
 <translation id="1593926297800505364">ପେମେଣ୍ଟ ପଦ୍ଧତିକୁ ସେଭ୍‍ କରନ୍ତୁ</translation>
@@ -820,6 +821,7 @@
 <translation id="1954813140452229842">ସେୟାର୍ ଖଞ୍ଜିବାରେ ତ୍ରୁଟି। ଦୟାକରି ଆପଣଙ୍କର କ୍ରେଡେନ୍ସିଆଲ୍ ଯାଞ୍ଚ କରନ୍ତୁ ଏବଂ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।</translation>
 <translation id="1956050014111002555">ଫାଇଲ୍‌ରେ ଅନେକ ସାର୍ଟିଫିକେଟ୍ ଅଛି, ଏଥିମଧ୍ୟରୁ କୌଣସିଟି ଇମ୍ପୋର୍ଟ ହୋଇନାହିଁ:</translation>
 <translation id="1956390763342388273">ଏହା "<ph name="FOLDER_PATH" />"ରୁ ସମସ୍ତ ଫାଇଲ୍‌କୁ ଅପ୍‌ଲୋଡ୍ କରିବ। ଆପଣ ଯଦି ସାଇଟ୍‌କୁ ବିଶ୍ଵାସ କରନ୍ତି, ତା'ହେଲେ ହିଁ ଏହା କରନ୍ତୁ।</translation>
+<translation id="196040970347962278">ପ୍ରଥମେ ଏକ ଇଣ୍ଟରନେଟ୍ ସଂଯୋଗ ସ୍ଥାପନ କରନ୍ତୁ</translation>
 <translation id="1962233722219655970">ଏହି ପୃଷ୍ଠାକୁ ଏପରି ମୂଳ କ୍ଲାଏଣ୍ଟର ବ୍ୟବହାର କରେ ଯାହା ଆପଣଙ୍କର କମ୍ପ୍ୟୁଟର୍‌ରେ କାର୍ଯ୍ୟ କରେନାହିଁ।</translation>
 <translation id="1963227389609234879">ସମସ୍ତ ଅପସାରଣ କରନ୍ତୁ</translation>
 <translation id="1963976881984600709">ଷ୍ଟାଣ୍ଡାର୍ଡ ସୁରକ୍ଷା</translation>
@@ -1857,6 +1859,7 @@
 <translation id="321834671654278338">Linux ଅନ୍‌ଇନ୍‌ଷ୍ଟଲର୍</translation>
 <translation id="3220586366024592812"><ph name="CLOUD_PRINT_NAME" />ସଂଯୋଜକ ପ୍ରକ୍ରିୟା କ୍ରାସ୍ ହୋଇଯାଇଛି। ରିଷ୍ଟାର୍ଟ କରିବେ?</translation>
 <translation id="3222066309010235055">ପୂର୍ବପ୍ରସ୍ତୁତି: <ph name="PRERENDER_CONTENTS_NAME" /></translation>
+<translation id="3222779980972075989"><ph name="USB_VM_NAME" />ରେ ସଂଯୋଗ କରନ୍ତୁ</translation>
 <translation id="3223531857777746191">ବଟନ୍‌କୁ ରିସେଟ୍ କରନ୍ତୁ</translation>
 <translation id="3225084153129302039">ଡିଫଲ୍ଟ ପର୍ପଲ୍ ଅବତାର</translation>
 <translation id="3225319735946384299">କୋଡ୍‌ ହସ୍ତାକ୍ଷର</translation>
@@ -1869,6 +1872,7 @@
 <translation id="3246107497225150582">{0,plural, =1{ଗୋଟିଏ ଦିନ ଭିତରେ ଡିଭାଇସ୍ ଅପଡେଟ୍ କରନ୍ତୁ}other{# ଦିନ ଭିତରେ ଡିଭାଇସ୍ ଅପଡେଟ୍ କରନ୍ତୁ}}</translation>
 <translation id="324849028894344899"><ph name="WINDOW_TITLE" /> - ନେଟ୍‌ୱର୍କ ତ୍ରୁଟି</translation>
 <translation id="3248902735035392926">ସୁରକ୍ଷା ଗୁରୁତ୍ୱପୂର୍ଣ୍ଣ ଅଟେ। କିଛି ସମୟ ନିଅନ୍ତୁ ଏବଂ <ph name="BEGIN_LINK" />ବର୍ତ୍ତମାନ ଆପଣଙ୍କ ଏକ୍ସଟେନ୍‍ସନ୍‍ଗୁଡ଼ିକର ଯାଞ୍ଚ କରନ୍ତୁ<ph name="END_LINK" /></translation>
+<translation id="325036368918787455">ଇନକଗ୍ନିଟୋ ୱିଣ୍ଡୋ ବନ୍ଦ କରନ୍ତୁ</translation>
 <translation id="3251759466064201842">&lt;ସାର୍ଟିଫିକେଟ୍‍ର ଅଂଶ ନୁହେଁ&gt;</translation>
 <translation id="3253225298092156258">ଉପଲବ୍ଧ ନାହିଁ</translation>
 <translation id="3253448572569133955">ଅଜଣା ଆକାଉଣ୍ଟ</translation>
@@ -2108,6 +2112,7 @@
 <translation id="3527085408025491307">ଫୋଲ୍ଡର୍</translation>
 <translation id="3528498924003805721">ସର୍ଟକଟ୍ ଟାର୍ଗେଟ୍</translation>
 <translation id="3532273508346491126">ସିଙ୍କ୍ ପରିଚାଳନା</translation>
+<translation id="3532521178906420528">ନେଟୱାର୍କ ସଂଯୋଗ ସ୍ଥାପନ କରାଯାଉଛି ...</translation>
 <translation id="353316712352074340"><ph name="WINDOW_TITLE" /> - ଅଡିଓକୁ ମ୍ୟୁଟ୍ କରାଗଲା</translation>
 <translation id="3537881477201137177">ଏହାକୁ ସେଟିଂସରେ ପରେ ପରିବର୍ତ୍ତନ କରାଯାଇପାରିବ</translation>
 <translation id="3538066758857505094">Linux ଅନ୍‍ଇନ୍‍ଷ୍ଟଲ୍ କରିବା ସମୟରେ ତ୍ରୁଟି ହୋଇଛି। ଦୟାକରି ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।</translation>
@@ -3116,6 +3121,7 @@
 <translation id="4750394297954878236">ପରାମର୍ଶ</translation>
 <translation id="475088594373173692">ପ୍ରଥମ ଉପଯୋଗକର୍ତ୍ତା</translation>
 <translation id="4751476147751820511">ମୋସନ୍ କିମ୍ବା ଲାଇଟ୍ ସେନ୍ସର୍</translation>
+<translation id="4752124003533492687"><ph name="USB_DEVICE_NAME" />କୁ ସଂଯୋଗ କରିବା ପାଇଁ ସେଟିଂସ୍ ଖୋଲନ୍ତୁ</translation>
 <translation id="4756378406049221019">ବନ୍ଦ/ପୁଣି ଲୋଡ୍ କରନ୍ତୁ</translation>
 <translation id="4756388243121344051">&amp;ଇତିବୃତ୍ତି</translation>
 <translation id="4759238208242260848">ଡାଉନଲୋଡସମୂହ</translation>
@@ -4634,6 +4640,7 @@
 <ph name="EXTENSION_NAME" /> ସ୍ଥାୟୀ ଆକ୍ସେସ୍ ଚାହୁଁଛି।</translation>
 <translation id="6635944431854494329">'ସେଟିଂସ୍ &gt; ଉନ୍ନତ &gt; ସ୍ଵଚାଳିତ ଭାବେ Googleକୁ ଡାଏଗ୍ନୋଷ୍ଟିକ୍ ଓ ବ୍ୟବହାର ଡାଟା ପଠାନ୍ତୁ'ରୁ ମାଲିକ ଏହି ଫିଚରକୁ ନିୟନ୍ତ୍ରଣ କରିପାରିବେ।</translation>
 <translation id="6635956300022133031">ଟେକ୍ସଟ୍‌ରୁ ସ୍ପିଚ୍‌ ଭଏସ୍ ବାଛନ୍ତୁ ଏବଂ କଷ୍ଟମାଇଜ୍ କରନ୍ତୁ</translation>
+<translation id="6636588250634969791">ଆଗକୁ ବଢ଼ିବା ପୂର୍ବରୁ SIM ଇନସାର୍ଟ କରନ୍ତୁ</translation>
 <translation id="6639554308659482635">SQLite ମେମୋରୀ</translation>
 <translation id="6641138807883536517">ମିଶାମିଶି ସୃଷ୍ଟି ହେଉଥିବା ସୁରକ୍ଷିତ ମଡ୍ୟୁଲ୍‍ ପାସ୍‌ୱର୍ଡ ଉପଲବ୍ଧ ନାହିଁ। ଏକ ପାୱାର୍‍ୱାସ୍ ପରେ ଏହା ସ୍ୱାଭାବିକ ଅଟେ।</translation>
 <translation id="6642720633335369752">ସବୁ ଦେଖିବା ପାଇଁ ଆପ୍ ୱିଣ୍ଡୋ ଖୋଲନ୍ତୁ, ତଳୁ ଉପରକୁ ସ୍ୱାଇପ୍ କରି ଧରି ରଖନ୍ତୁ।</translation>
@@ -5176,6 +5183,7 @@
 <translation id="7303900363563182677">କ୍ଲିପବୋର୍ଡ୍‌କୁ ଛବି କପି କରିବା ଏବଂ ଟେକ୍ସଟ୍ ଦେଖିବାରୁ ଏହି ସାଇଟ୍‌କୁ ଅବରୋଧ କରିଦିଆଯାଇଛି।</translation>
 <translation id="7305123176580523628">USB ପ୍ରିଣ୍ଟର୍ ସଂଯୋଗ କରାଯାଇଛି</translation>
 <translation id="730515362922783851">ସ୍ଥାନୀୟ ନେଟ୍‍ୱର୍କ କିମ୍ବା ଇଣ୍ଟର୍ନେଟ୍‌ରେ ଥିବା ଯେକୌଣସି ଡିଭାଇସ୍ ସହିତ ଡାଟା ଆଦାନ-ପ୍ରଦାନ କରନ୍ତୁ</translation>
+<translation id="7306521477691455105"><ph name="USB_DEVICE_NAME" />କୁ <ph name="USB_VM_NAME" />ରେ ସଂଯୋଗ କରିବା ପାଇଁ ସେଟିଂସ୍ ଖୋଲନ୍ତୁ</translation>
 <translation id="7307129035224081534">ବିରତ କରାଯାଇଛି</translation>
 <translation id="7308002049209013926">ନୂଆ ଆପ୍‍ ଓ ଗତିବିଧିଗୁଡ଼ିକୁ ଶୀଘ୍ର ପ୍ରାପ୍ତ କରିବା ପାଇଁ ଲଞ୍ଚର୍ ବ୍ୟବହାର କରନ୍ତୁ। କୀବୋର୍ଡ ଦ୍ୱାରା ଏଠାରେ ପହଞ୍ଚିବା ପାଇଁ, Alt + Shift + L ଦବାନ୍ତୁ।</translation>
 <translation id="7309257895202129721">&amp;ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ ଦେଖାନ୍ତୁ</translation>
@@ -6794,6 +6802,7 @@
 <translation id="947329552760389097">&amp;ଉପାଦାନଗୁଡ଼ିକ ନିରୀକ୍ଷଣ କରନ୍ତୁ</translation>
 <translation id="951991426597076286">ଅଗ୍ରାହ୍ୟ କରନ୍ତୁ</translation>
 <translation id="952992212772159698">ସକ୍ରିୟ ହୋ‍ଇନାହିଁ</translation>
+<translation id="956444359529327203">ଅତିଥି ୱିଣ୍ଡୋ ବନ୍ଦ କରନ୍ତୁ</translation>
 <translation id="956500788634395331">ଆପଣ ସମ୍ଭାବ୍ୟ କ୍ଷତିକାରକ ଏକ୍ସଟେନସନଗୁଡ଼ିକରୁ ସୁରକ୍ଷିତ ଅଛନ୍ତି</translation>
 <translation id="957960681186851048">ଏହି ସାଇଟ୍ ସ୍ୱଚାଳିତ ଭାବେ ଏକାଧିକ ଫାଇଲ୍ ଡାଉନ୍‍‍ଲୋଡ୍ କରିବାକୁ ଚେଷ୍ଟା କରୁଛି</translation>
 <translation id="9580706199804957">Google ସେବା ସହ ସଂଯୋଗ ହୋଇପାରିଲା ନାହିଁ</translation>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index f4837be..7d3b989d 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -300,6 +300,8 @@
     "component_updater/crowd_deny_component_installer.h",
     "component_updater/file_type_policies_component_installer.cc",
     "component_updater/file_type_policies_component_installer.h",
+    "component_updater/first_party_sets_component_installer.cc",
+    "component_updater/first_party_sets_component_installer.h",
     "component_updater/floc_blocklist_component_installer.cc",
     "component_updater/floc_blocklist_component_installer.h",
     "component_updater/games_component_installer.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index ea7422e..121ca25 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -5939,6 +5939,10 @@
      flag_descriptions::kReleaseNotesNotificationName,
      flag_descriptions::kReleaseNotesNotificationDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(chromeos::features::kReleaseNotesNotification)},
+    {"use-wallpaper-staging-url",
+     flag_descriptions::kUseWallpaperStagingUrlName,
+     flag_descriptions::kUseWallpaperStagingUrlDescription, kOsCrOS,
+     FEATURE_VALUE_TYPE(chromeos::features::kUseWallpaperStagingUrl)},
 #endif  // defined(OS_CHROMEOS)
 
     {"passive-mixed-content-warning",
diff --git a/chrome/browser/apps/app_shim/app_shim_manager_mac.cc b/chrome/browser/apps/app_shim/app_shim_manager_mac.cc
index 041afeb..56e14baa 100644
--- a/chrome/browser/apps/app_shim/app_shim_manager_mac.cc
+++ b/chrome/browser/apps/app_shim/app_shim_manager_mac.cc
@@ -297,9 +297,18 @@
     std::unique_ptr<AppShimHostBootstrap> bootstrap) {
   DCHECK(crx_file::id_util::IdIsValid(bootstrap->GetAppId()));
   switch (bootstrap->GetLaunchType()) {
-    case chrome::mojom::AppShimLaunchType::kNormal:
-      OnShimProcessConnectedForLaunch(std::move(bootstrap));
+    case chrome::mojom::AppShimLaunchType::kNormal: {
+      const web_app::AppId app_id = bootstrap->GetAppId();
+      const base::FilePath profile_path = bootstrap->GetProfilePath();
+      const std::vector<base::FilePath> launch_files =
+          bootstrap->GetLaunchFiles();
+      LoadAndLaunchAppCallback launch_callback = base::BindOnce(
+          &AppShimManager::OnShimProcessConnectedAndAllLaunchesDone,
+          weak_factory_.GetWeakPtr(), std::move(bootstrap));
+      LoadAndLaunchApp(app_id, profile_path, launch_files,
+                       std::move(launch_callback));
       break;
+    }
     case chrome::mojom::AppShimLaunchType::kRegisterOnly:
       OnShimProcessConnectedForRegisterOnly(std::move(bootstrap));
       break;
@@ -339,18 +348,17 @@
   }
 
   OnShimProcessConnectedAndAllLaunchesDone(
-      profile_state,
-      profile_state ? chrome::mojom::AppShimLaunchResult::kSuccess
-                    : chrome::mojom::AppShimLaunchResult::kSuccessAndDisconnect,
-      std::move(bootstrap));
+      std::move(bootstrap), profile_state,
+      profile_state
+          ? chrome::mojom::AppShimLaunchResult::kSuccess
+          : chrome::mojom::AppShimLaunchResult::kSuccessAndDisconnect);
 }
 
-void AppShimManager::OnShimProcessConnectedForLaunch(
-    std::unique_ptr<AppShimHostBootstrap> bootstrap) {
-  const web_app::AppId& app_id = bootstrap->GetAppId();
-  DCHECK_EQ(bootstrap->GetLaunchType(),
-            chrome::mojom::AppShimLaunchType::kNormal);
-
+void AppShimManager::LoadAndLaunchApp(
+    const web_app::AppId& app_id,
+    const base::FilePath& profile_path,
+    std::vector<base::FilePath> launch_files,
+    LoadAndLaunchAppCallback launch_callback) {
   // Retrieve the list of last-active profiles. If there are no last-active
   // profiles (which is rare -- e.g, when the last-active profiles were
   // removed), then use all profiles for which the app is installed.
@@ -364,8 +372,7 @@
   // Construct |profile_paths_to_launch| to be the list of all profiles to
   // attempt to launch, starting with the profile specified in |bootstrap|,
   // at the front of the list.
-  std::vector<base::FilePath> profile_paths_to_launch = {
-      bootstrap->GetProfilePath()};
+  std::vector<base::FilePath> profile_paths_to_launch = {profile_path};
   for (const auto& profile_path : last_active_profile_paths)
     profile_paths_to_launch.push_back(profile_path);
 
@@ -373,9 +380,9 @@
   // they're loaded (or have failed to load), call
   // OnShimProcessConnectedAndProfilesToLaunchLoaded.
   base::OnceClosure callback = base::BindOnce(
-      &AppShimManager::OnShimProcessConnectedAndProfilesToLaunchLoaded,
-      weak_factory_.GetWeakPtr(), std::move(bootstrap),
-      profile_paths_to_launch);
+      &AppShimManager::LoadAndLaunchApp_OnProfilesAndAppReady,
+      weak_factory_.GetWeakPtr(), app_id, std::move(launch_files),
+      profile_paths_to_launch, std::move(launch_callback));
   {
     // This will update |callback| to be a chain of callbacks that load the
     // profiles in |profile_paths_to_load|, one by one, using
@@ -385,7 +392,7 @@
     for (const auto& profile_path : profile_paths_to_launch) {
       if (profile_path.empty())
         continue;
-      LoadProfileAppCallback callback_wrapped =
+      LoadProfileAndAppCallback callback_wrapped =
           base::BindOnce([](base::OnceClosure callback_to_wrap,
                             Profile*) { std::move(callback_to_wrap).Run(); },
                          std::move(callback));
@@ -397,16 +404,11 @@
   std::move(callback).Run();
 }
 
-void AppShimManager::OnShimProcessConnectedAndProfilesToLaunchLoaded(
-    std::unique_ptr<AppShimHostBootstrap> bootstrap,
-    const std::vector<base::FilePath>& profile_paths_to_launch) {
-  // The the profile specified in |bootstrap| (even if it's empty) should be the
-  // first profile listed in |profile_paths_to_launch|.
-  DCHECK_EQ(profile_paths_to_launch[0], bootstrap->GetProfilePath());
-
-  const auto& app_id = bootstrap->GetAppId();
-  auto launch_files = bootstrap->GetLaunchFiles();
-
+void AppShimManager::LoadAndLaunchApp_OnProfilesAndAppReady(
+    const web_app::AppId& app_id,
+    std::vector<base::FilePath> launch_files,
+    const std::vector<base::FilePath>& profile_paths_to_launch,
+    LoadAndLaunchAppCallback launch_callback) {
   // Launch all of the profiles in |profile_paths_to_launch|. Record the most
   // profile successfully launched in |launched_profile_state|, and the most
   // recent reason for a failure (if any) in |launch_result|.
@@ -472,14 +474,13 @@
   if (launched_profile_state)
     launch_result = chrome::mojom::AppShimLaunchResult::kSuccess;
 
-  OnShimProcessConnectedAndAllLaunchesDone(launched_profile_state,
-                                           launch_result, std::move(bootstrap));
+  std::move(launch_callback).Run(launched_profile_state, launch_result);
 }
 
 void AppShimManager::OnShimProcessConnectedAndAllLaunchesDone(
+    std::unique_ptr<AppShimHostBootstrap> bootstrap,
     ProfileState* profile_state,
-    chrome::mojom::AppShimLaunchResult result,
-    std::unique_ptr<AppShimHostBootstrap> bootstrap) {
+    chrome::mojom::AppShimLaunchResult result) {
   // If we failed because the profile was locked, launch the profile manager.
   if (result == chrome::mojom::AppShimLaunchResult::kProfileLocked)
     LaunchUserManager();
@@ -565,22 +566,23 @@
 
 void AppShimManager::LoadProfileAndApp(const base::FilePath& profile_path,
                                        const web_app::AppId& app_id,
-                                       LoadProfileAppCallback callback) {
+                                       LoadProfileAndAppCallback callback) {
   // Run |profile_loaded_callback| when the profile is loaded (be that now, or
   // after having to asynchronously load the profile).
   auto profile_loaded_callback = base::BindOnce(
-      &AppShimManager::OnProfileLoaded, weak_factory_.GetWeakPtr(),
-      profile_path, app_id, std::move(callback));
+      &AppShimManager::LoadProfileAndApp_OnProfileLoaded,
+      weak_factory_.GetWeakPtr(), profile_path, app_id, std::move(callback));
   if (auto* profile = ProfileForPath(profile_path))
     std::move(profile_loaded_callback).Run(profile);
   else
     LoadProfileAsync(profile_path, std::move(profile_loaded_callback));
 }
 
-void AppShimManager::OnProfileLoaded(const base::FilePath& profile_path,
-                                     const web_app::AppId& app_id,
-                                     LoadProfileAppCallback callback,
-                                     Profile* profile) {
+void AppShimManager::LoadProfileAndApp_OnProfileLoaded(
+    const base::FilePath& profile_path,
+    const web_app::AppId& app_id,
+    LoadProfileAndAppCallback callback,
+    Profile* profile) {
   // It may be that the profile fails to load.
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   if (!profile) {
@@ -593,15 +595,15 @@
   // launching.
   // https://crbug.com/1094419.
   auto registry_ready_callback = base::BindOnce(
-      &AppShimManager::OnProfileAppRegistryReady, weak_factory_.GetWeakPtr(),
-      profile_path, app_id, std::move(callback));
+      &AppShimManager::LoadProfileAndApp_OnProfileAppRegistryReady,
+      weak_factory_.GetWeakPtr(), profile_path, app_id, std::move(callback));
   WaitForAppRegistryReadyAsync(profile, std::move(registry_ready_callback));
 }
 
-void AppShimManager::OnProfileAppRegistryReady(
+void AppShimManager::LoadProfileAndApp_OnProfileAppRegistryReady(
     const base::FilePath& profile_path,
     const web_app::AppId& app_id,
-    LoadProfileAppCallback callback) {
+    LoadProfileAndAppCallback callback) {
   // It may be that the profile was destroyed while waiting for the callback to
   // be issued.
   Profile* profile = ProfileForPath(profile_path);
@@ -611,9 +613,9 @@
   }
   // Run |app_enabled_callback| once the app is enabled (now or async). Note
   // that this is only relevant for extension-based apps.
-  auto app_enabled_callback =
-      base::BindOnce(&AppShimManager::OnAppEnabled, weak_factory_.GetWeakPtr(),
-                     profile_path, app_id, std::move(callback));
+  auto app_enabled_callback = base::BindOnce(
+      &AppShimManager::LoadProfileAndApp_OnAppEnabled,
+      weak_factory_.GetWeakPtr(), profile_path, app_id, std::move(callback));
   if (delegate_->AppIsInstalled(profile, app_id)) {
     std::move(app_enabled_callback).Run();
   } else {
@@ -622,9 +624,10 @@
   }
 }
 
-void AppShimManager::OnAppEnabled(const base::FilePath& profile_path,
-                                  const web_app::AppId& app_id,
-                                  LoadProfileAppCallback callback) {
+void AppShimManager::LoadProfileAndApp_OnAppEnabled(
+    const base::FilePath& profile_path,
+    const web_app::AppId& app_id,
+    LoadProfileAndAppCallback callback) {
   std::move(callback).Run(ProfileForPath(profile_path));
 }
 
diff --git a/chrome/browser/apps/app_shim/app_shim_manager_mac.h b/chrome/browser/apps/app_shim/app_shim_manager_mac.h
index 7ae2f41..0aac4a5 100644
--- a/chrome/browser/apps/app_shim/app_shim_manager_mac.h
+++ b/chrome/browser/apps/app_shim/app_shim_manager_mac.h
@@ -242,27 +242,39 @@
   void OnShimProcessConnectedForRegisterOnly(
       std::unique_ptr<AppShimHostBootstrap> bootstrap);
 
-  // This is called by OnShimProcessConnected when the shim was was launched
-  // not by Chrome, and needs to launch the app (that is, open a new app
-  // window).
-  void OnShimProcessConnectedForLaunch(
-      std::unique_ptr<AppShimHostBootstrap> bootstrap);
-
-  // Continuation of OnShimProcessConnectedForLaunch, once all of the profiles
-  // to use have been loaded. The list of profiles to launch is in
-  // |profile_paths_to_launch|. The first entry corresponds to the bootstrap-
-  // specified profile, and may be a blank path.
-  void OnShimProcessConnectedAndProfilesToLaunchLoaded(
-      std::unique_ptr<AppShimHostBootstrap> bootstrap,
-      const std::vector<base::FilePath>& profile_paths_to_launch);
+  // The function LoadAndLaunchApp will:
+  // - Find the appropriate profiles for which |app_id| should be launched.
+  // - Load the profiles and ensure the app is enabled (using
+  //   LoadProfileAndApp).
+  // - Launch the app, if appropriate.
+  // The "if appropriate" above is defined as:
+  // - If |launch_files| is non-empty, then will always launch the app
+  //   - If |profile_path| is non-empty, then use that profile.
+  //   - In the most recently used profile, otherwise
+  // - If |launch_files| is empty, then launch the app only if:
+  //   - If |profile_path| is non-empty, then launch if the app is not running
+  //     in that profile.
+  //   - Otherwise, launch the app only if it is not running any profile.
+  using LoadAndLaunchAppCallback =
+      base::OnceCallback<void(ProfileState* profile_state,
+                              chrome::mojom::AppShimLaunchResult result)>;
+  void LoadAndLaunchApp(const web_app::AppId& app_id,
+                        const base::FilePath& profile_path,
+                        std::vector<base::FilePath> launch_files,
+                        LoadAndLaunchAppCallback launch_callback);
+  void LoadAndLaunchApp_OnProfilesAndAppReady(
+      const web_app::AppId& app_id,
+      std::vector<base::FilePath> launch_files,
+      const std::vector<base::FilePath>& profile_paths_to_launch,
+      LoadAndLaunchAppCallback launch_callback);
 
   // The final step of both paths for OnShimProcessConnected. This will connect
   // |bootstrap| to |profile_state|'s AppShimHost, if possible. The value of
   // |profile_state| is non-null if and only if |result| is success.
   void OnShimProcessConnectedAndAllLaunchesDone(
+      std::unique_ptr<AppShimHostBootstrap> bootstrap,
       ProfileState* profile_state,
-      chrome::mojom::AppShimLaunchResult result,
-      std::unique_ptr<AppShimHostBootstrap> bootstrap);
+      chrome::mojom::AppShimLaunchResult result);
 
   // Continuation of OnShimSelectedProfile, once the profile has loaded.
   void OnShimSelectedProfileAndAppLoaded(const web_app::AppId& app_id,
@@ -270,20 +282,21 @@
 
   // Load the specified profile and extension, and run |callback| with
   // the result. The callback's arguments may be nullptr on failure.
-  using LoadProfileAppCallback = base::OnceCallback<void(Profile*)>;
+  using LoadProfileAndAppCallback = base::OnceCallback<void(Profile*)>;
   void LoadProfileAndApp(const base::FilePath& profile_path,
                          const web_app::AppId& app_id,
-                         LoadProfileAppCallback callback);
-  void OnProfileLoaded(const base::FilePath& profile_path,
-                       const web_app::AppId& app_id,
-                       LoadProfileAppCallback callback,
-                       Profile* profile);
-  void OnProfileAppRegistryReady(const base::FilePath& profile_path,
-                                 const web_app::AppId& app_id,
-                                 LoadProfileAppCallback callback);
-  void OnAppEnabled(const base::FilePath& profile_path,
-                    const web_app::AppId& app_id,
-                    LoadProfileAppCallback callback);
+                         LoadProfileAndAppCallback callback);
+  void LoadProfileAndApp_OnProfileLoaded(const base::FilePath& profile_path,
+                                         const web_app::AppId& app_id,
+                                         LoadProfileAndAppCallback callback,
+                                         Profile* profile);
+  void LoadProfileAndApp_OnProfileAppRegistryReady(
+      const base::FilePath& profile_path,
+      const web_app::AppId& app_id,
+      LoadProfileAndAppCallback callback);
+  void LoadProfileAndApp_OnAppEnabled(const base::FilePath& profile_path,
+                                      const web_app::AppId& app_id,
+                                      LoadProfileAndAppCallback callback);
 
   // Update the profiles menu for the specified host.
   void UpdateAppProfileMenu(AppState* app_state);
diff --git a/chrome/browser/chrome_find_request_manager_browsertest.cc b/chrome/browser/chrome_find_request_manager_browsertest.cc
index 6b14197..e622c3e 100644
--- a/chrome/browser/chrome_find_request_manager_browsertest.cc
+++ b/chrome/browser/chrome_find_request_manager_browsertest.cc
@@ -7,6 +7,7 @@
 #include "base/path_service.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "chrome/browser/pdf/pdf_extension_test_util.h"
@@ -27,6 +28,7 @@
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/controllable_http_response.h"
 #include "pdf/document_loader_impl.h"
+#include "pdf/pdf_features.h"
 #include "third_party/blink/public/mojom/frame/find_in_page.mojom.h"
 
 namespace content {
@@ -90,6 +92,20 @@
   DISALLOW_COPY_AND_ASSIGN(ChromeFindRequestManagerTest);
 };
 
+class ChromeFindRequestManagerTestWithPdfPartialLoading
+    : public ChromeFindRequestManagerTest {
+ public:
+  ChromeFindRequestManagerTestWithPdfPartialLoading() {
+    feature_list_.InitWithFeatures(
+        {chrome_pdf::features::kPdfIncrementalLoading,
+         chrome_pdf::features::kPdfPartialLoading},
+        {});
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
 // Tests searching in a full-page PDF.
 // Flaky on Windows ASAN: crbug.com/1030368.
 #if defined(OS_WIN) && defined(ADDRESS_SANITIZER)
@@ -157,7 +173,8 @@
 
 // Tests searching in a PDF received in chunks via range-requests.  See also
 // https://crbug.com/1027173.
-IN_PROC_BROWSER_TEST_F(ChromeFindRequestManagerTest, FindInChunkedPDF) {
+IN_PROC_BROWSER_TEST_F(ChromeFindRequestManagerTestWithPdfPartialLoading,
+                       FindInChunkedPDF) {
   constexpr uint32_t kStalledResponseSize =
       chrome_pdf::DocumentLoaderImpl::kDefaultRequestSize + 123;
 
diff --git a/chrome/browser/chromeos/backdrop_wallpaper_handlers/backdrop_wallpaper_handlers.cc b/chrome/browser/chromeos/backdrop_wallpaper_handlers/backdrop_wallpaper_handlers.cc
index 8977c0c3..445d3ad 100644
--- a/chrome/browser/chromeos/backdrop_wallpaper_handlers/backdrop_wallpaper_handlers.cc
+++ b/chrome/browser/chromeos/backdrop_wallpaper_handlers/backdrop_wallpaper_handlers.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/chromeos/backdrop_wallpaper_handlers/backdrop_wallpaper.pb.h"
 #include "chrome/browser/net/system_network_context_manager.h"
 #include "chrome/common/extensions/api/wallpaper_private.h"
+#include "chromeos/constants/chromeos_features.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/constants/devicetype.h"
 #include "content/public/browser/browser_thread.h"
@@ -50,6 +51,10 @@
           chromeos::switches::kTestWallpaperServer)) {
     base::ReplaceFirstSubstringAfterOffset(&url, 0, "clients3",
                                            "chromecast-dev.sandbox");
+  } else if (base::FeatureList::IsEnabled(
+                 chromeos::features::kUseWallpaperStagingUrl)) {
+    base::ReplaceFirstSubstringAfterOffset(&url, 0, "clients3",
+                                           "chromecast-staging.sandbox");
   }
   return url;
 }
diff --git a/chrome/browser/chromeos/policy/auto_enrollment_client_impl.cc b/chrome/browser/chromeos/policy/auto_enrollment_client_impl.cc
index 63667b3..1eb01ba7 100644
--- a/chrome/browser/chromeos/policy/auto_enrollment_client_impl.cc
+++ b/chrome/browser/chromeos/policy/auto_enrollment_client_impl.cc
@@ -51,6 +51,18 @@
     base::TimeDelta::FromSeconds(15);
 
 // UMA histogram names.
+constexpr char kUMAHashDanceSuccessTime[] =
+    "Enterprise.AutoEnrollmentHashDanceSuccessTime";
+constexpr char kUMAPrivateSetMembershipHashDanceComparison[] =
+    "Enterprise.AutoEnrollmentPrivateSetMembershipHashDanceComparison";
+constexpr char kUMAPrivateSetMembershipSuccessTime[] =
+    "Enterprise.AutoEnrollmentPrivateSetMembershipSuccessTime";
+constexpr char kUMAPrivateSetMembershipRequestStatus[] =
+    "Enterprise.AutoEnrollmentPrivateSetMembershipRequestStatus";
+
+// The following histogram names where added before private set membership
+// existed. They are only recorded for hash dance.
+
 constexpr char kUMAProtocolTime[] = "Enterprise.AutoEnrollmentProtocolTime";
 constexpr char kUMABucketDownloadTime[] =
     "Enterprise.AutoEnrollmentBucketDownloadTime";
@@ -259,6 +271,12 @@
       return;
     }
 
+    // Report the psm attempt and start the timer to measure successful private
+    // set membership requests.
+    base::UmaHistogramEnumeration(kUMAPrivateSetMembershipRequestStatus,
+                                  PrivateSetMembershipStatus::kAttempt);
+    time_start_ = base::TimeTicks::Now();
+
     on_completion_callback_ = std::move(callback);
 
     // Start the protocol and its timeout timer.
@@ -311,9 +329,17 @@
   }
 
  private:
-  void OnTimeout() { StoreErrorAndStop(); }
+  void OnTimeout() {
+    base::UmaHistogramEnumeration(kUMAPrivateSetMembershipRequestStatus,
+                                  PrivateSetMembershipStatus::kTimeout);
+    StoreErrorAndStop();
+  }
 
   void StoreErrorAndStop() {
+    // Record the error. Note that a timeout is also recorded as error.
+    base::UmaHistogramEnumeration(kUMAPrivateSetMembershipRequestStatus,
+                                  PrivateSetMembershipStatus::kError);
+
     // Stop the private set membership timer.
     private_set_membership_timeout_.Stop();
 
@@ -482,6 +508,11 @@
 
         LOG(WARNING) << "PSM query request completed successfully";
 
+        base::UmaHistogramEnumeration(
+            kUMAPrivateSetMembershipRequestStatus,
+            PrivateSetMembershipStatus::kSuccessfulDetermination);
+        RecordPrivateSetMembershipSuccessTimeHistogram();
+
         // The RLWE query response has been processed successfully. Extract
         // the membership response, and report the result.
         psm_rlwe::MembershipResponseMap membership_responses_map =
@@ -538,6 +569,23 @@
         std::move(callback));
   }
 
+  // Record UMA histogram for timing of successful private set membership
+  // request.
+  void RecordPrivateSetMembershipSuccessTimeHistogram() {
+    // These values determine bucketing of the histogram, they should not be
+    // changed.
+    static const base::TimeDelta kMin = base::TimeDelta::FromMilliseconds(1);
+    static const base::TimeDelta kMax = base::TimeDelta::FromSeconds(25);
+    static const int kBuckets = 50;
+
+    base::TimeTicks now = base::TimeTicks::Now();
+    if (!time_start_.is_null()) {
+      base::TimeDelta delta = now - time_start_;
+      base::UmaHistogramCustomTimes(kUMAPrivateSetMembershipSuccessTime, delta,
+                                    kMin, kMax, kBuckets);
+    }
+  }
+
   // Private Set Membership RLWE client, used for preparing PSM requests and
   // parsing PSM responses.
   std::unique_ptr<psm_rlwe::PrivateMembershipRlweClient>
@@ -575,6 +623,9 @@
   // membership protocol.
   base::OneShotTimer private_set_membership_timeout_;
 
+  // The time when the private set membership request started.
+  base::TimeTicks time_start_;
+
   // A sequence checker to prevent the race condition of having the possibility
   // of the destructor being called and any of the callbacks.
   SEQUENCE_CHECKER(sequence_checker_);
@@ -857,7 +908,7 @@
   // Drop the previous job and reset state.
   request_job_.reset();
   state_ = AUTO_ENROLLMENT_STATE_PENDING;
-  time_start_ = base::Time::Now();
+  time_start_ = base::TimeTicks::Now();
   modulus_updates_received_ = 0;
   has_server_state_ = false;
   device_state_available_ = false;
@@ -877,7 +928,7 @@
     // Client still running, but our owner isn't interested in the result
     // anymore. Wait until the protocol completes to measure the extra time
     // needed.
-    time_extra_start_ = base::Time::Now();
+    time_extra_start_ = base::TimeTicks::Now();
     progress_callback_.Reset();
   }
 }
@@ -927,7 +978,8 @@
       state_download_message_processor_(
           std::move(state_download_message_processor)),
       private_set_membership_helper_(std::move(private_set_membership_helper)),
-      uma_suffix_(uma_suffix) {
+      uma_suffix_(uma_suffix),
+      recorded_psm_hash_dance_comparison_(false) {
   DCHECK_LE(current_power_, power_limit_);
   DCHECK(!progress_callback_.is_null());
 }
@@ -1015,6 +1067,18 @@
 
 void AutoEnrollmentClientImpl::ReportProgress(AutoEnrollmentState state) {
   state_ = state;
+  // If hash dance finished with an error or result, record comparison with
+  // private set membership. Note that hash dance might be retried but for
+  // recording we only care about the first attempt.
+  // If |private_set_membership_helper_| is non-null, a private set membership
+  // request has been made at this point because it is executed before hash
+  // dance.
+  const bool has_hash_dance_result = (state != AUTO_ENROLLMENT_STATE_IDLE &&
+                                      state != AUTO_ENROLLMENT_STATE_PENDING);
+  if (private_set_membership_helper_ && !recorded_psm_hash_dance_comparison_ &&
+      has_hash_dance_result) {
+    RecordPrivateSetMembershipHashDanceComparison();
+  }
   if (progress_callback_.is_null()) {
     base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
   } else {
@@ -1067,7 +1131,7 @@
   // Record the time when the bucket download request is started. Note that the
   // time may be set multiple times. This is fine, only the last request is the
   // one where the hash bucket is actually downloaded.
-  time_start_bucket_download_ = base::Time::Now();
+  time_start_bucket_download_ = base::TimeTicks::Now();
 
   VLOG(1) << "Request bucket #" << remainder;
   std::unique_ptr<DMServerJobConfiguration> config = std::make_unique<
@@ -1209,6 +1273,10 @@
     local_state_->CommitPendingWrite();
     VLOG(1) << "Received has_state=" << has_server_state_;
     progress = true;
+    // Report timing if hash dance finished successfully and if the caller is
+    // still interested in the result.
+    if (!progress_callback_.is_null())
+      RecordHashDanceSuccessTimeHistogram();
   }
 
   // Bucket download done, update UMA.
@@ -1269,6 +1337,8 @@
 }
 
 void AutoEnrollmentClientImpl::UpdateBucketDownloadTimingHistograms() {
+  // These values determine bucketing of the histogram, they should not be
+  // changed.
   // The minimum time can't be 0, must be at least 1.
   static const base::TimeDelta kMin = base::TimeDelta::FromMilliseconds(1);
   static const base::TimeDelta kMax = base::TimeDelta::FromMinutes(5);
@@ -1276,7 +1346,7 @@
   static const base::TimeDelta kZero = base::TimeDelta::FromMilliseconds(0);
   static const int kBuckets = 50;
 
-  base::Time now = base::Time::Now();
+  base::TimeTicks now = base::TimeTicks::Now();
   if (!time_start_.is_null()) {
     base::TimeDelta delta = now - time_start_;
     base::UmaHistogramCustomTimes(kUMAProtocolTime + uma_suffix_, delta, kMin,
@@ -1297,4 +1367,74 @@
                                 kBuckets);
 }
 
+void AutoEnrollmentClientImpl::RecordHashDanceSuccessTimeHistogram() {
+  // These values determine bucketing of the histogram, they should not be
+  // changed.
+  static const base::TimeDelta kMin = base::TimeDelta::FromMilliseconds(1);
+  static const base::TimeDelta kMax = base::TimeDelta::FromSeconds(25);
+  static const int kBuckets = 50;
+
+  base::TimeTicks now = base::TimeTicks::Now();
+  if (!time_start_.is_null()) {
+    base::TimeDelta delta = now - time_start_;
+    base::UmaHistogramCustomTimes(kUMAHashDanceSuccessTime + uma_suffix_, delta,
+                                  kMin, kMax, kBuckets);
+  }
+}
+
+void AutoEnrollmentClientImpl::RecordPrivateSetMembershipHashDanceComparison() {
+  // Private set membership timeout is enforced in the helper class. This method
+  // should only be called after private set membership request finished or ran
+  // into timeout.
+  DCHECK(private_set_membership_helper_);
+  DCHECK(!private_set_membership_helper_->IsCheckMembershipInProgress());
+
+  // Make sure to only record once per instance.
+  recorded_psm_hash_dance_comparison_ = true;
+
+  bool private_set_membership_decision =
+      private_set_membership_helper_->GetPrivateSetMembershipCachedDecision();
+  bool private_set_membership_error =
+      private_set_membership_helper_->HasPrivateSetMembershipError();
+
+  bool hash_dance_decision = has_server_state_;
+  bool hash_dance_error = false;
+  switch (state_) {
+    case AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT:
+    case AUTO_ENROLLMENT_STATE_NO_ENROLLMENT:
+    case AUTO_ENROLLMENT_STATE_TRIGGER_ZERO_TOUCH:
+    case AUTO_ENROLLMENT_STATE_DISABLED:
+      hash_dance_error = false;
+      break;
+    case AUTO_ENROLLMENT_STATE_CONNECTION_ERROR:
+    case AUTO_ENROLLMENT_STATE_SERVER_ERROR:
+      hash_dance_error = true;
+      break;
+    // This method should only be called if hash dance finished.
+    case AUTO_ENROLLMENT_STATE_IDLE:
+    case AUTO_ENROLLMENT_STATE_PENDING:
+    default:
+      NOTREACHED();
+  }
+
+  auto comparison = PrivateSetMembershipHashDanceComparison::kEqualResults;
+  if (!hash_dance_error && !private_set_membership_error) {
+    comparison =
+        (hash_dance_decision == private_set_membership_decision)
+            ? PrivateSetMembershipHashDanceComparison::kEqualResults
+            : PrivateSetMembershipHashDanceComparison::kDifferentResults;
+  } else if (hash_dance_error && !private_set_membership_error) {
+    comparison =
+        PrivateSetMembershipHashDanceComparison::kPSMSuccessHashDanceError;
+  } else if (!hash_dance_error && private_set_membership_error) {
+    comparison =
+        PrivateSetMembershipHashDanceComparison::kPSMErrorHashDanceSuccess;
+  } else {
+    comparison = PrivateSetMembershipHashDanceComparison::kBothError;
+  }
+
+  base::UmaHistogramEnumeration(kUMAPrivateSetMembershipHashDanceComparison,
+                                comparison);
+}
+
 }  // namespace policy
diff --git a/chrome/browser/chromeos/policy/auto_enrollment_client_impl.h b/chrome/browser/chromeos/policy/auto_enrollment_client_impl.h
index 68c34e8..932fd18f 100644
--- a/chrome/browser/chromeos/policy/auto_enrollment_client_impl.h
+++ b/chrome/browser/chromeos/policy/auto_enrollment_client_impl.h
@@ -47,6 +47,27 @@
 // Upon a failed determination it won't allow another membership check.
 class PrivateSetMembershipHelper;
 
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class PrivateSetMembershipStatus {
+  kAttempt = 0,
+  kSuccessfulDetermination = 1,
+  kError = 2,
+  kTimeout = 3,
+  kMaxValue = kTimeout,
+};
+
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class PrivateSetMembershipHashDanceComparison {
+  kEqualResults = 0,
+  kDifferentResults = 1,
+  kPSMErrorHashDanceSuccess = 2,
+  kPSMSuccessHashDanceError = 3,
+  kBothError = 4,
+  kMaxValue = kBothError,
+};
+
 // Interacts with the device management service and determines whether this
 // machine should automatically enter the Enterprise Enrollment screen during
 // OOBE.
@@ -194,6 +215,14 @@
   // Updates UMA histograms for bucket download timings.
   void UpdateBucketDownloadTimingHistograms();
 
+  // Updates the UMA histogram for successful hash dance.
+  void RecordHashDanceSuccessTimeHistogram();
+
+  // Records the UMA histogram comparing results of hash dance and private set
+  // membership. This function should be called after PSM and hash dance
+  // requests finished.
+  void RecordPrivateSetMembershipHashDanceComparison();
+
   // Callback to invoke when the protocol generates a relevant event. This can
   // be either successful completion or an error that requires external action.
   ProgressCallback progress_callback_;
@@ -253,17 +282,22 @@
   // If |time_start_| is not null, the protocol is still running.
   // If |time_extra_start_| is not null, the protocol is still running but our
   // owner has relinquished ownership.
-  base::Time time_start_;
-  base::Time time_extra_start_;
+  base::TimeTicks time_start_;
+  base::TimeTicks time_extra_start_;
 
   // The time when the bucket download part of the protocol started.
-  base::Time time_start_bucket_download_;
+  base::TimeTicks time_start_bucket_download_;
 
   // The UMA histogram suffix. Will be ".ForcedReenrollment" for an
   // |AutoEnrollmentClient| used for FRE and ".InitialEnrollment" for an
   // |AutoEnrollmentclient| used for initial enrollment.
   const std::string uma_suffix_;
 
+  // Whether this instance already recorded the comparison of private set
+  // membership and hash dance. This is required because we do not want to
+  // record the result again on a hash dance retry.
+  bool recorded_psm_hash_dance_comparison_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(AutoEnrollmentClientImpl);
 };
 
diff --git a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
index 3352ae4..ee6a2f0 100644
--- a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
+++ b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
@@ -477,6 +477,10 @@
   RestartDeviceCloudPolicyInitializer();
 }
 
+bool BrowserPolicyConnectorChromeOS::IsCommandLineSwitchSupported() const {
+  return true;
+}
+
 std::vector<std::unique_ptr<policy::ConfigurationPolicyProvider>>
 BrowserPolicyConnectorChromeOS::CreatePolicyProviders() {
   auto providers = ChromeBrowserPolicyConnector::CreatePolicyProviders();
diff --git a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h
index b47e167..9d7b7f0 100644
--- a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h
+++ b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h
@@ -226,6 +226,10 @@
 
   chromeos::AffiliationIDSet GetDeviceAffiliationIDs() const;
 
+  // BrowserPolicyConnector:
+  // Always returns true as command line flag can be set under dev mode only.
+  bool IsCommandLineSwitchSupported() const override;
+
  protected:
   // ChromeBrowserPolicyConnector:
   std::vector<std::unique_ptr<policy::ConfigurationPolicyProvider>>
diff --git a/chrome/browser/chromeos/policy/extension_install_event_log_collector.cc b/chrome/browser/chromeos/policy/extension_install_event_log_collector.cc
index 137ca4b..e1bbb06a 100644
--- a/chrome/browser/chromeos/policy/extension_install_event_log_collector.cc
+++ b/chrome/browser/chromeos/policy/extension_install_event_log_collector.cc
@@ -124,6 +124,8 @@
       return em::ExtensionInstallReportLogEvent::CRX_FETCH_URL_EMPTY;
     case extensions::InstallStageTracker::FailureReason::CRX_FETCH_URL_INVALID:
       return em::ExtensionInstallReportLogEvent::CRX_FETCH_URL_INVALID;
+    case extensions::InstallStageTracker::FailureReason::OVERRIDDEN_BY_SETTINGS:
+      return em::ExtensionInstallReportLogEvent::OVERRIDDEN_BY_SETTINGS;
     default:
       NOTREACHED();
   }
diff --git a/chrome/browser/chromeos/policy/system_log_uploader.cc b/chrome/browser/chromeos/policy/system_log_uploader.cc
index 5b5d063c..9148c6c 100644
--- a/chrome/browser/chromeos/policy/system_log_uploader.cc
+++ b/chrome/browser/chromeos/policy/system_log_uploader.cc
@@ -28,6 +28,7 @@
 #include "chrome/browser/chromeos/policy/upload_job_impl.h"
 #include "chrome/browser/device_identity/device_oauth2_token_service.h"
 #include "chrome/browser/device_identity/device_oauth2_token_service_factory.h"
+#include "chrome/browser/policy/chrome_browser_policy_connector.h"
 #include "chrome/browser/policy/chrome_policy_conversions_client.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/chrome_features.h"
@@ -267,7 +268,8 @@
 }
 
 std::string GetUploadUrl() {
-  return BrowserPolicyConnector::GetDeviceManagementUrl() +
+  return g_browser_process->browser_policy_connector()
+             ->GetDeviceManagementUrl() +
          kSystemLogUploadUrlTail;
 }
 
diff --git a/chrome/browser/chromeos/profiles/profile_helper.cc b/chrome/browser/chromeos/profiles/profile_helper.cc
index 955ccd46..249740f 100644
--- a/chrome/browser/chromeos/profiles/profile_helper.cc
+++ b/chrome/browser/chromeos/profiles/profile_helper.cc
@@ -62,6 +62,7 @@
     "40FF1103292F40C34066E023B8BE8CAE18306EAE",  // Chromeos help
     "3C654B3B6682CA194E75AD044CEDE927675DDEE8",  // Easy unlock
     "75C7F4B720314B6CB1B5817CD86089DB95CD2461",  // ChromeVox
+    "4D725C894DA4CF1F4D96C60F0D83BD745EB530CA",  // Switch Access
 };
 
 // As defined in /chromeos/dbus/cryptohome/cryptohome_client.cc.
diff --git a/chrome/browser/component_updater/first_party_sets_component_installer.cc b/chrome/browser/component_updater/first_party_sets_component_installer.cc
new file mode 100644
index 0000000..4af1937
--- /dev/null
+++ b/chrome/browser/component_updater/first_party_sets_component_installer.cc
@@ -0,0 +1,162 @@
+// 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/component_updater/first_party_sets_component_installer.h"
+
+#include "base/bind.h"
+#include "base/feature_list.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/optional.h"
+#include "base/path_service.h"
+#include "base/stl_util.h"
+#include "base/task/post_task.h"
+#include "base/task/thread_pool.h"
+#include "base/version.h"
+#include "components/component_updater/component_updater_paths.h"
+#include "services/network/public/cpp/features.h"
+
+using component_updater::ComponentUpdateService;
+
+namespace {
+
+constexpr base::FilePath::CharType kFirstPartySetsSetsFileName[] =
+    FILE_PATH_LITERAL("sets.json");
+
+// The SHA256 of the SubjectPublicKeyInfo used to sign the extension.
+// The extension id is: gonpemdgkjcecdgbnaabipppbmgfggbe
+constexpr uint8_t kFirstPartySetsPublicKeySHA256[32] = {
+    0x6e, 0xdf, 0x4c, 0x36, 0xa9, 0x24, 0x23, 0x61, 0xd0, 0x01, 0x8f,
+    0xff, 0x1c, 0x65, 0x66, 0x14, 0xa8, 0x46, 0x37, 0xe6, 0xeb, 0x80,
+    0x8b, 0x8f, 0xb0, 0xb6, 0x18, 0xa7, 0xcd, 0x3d, 0xbb, 0xfb};
+
+constexpr char kFirstPartySetsManifestName[] = "First-Party Sets";
+
+constexpr base::FilePath::CharType kFirstPartySetsRelativeInstallDir[] =
+    FILE_PATH_LITERAL("FirstPartySetsPreloaded");
+
+// Reads the sets as raw JSON from their storage file, returning the raw sets on
+// success and nullopt on failure.
+base::Optional<std::string> LoadSetsFromDisk(const base::FilePath& pb_path) {
+  if (pb_path.empty())
+    return base::nullopt;
+
+  VLOG(1) << "Reading First-Party Sets from file: " << pb_path.value();
+  std::string result;
+  if (!base::ReadFileToString(pb_path, &result)) {
+    // The file won't exist on new installations, so this is not always an
+    // error.
+    VLOG(1) << "Failed reading from " << pb_path.value();
+    return base::nullopt;
+  }
+  return result;
+}
+
+}  // namespace
+
+namespace component_updater {
+
+FirstPartySetsComponentInstallerPolicy::FirstPartySetsComponentInstallerPolicy(
+    base::RepeatingCallback<void(const std::string&)> on_sets_ready)
+    : on_sets_ready_(std::move(on_sets_ready)) {}
+
+FirstPartySetsComponentInstallerPolicy::
+    ~FirstPartySetsComponentInstallerPolicy() = default;
+
+bool FirstPartySetsComponentInstallerPolicy::
+    SupportsGroupPolicyEnabledComponentUpdates() const {
+  // False since this is a data, non-binary component.
+  return false;
+}
+
+bool FirstPartySetsComponentInstallerPolicy::RequiresNetworkEncryption() const {
+  // Update checks and pings associated with this component do not require
+  // confidentiality, since the component is identical for all users.
+  return false;
+}
+
+update_client::CrxInstaller::Result
+FirstPartySetsComponentInstallerPolicy::OnCustomInstall(
+    const base::DictionaryValue& manifest,
+    const base::FilePath& install_dir) {
+  return update_client::CrxInstaller::Result(0);  // Nothing custom here.
+}
+
+void FirstPartySetsComponentInstallerPolicy::OnCustomUninstall() {}
+
+base::FilePath FirstPartySetsComponentInstallerPolicy::GetInstalledPath(
+    const base::FilePath& base) {
+  return base.Append(kFirstPartySetsSetsFileName);
+}
+
+void FirstPartySetsComponentInstallerPolicy::ComponentReady(
+    const base::Version& version,
+    const base::FilePath& install_dir,
+    std::unique_ptr<base::DictionaryValue> manifest) {
+  VLOG(1) << "First-Party Sets Component ready, version " << version.GetString()
+          << " in " << install_dir.value();
+
+  base::ThreadPool::PostTaskAndReplyWithResult(
+      FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
+      base::BindOnce(&LoadSetsFromDisk, GetInstalledPath(install_dir)),
+      base::BindOnce(
+          [](base::RepeatingCallback<void(const std::string&)> on_sets_ready,
+             base::Optional<std::string> raw_sets) {
+            if (raw_sets.has_value())
+              on_sets_ready.Run(*raw_sets);
+          },
+          on_sets_ready_));
+}
+
+// Called during startup and installation before ComponentReady().
+bool FirstPartySetsComponentInstallerPolicy::VerifyInstallation(
+    const base::DictionaryValue& manifest,
+    const base::FilePath& install_dir) const {
+  // No need to actually validate the sets here, since we'll do the validation
+  // in the Network Service.
+  return base::PathExists(GetInstalledPath(install_dir));
+}
+
+base::FilePath FirstPartySetsComponentInstallerPolicy::GetRelativeInstallDir()
+    const {
+  return base::FilePath(kFirstPartySetsRelativeInstallDir);
+}
+
+void FirstPartySetsComponentInstallerPolicy::GetHash(
+    std::vector<uint8_t>* hash) const {
+  hash->assign(kFirstPartySetsPublicKeySHA256,
+               kFirstPartySetsPublicKeySHA256 +
+                   base::size(kFirstPartySetsPublicKeySHA256));
+}
+
+std::string FirstPartySetsComponentInstallerPolicy::GetName() const {
+  return kFirstPartySetsManifestName;
+}
+
+update_client::InstallerAttributes
+FirstPartySetsComponentInstallerPolicy::GetInstallerAttributes() const {
+  return update_client::InstallerAttributes();
+}
+
+std::vector<std::string> FirstPartySetsComponentInstallerPolicy::GetMimeTypes()
+    const {
+  return {};
+}
+
+void RegisterFirstPartySetsComponent(ComponentUpdateService* cus) {
+  if (!base::FeatureList::IsEnabled(network::features::kFirstPartySets))
+    return;
+  VLOG(1) << "Registering First-Party Sets component.";
+  auto installer = base::MakeRefCounted<ComponentInstaller>(
+      std::make_unique<FirstPartySetsComponentInstallerPolicy>(
+          /*on_sets_ready=*/base::BindRepeating(
+              [](const std ::string& raw_sets) {
+                // TODO(cfredric): forward to NetworkService here.
+                VLOG(1) << "Received Sets: \"" << raw_sets << "\"";
+              })));
+  installer->Register(cus, base::OnceClosure());
+}
+
+}  // namespace component_updater
diff --git a/chrome/browser/component_updater/first_party_sets_component_installer.h b/chrome/browser/component_updater/first_party_sets_component_installer.h
new file mode 100644
index 0000000..063334553
--- /dev/null
+++ b/chrome/browser/component_updater/first_party_sets_component_installer.h
@@ -0,0 +1,71 @@
+// 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_COMPONENT_UPDATER_FIRST_PARTY_SETS_COMPONENT_INSTALLER_H_
+#define CHROME_BROWSER_COMPONENT_UPDATER_FIRST_PARTY_SETS_COMPONENT_INSTALLER_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/values.h"
+#include "components/component_updater/component_installer.h"
+
+namespace base {
+class FilePath;
+}  // namespace base
+
+namespace component_updater {
+
+class ComponentUpdateService;
+
+class FirstPartySetsComponentInstallerPolicy : public ComponentInstallerPolicy {
+ public:
+  // |on_sets_ready| will be called on the UI thread when the sets are ready. It
+  // is exposed here for testing.
+  explicit FirstPartySetsComponentInstallerPolicy(
+      base::RepeatingCallback<void(const std::string&)> on_sets_ready);
+  ~FirstPartySetsComponentInstallerPolicy() override;
+
+  FirstPartySetsComponentInstallerPolicy(
+      const FirstPartySetsComponentInstallerPolicy&) = delete;
+  FirstPartySetsComponentInstallerPolicy operator=(
+      const FirstPartySetsComponentInstallerPolicy&) = delete;
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(FirstPartySetsComponentInstallerTest, LoadsSets);
+
+  // The following methods override ComponentInstallerPolicy.
+  bool SupportsGroupPolicyEnabledComponentUpdates() const override;
+  bool RequiresNetworkEncryption() const override;
+  update_client::CrxInstaller::Result OnCustomInstall(
+      const base::DictionaryValue& manifest,
+      const base::FilePath& install_dir) override;
+  void OnCustomUninstall() override;
+  bool VerifyInstallation(const base::DictionaryValue& manifest,
+                          const base::FilePath& install_dir) const override;
+  void ComponentReady(const base::Version& version,
+                      const base::FilePath& install_dir,
+                      std::unique_ptr<base::DictionaryValue> manifest) override;
+  base::FilePath GetRelativeInstallDir() const override;
+  void GetHash(std::vector<uint8_t>* hash) const override;
+  std::string GetName() const override;
+  update_client::InstallerAttributes GetInstallerAttributes() const override;
+  std::vector<std::string> GetMimeTypes() const override;
+
+  static base::FilePath GetInstalledPath(const base::FilePath& base);
+
+  base::RepeatingCallback<void(const std::string&)> on_sets_ready_;
+};
+
+// Call once during startup to make the component update service aware of
+// the First-Party Sets component.
+void RegisterFirstPartySetsComponent(ComponentUpdateService* cus);
+
+}  // namespace component_updater
+
+#endif  // CHROME_BROWSER_COMPONENT_UPDATER_FIRST_PARTY_SETS_COMPONENT_INSTALLER_H_
diff --git a/chrome/browser/component_updater/first_party_sets_component_installer_unittest.cc b/chrome/browser/component_updater/first_party_sets_component_installer_unittest.cc
new file mode 100644
index 0000000..97c4f072
--- /dev/null
+++ b/chrome/browser/component_updater/first_party_sets_component_installer_unittest.cc
@@ -0,0 +1,77 @@
+// 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/component_updater/first_party_sets_component_installer.h"
+
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/run_loop.h"
+#include "base/sequence_checker.h"
+#include "base/test/bind_test_util.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/task_environment.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/version.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/base/testing_browser_process.h"
+#include "components/component_updater/mock_component_updater_service.h"
+#include "services/network/public/cpp/features.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace component_updater {
+
+namespace {
+using ::testing::_;
+}  // namespace
+
+class FirstPartySetsComponentInstallerTest : public ::testing::Test {
+ public:
+  FirstPartySetsComponentInstallerTest() {
+    CHECK(component_install_dir_.CreateUniqueTempDir());
+  }
+
+ protected:
+  base::test::TaskEnvironment env_;
+
+  base::ScopedTempDir component_install_dir_;
+};
+
+TEST_F(FirstPartySetsComponentInstallerTest, FeatureDisabled) {
+  base::test::ScopedFeatureList scoped_list;
+  scoped_list.InitAndDisableFeature(network::features::kFirstPartySets);
+  auto service =
+      std::make_unique<component_updater::MockComponentUpdateService>();
+  EXPECT_CALL(*service, RegisterComponent(_)).Times(0);
+  RegisterFirstPartySetsComponent(service.get());
+
+  env_.RunUntilIdle();
+}
+
+TEST_F(FirstPartySetsComponentInstallerTest, LoadsSets) {
+  base::test::ScopedFeatureList scoped_list;
+  scoped_list.InitAndEnableFeature(network::features::kFirstPartySets);
+
+  SEQUENCE_CHECKER(sequence_checker);
+  const std::string expectation = "some first party sets";
+  base::RunLoop run_loop;
+  auto policy = std::make_unique<FirstPartySetsComponentInstallerPolicy>(
+      base::BindLambdaForTesting([&](const std::string& got) {
+        DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker);
+        EXPECT_EQ(got, expectation);
+        run_loop.Quit();
+      }));
+
+  ASSERT_TRUE(
+      base::WriteFile(FirstPartySetsComponentInstallerPolicy::GetInstalledPath(
+                          component_install_dir_.GetPath()),
+                      expectation));
+
+  policy->ComponentReady(base::Version(), component_install_dir_.GetPath(),
+                         std::make_unique<base::DictionaryValue>());
+
+  run_loop.Run();
+}
+
+}  // namespace component_updater
diff --git a/chrome/browser/component_updater/origin_trials_component_installer.cc b/chrome/browser/component_updater/origin_trials_component_installer.cc
index ae36148..dbac2b8 100644
--- a/chrome/browser/component_updater/origin_trials_component_installer.cc
+++ b/chrome/browser/component_updater/origin_trials_component_installer.cc
@@ -146,8 +146,7 @@
   return std::vector<std::string>();
 }
 
-void RegisterOriginTrialsComponent(ComponentUpdateService* cus,
-                                   const base::FilePath& user_data_dir) {
+void RegisterOriginTrialsComponent(ComponentUpdateService* cus) {
   auto installer = base::MakeRefCounted<ComponentInstaller>(
       std::make_unique<OriginTrialsComponentInstallerPolicy>());
   installer->Register(cus, base::OnceClosure());
diff --git a/chrome/browser/component_updater/origin_trials_component_installer.h b/chrome/browser/component_updater/origin_trials_component_installer.h
index 81df45b2..03c059e 100644
--- a/chrome/browser/component_updater/origin_trials_component_installer.h
+++ b/chrome/browser/component_updater/origin_trials_component_installer.h
@@ -49,8 +49,7 @@
 
 // Call once during startup to make the component update service aware of
 // the origin trials update component.
-void RegisterOriginTrialsComponent(ComponentUpdateService* cus,
-                                   const base::FilePath& user_data_dir);
+void RegisterOriginTrialsComponent(ComponentUpdateService* cus);
 
 }  // namespace component_updater
 
diff --git a/chrome/browser/component_updater/registration.cc b/chrome/browser/component_updater/registration.cc
index d5d00c9..302cca1f3 100644
--- a/chrome/browser/component_updater/registration.cc
+++ b/chrome/browser/component_updater/registration.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/component_updater/crl_set_component_installer.h"
 #include "chrome/browser/component_updater/crowd_deny_component_installer.h"
 #include "chrome/browser/component_updater/file_type_policies_component_installer.h"
+#include "chrome/browser/component_updater/first_party_sets_component_installer.h"
 #include "chrome/browser/component_updater/floc_blocklist_component_installer.h"
 #include "chrome/browser/component_updater/games_component_installer.h"
 #include "chrome/browser/component_updater/mei_preload_component_installer.h"
@@ -126,6 +127,7 @@
       cus, g_browser_process->GetApplicationLocale());
   RegisterOptimizationHintsComponent(cus, is_off_the_record_profile);
   RegisterTrustTokenKeyCommitmentsComponentIfTrustTokensEnabled(cus);
+  RegisterFirstPartySetsComponent(cus);
 
   base::FilePath path;
   if (base::PathService::Get(chrome::DIR_USER_DATA, &path)) {
@@ -140,8 +142,6 @@
     // Chrome OS: On Chrome OS, this cleanup is delayed until user login.
     component_updater::DeleteLegacySTHSet(path);
 #endif
-
-    RegisterOriginTrialsComponent(cus, path);
   }
   RegisterSSLErrorAssistantComponent(cus);
   RegisterFileTypePoliciesComponent(cus);
@@ -152,6 +152,7 @@
   component_updater::RegisterCRLSetComponent(cus);
 #endif  // !defined(OS_CHROMEOS)
 
+  RegisterOriginTrialsComponent(cus);
   RegisterMediaEngagementPreloadComponent(cus, base::OnceClosure());
 
 #if defined(OS_WIN)
diff --git a/chrome/browser/devtools/devtools_sanity_browsertest.cc b/chrome/browser/devtools/devtools_sanity_browsertest.cc
index e85be3f..c997b14b 100644
--- a/chrome/browser/devtools/devtools_sanity_browsertest.cc
+++ b/chrome/browser/devtools/devtools_sanity_browsertest.cc
@@ -29,6 +29,7 @@
 #include "base/threading/thread_restrictions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/devtools/device/tcp_device_provider.h"
 #include "chrome/browser/devtools/devtools_window_testing.h"
@@ -66,6 +67,7 @@
 #include "components/javascript_dialogs/app_modal_dialog_view.h"
 #include "components/keep_alive_registry/keep_alive_registry.h"
 #include "components/keep_alive_registry/keep_alive_types.h"
+#include "components/language/core/browser/pref_names.h"
 #include "components/policy/core/common/mock_configuration_policy_provider.h"
 #include "components/policy/core/common/policy_map.h"
 #include "components/policy/policy_constants.h"
@@ -2578,24 +2580,53 @@
   CloseDevToolsWindow();
 }
 
+namespace {
+
 class DevToolsLocalizationTest : public DevToolsSanityTest {
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    command_line->AppendSwitchASCII(switches::kLang, "es-ES");
+ public:
+  bool NavigatorLanguageMatches(const std::string& expected_locale) {
+    bool result = false;
+    const bool execute_result = content::ExecuteScriptAndExtractBool(
+        main_web_contents(),
+        "window.domAutomationController.send(window.navigator.language === "
+        "'" +
+            expected_locale + "')",
+        &result);
+    return execute_result && result;
   }
 };
 
-// Make it run on Windows only since the browser language on Mac
-// is tied to the OS language and --lang flag won't work
-#if defined(OS_WIN)
-IN_PROC_BROWSER_TEST_F(DevToolsLocalizationTest, testNavigatorLanguage) {
-  bool result = false;
-  OpenDevToolsWindow("about:blank", true);
-  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
-      main_web_contents(),
-      "window.domAutomationController.send(window.navigator.language === "
-      "'es-ES')",
-      &result));
-  EXPECT_TRUE(result);
+}  // namespace
+
+IN_PROC_BROWSER_TEST_F(DevToolsLocalizationTest,
+                       NavigatorLanguageMatchesApplicationLocaleDocked) {
+  g_browser_process->SetApplicationLocale("es");
+
+  OpenDevToolsWindow("about:blank", /* is_docked */ true);
+  EXPECT_TRUE(NavigatorLanguageMatches("es"));
   CloseDevToolsWindow();
 }
-#endif  // defined(OS_WIN)
+
+IN_PROC_BROWSER_TEST_F(DevToolsLocalizationTest,
+                       NavigatorLanguageMatchesApplicationLocaleUndocked) {
+  g_browser_process->SetApplicationLocale("es");
+
+  OpenDevToolsWindow("about:blank", /* is_docked */ false);
+  EXPECT_TRUE(NavigatorLanguageMatches("es"));
+  CloseDevToolsWindow();
+}
+
+IN_PROC_BROWSER_TEST_F(DevToolsLocalizationTest,
+                       AcceptedLanguageChangesWhileDevToolsIsOpen) {
+  g_browser_process->SetApplicationLocale("es");
+
+  OpenDevToolsWindow("about:blank", true);
+  EXPECT_TRUE(NavigatorLanguageMatches("es"));
+
+  PrefService* prefs = browser()->profile()->GetPrefs();
+  prefs->SetString(language::prefs::kAcceptLanguages, "de-DE");
+
+  EXPECT_TRUE(NavigatorLanguageMatches("es"));
+
+  CloseDevToolsWindow();
+}
diff --git a/chrome/browser/devtools/devtools_ui_bindings.cc b/chrome/browser/devtools/devtools_ui_bindings.cc
index 441559ec..e457463 100644
--- a/chrome/browser/devtools/devtools_ui_bindings.cc
+++ b/chrome/browser/devtools/devtools_ui_bindings.cc
@@ -130,6 +130,10 @@
     "DevTools.ColorPicker.FixedColor";
 static const char kDevToolsComputedStyleGroupingHistogram[] =
     "DevTools.ComputedStyleGrouping";
+static const char kDevtoolsIssuesPanelIssueExpandedHistogram[] =
+    "DevTools.IssuesPanelIssueExpanded";
+static const char kDevtoolsIssuesPanelResourceOpenedHistogram[] =
+    "DevTools.IssuesPanelResourceOpened";
 
 static const char kRemotePageActionInspect[] = "inspect";
 static const char kRemotePageActionReload[] = "reload";
@@ -677,9 +681,6 @@
       frontend_loaded_(false) {
   g_devtools_ui_bindings_instances.Get().push_back(this);
   frontend_contents_observer_.reset(new FrontendWebContentsObserver(this));
-  web_contents_->GetMutableRendererPrefs()->can_accept_load_drops = false;
-  web_contents_->GetMutableRendererPrefs()->accept_languages =
-      g_browser_process->GetApplicationLocale();
 
   file_helper_.reset(new DevToolsFileHelper(web_contents_, profile_, this));
   file_system_indexer_ = new DevToolsFileSystemIndexer();
@@ -1311,6 +1312,10 @@
     base::UmaHistogramExactLinear(name, sample, boundary_value);
   else if (name == kDevToolsComputedStyleGroupingHistogram)
     base::UmaHistogramExactLinear(name, sample, boundary_value);
+  else if (name == kDevtoolsIssuesPanelIssueExpandedHistogram)
+    base::UmaHistogramExactLinear(name, sample, boundary_value);
+  else if (name == kDevtoolsIssuesPanelResourceOpenedHistogram)
+    base::UmaHistogramExactLinear(name, sample, boundary_value);
   else
     frontend_host_->BadMessageRecieved();
 }
diff --git a/chrome/browser/devtools/devtools_window.cc b/chrome/browser/devtools/devtools_window.cc
index ec271f2f..fc368fb 100644
--- a/chrome/browser/devtools/devtools_window.cc
+++ b/chrome/browser/devtools/devtools_window.cc
@@ -17,6 +17,7 @@
 #include "base/metrics/user_metrics.h"
 #include "base/time/time.h"
 #include "base/values.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/certificate_viewer.h"
 #include "chrome/browser/devtools/chrome_devtools_manager_delegate.h"
 #include "chrome/browser/devtools/devtools_eye_dropper.h"
@@ -39,6 +40,7 @@
 #include "components/javascript_dialogs/app_modal_dialog_manager.h"
 #include "components/keep_alive_registry/keep_alive_types.h"
 #include "components/keep_alive_registry/scoped_keep_alive.h"
+#include "components/language/core/browser/pref_names.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/scoped_user_pref_update.h"
 #include "components/sessions/content/session_tab_helper.h"
@@ -66,6 +68,7 @@
 #include "net/base/escape.h"
 #include "third_party/blink/public/common/input/web_gesture_event.h"
 #include "third_party/blink/public/common/input/web_input_event.h"
+#include "third_party/blink/public/mojom/renderer_preferences.mojom.h"
 #include "third_party/blink/public/public_buildflags.h"
 #include "ui/base/page_transition_types.h"
 #include "ui/events/keycodes/dom/keycode_converter.h"
@@ -860,7 +863,7 @@
     main_web_contents_->SetInitialFocus();
 
     PrefsTabHelper::CreateForWebContents(main_web_contents_);
-    main_web_contents_->SyncRendererPrefs();
+    OverrideAndSyncDevToolsRendererPrefs();
 
     DoAction(action);
     return;
@@ -1021,6 +1024,12 @@
       g_creation_callbacks.Get());
   for (const auto& callback : copy)
     callback.Run(this);
+
+  pref_change_registrar_.Init(profile_->GetPrefs());
+  pref_change_registrar_.Add(
+      language::prefs::kAcceptLanguages,
+      base::BindRepeating(&DevToolsWindow::OnLocaleChanged,
+                          base::Unretained(this)));
 }
 
 // static
@@ -1579,7 +1588,7 @@
       OwnedMainWebContents::TakeWebContents(
           std::move(owned_main_web_contents_)),
       -1, ui::PAGE_TRANSITION_AUTO_TOPLEVEL, TabStripModel::ADD_ACTIVE);
-  main_web_contents_->SyncRendererPrefs();
+  OverrideAndSyncDevToolsRendererPrefs();
 }
 
 BrowserWindow* DevToolsWindow::GetInspectedBrowserWindow() {
@@ -1681,3 +1690,14 @@
 void DevToolsWindow::OnReattachMainTargetComplete(base::Value) {
   std::move(reattach_complete_callback_).Run();
 }
+
+void DevToolsWindow::OnLocaleChanged() {
+  OverrideAndSyncDevToolsRendererPrefs();
+}
+
+void DevToolsWindow::OverrideAndSyncDevToolsRendererPrefs() {
+  main_web_contents_->GetMutableRendererPrefs()->can_accept_load_drops = false;
+  main_web_contents_->GetMutableRendererPrefs()->accept_languages =
+      g_browser_process->GetApplicationLocale();
+  main_web_contents_->SyncRendererPrefs();
+}
diff --git a/chrome/browser/devtools/devtools_window.h b/chrome/browser/devtools/devtools_window.h
index 5149147..2d481b5 100644
--- a/chrome/browser/devtools/devtools_window.h
+++ b/chrome/browser/devtools/devtools_window.h
@@ -384,6 +384,15 @@
 
   void OnReattachMainTargetComplete(base::Value);
 
+  // Called when the accepted language changes. |navigator.language| of the
+  // DevTools window should match the application language. When the user
+  // changes the accepted language then this listener flips the language back
+  // to the application language for the DevTools renderer process.
+  // Please note that |navigator.language| will have the wrong language for
+  // a very short period of time (until this handler has reset it again).
+  void OnLocaleChanged();
+  void OverrideAndSyncDevToolsRendererPrefs();
+
   std::unique_ptr<ObserverWithAccessor> inspected_contents_observer_;
 
   FrontendType frontend_type_;
@@ -432,6 +441,8 @@
 
   base::OnceCallback<void()> reattach_complete_callback_;
 
+  PrefChangeRegistrar pref_change_registrar_;
+
   friend class DevToolsEventForwarder;
   DISALLOW_COPY_AND_ASSIGN(DevToolsWindow);
 };
diff --git a/chrome/browser/download/save_page_browsertest.cc b/chrome/browser/download/save_page_browsertest.cc
index 51f9d39f..1450ce297 100644
--- a/chrome/browser/download/save_page_browsertest.cc
+++ b/chrome/browser/download/save_page_browsertest.cc
@@ -535,8 +535,7 @@
 };
 
 // Disabled on multiple platforms due to flakiness. crbug.com/580766
-#if defined(OS_CHROMEOS) || \
-    (defined(OS_WIN) || defined(OS_LINUX)) && defined(NDEBUG)
+#if defined(OS_CHROMEOS) || defined(OS_WIN) || defined(OS_LINUX)
 #define MAYBE_SaveHTMLOnlyTabDestroy DISABLED_SaveHTMLOnlyTabDestroy
 #else
 #define MAYBE_SaveHTMLOnlyTabDestroy SaveHTMLOnlyTabDestroy
diff --git a/chrome/browser/extensions/api/passwords_private/password_check_delegate_unittest.cc b/chrome/browser/extensions/api/passwords_private/password_check_delegate_unittest.cc
index a442f53..7ffbb997 100644
--- a/chrome/browser/extensions/api/passwords_private/password_check_delegate_unittest.cc
+++ b/chrome/browser/extensions/api/passwords_private/password_check_delegate_unittest.cc
@@ -216,8 +216,6 @@
  public:
   PasswordCheckDelegateTest() {
     prefs_.registry()->RegisterDoublePref(kLastTimePasswordCheckCompleted, 0.0);
-    scoped_feature_list_.InitAndEnableFeature(
-        password_manager::features::kPasswordCheck);
   }
 
   void RunUntilIdle() { task_env_.RunUntilIdle(); }
@@ -232,13 +230,8 @@
   PasswordCheckDelegate& delegate() { return delegate_; }
 
   void EnableWellKnownChangePasswordFeatureFlag() {
-    scoped_feature_list_.Reset();
-    scoped_feature_list_.InitWithFeatures(
-        {
-            password_manager::features::kPasswordCheck,
-            password_manager::features::kWellKnownChangePassword,
-        },
-        {});
+    scoped_feature_list_.InitAndEnableFeature(
+        password_manager::features::kWellKnownChangePassword);
   }
 
  private:
diff --git a/chrome/browser/extensions/extension_management.cc b/chrome/browser/extensions/extension_management.cc
index c6a79618..4530035 100644
--- a/chrome/browser/extensions/extension_management.cc
+++ b/chrome/browser/extensions/extension_management.cc
@@ -502,6 +502,8 @@
             continue;
           }
           internal::IndividualSettings* by_id = AccessById(extension_id);
+          const bool included_in_forcelist =
+              by_id->installation_mode == InstallationMode::INSTALLATION_FORCED;
           if (!by_id->Parse(subdict,
                             internal::IndividualSettings::SCOPE_INDIVIDUAL)) {
             settings_by_id_.erase(extension_id);
@@ -511,6 +513,16 @@
             SYSLOG(WARNING) << "Malformed Extension Management settings for "
                             << extension_id << ".";
           }
+          // If applying the ExtensionSettings policy changes installation mode
+          // from force-installed to anything else, the extension might not get
+          // installed and will get stuck in CREATED stage.
+          if (included_in_forcelist &&
+              by_id->installation_mode !=
+                  InstallationMode::INSTALLATION_FORCED) {
+            install_stage_tracker->ReportFailure(
+                extension_id,
+                InstallStageTracker::FailureReason::OVERRIDDEN_BY_SETTINGS);
+          }
         }
       }
     }
diff --git a/chrome/browser/extensions/forced_extensions/force_installed_metrics_unittest.cc b/chrome/browser/extensions/forced_extensions/force_installed_metrics_unittest.cc
index bf585a2..e3a2d3e6 100644
--- a/chrome/browser/extensions/forced_extensions/force_installed_metrics_unittest.cc
+++ b/chrome/browser/extensions/forced_extensions/force_installed_metrics_unittest.cc
@@ -193,6 +193,18 @@
     base::RunLoop().RunUntilIdle();
   }
 
+  void SetupExtensionManagementPref() {
+    std::unique_ptr<base::DictionaryValue> extension_entry =
+        DictionaryBuilder()
+            .Set("installation_mode", "allowed")
+            .Set(ExternalProviderImpl::kExternalUpdateUrl, kExtensionUpdateUrl)
+            .Build();
+    prefs_->SetManagedPref(pref_names::kExtensionManagement,
+                           DictionaryBuilder()
+                               .Set(kExtensionId1, std::move(extension_entry))
+                               .Build());
+  }
+
   void SetupEmptyForceList() {
     std::unique_ptr<base::Value> dict = DictionaryBuilder().Build();
     prefs_->SetManagedPref(pref_names::kInstallForceList, std::move(dict));
@@ -299,6 +311,23 @@
   EXPECT_EQ(1u, ready_call_count_);
 }
 
+// Verifies that failure is reported for the extensions which are listed in
+// forced list, and their installation mode are overridden by ExtensionSettings
+// policy to something else.
+TEST_F(ForceInstalledMetricsTest, ExtensionSettingsOverrideForcedList) {
+  SetupForceList();
+  SetupExtensionManagementPref();
+  auto ext2 = ExtensionBuilder(kExtensionName2).SetID(kExtensionId2).Build();
+  tracker_->OnExtensionLoaded(profile_, ext2.get());
+  // ForceInstalledMetrics shuts down timer because all extension are either
+  // loaded or failed.
+  EXPECT_FALSE(fake_timer_->IsRunning());
+  EXPECT_EQ(1u, loaded_call_count_);
+  histogram_tester_.ExpectBucketCount(
+      kFailureReasonsCWS,
+      InstallStageTracker::FailureReason::OVERRIDDEN_BY_SETTINGS, 1);
+}
+
 TEST_F(ForceInstalledMetricsTest, ObserversOnlyCalledOnce) {
   // Start with a non-empty force-list, and install them, which triggers
   // observer.
diff --git a/chrome/browser/extensions/forced_extensions/install_stage_tracker.h b/chrome/browser/extensions/forced_extensions/install_stage_tracker.h
index 6a3878d1..84424e7 100644
--- a/chrome/browser/extensions/forced_extensions/install_stage_tracker.h
+++ b/chrome/browser/extensions/forced_extensions/install_stage_tracker.h
@@ -184,9 +184,13 @@
     // The download of the crx failed.
     CRX_FETCH_URL_INVALID = 26,
 
+    // Applying the ExtensionSettings policy changed installation mode from
+    // force-installed to anything else.
+    OVERRIDDEN_BY_SETTINGS = 27,
+
     // Magic constant used by the histogram macros.
     // Always update it to the max value.
-    kMaxValue = CRX_FETCH_URL_INVALID,
+    kMaxValue = OVERRIDDEN_BY_SETTINGS,
   };
 
   // Status for the app returned by server while fetching manifest when status
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index da69301..09c70413 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -4563,6 +4563,12 @@
     "expiry_milestone": -1
   },
   {
+    "name": "use-wallpaper-staging-url",
+    "owners": [ "cros-customization@google.com", "hsuregan", "khorimoto" ],
+    // This flag is required for QA and dogfood testing.
+    "expiry_milestone": -1
+  },
+  {
     "name": "use-winrt-midi-api",
     "owners": [ "toyoshim" ],
     "expiry_milestone": 86
diff --git a/chrome/browser/flag-never-expire-list.json b/chrome/browser/flag-never-expire-list.json
index 1f476ec0..9def851e 100644
--- a/chrome/browser/flag-never-expire-list.json
+++ b/chrome/browser/flag-never-expire-list.json
@@ -95,6 +95,7 @@
   "use-fake-device-for-media-stream",
   "use_messages_staging_url",
   "use-sync-sandbox",
+  "use-wallpaper-staging-url",
   "wallet-service-use-sandbox",
   "webxr-runtime"
 ]
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index c5f0c535..221ba13 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -156,6 +156,11 @@
     "Use lookalike URL suggestions to suggest navigations to users who "
     "face domain not found error.";
 
+const char kUseWallpaperStagingUrlName[] = "Use Wallpaper staging URL";
+const char kUseWallpaperStagingUrlDescription[] =
+    "Use the staging server as part of the Wallpaper App to verify "
+    "additions/removals of wallpapers.";
+
 const char kUseMessagesStagingUrlName[] = "Use Messages staging URL";
 const char kUseMessagesStagingUrlDescription[] =
     "Use the staging server as part of the \"Messages\" feature under "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 3744848..627bfd0 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -114,6 +114,9 @@
 extern const char kUseLookalikesForNavigationSuggestionsName[];
 extern const char kUseLookalikesForNavigationSuggestionsDescription[];
 
+extern const char kUseWallpaperStagingUrlName[];
+extern const char kUseWallpaperStagingUrlDescription[];
+
 extern const char kUseMessagesStagingUrlName[];
 extern const char kUseMessagesStagingUrlDescription[];
 
diff --git a/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager.cc b/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager.cc
index 109c3d3..2b0524f 100644
--- a/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager.cc
+++ b/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager.cc
@@ -17,13 +17,17 @@
 }
 
 void NearbyShareCertificateManager::Start() {
-  DCHECK(!is_running_);
+  if (is_running_)
+    return;
+
   is_running_ = true;
   OnStart();
 }
 
 void NearbyShareCertificateManager::Stop() {
-  DCHECK(is_running_);
+  if (!is_running_)
+    return;
+
   is_running_ = false;
   OnStop();
 }
diff --git a/chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager.cc b/chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager.cc
index 02be5f0..941e1b7 100644
--- a/chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager.cc
+++ b/chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager.cc
@@ -17,13 +17,17 @@
 }
 
 void NearbyShareContactManager::Start() {
-  DCHECK(!is_running_);
+  if (is_running_)
+    return;
+
   is_running_ = true;
   OnStart();
 }
 
 void NearbyShareContactManager::Stop() {
-  DCHECK(is_running_);
+  if (!is_running_)
+    return;
+
   is_running_ = false;
   OnStop();
 }
diff --git a/chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager_impl.cc b/chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager_impl.cc
index 56211c48..7a84f36 100644
--- a/chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager_impl.cc
+++ b/chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager_impl.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/nearby_sharing/contacts/nearby_share_contact_downloader.h"
 #include "chrome/browser/nearby_sharing/contacts/nearby_share_contact_downloader_impl.h"
 #include "chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager.h"
+#include "chrome/browser/nearby_sharing/logging/logging.h"
 #include "chrome/browser/nearby_sharing/proto/device_rpc.pb.h"
 #include "chrome/browser/nearby_sharing/proto/rpc_resources.pb.h"
 #include "chrome/browser/nearby_sharing/scheduling/nearby_share_scheduler.h"
@@ -151,6 +152,8 @@
 }
 
 void NearbyShareContactManagerImpl::OnContactsDownloadRequested() {
+  NS_LOG(VERBOSE) << __func__ << ": Nearby Share contacts download requested.";
+
   DCHECK(!contact_downloader_);
   contact_downloader_ = NearbyShareContactDownloaderImpl::Factory::Create(
       only_download_if_changed_, local_device_data_manager_->GetId(),
@@ -167,6 +170,13 @@
     base::Optional<std::vector<nearbyshare::proto::ContactRecord>> contacts) {
   contact_downloader_.reset();
 
+  NS_LOG(VERBOSE) << __func__ << ": Nearby Share contacts download succeeded."
+                  << "\n  Did contacts change since last upload? "
+                  << (did_contacts_change_since_last_upload ? "Yes." : "No.")
+                  << "\n  Were contacts returned? "
+                  << (contacts.has_value() ? "Yes." : "No.")
+                  << "\n  Number of contacts returned: "
+                  << (contacts.has_value() ? contacts->size() : 0u);
   if (contacts) {
     // A complete list of contacts was returned. Do not download list again
     // until contacts change or until explicitly requested.
@@ -217,9 +227,13 @@
 void NearbyShareContactManagerImpl::OnContactsUploadRequested() {
   DCHECK_EQ(UploadState::kIdle, upload_state_);
 
+  NS_LOG(VERBOSE) << __func__
+                  << ": Nearby Share contact upload requested. Waiting to "
+                  << "download full contact list.";
+
   // Because the user's contact list is not persisted locally, we have to
-  // retrieve the full contact list ContactRecord protos from the server before
-  // uploading the list of Contact protos to the server.
+  // retrieve the full contact list ContactRecord protos from the server
+  // before uploading the list of Contact protos to the server.
   upload_state_ = UploadState::kWaitingForDownload;
   DownloadContacts(/*only_download_if_changed=*/false);
 }
@@ -227,6 +241,8 @@
 void NearbyShareContactManagerImpl::StartContactsUpload(
     bool did_contacts_change_since_last_upload,
     const std::vector<nearbyshare::proto::ContactRecord>& contacts) {
+  NS_LOG(VERBOSE) << __func__
+                  << ": Starting contacts upload to Nearby Share server.";
   upload_state_ = UploadState::kInProgress;
   local_device_data_manager_->UploadContacts(
       ContactRecordsToContacts(GetAllowedContacts(), contacts),
@@ -238,6 +254,10 @@
 void NearbyShareContactManagerImpl::OnContactsUploadFinished(
     bool did_contacts_change_since_last_upload,
     bool success) {
+  NS_LOG(VERBOSE) << __func__ << ": Upload of contacts to Nearby Share server "
+                  << (success ? "succeeded." : "failed.")
+                  << " Did contacts change since last upload? "
+                  << (did_contacts_change_since_last_upload ? "Yes." : "No.");
   if (success) {
     NotifyContactsUploaded(did_contacts_change_since_last_upload);
   }
diff --git a/chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager.cc b/chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager.cc
index 871f797b..5e457d9 100644
--- a/chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager.cc
+++ b/chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager.cc
@@ -19,13 +19,17 @@
 }
 
 void NearbyShareLocalDeviceDataManager::Start() {
-  DCHECK(!is_running_);
+  if (is_running_)
+    return;
+
   is_running_ = true;
   OnStart();
 }
 
 void NearbyShareLocalDeviceDataManager::Stop() {
-  DCHECK(is_running_);
+  if (!is_running_)
+    return;
+
   is_running_ = false;
   OnStop();
 }
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
index f66f0609..d0b87ff 100644
--- a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
+++ b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
@@ -237,6 +237,12 @@
 
   nearby_notification_manager_ = std::make_unique<NearbyNotificationManager>(
       notification_display_service, this, prefs, profile_);
+
+  if (settings_.GetEnabled()) {
+    local_device_data_manager_->Start();
+    contact_manager_->Start();
+    certificate_manager_->Start();
+  }
 }
 
 NearbySharingServiceImpl::~NearbySharingServiceImpl() {
@@ -287,6 +293,12 @@
 
   settings_receiver_.reset();
 
+  if (settings_.GetEnabled()) {
+    local_device_data_manager_->Stop();
+    contact_manager_->Stop();
+    certificate_manager_->Stop();
+  }
+
   // |profile_| has now been shut down so we shouldn't use it anymore.
   profile_ = nullptr;
 }
@@ -789,11 +801,17 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (enabled) {
     NS_LOG(VERBOSE) << __func__ << ": Nearby sharing enabled!";
+    local_device_data_manager_->Start();
+    contact_manager_->Start();
+    certificate_manager_->Start();
   } else {
     NS_LOG(VERBOSE) << __func__ << ": Nearby sharing disabled!";
     StopAdvertising();
     StopScanning();
     nearby_connections_manager_->Shutdown();
+    local_device_data_manager_->Stop();
+    contact_manager_->Stop();
+    certificate_manager_->Stop();
   }
   InvalidateSurfaceState();
 }
diff --git a/chrome/browser/nearby_sharing/scheduling/BUILD.gn b/chrome/browser/nearby_sharing/scheduling/BUILD.gn
index 375d81ca..7055ef73 100644
--- a/chrome/browser/nearby_sharing/scheduling/BUILD.gn
+++ b/chrome/browser/nearby_sharing/scheduling/BUILD.gn
@@ -21,6 +21,7 @@
   deps = [
     "//base",
     "//base/util/values:values_util",
+    "//chrome/browser/nearby_sharing/logging",
     "//components/prefs",
     "//content/public/browser",
     "//services/network/public/cpp",
diff --git a/chrome/browser/nearby_sharing/scheduling/nearby_share_scheduler_base.cc b/chrome/browser/nearby_sharing/scheduling/nearby_share_scheduler_base.cc
index db320b9..c500349 100644
--- a/chrome/browser/nearby_sharing/scheduling/nearby_share_scheduler_base.cc
+++ b/chrome/browser/nearby_sharing/scheduling/nearby_share_scheduler_base.cc
@@ -5,12 +5,15 @@
 #include "chrome/browser/nearby_sharing/scheduling/nearby_share_scheduler_base.h"
 
 #include <algorithm>
+#include <sstream>
 #include <utility>
 
+#include "base/i18n/time_formatting.h"
 #include "base/numerics/clamped_math.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/time/clock.h"
 #include "base/util/values/values_util.h"
+#include "chrome/browser/nearby_sharing/logging/logging.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
 #include "content/public/browser/network_service_instance.h"
@@ -67,6 +70,9 @@
   base::Time now = clock_->Now();
   SetLastAttemptTime(now);
 
+  NS_LOG(VERBOSE) << "Nearby Share scheduler \"" << pref_name_
+                  << "\" latest attempt " << (success ? "succeeded" : "failed");
+
   if (success) {
     SetLastSuccessTime(now);
     SetNumConsecutiveFailures(0);
@@ -76,6 +82,7 @@
 
   SetIsWaitingForResult(false);
   Reschedule();
+  PrintSchedulerState();
 }
 
 void NearbyShareSchedulerBase::Reschedule() {
@@ -139,6 +146,8 @@
 
 void NearbyShareSchedulerBase::OnStart() {
   Reschedule();
+  NS_LOG(VERBOSE) << "Starting Nearby Share scheduler \"" << pref_name_ << "\"";
+  PrintSchedulerState();
 }
 
 void NearbyShareSchedulerBase::OnStop() {
@@ -241,3 +250,46 @@
   SetHasPendingImmediateRequest(false);
   NotifyOfRequest();
 }
+
+void NearbyShareSchedulerBase::PrintSchedulerState() const {
+  base::Optional<base::Time> last_attempt_time = GetLastAttemptTime();
+  base::Optional<base::Time> last_success_time = GetLastSuccessTime();
+  base::Optional<base::TimeDelta> time_until_next_request =
+      GetTimeUntilNextRequest();
+
+  std::stringstream ss;
+  ss << "State of Nearby Share scheduler \"" << pref_name_ << "\":"
+     << "\n  Last attempt time: ";
+  if (last_attempt_time) {
+    ss << base::TimeFormatShortDateAndTimeWithTimeZone(*last_attempt_time);
+  } else {
+    ss << "Never";
+  }
+
+  ss << "\n  Last success time: ";
+  if (last_success_time) {
+    ss << base::TimeFormatShortDateAndTimeWithTimeZone(*last_success_time);
+  } else {
+    ss << "Never";
+  }
+
+  ss << "\n  Time until next request: ";
+  if (time_until_next_request) {
+    base::string16 next_request_delay;
+    bool success = base::TimeDurationFormatWithSeconds(
+        *time_until_next_request,
+        base::DurationFormatWidth::DURATION_WIDTH_NARROW, &next_request_delay);
+    if (success) {
+      ss << next_request_delay;
+    }
+  } else {
+    ss << "Never";
+  }
+
+  ss << "\n  Is waiting for result? " << (IsWaitingForResult() ? "Yes" : "No");
+  ss << "\n  Pending immediate request? "
+     << (HasPendingImmediateRequest() ? "Yes" : "No");
+  ss << "\n  Num consecutive failures: " << GetNumConsecutiveFailures();
+
+  NS_LOG(VERBOSE) << ss.str();
+}
diff --git a/chrome/browser/nearby_sharing/scheduling/nearby_share_scheduler_base.h b/chrome/browser/nearby_sharing/scheduling/nearby_share_scheduler_base.h
index cc3bdc36..065239a 100644
--- a/chrome/browser/nearby_sharing/scheduling/nearby_share_scheduler_base.h
+++ b/chrome/browser/nearby_sharing/scheduling/nearby_share_scheduler_base.h
@@ -101,6 +101,8 @@
   // connectivity is restored.
   void OnTimerFired();
 
+  void PrintSchedulerState() const;
+
   bool retry_failures_;
   bool require_connectivity_;
   std::string pref_name_;
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc
index 72f4cce..9076e58 100644
--- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc
+++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc
@@ -433,7 +433,7 @@
   PageAdDensityIgnoreDisplayNoneFrame
 #endif
 IN_PROC_BROWSER_TEST_F(AdsPageLoadMetricsObserverBrowserTest,
-                       PageAdDensityIgnoreDisplayNoneFrame) {
+                       MAYBE_PageAdDensityIgnoreDisplayNoneFrame) {
   base::HistogramTester histogram_tester;
   ukm::TestAutoSetUkmRecorder ukm_recorder;
   auto waiter = CreatePageLoadMetricsTestWaiter();
diff --git a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc
index 39bbf3d..f8e3c20e 100644
--- a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc
@@ -99,21 +99,6 @@
   return data;
 }
 
-int8_t ComputeMedianForThroughput(const base::flat_map<int8_t, int>& data) {
-  int total_samples = 0;
-  for (const auto& e : data)
-    total_samples += e.second;
-  int half_samples = total_samples / 2;
-  int current_samples = 0;
-  for (const auto& e : data) {
-    current_samples += e.second;
-    if (current_samples > half_samples)
-      return e.first;
-  }
-  NOTREACHED();
-  return 0;
-}
-
 bool ValidatePercent(int8_t percent) {
   if (percent >= 0 && percent <= 100)
     return true;
@@ -612,9 +597,6 @@
     ReportMainResourceTimingMetrics(timing, &builder);
 
   builder.Record(ukm::UkmRecorder::Get());
-
-  if (throughput_source_id_ != ukm::kInvalidSourceId)
-    ReportThroughputUkm();
 }
 
 void UkmPageLoadMetricsObserver::RecordInternalTimingMetrics(
@@ -1038,29 +1020,6 @@
     ++main_throughput_data_[main_throughput_percent->percent];
 }
 
-void UkmPageLoadMetricsObserver::ReportThroughputUkm() {
-  DCHECK_NE(throughput_source_id_, ukm::kInvalidSourceId);
-
-  ukm::builders::Graphics_Smoothness_PercentDroppedFrames builder(
-      throughput_source_id_);
-  if (aggregated_throughput_data_.size() > 0) {
-    builder.SetSlowerThread_Universal(
-        ComputeMedianForThroughput(aggregated_throughput_data_));
-    aggregated_throughput_data_.clear();
-  }
-  if (impl_throughput_data_.size() > 0) {
-    builder.SetCompositorThread_Universal(
-        ComputeMedianForThroughput(impl_throughput_data_));
-    impl_throughput_data_.clear();
-  }
-  if (main_throughput_data_.size() > 0) {
-    builder.SetMainThread_Universal(
-        ComputeMedianForThroughput(main_throughput_data_));
-    main_throughput_data_.clear();
-  }
-  builder.Record(ukm::UkmRecorder::Get());
-}
-
 void UkmPageLoadMetricsObserver::OnCpuTimingUpdate(
     content::RenderFrameHost* subframe_rfh,
     const page_load_metrics::mojom::CpuTiming& timing) {
diff --git a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h
index c42eafa7..952045e 100644
--- a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h
@@ -149,9 +149,6 @@
 
   void RecordInputTimingMetrics();
 
-  // Report throughput to Ukm.
-  void ReportThroughputUkm();
-
   // Captures the site engagement score for the committed URL and
   // returns the score rounded to the nearest 10.
   base::Optional<int64_t> GetRoundedSiteEngagementScore() const;
diff --git a/chrome/browser/paint_preview/android/BUILD.gn b/chrome/browser/paint_preview/android/BUILD.gn
index a3d2cf39..2c6db38 100644
--- a/chrome/browser/paint_preview/android/BUILD.gn
+++ b/chrome/browser/paint_preview/android/BUILD.gn
@@ -25,14 +25,12 @@
     "java/src/org/chromium/chrome/browser/paint_preview/services/PaintPreviewDemoServiceFactory.java",
     "java/src/org/chromium/chrome/browser/paint_preview/services/PaintPreviewTabService.java",
     "java/src/org/chromium/chrome/browser/paint_preview/services/PaintPreviewTabServiceFactory.java",
-    "java/src/org/chromium/chrome/browser/paint_preview/services/PaintPreviewTabServiceNativeInitObserver.java",
   ]
 
   deps = [
     ":java_resources",
     "//base:base_java",
     "//base:jni_java",
-    "//chrome/browser/android/lifecycle:java",
     "//chrome/browser/flags:java",
     "//chrome/browser/tab:java",
     "//chrome/browser/tabmodel:java",
diff --git a/chrome/browser/paint_preview/android/java/src/org/chromium/chrome/browser/paint_preview/TabbedPaintPreviewPlayer.java b/chrome/browser/paint_preview/android/java/src/org/chromium/chrome/browser/paint_preview/TabbedPaintPreviewPlayer.java
index f55de96..019a157 100644
--- a/chrome/browser/paint_preview/android/java/src/org/chromium/chrome/browser/paint_preview/TabbedPaintPreviewPlayer.java
+++ b/chrome/browser/paint_preview/android/java/src/org/chromium/chrome/browser/paint_preview/TabbedPaintPreviewPlayer.java
@@ -153,10 +153,7 @@
         boolean hasCapture = mPaintPreviewTabService.hasCaptureForTab(mTab.getId());
         mInitializing = hasCapture;
         mMetricsHelper.recordHadCapture(hasCapture);
-        if (!hasCapture) {
-            mPaintPreviewTabService.stopWarmCompositor();
-            return false;
-        }
+        if (!hasCapture) return false;
         mFirstMeaningfulPaintHappened = false;
 
         mPlayerManager = new PlayerManager(mTab.getUrl(), mTab.getContext(),
@@ -190,7 +187,6 @@
      * nothing if there is no view showing.
      */
     private void removePaintPreview(@ExitCause int exitCause) {
-        mPaintPreviewTabService.stopWarmCompositor();
         mOnDismissed = null;
         mInitializing = false;
         if (mTab == null || mPlayerManager == null) return;
diff --git a/chrome/browser/paint_preview/android/java/src/org/chromium/chrome/browser/paint_preview/services/PaintPreviewTabService.java b/chrome/browser/paint_preview/android/java/src/org/chromium/chrome/browser/paint_preview/services/PaintPreviewTabService.java
index afdabe0..a4ffdebd 100644
--- a/chrome/browser/paint_preview/android/java/src/org/chromium/chrome/browser/paint_preview/services/PaintPreviewTabService.java
+++ b/chrome/browser/paint_preview/android/java/src/org/chromium/chrome/browser/paint_preview/services/PaintPreviewTabService.java
@@ -116,17 +116,6 @@
     }
 
     /**
-     * Stops the pre-warmed compositor service if it isn't needed.
-     * @return Whether a pre-warmed compositor service was actually stopped.
-     */
-    public boolean stopWarmCompositor() {
-        if (mNativePaintPreviewTabService == 0) return false;
-
-        return PaintPreviewTabServiceJni.get().stopWarmCompositorAndroid(
-                mNativePaintPreviewTabService);
-    }
-
-    /**
      * Should be called when all tabs are restored. Registers a {@link TabModelSelectorTabObserver}
      * for the regular to capture and delete paint previews as needed. Audits restored tabs to
      * remove any failed deletions.
@@ -153,7 +142,8 @@
                 AUDIT_START_DELAY_MS);
     }
 
-    private void auditOnStart(TabModel regularTabModel) {
+    @VisibleForTesting
+    void auditOnStart(TabModel regularTabModel) {
         int tabCount = regularTabModel.getCount();
         int[] tabIds = new int[tabCount];
         for (int i = 0; i < tabCount; i++) {
@@ -236,6 +226,5 @@
         void auditArtifactsAndroid(long nativePaintPreviewTabService, int[] activeTabIds);
         boolean isCacheInitializedAndroid(long nativePaintPreviewTabService);
         String getPathAndroid(long nativePaintPreviewTabService);
-        boolean stopWarmCompositorAndroid(long nativePaintPreviewTabService);
     }
 }
diff --git a/chrome/browser/paint_preview/android/java/src/org/chromium/chrome/browser/paint_preview/services/PaintPreviewTabServiceNativeInitObserver.java b/chrome/browser/paint_preview/android/java/src/org/chromium/chrome/browser/paint_preview/services/PaintPreviewTabServiceNativeInitObserver.java
deleted file mode 100644
index 33b1feab..0000000
--- a/chrome/browser/paint_preview/android/java/src/org/chromium/chrome/browser/paint_preview/services/PaintPreviewTabServiceNativeInitObserver.java
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.paint_preview.services;
-
-import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
-import org.chromium.chrome.browser.lifecycle.NativeInitObserver;
-
-/**
- * Watches for native init to pre-warm the compositor.
- */
-public class PaintPreviewTabServiceNativeInitObserver implements NativeInitObserver {
-    private ActivityLifecycleDispatcher mActvityLifecycleDispatcher;
-
-    public PaintPreviewTabServiceNativeInitObserver(
-            ActivityLifecycleDispatcher activityLifecycleDispatcher) {
-        mActvityLifecycleDispatcher = activityLifecycleDispatcher;
-    }
-
-    @Override
-    public void onFinishNativeInitialization() {
-        // Warms-up the service and prepares the compositor service.
-        PaintPreviewTabServiceFactory.getServiceInstance();
-        mActvityLifecycleDispatcher.unregister(this);
-    }
-}
diff --git a/chrome/browser/paint_preview/paint_preview_compositor_browsertest.cc b/chrome/browser/paint_preview/paint_preview_compositor_browsertest.cc
index 2524069..b765dd6 100644
--- a/chrome/browser/paint_preview/paint_preview_compositor_browsertest.cc
+++ b/chrome/browser/paint_preview/paint_preview_compositor_browsertest.cc
@@ -18,7 +18,6 @@
 #include "components/paint_preview/browser/paint_preview_base_service_test_factory.h"
 #include "components/paint_preview/browser/paint_preview_compositor_client_impl.h"
 #include "components/paint_preview/browser/paint_preview_compositor_service_impl.h"
-#include "components/paint_preview/browser/warm_compositor.h"
 #include "components/paint_preview/public/paint_preview_compositor_client.h"
 #include "components/paint_preview/public/paint_preview_compositor_service.h"
 #include "components/services/paint_preview_compositor/public/mojom/paint_preview_compositor.mojom.h"
@@ -199,28 +198,4 @@
   EXPECT_FALSE(IsBoundAndConnected(compositor.get()));
 }
 
-IN_PROC_BROWSER_TEST_F(PaintPreviewCompositorBrowserTest, PreWarmCompositor) {
-  // Start with warm compositor.
-  WarmCompositor* warm_compositor = WarmCompositor::GetInstance();
-  warm_compositor->WarmupCompositor();
-  auto compositor_service = ToCompositorServiceImpl(
-      warm_compositor->GetOrStartCompositorService(base::DoNothing()));
-  EXPECT_FALSE(warm_compositor->StopCompositor());
-  EXPECT_NE(compositor_service, nullptr);
-  compositor_service.reset();
-  EXPECT_EQ(compositor_service, nullptr);
-
-  // Start and stop.
-  warm_compositor->WarmupCompositor();
-  EXPECT_TRUE(warm_compositor->StopCompositor());
-
-  // Verify it is still possible to start if the compositor was prematurely
-  // stopped.
-  compositor_service = ToCompositorServiceImpl(
-      warm_compositor->GetOrStartCompositorService(base::DoNothing()));
-  EXPECT_NE(compositor_service, nullptr);
-  compositor_service.reset();
-  EXPECT_EQ(compositor_service, nullptr);
-}
-
 }  // namespace paint_preview
diff --git a/chrome/browser/paint_preview/services/paint_preview_tab_service.cc b/chrome/browser/paint_preview/services/paint_preview_tab_service.cc
index 332544e6..a78ee55 100644
--- a/chrome/browser/paint_preview/services/paint_preview_tab_service.cc
+++ b/chrome/browser/paint_preview/services/paint_preview_tab_service.cc
@@ -13,7 +13,6 @@
 #include "base/task/post_task.h"
 #include "base/task/task_traits.h"
 #include "components/paint_preview/browser/file_manager.h"
-#include "components/paint_preview/browser/warm_compositor.h"
 #include "ui/gfx/geometry/rect.h"
 
 #if defined(OS_ANDROID)
@@ -56,16 +55,12 @@
     const base::FilePath& profile_dir,
     base::StringPiece ascii_feature_name,
     std::unique_ptr<PaintPreviewPolicy> policy,
-    bool is_off_the_record,
-    bool prewarm_compositor)
+    bool is_off_the_record)
     : PaintPreviewBaseService(profile_dir,
                               ascii_feature_name,
                               std::move(policy),
                               is_off_the_record),
       cache_ready_(false) {
-  if (prewarm_compositor)
-    WarmCompositor::GetInstance()->WarmupCompositor();
-
   GetTaskRunner()->PostTaskAndReplyWithResult(
       FROM_HERE, base::BindOnce(&FileManager::ListUsedKeys, GetFileManager()),
       base::BindOnce(&PaintPreviewTabService::InitializeCache,
@@ -160,11 +155,6 @@
                      weak_ptr_factory_.GetWeakPtr(), active_tab_ids));
 }
 
-bool PaintPreviewTabService::StopWarmCompositor() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  return WarmCompositor::GetInstance()->StopCompositor();
-}
-
 void PaintPreviewTabService::GetCapturedPaintPreviewProto(
     const DirectoryKey& key,
     base::Optional<base::TimeDelta> expiry_horizon,
@@ -219,10 +209,6 @@
   return base::android::ConvertUTF8ToJavaString(
       env, GetFileManager()->GetPath().AsUTF8Unsafe());
 }
-
-jboolean PaintPreviewTabService::StopWarmCompositorAndroid(JNIEnv* env) {
-  return static_cast<jboolean>(StopWarmCompositor());
-}
 #endif  // defined(OS_ANDROID)
 
 void PaintPreviewTabService::InitializeCache(
diff --git a/chrome/browser/paint_preview/services/paint_preview_tab_service.h b/chrome/browser/paint_preview/services/paint_preview_tab_service.h
index 2f708ef..0a591c7 100644
--- a/chrome/browser/paint_preview/services/paint_preview_tab_service.h
+++ b/chrome/browser/paint_preview/services/paint_preview_tab_service.h
@@ -41,8 +41,7 @@
   PaintPreviewTabService(const base::FilePath& profile_dir,
                          base::StringPiece ascii_feature_name,
                          std::unique_ptr<PaintPreviewPolicy> policy,
-                         bool is_off_the_record,
-                         bool prewarm_compositor = true);
+                         bool is_off_the_record);
   ~PaintPreviewTabService() override;
 
   enum Status {
@@ -79,9 +78,6 @@
   // occurred.
   void AuditArtifacts(const std::vector<int>& active_tab_ids);
 
-  // Stops the pre-warmed compositor service.
-  bool StopWarmCompositor();
-
   // Override for GetCapturedPaintPreviewProto. Defaults expiry horizon to 72
   // hrs if not specified.
   void GetCapturedPaintPreviewProto(
@@ -104,7 +100,6 @@
       const base::android::JavaParamRef<jintArray>& j_tab_ids);
   jboolean IsCacheInitializedAndroid(JNIEnv* env);
   base::android::ScopedJavaLocalRef<jstring> GetPathAndroid(JNIEnv* env);
-  jboolean StopWarmCompositorAndroid(JNIEnv* env);
 
   base::android::ScopedJavaGlobalRef<jobject> GetJavaRef() { return java_ref_; }
 #endif  // defined(OS_ANDROID)
diff --git a/chrome/browser/paint_preview/services/paint_preview_tab_service_unittest.cc b/chrome/browser/paint_preview/services/paint_preview_tab_service_unittest.cc
index 76a37d5..86d91bf8a 100644
--- a/chrome/browser/paint_preview/services/paint_preview_tab_service_unittest.cc
+++ b/chrome/browser/paint_preview/services/paint_preview_tab_service_unittest.cc
@@ -85,7 +85,7 @@
     ChromeRenderViewHostTestHarness::SetUp();
     EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
     service_ = std::make_unique<PaintPreviewTabService>(
-        temp_dir_.GetPath(), kFeatureName, nullptr, false, false);
+        temp_dir_.GetPath(), kFeatureName, nullptr, false);
     task_environment()->RunUntilIdle();
     EXPECT_TRUE(service_->CacheInitialized());
   }
@@ -119,7 +119,7 @@
     }
 
     return std::make_unique<PaintPreviewTabService>(GetPath(), kFeatureName,
-                                                    nullptr, false, false);
+                                                    nullptr, false);
   }
 
  private:
diff --git a/chrome/browser/password_check/android/DEPS b/chrome/browser/password_check/android/DEPS
index 7ea4d93..c78d4d2 100644
--- a/chrome/browser/password_check/android/DEPS
+++ b/chrome/browser/password_check/android/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
   "+chrome/android",
   "+chrome/browser/ui/android",
+  "+content/public/android",
 ]
\ No newline at end of file
diff --git a/chrome/browser/password_check/android/internal/BUILD.gn b/chrome/browser/password_check/android/internal/BUILD.gn
index 4e394ab..feeb49ee 100644
--- a/chrome/browser/password_check/android/internal/BUILD.gn
+++ b/chrome/browser/password_check/android/internal/BUILD.gn
@@ -67,6 +67,7 @@
     "//chrome/browser/ui/android/strings:ui_strings_grd",
     "//components/browser_ui/widget/android:java",
     "//components/embedder_support/android:util_java",
+    "//content/public/android:content_java",
     "//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",
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 7cce3cce..fca7aa28 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
@@ -25,12 +25,15 @@
 import android.content.DialogInterface;
 import android.util.Pair;
 
+import androidx.annotation.VisibleForTesting;
 import androidx.appcompat.app.AlertDialog;
 
+import org.chromium.base.task.PostTask;
 import org.chromium.chrome.browser.password_check.helper.PasswordCheckChangePasswordHelper;
 import org.chromium.chrome.browser.password_check.helper.PasswordCheckIconHelper;
 import org.chromium.chrome.browser.password_check.helper.PasswordCheckReauthenticationHelper;
 import org.chromium.chrome.browser.password_check.helper.PasswordCheckReauthenticationHelper.ReauthReason;
+import org.chromium.content_public.browser.UiThreadTaskTraits;
 import org.chromium.ui.modelutil.ListModel;
 import org.chromium.ui.modelutil.MVCListAdapter.ListItem;
 import org.chromium.ui.modelutil.PropertyModel;
@@ -46,6 +49,8 @@
  */
 class PasswordCheckMediator
         implements PasswordCheckCoordinator.CredentialEventHandler, PasswordCheck.Observer {
+    private static long sStatusUpdateDelayMillis = 1000;
+
     private final PasswordCheckReauthenticationHelper mReauthenticationHelper;
     private final PasswordCheckChangePasswordHelper mChangePasswordDelegate;
     private PropertyModel mModel;
@@ -53,6 +58,7 @@
     private Runnable mLaunchCheckupInAccount;
     private HashSet<CompromisedCredential> mPreCheckSet;
     private final PasswordCheckIconHelper mIconHelper;
+    private long mLastStatusUpdate;
 
     PasswordCheckMediator(PasswordCheckChangePasswordHelper changePasswordDelegate,
             PasswordCheckReauthenticationHelper reauthenticationHelper,
@@ -106,6 +112,7 @@
                             .with(LAUNCH_ACCOUNT_CHECKUP_ACTION, mLaunchCheckupInAccount)
                             .with(RESTART_BUTTON_ACTION, this::startCheckManually)
                             .build()));
+            mLastStatusUpdate = System.currentTimeMillis();
         }
         if (items.size() > 1) items.removeRange(1, items.size() - 1);
 
@@ -120,6 +127,19 @@
 
     @Override
     public void onPasswordCheckStatusChanged(@PasswordCheckUIStatus int status) {
+        long currentTime = System.currentTimeMillis();
+
+        if (shouldDelayStatusChange(status, currentTime)) {
+            mLastStatusUpdate += sStatusUpdateDelayMillis;
+            PostTask.postDelayedTask(UiThreadTaskTraits.DEFAULT,
+                    () -> changePasswordCheckStatus(status), mLastStatusUpdate - currentTime);
+        } else {
+            mLastStatusUpdate = currentTime;
+            changePasswordCheckStatus(status);
+        }
+    }
+
+    private void changePasswordCheckStatus(@PasswordCheckUIStatus int status) {
         // There is no UI representation of a canceled check. This status can be sent when
         // the bridge and the password check UI are being torn down while a check is running.
         if (status == PasswordCheckUIStatus.CANCELED) return;
@@ -139,8 +159,9 @@
             header = items.get(0).model;
         }
         header.set(CHECK_STATUS, status);
-        header.set(
-                CHECK_PROGRESS, status == PasswordCheckUIStatus.RUNNING ? UNKNOWN_PROGRESS : null);
+        Pair<Integer, Integer> progress = header.get(CHECK_PROGRESS);
+        if (progress == null) progress = UNKNOWN_PROGRESS;
+        header.set(CHECK_PROGRESS, status == PasswordCheckUIStatus.RUNNING ? progress : null);
         Long checkTimestamp = null;
         Integer compromisedCredentialCount = null;
         if (status == PasswordCheckUIStatus.IDLE) {
@@ -164,7 +185,10 @@
         assert remainingInQueue >= 0;
 
         PropertyModel header = items.get(0).model;
-        header.set(CHECK_STATUS, PasswordCheckUIStatus.RUNNING);
+        if (header.get(CHECK_STATUS) != PasswordCheckUIStatus.RUNNING) {
+            mLastStatusUpdate = System.currentTimeMillis();
+            header.set(CHECK_STATUS, PasswordCheckUIStatus.RUNNING);
+        }
         header.set(
                 CHECK_PROGRESS, new Pair<>(alreadyProcessed, alreadyProcessed + remainingInQueue));
         header.set(CHECK_TIMESTAMP, null);
@@ -304,6 +328,16 @@
                 && mModel.get(ITEMS).get(0).model.get(CHECK_STATUS)
                 == PasswordCheckUIStatus.RUNNING;
     }
+
+    private boolean shouldDelayStatusChange(
+            @PasswordCheckUIStatus int newStatus, long currentTime) {
+        ListModel<ListItem> items = mModel.get(ITEMS);
+        return items.size() > 0
+                && items.get(0).model.get(CHECK_STATUS) == PasswordCheckUIStatus.RUNNING
+                && newStatus != PasswordCheckUIStatus.RUNNING
+                && mLastStatusUpdate + sStatusUpdateDelayMillis > currentTime;
+    }
+
     private ListItem createEntryForCredential(CompromisedCredential credential) {
         PropertyModel credentialModel =
                 new PropertyModel
@@ -360,4 +394,9 @@
             return originComparisonResult == 0 ? usernameComparisonResult : originComparisonResult;
         });
     }
+
+    @VisibleForTesting
+    protected static void setStatusUpdateDelayMillis(long statusUpdateDelayMillis) {
+        sStatusUpdateDelayMillis = statusUpdateDelayMillis;
+    }
 }
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 9927266..043bc85 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
@@ -129,6 +129,7 @@
                 mChangePasswordDelegate, mReauthenticationHelper, mIconHelper);
         PasswordCheckFactory.setPasswordCheckForTesting(mPasswordCheck);
         mMediator.initialize(mModel, mDelegate, PasswordCheckReferrer.PASSWORD_SETTINGS, () -> {});
+        PasswordCheckMediator.setStatusUpdateDelayMillis(0);
     }
 
     @Test
diff --git a/chrome/browser/payments/BUILD.gn b/chrome/browser/payments/BUILD.gn
index 279923a5..ff5578a 100644
--- a/chrome/browser/payments/BUILD.gn
+++ b/chrome/browser/payments/BUILD.gn
@@ -15,6 +15,7 @@
     "iframe_csp_browsertest.cc",
     "ignore_payment_method_browsertest.cc",
     "journey_logger_browsertest.cc",
+    "load_and_remove_iframe_with_many_payment_requests_browsertest.cc",
     "payment_handler_capabilities_browsertest.cc",
     "payment_handler_change_shipping_address_option_browsertest.cc",
     "payment_handler_enable_delegations_browsertest.cc",
diff --git a/chrome/browser/payments/android/journey_logger_android.cc b/chrome/browser/payments/android/journey_logger_android.cc
index 1b11d69..eb5df50 100644
--- a/chrome/browser/payments/android/journey_logger_android.cc
+++ b/chrome/browser/payments/android/journey_logger_android.cc
@@ -184,6 +184,7 @@
     const JavaParamRef<jobject>& jweb_contents) {
   content::WebContents* web_contents =
       content::WebContents::FromJavaWebContents(jweb_contents);
+  DCHECK(web_contents);  // Verified in Java before invoking this function.
   return reinterpret_cast<jlong>(new JourneyLoggerAndroid(
       jis_incognito, ukm::GetSourceIdForWebContentsDocument(web_contents)));
 }
diff --git a/chrome/browser/payments/android/payment_app_service_bridge.cc b/chrome/browser/payments/android/payment_app_service_bridge.cc
index ea6fc8d..4a00569 100644
--- a/chrome/browser/payments/android/payment_app_service_bridge.cc
+++ b/chrome/browser/payments/android/payment_app_service_bridge.cc
@@ -95,6 +95,9 @@
 
   auto* render_frame_host =
       content::RenderFrameHost::FromJavaRenderFrameHost(jrender_frame_host);
+  if (!render_frame_host)  // The frame is being unloaded.
+    return;
+
   std::string top_origin = ConvertJavaStringToUTF8(jtop_origin);
 
   scoped_refptr<payments::PaymentManifestWebDataService> web_data_service =
diff --git a/chrome/browser/payments/android/service_worker_payment_app_bridge.cc b/chrome/browser/payments/android/service_worker_payment_app_bridge.cc
index ac949fc..2d4ac9ba 100644
--- a/chrome/browser/payments/android/service_worker_payment_app_bridge.cc
+++ b/chrome/browser/payments/android/service_worker_payment_app_bridge.cc
@@ -124,7 +124,7 @@
     jint reason) {
   content::WebContents* web_contents =
       content::WebContents::FromJavaWebContents(jweb_contents);
-
+  DCHECK(web_contents);  // Verified in Java before invoking this function.
   content::PaymentAppProvider::GetInstance()->OnClosingOpenedWindow(
       web_contents,
       static_cast<payments::mojom::PaymentEventResponseType>(reason));
diff --git a/chrome/browser/payments/android/ssl_validity_checker_android.cc b/chrome/browser/payments/android/ssl_validity_checker_android.cc
index 6f9a5939..3590be3 100644
--- a/chrome/browser/payments/android/ssl_validity_checker_android.cc
+++ b/chrome/browser/payments/android/ssl_validity_checker_android.cc
@@ -17,6 +17,7 @@
     const base::android::JavaParamRef<jobject>& jweb_contents) {
   content::WebContents* web_contents =
       content::WebContents::FromJavaWebContents(jweb_contents);
+  // SslValidityChecker checks for null `web_contents` parameter.
   return base::android::ConvertUTF8ToJavaString(
       env,
       SslValidityChecker::GetInvalidSslCertificateErrorMessage(web_contents));
@@ -26,6 +27,7 @@
 jboolean JNI_SslValidityChecker_IsValidPageInPaymentHandlerWindow(
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& jweb_contents) {
+  // SslValidityChecker checks for null `web_contents` parameter.
   return SslValidityChecker::IsValidPageInPaymentHandlerWindow(
       content::WebContents::FromJavaWebContents(jweb_contents));
 }
diff --git a/chrome/browser/payments/load_and_remove_iframe_with_many_payment_requests_browsertest.cc b/chrome/browser/payments/load_and_remove_iframe_with_many_payment_requests_browsertest.cc
new file mode 100644
index 0000000..79989330
--- /dev/null
+++ b/chrome/browser/payments/load_and_remove_iframe_with_many_payment_requests_browsertest.cc
@@ -0,0 +1,42 @@
+// 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/test/payments/payment_request_platform_browsertest_base.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace payments {
+namespace {
+
+class LoadAndRemoveIframeWithManyPaymentRequestsTest
+    : public PaymentRequestPlatformBrowserTestBase {
+ public:
+  void RunTest(const std::string& iframe_hostname) {
+    NavigateTo("a.com", "/load_and_remove_iframe.html");
+
+    // EvalJs waits for JavaScript promise to resolve.
+    EXPECT_EQ("success",
+              content::EvalJs(GetActiveWebContents(),
+                              content::JsReplace(
+                                  "loadAndRemoveIframe($1, /*timeout=*/100);",
+                                  https_server()
+                                      ->GetURL(iframe_hostname,
+                                               "/create_many_requests.html")
+                                      .spec())));
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(LoadAndRemoveIframeWithManyPaymentRequestsTest,
+                       CrossOriginNoCrash) {
+  RunTest(/*iframe_hostname=*/"b.com");
+}
+
+IN_PROC_BROWSER_TEST_F(LoadAndRemoveIframeWithManyPaymentRequestsTest,
+                       SameOriginNoCrash) {
+  RunTest(/*iframe_hostname=*/"a.com");
+}
+
+}  // namespace
+}  // namespace payments
diff --git a/chrome/browser/policy/chrome_browser_policy_connector.cc b/chrome/browser/policy/chrome_browser_policy_connector.cc
index 41af54f..f359971c 100644
--- a/chrome/browser/policy/chrome_browser_policy_connector.cc
+++ b/chrome/browser/policy/chrome_browser_policy_connector.cc
@@ -32,6 +32,7 @@
 #include "components/policy/core/common/policy_service.h"
 #include "components/policy/core/common/policy_types.h"
 #include "components/policy/policy_constants.h"
+#include "content/public/common/content_switches.h"
 #include "extensions/buildflags/buildflags.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
@@ -61,6 +62,9 @@
 #endif
 
 namespace policy {
+namespace {
+bool command_line_enabled_for_testing = false;
+}  // namespace
 
 ChromeBrowserPolicyConnector::ChromeBrowserPolicyConnector()
     : BrowserPolicyConnector(base::Bind(&BuildHandlerList)) {
@@ -81,9 +85,8 @@
     PrefService* local_state,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
   std::unique_ptr<DeviceManagementService::Configuration> configuration(
-      new DeviceManagementServiceConfiguration(
-          BrowserPolicyConnector::GetDeviceManagementUrl(),
-          BrowserPolicyConnector::GetRealtimeReportingUrl()));
+      new DeviceManagementServiceConfiguration(GetDeviceManagementUrl(),
+                                               GetRealtimeReportingUrl()));
   std::unique_ptr<DeviceManagementService> device_management_service(
       new DeviceManagementService(std::move(configuration)));
   device_management_service->ScheduleInitialization(
@@ -126,6 +129,20 @@
   return provider ? provider : platform_provider_;
 }
 
+bool ChromeBrowserPolicyConnector::IsCommandLineSwitchSupported() const {
+  if (command_line_enabled_for_testing)
+    return true;
+
+  version_info::Channel channel = chrome::GetChannel();
+  return channel != version_info::Channel::STABLE &&
+         channel != version_info::Channel::BETA;
+}
+
+// static
+void ChromeBrowserPolicyConnector::EnableCommandLineSupportForTesting() {
+  command_line_enabled_for_testing = true;
+}
+
 std::vector<std::unique_ptr<policy::ConfigurationPolicyProvider>>
 ChromeBrowserPolicyConnector::CreatePolicyProviders() {
   auto providers = BrowserPolicyConnector::CreatePolicyProviders();
diff --git a/chrome/browser/policy/chrome_browser_policy_connector.h b/chrome/browser/policy/chrome_browser_policy_connector.h
index da267559..29456ba1 100644
--- a/chrome/browser/policy/chrome_browser_policy_connector.h
+++ b/chrome/browser/policy/chrome_browser_policy_connector.h
@@ -66,8 +66,15 @@
   }
 #endif
 
- protected:
   // BrowserPolicyConnector:
+  // Command line switch only supports Dev and Canary channel, trunk and browser
+  // tests on Win, Mac, Linux and Android.
+  bool IsCommandLineSwitchSupported() const override;
+
+  static void EnableCommandLineSupportForTesting();
+
+ protected:
+  // BrowserPolicyConnectorBase::
   std::vector<std::unique_ptr<policy::ConfigurationPolicyProvider>>
   CreatePolicyProviders() override;
 
diff --git a/chrome/browser/policy/cloud/chrome_browser_cloud_management_browsertest.cc b/chrome/browser/policy/cloud/chrome_browser_cloud_management_browsertest.cc
index 8f898f6..799cf5c 100644
--- a/chrome/browser/policy/cloud/chrome_browser_cloud_management_browsertest.cc
+++ b/chrome/browser/policy/cloud/chrome_browser_cloud_management_browsertest.cc
@@ -462,6 +462,7 @@
     base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
     command_line->AppendSwitchASCII(switches::kDeviceManagementUrl,
                                     test_server_.GetServiceURL().spec());
+    ChromeBrowserPolicyConnector::EnableCommandLineSupportForTesting();
 
     histogram_tester_.ExpectTotalCount(kEnrollmentResultMetrics, 0);
   }
@@ -602,6 +603,7 @@
     base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
     command_line->AppendSwitchASCII(switches::kDeviceManagementUrl,
                                     test_server_->GetServiceURL().spec());
+    ChromeBrowserPolicyConnector::EnableCommandLineSupportForTesting();
   }
 
 #if !BUILDFLAG(GOOGLE_CHROME_BRANDING)
@@ -762,6 +764,7 @@
     base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
     command_line->AppendSwitchASCII(switches::kDeviceManagementUrl,
                                     test_server_->GetServiceURL().spec());
+    ChromeBrowserPolicyConnector::EnableCommandLineSupportForTesting();
   }
 
 #if !BUILDFLAG(GOOGLE_CHROME_BRANDING)
diff --git a/chrome/browser/policy/cloud/cloud_policy_browsertest.cc b/chrome/browser/policy/cloud/cloud_policy_browsertest.cc
index 8a69bc50..e1b3e6e 100644
--- a/chrome/browser/policy/cloud/cloud_policy_browsertest.cc
+++ b/chrome/browser/policy/cloud/cloud_policy_browsertest.cc
@@ -197,6 +197,7 @@
 
     base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
     command_line->AppendSwitchASCII(switches::kDeviceManagementUrl, url);
+    ChromeBrowserPolicyConnector::EnableCommandLineSupportForTesting();
   }
 
   void CreatedBrowserMainParts(
diff --git a/chrome/browser/policy/cloud/cloud_policy_manager_browsertest.cc b/chrome/browser/policy/cloud/cloud_policy_manager_browsertest.cc
index 896c836..b08f6e3 100644
--- a/chrome/browser/policy/cloud/cloud_policy_manager_browsertest.cc
+++ b/chrome/browser/policy/cloud/cloud_policy_manager_browsertest.cc
@@ -151,6 +151,7 @@
     base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
     command_line->AppendSwitchASCII(switches::kDeviceManagementUrl,
                                     "http://localhost");
+    ChromeBrowserPolicyConnector::EnableCommandLineSupportForTesting();
 
     // Set retry delay to prevent timeouts.
     policy::DeviceManagementService::SetRetryDelayForTesting(0);
diff --git a/chrome/browser/policy/cloud/component_cloud_policy_browsertest.cc b/chrome/browser/policy/cloud/component_cloud_policy_browsertest.cc
index a2e39169..4a37d23 100644
--- a/chrome/browser/policy/cloud/component_cloud_policy_browsertest.cc
+++ b/chrome/browser/policy/cloud/component_cloud_policy_browsertest.cc
@@ -122,6 +122,7 @@
     std::string url = test_server_.GetServiceURL().spec();
     base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
     command_line->AppendSwitchASCII(switches::kDeviceManagementUrl, url);
+    ChromeBrowserPolicyConnector::EnableCommandLineSupportForTesting();
 
     extensions::ExtensionBrowserTest::SetUpInProcessBrowserTestFixture();
   }
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_browsertest.cc b/chrome/browser/policy/cloud/user_policy_signin_service_browsertest.cc
index 0e00305..0f63f6c 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service_browsertest.cc
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_browsertest.cc
@@ -9,6 +9,7 @@
 #include "base/command_line.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/policy/chrome_browser_policy_connector.h"
 #include "chrome/browser/policy/profile_policy_connector.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/ui/browser.h"
@@ -195,6 +196,7 @@
     command_line->AppendSwitchASCII(switches::kGaiaUrl, base_url.spec());
     command_line->AppendSwitchASCII(switches::kLsoUrl, base_url.spec());
     command_line->AppendSwitchASCII(switches::kGoogleApisUrl, base_url.spec());
+    policy::ChromeBrowserPolicyConnector::EnableCommandLineSupportForTesting();
     fake_gaia_.Initialize();
     // Configure Sync server.
     command_line->AppendSwitch(switches::kDisableSync);
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/i_tutorial.js b/chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/i_tutorial.js
index dc93de8..3082c734 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/i_tutorial.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/i_tutorial.js
@@ -67,6 +67,18 @@
 
     interactiveMode: {type: Boolean, value: false},
 
+    nudgeIntervalId: {type: Number},
+
+    /** @const */
+    NUDGE_INTERVAL_TIME_MS: {type: Number, value: 45 * 1000},
+
+    nudgeCounter: {type: Number, value: 0},
+
+    /** @type {Array<function(): void>} */
+    nudgeArray: {type: Array},
+
+    isPracticeAreaActive: {type: Boolean, value: false},
+
     // Labels and text content.
 
     chooseYourExperience: {
@@ -440,10 +452,23 @@
   ready() {
     document.addEventListener('keydown', this.onKeyDown.bind(this));
     this.hideAllScreens();
+    this.initializeNudges();
     this.$.lessonTemplate.addEventListener('dom-change', (evt) => {
       // Executes once all lessons have been added to the dom.
       this.show();
     });
+    this.$.tutorial.addEventListener('focus', this.onFocus.bind(this), true);
+    this.addEventListener('startpractice', (evt) => {
+      // Stop nudges when the practice area opens. This is because the practice
+      // area can provide hints and we don't want nudges to conflict with them.
+      this.stopNudges();
+      this.isPracticeAreaActive = true;
+    });
+    this.addEventListener('endpractice', (evt) => {
+      // When the practice area closes, it's safe to resume nudges.
+      this.startNudges();
+      this.isPracticeAreaActive = false;
+    });
   },
 
   /** Shows the tutorial */
@@ -456,6 +481,7 @@
     } else {
       this.showMainMenu();
     }
+    this.startNudges();
   },
 
   /**
@@ -675,6 +701,7 @@
 
   /** @private */
   exit() {
+    this.stopNudges();
     this.dispatchEvent(new CustomEvent('closetutorial', {}));
   },
 
@@ -725,4 +752,84 @@
       evt.stopPropagation();
     }
   },
+
+  /** @private */
+  startNudges() {
+    this.stopNudges();
+    this.nudgeIntervalId =
+        setInterval(this.giveNudge.bind(this), this.NUDGE_INTERVAL_TIME_MS);
+  },
+
+  /** @private */
+  stopNudges() {
+    this.nudgeCounter = 0;
+    if (this.nudgeIntervalId) {
+      clearInterval(this.nudgeIntervalId);
+    }
+  },
+
+  /** @private */
+  giveNudge() {
+    if (this.nudgeCounter < 0 || this.nudgeCounter >= this.nudgeArray.length) {
+      this.stopNudges();
+      return;
+    }
+
+    this.nudgeArray[this.nudgeCounter]();
+    this.nudgeCounter += 1;
+  },
+
+  /**
+   * @param {string} text
+   * @private
+   */
+  requestSpeech(text) {
+    this.dispatchEvent(
+        new CustomEvent('requestspeech', {composed: true, detail: {text}}));
+  },
+
+  /** @private */
+  requestFullyDescribe() {
+    this.dispatchEvent(
+        new CustomEvent('requestfullydescribe', {composed: true}));
+  },
+
+  /** @private */
+  initializeNudges() {
+    const maybeGiveNudge = (msg) => {
+      if (this.interactiveMode) {
+        // Do not announce message since ChromeVox blocks actions in interactive
+        // mode.
+        return;
+      }
+
+      this.requestSpeech(msg);
+    };
+
+    this.nudgeArray = [
+      this.requestFullyDescribe.bind(this),
+      this.requestFullyDescribe.bind(this),
+      this.requestFullyDescribe.bind(this),
+      maybeGiveNudge.bind(
+          this, 'Hint: Hold Search and press the arrow keys to navigate.'),
+      maybeGiveNudge.bind(
+          this, 'Hint: Press Search + Space to activate the current item.'),
+      this.requestSpeech.bind(
+          this, 'Hint: Press Escape if you would like to exit this tutorial.')
+    ];
+  },
+
+  /**
+   * @param {Event} evt
+   * @private
+   */
+  onFocus(evt) {
+    // Restart nudges whenever focus changes, as long as the practice area is
+    // inactive.
+    if (this.isPracticeAreaActive) {
+      return;
+    }
+
+    this.startNudges();
+  }
 });
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/tutorial_lesson.js b/chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/tutorial_lesson.js
index a2fd4815..b8a7450 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/tutorial_lesson.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/i_tutorial/components/tutorial_lesson.js
@@ -134,6 +134,7 @@
 
   /** @private */
   startPractice() {
+    this.notifyStartPractice();
     this.$.practice.showModal();
     this.startHints();
     this.$.practiceTitle.focus();
@@ -141,10 +142,21 @@
 
   /** @private */
   endPractice() {
+    this.notifyEndPractice();
     this.stopHints();
     this.$.startPractice.focus();
   },
 
+  /** @private */
+  notifyStartPractice() {
+    this.dispatchEvent(new CustomEvent('startpractice', {composed: true}));
+  },
+
+  /** @private */
+  notifyEndPractice() {
+    this.dispatchEvent(new CustomEvent('endpractice', {composed: true}));
+  },
+
 
   // Methods for tracking the state of the practice area.
 
@@ -204,7 +216,6 @@
     }
   },
 
-
   // Methods for managing hints.
 
   /** @private */
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.js b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.js
index 05695f8..ffdf1d1e1 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.js
@@ -1219,6 +1219,11 @@
           chrome.extension.getBackgroundPage()['ChromeVoxState']['instance'];
       background.destroyUserActionMonitor();
     });
+    $('i-tutorial').addEventListener('requestfullydescribe', (evt) => {
+      const commandHandler =
+          chrome.extension.getBackgroundPage()['CommandHandler'];
+      commandHandler.onCommand('fullyDescribe');
+    });
   }
 
   /**
diff --git a/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_or.xtb b/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_or.xtb
index fb785384..170120c 100644
--- a/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_or.xtb
+++ b/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_or.xtb
@@ -280,6 +280,7 @@
 <translation id="3103579948980282461">ମଧ୍ୟମ ବାଇଗଣୀ ନାଲି</translation>
 <translation id="3104705064753753826">ଅଲର୍ଟ ଡାଇଲଗ୍‍</translation>
 <translation id="3109724472072898302">ସଙ୍କୁଚିତ କରାଗଲା</translation>
+<translation id="311015743332597320">ଚାରି ଆଙ୍ଗୁଠିରେ ଡାହାଣକୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ</translation>
 <translation id="3112457281078985179">ChromeVoxକୁ ଚାଲୁ କିମ୍ବା ବନ୍ଦ କରିବାକୁ Control+Alt+Zକୁ ବ୍ୟବହାର କରନ୍ତୁ।</translation>
 <translation id="3131002934070407451">ନମ୍ବରକୁ ଏପରି ଭାବେ ପଢ଼ନ୍ତୁ:</translation>
 <translation id="3134461040845705080">rdonly</translation>
@@ -901,6 +902,7 @@
 <translation id="812886159861361726"><ph name="FILE_NAME" /> ଡାଉନ୍‌ଲୋଡ୍ ହେବା ବନ୍ଦ ହୋଇଗଲା</translation>
 <translation id="8129445297241948503">ଉପରେ କୌଣସି ସେଲ୍ ନାହିଁ</translation>
 <translation id="8138880386467279117">ସ୍ପର୍ଶ</translation>
+<translation id="8173092779156526980">ଚାରି ଆଙ୍ଗୁଠିରେ ବାମକୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ</translation>
 <translation id="817440585505441544">{COUNT,plural, =1{ଟି ଅଣ୍ଡରସ୍କୋର୍‌}other{#ଟି ଅଣ୍ଡରସ୍କୋର୍‌}}</translation>
 <translation id="8184828902145951186">ଧାଡ଼ି</translation>
 <translation id="8186185314313222077">ପୂର୍ଣ୍ଣସ୍କ୍ରିନ୍ ଟୋଗଲ୍ କରନ୍ତୁ</translation>
diff --git a/chrome/browser/resources/settings/autofill_page/autofill_page.html b/chrome/browser/resources/settings/autofill_page/autofill_page.html
index c6e70b9e..6510541 100644
--- a/chrome/browser/resources/settings/autofill_page/autofill_page.html
+++ b/chrome/browser/resources/settings/autofill_page/autofill_page.html
@@ -49,8 +49,7 @@
           </passwords-device-section>
         </settings-subpage>
       </template>
-      <template is="dom-if" route-path="/passwords/check"
-          no-search="[[!enablePasswordCheck_]]">
+      <template is="dom-if" route-path="/passwords/check">
         <settings-subpage
             associated-control="[[$$('#passwordManagerButton')]]"
             page-title="$i18n{checkPasswords}"
diff --git a/chrome/browser/resources/settings/autofill_page/autofill_page.js b/chrome/browser/resources/settings/autofill_page/autofill_page.js
index 5c972a9..ede7841 100644
--- a/chrome/browser/resources/settings/autofill_page/autofill_page.js
+++ b/chrome/browser/resources/settings/autofill_page/autofill_page.js
@@ -62,12 +62,6 @@
       type: String,
       computed: 'computePasswordManagerSubLabel_(compromisedPasswordsCount)',
     },
-
-    /** @private */
-    enablePasswordCheck_: {
-      type: Boolean,
-      value: () => loadTimeData.getBoolean('enablePasswordCheck'),
-    },
   },
 
   /**
@@ -102,10 +96,6 @@
    * @private
    */
   computePasswordManagerSubLabel_() {
-    if (!this.enablePasswordCheck_) {
-      return '';
-    }
-
     return this.leakedPasswords.length > 0 ? this.compromisedPasswordsCount :
                                              '';
   },
diff --git a/chrome/browser/resources/settings/autofill_page/passwords_list_handler.html b/chrome/browser/resources/settings/autofill_page/passwords_list_handler.html
index 0a41382..59156a82 100644
--- a/chrome/browser/resources/settings/autofill_page/passwords_list_handler.html
+++ b/chrome/browser/resources/settings/autofill_page/passwords_list_handler.html
@@ -12,11 +12,9 @@
     <slot name="body"></slot>
 
     <cr-action-menu id="menu" role-description="$i18n{menu}">
-      <template is="dom-if" if="[[enablePasswordCheck_]]">
-        <button id="menuCopyPassword" class="dropdown-item"
-            hidden$="[[activePassword.entry.federationText]]"
-            on-click="onMenuCopyPasswordButtonTap_">$i18n{copyPassword}</button>
-      </template>
+      <button id="menuCopyPassword" class="dropdown-item"
+          hidden$="[[activePassword.entry.federationText]]"
+          on-click="onMenuCopyPasswordButtonTap_">$i18n{copyPassword}</button>
       <button id="menuEditPassword" class="dropdown-item"
           on-click="onMenuEditPasswordTap_">
         [[getMenuEditPasswordName_(isEditDialog_)]]
diff --git a/chrome/browser/resources/settings/autofill_page/passwords_list_handler.js b/chrome/browser/resources/settings/autofill_page/passwords_list_handler.js
index 9834dc35..14f5547 100644
--- a/chrome/browser/resources/settings/autofill_page/passwords_list_handler.js
+++ b/chrome/browser/resources/settings/autofill_page/passwords_list_handler.js
@@ -74,14 +74,6 @@
     // </if>
 
     /** @private */
-    enablePasswordCheck_: {
-      type: Boolean,
-      value() {
-        return loadTimeData.getBoolean('enablePasswordCheck');
-      }
-    },
-
-    /** @private */
     editPasswordsInSettings_: {
       type: Boolean,
       value() {
diff --git a/chrome/browser/resources/settings/autofill_page/passwords_section.html b/chrome/browser/resources/settings/autofill_page/passwords_section.html
index 75ac76d..2c62d14 100644
--- a/chrome/browser/resources/settings/autofill_page/passwords_section.html
+++ b/chrome/browser/resources/settings/autofill_page/passwords_section.html
@@ -98,51 +98,49 @@
         label="$i18n{passwordsAutosigninLabel}"
         sub-label="$i18n{passwordsAutosigninDescription}">
     </settings-toggle-button>
-    <template is="dom-if" if="[[enablePasswordCheck_]]">
-      <div id="checkPasswordsBannerContainer" class="cr-row"
-          hidden$="[[!shouldShowBanner_]]">
-        <picture>
-          <source
-              srcset="chrome://settings/images/password_check_neutral_dark.svg"
-              media="(prefers-color-scheme: dark)">
-          <img id="banner" alt=""
-              src="chrome://settings/images/password_check_neutral.svg">
-        </picture>
+    <div id="checkPasswordsBannerContainer" class="cr-row"
+        hidden$="[[!shouldShowBanner_]]">
+      <picture>
+        <source
+            srcset="chrome://settings/images/password_check_neutral_dark.svg"
+            media="(prefers-color-scheme: dark)">
+        <img id="banner" alt=""
+            src="chrome://settings/images/password_check_neutral.svg">
+      </picture>
+    </div>
+    <div id="checkPasswordsButtonRow" class="cr-row continuation"
+        hidden$="[[!shouldShowBanner_]]">
+      <div class="flex cr-padded-text">
+        <div>$i18n{checkPasswords}</div>
+        <div class="secondary">$i18n{checkPasswordsDescription}</div>
       </div>
-      <div id="checkPasswordsButtonRow" class="cr-row continuation"
-          hidden$="[[!shouldShowBanner_]]">
-        <div class="flex cr-padded-text">
-          <div>$i18n{checkPasswords}</div>
-          <div class="secondary">$i18n{checkPasswordsDescription}</div>
-        </div>
-        <cr-button id="checkPasswordsButton" class="action-button cr-button-gap"
-            on-click="onCheckPasswordsClick_">
+      <cr-button id="checkPasswordsButton" class="action-button cr-button-gap"
+          on-click="onCheckPasswordsClick_">
+        $i18n{checkPasswords}
+      </cr-button>
+    </div>
+    <div class="cr-row" id="checkPasswordsLinkRow"
+        on-click="onCheckPasswordsClick_" actionable
+        hidden$="[[shouldShowBanner_]]">
+      <iron-icon icon="cr:warning" id="checkPasswordWarningIcon"
+          hidden$="[[!hasLeakedCredentials_]]"></iron-icon>
+      <div class="flex cr-padded-text">
+        <div>
           $i18n{checkPasswords}
-        </cr-button>
-      </div>
-      <div class="cr-row" id="checkPasswordsLinkRow"
-          on-click="onCheckPasswordsClick_" actionable
-          hidden$="[[shouldShowBanner_]]">
-        <iron-icon icon="cr:warning" id="checkPasswordWarningIcon"
-            hidden$="[[!hasLeakedCredentials_]]"></iron-icon>
-        <div class="flex cr-padded-text">
-          <div>
-            $i18n{checkPasswords}
-          </div>
-          <div class="secondary" id="checkPasswordLeakCount"
-              hidden$="[[!hasLeakedCredentials_]]">
-            [[compromisedPasswordsCount]]
-          </div>
-          <div class="secondary" id="checkPasswordLeakDescription"
-              hidden$="[[hasLeakedCredentials_]]">
-            $i18n{checkPasswordsDescription}
-          </div>
         </div>
-        <cr-icon-button id="icon" class="subpage-arrow"
-            aria-label="$i18n{checkPasswords}">
-        </cr-icon-button>
+        <div class="secondary" id="checkPasswordLeakCount"
+            hidden$="[[!hasLeakedCredentials_]]">
+          [[compromisedPasswordsCount]]
+        </div>
+        <div class="secondary" id="checkPasswordLeakDescription"
+            hidden$="[[hasLeakedCredentials_]]">
+          $i18n{checkPasswordsDescription}
+        </div>
       </div>
-    </template>
+      <cr-icon-button id="icon" class="subpage-arrow"
+          aria-label="$i18n{checkPasswords}">
+      </cr-icon-button>
+    </div>
     <div id="manageLink" class="cr-row two-line"
         hidden$="[[hidePasswordsLink_]]">
       <!-- This div lays out the link correctly, relative to the text. -->
diff --git a/chrome/browser/resources/settings/autofill_page/passwords_section.js b/chrome/browser/resources/settings/autofill_page/passwords_section.js
index 9c4287a..c9ed577f 100644
--- a/chrome/browser/resources/settings/autofill_page/passwords_section.js
+++ b/chrome/browser/resources/settings/autofill_page/passwords_section.js
@@ -120,14 +120,6 @@
     },
 
     /** @private */
-    enablePasswordCheck_: {
-      type: Boolean,
-      value() {
-        return loadTimeData.getBoolean('enablePasswordCheck');
-      }
-    },
-
-    /** @private */
     signedIn_: {
       type: Boolean,
       value: true,
@@ -328,11 +320,9 @@
     // Populate the |focusConfig| map of the parent <settings-autofill-page>
     // element, with additional entries that correspond to subpage trigger
     // elements residing in this element's Shadow DOM.
-    if (this.enablePasswordCheck_) {
-      this.focusConfig.set(assert(routes.CHECK_PASSWORDS).path, () => {
-        focusWithoutInk(assert(this.$$('#icon')));
-      });
-    }
+    this.focusConfig.set(assert(routes.CHECK_PASSWORDS).path, () => {
+      focusWithoutInk(assert(this.$$('#icon')));
+    });
   },
 
   /** @override */
diff --git a/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.html b/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.html
index d528dc9..c7015db0 100644
--- a/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.html
+++ b/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.html
@@ -154,13 +154,15 @@
               </a>
             </div>
           </cr-link-row>
-          <template is="dom-if" if="[[hasReleaseNotes_]]">
+          <template is="dom-if" if="[[showReleaseNotesOnline_(hasReleaseNotes_,
+              hasInternetConnection_)]]">
             <cr-link-row class="hr" id="releaseNotesOnline"
-                hidden="[[!hasInternetConnection_]]"
                 on-click="onReleaseNotesTap_"
                 label="$i18n{aboutShowReleaseNotes}" external></cr-link-row>
+          </template>
+          <template is="dom-if" if="[[showReleaseNotesOffline_(hasReleaseNotes_,
+              hasInternetConnection_)]]">
             <cr-link-row class="hr" id="releaseNotesOffline"
-                hidden="[[hasInternetConnection_]]"
                 on-click="onReleaseNotesTap_"
                 label="$i18n{aboutShowReleaseNotes}"
                 title="$i18n{aboutReleaseNotesOffline}" external></cr-link-row>
diff --git a/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.js b/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.js
index 8d48bf7..498acd3 100644
--- a/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.js
+++ b/chrome/browser/resources/settings/chromeos/os_about_page/os_about_page.js
@@ -317,6 +317,23 @@
   },
 
   /**
+   * @return {boolean}
+   * @private
+   */
+  showReleaseNotesOnline_() {
+    return this.hasReleaseNotes_ && this.hasInternetConnection_;
+  },
+
+  /**
+   * @return {boolean}
+   * @private
+   */
+  showReleaseNotesOffline_() {
+    return this.hasReleaseNotes_ && !this.hasInternetConnection_;
+  },
+
+
+  /**
    * @return {string}
    * @private
    */
diff --git a/chrome/browser/resources/settings/languages_page/languages_page.js b/chrome/browser/resources/settings/languages_page/languages_page.js
index deb7972f..f0545ed 100644
--- a/chrome/browser/resources/settings/languages_page/languages_page.js
+++ b/chrome/browser/resources/settings/languages_page/languages_page.js
@@ -106,9 +106,6 @@
         return [];
       },
     },
-
-    /** @private {string|undefined} */
-    languageSyncedWithBrowserEnableSpellchecking_: String,
     // </if>
 
     /**
@@ -641,29 +638,12 @@
 
       // Hide list of spell check languages if there is only 1 language
       // and we don't need to display any errors for that language
+
+      // TODO(crbug/1124888): Make hideSpellCheckLanugages_ a computed property
       this.hideSpellCheckLanguages_ = !singleLanguage.isManaged &&
           singleLanguage.downloadDictionaryFailureCount === 0;
-
-      // Turn off spell check if spell check for the 1 remaining language is
-      // off
-      if (!singleLanguage.spellCheckEnabled) {
-        this.setPrefValue('browser.enable_spellchecking', false);
-        this.languageSyncedWithBrowserEnableSpellchecking_ =
-            singleLanguage.language.code;
-      }
-
-      // Undo the sync if spell check appeared as turned off for the language
-      // because a download was still in progress. This only occurs when
-      // Settings is loaded for the very first time and dictionaries have not
-      // been downloaded yet.
-      if (this.languageSyncedWithBrowserEnableSpellchecking_ ===
-              singleLanguage.language.code &&
-          singleLanguage.spellCheckEnabled) {
-        this.setPrefValue('browser.enable_spellchecking', true);
-      }
     } else {
       this.hideSpellCheckLanguages_ = false;
-      this.languageSyncedWithBrowserEnableSpellchecking_ = undefined;
     }
   },
 
diff --git a/chrome/browser/resources/settings/route.js b/chrome/browser/resources/settings/route.js
index 162b5ec..8f61f71e 100644
--- a/chrome/browser/resources/settings/route.js
+++ b/chrome/browser/resources/settings/route.js
@@ -132,15 +132,12 @@
   if (visibility.autofill !== false) {
     r.AUTOFILL = r.BASIC.createSection('/autofill', 'autofill');
     r.PASSWORDS = r.AUTOFILL.createChild('/passwords');
+    r.CHECK_PASSWORDS = r.PASSWORDS.createChild('check');
 
     if (loadTimeData.getBoolean('enableAccountStorage')) {
       r.DEVICE_PASSWORDS = r.PASSWORDS.createChild('device');
     }
 
-    if (loadTimeData.getBoolean('enablePasswordCheck')) {
-      r.CHECK_PASSWORDS = r.PASSWORDS.createChild('check');
-    }
-
     r.PAYMENTS = r.AUTOFILL.createChild('/payments');
     r.ADDRESSES = r.AUTOFILL.createChild('/addresses');
   }
diff --git a/chrome/browser/sharing/sharing_ui_controller.h b/chrome/browser/sharing/sharing_ui_controller.h
index 7f03554..43b86775 100644
--- a/chrome/browser/sharing/sharing_ui_controller.h
+++ b/chrome/browser/sharing/sharing_ui_controller.h
@@ -24,7 +24,6 @@
 #include "components/sync/protocol/device_info_specifics.pb.h"
 #include "components/sync_device_info/device_info.h"
 #include "ui/views/controls/styled_label.h"
-#include "ui/views/controls/styled_label_listener.h"
 #include "url/origin.h"
 
 class SharingDialog;
diff --git a/chrome/browser/spellchecker/spellcheck_service.cc b/chrome/browser/spellchecker/spellcheck_service.cc
index 563483f..0925657 100644
--- a/chrome/browser/spellchecker/spellcheck_service.cc
+++ b/chrome/browser/spellchecker/spellcheck_service.cc
@@ -829,8 +829,15 @@
 
   // If there are no hunspell dictionaries to load, then immediately let the
   // renderers know the new state.
-  if (hunspell_dictionaries_.empty())
+  if (hunspell_dictionaries_.empty()) {
+#if !defined(OS_MAC)
+    // Only update non-MacOS platform because basic spell check on Mac OS
+    // is controlled by OS and doesn't depend on users' dictionaries pref
+    user_prefs::UserPrefs::Get(context_)->SetBoolean(
+        spellcheck::prefs::kSpellCheckEnable, false);
+#endif  // !defined(OS_MAC)
     InitForAllRenderers();
+  }
 }
 
 void SpellcheckService::OnUseSpellingServiceChanged() {
diff --git a/chrome/browser/spellchecker/spellcheck_service_browsertest.cc b/chrome/browser/spellchecker/spellcheck_service_browsertest.cc
index b90df83..da20411c 100644
--- a/chrome/browser/spellchecker/spellcheck_service_browsertest.cc
+++ b/chrome/browser/spellchecker/spellcheck_service_browsertest.cc
@@ -149,11 +149,6 @@
     spellcheck->OnCustomDictionaryChanged(change);
   }
 
-  void SetSingleLanguageDictionary(const std::string& single_dictionary) {
-    prefs_->SetString(spellcheck::prefs::kSpellCheckDictionary,
-                      single_dictionary);
-  }
-
   void SetMultiLingualDictionaries(const std::string& multiple_dictionaries) {
     base::ListValue dictionaries_value;
     dictionaries_value.AppendStrings(
@@ -335,6 +330,16 @@
       GetPrefs()->GetBoolean(spellcheck::prefs::kSpellCheckUseSpellingService));
 }
 
+#if !defined(OS_MAC)
+IN_PROC_BROWSER_TEST_F(SpellcheckServiceBrowserTest,
+                       DisableSpellcheckIfDictionaryIsEmpty) {
+  InitSpellcheck(true, "", "en-US");
+  SetMultiLingualDictionaries("");
+
+  EXPECT_FALSE(GetPrefs()->GetBoolean(spellcheck::prefs::kSpellCheckEnable));
+}
+#endif  // !defined(OS_MAC)
+
 // Removing a spellcheck language from accept languages should remove it from
 // spellcheck languages list as well.
 IN_PROC_BROWSER_TEST_F(SpellcheckServiceBrowserTest,
diff --git a/chrome/browser/sync/profile_sync_service_android.cc b/chrome/browser/sync/profile_sync_service_android.cc
index 713e0fa..d790875 100644
--- a/chrome/browser/sync/profile_sync_service_android.cc
+++ b/chrome/browser/sync/profile_sync_service_android.cc
@@ -392,6 +392,20 @@
   return sync_service_->RequiresClientUpgrade();
 }
 
+void ProfileSyncServiceAndroid::SetDecoupledFromAndroidMasterSync(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& obj) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  sync_service_->SetDecoupledFromAndroidMasterSync();
+}
+
+jboolean ProfileSyncServiceAndroid::GetDecoupledFromAndroidMasterSync(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& obj) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  return sync_service_->GetDecoupledFromAndroidMasterSync();
+}
+
 jboolean ProfileSyncServiceAndroid::IsPassphrasePrompted(
     JNIEnv* env,
     const JavaParamRef<jobject>& obj) {
diff --git a/chrome/browser/sync/profile_sync_service_android.h b/chrome/browser/sync/profile_sync_service_android.h
index 74a55033..28dbd24 100644
--- a/chrome/browser/sync/profile_sync_service_android.h
+++ b/chrome/browser/sync/profile_sync_service_android.h
@@ -131,6 +131,12 @@
   jboolean RequiresClientUpgrade(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj);
+  void SetDecoupledFromAndroidMasterSync(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj);
+  jboolean GetDecoupledFromAndroidMasterSync(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj);
 
   // Pure SyncPrefs calls.
   jboolean IsPassphrasePrompted(
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd
index 34bb275..6294de4 100644
--- a/chrome/browser/ui/android/strings/android_chrome_strings.grd
+++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -2491,9 +2491,6 @@
       <message name="IDS_SIGNIN_PROMO_CHOOSE_ANOTHER_ACCOUNT" desc="Button that the user can press if they want to select a different account before signing in. This button is shown below 'Continue as Joe Doe' button that signs user in with default account.">
         Choose another account
       </message>
-      <message name="IDS_SIGNIN_PROMO_STATUS_MESSAGE" desc="Title string for 'Turn on sync' sync promos.">
-        Sync is off
-      </message>
       <message name="IDS_SYNC_PROMO_TURN_ON_SYNC" desc="Button that the user can press if they want to turn on sync with this account.">
         Turn on sync
       </message>
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_SIGNIN_PROMO_STATUS_MESSAGE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_SIGNIN_PROMO_STATUS_MESSAGE.png.sha1
deleted file mode 100644
index 305d3b01..0000000
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_SIGNIN_PROMO_STATUS_MESSAGE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-e9f89af85ba18833c1eb62aa3654062ab3da1146
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_bn.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_bn.xtb
index c4d54d0..48f911d 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_bn.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_bn.xtb
@@ -1,6 +1,7 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="bn">
+<translation id="1013149566889033026">একটি নতুন ছদ্মবেশী মোড খুলে যাবে</translation>
 <translation id="1028699632127661925"><ph name="DEVICE_NAME" />-এ পাঠানো হচ্ছে...</translation>
 <translation id="103269572468856066">এই সাইট ও অ্যাপের ডেটাও মুছে ফেলতে চান?</translation>
 <translation id="1036348656032585052">বন্ধ করুন</translation>
@@ -345,6 +346,7 @@
 <translation id="3775705724665058594">আপনার ডিভাইসে পাঠান</translation>
 <translation id="3778956594442850293">হোম স্ক্রিনে যোগ করা হয়েছে</translation>
 <translation id="3789841737615482174">ইনস্টল করুন</translation>
+<translation id="3800748312755064483">কিছু সময়ের সাইন-ইন করুন</translation>
 <translation id="3810838688059735925">ভিডিও</translation>
 <translation id="3810973564298564668">পরিচালনা</translation>
 <translation id="3819178904835489326"><ph name="NUMBER_OF_DOWNLOADS" />টি ডাউনলোড মোছা হয়েছে</translation>
diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
index c488d5b..1bdc604 100644
--- a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
@@ -616,15 +616,8 @@
 
 void ManagePasswordsUIController::NavigateToPasswordCheckup(
     password_manager::PasswordCheckReferrer referrer) {
-  if (base::FeatureList::IsEnabled(
-          password_manager::features::kPasswordCheck)) {
-    chrome::ShowPasswordCheck(
-        chrome::FindBrowserWithWebContents(web_contents()));
-    password_manager::LogPasswordCheckReferrer(referrer);
-  } else {
-    NavigateToPasswordCheckupPage(
-        Profile::FromBrowserContext(web_contents()->GetBrowserContext()));
-  }
+  chrome::ShowPasswordCheck(chrome::FindBrowserWithWebContents(web_contents()));
+  password_manager::LogPasswordCheckReferrer(referrer);
 }
 
 void ManagePasswordsUIController::EnableSync(const AccountInfo& account,
diff --git a/chrome/browser/ui/thumbnails/thumbnail_tab_helper.cc b/chrome/browser/ui/thumbnails/thumbnail_tab_helper.cc
index feeb1cf6..8692627 100644
--- a/chrome/browser/ui/thumbnails/thumbnail_tab_helper.cc
+++ b/chrome/browser/ui/thumbnails/thumbnail_tab_helper.cc
@@ -284,6 +284,7 @@
     return;
 
   start_video_capture_time_ = base::TimeTicks::Now();
+  got_first_frame_ = false;
 
   // Figure out how large we want the capture target to be.
   last_frame_capture_info_ =
@@ -304,11 +305,18 @@
 }
 
 void ThumbnailTabHelper::StopVideoCapture() {
-  if (video_capturer_) {
-    video_capturer_->Stop();
-    video_capturer_.reset();
+  if (!video_capturer_) {
+    DCHECK_EQ(start_video_capture_time_, base::TimeTicks());
+    return;
   }
 
+  video_capturer_->Stop();
+  video_capturer_.reset();
+
+  UMA_HISTOGRAM_MEDIUM_TIMES(
+      "Tab.Preview.VideoCaptureDuration",
+      base::TimeTicks::Now() - start_video_capture_time_);
+
   start_video_capture_time_ = base::TimeTicks();
 }
 
@@ -344,10 +352,10 @@
     return;
   }
 
-  if (start_video_capture_time_ != base::TimeTicks()) {
+  if (!got_first_frame_) {
     UMA_HISTOGRAM_TIMES("Tab.Preview.TimeToFirstUsableFrameAfterStartCapture",
                         time_of_call - start_video_capture_time_);
-    start_video_capture_time_ = base::TimeTicks();
+    got_first_frame_ = true;
   }
 
   // The SkBitmap's pixels will be marked as immutable, but the installPixels()
diff --git a/chrome/browser/ui/thumbnails/thumbnail_tab_helper.h b/chrome/browser/ui/thumbnails/thumbnail_tab_helper.h
index c2660bcd..9ba8bff 100644
--- a/chrome/browser/ui/thumbnails/thumbnail_tab_helper.h
+++ b/chrome/browser/ui/thumbnails/thumbnail_tab_helper.h
@@ -99,6 +99,9 @@
   // Times for computing metrics.
   base::TimeTicks start_video_capture_time_;
 
+  // Whether the first frame has been received after StartVideoCapture().
+  bool got_first_frame_ = false;
+
   // The thumbnail maintained by this instance.
   scoped_refptr<ThumbnailImage> thumbnail_;
 
diff --git a/chrome/browser/ui/views/apps/app_dialog/app_uninstall_dialog_view.cc b/chrome/browser/ui/views/apps/app_dialog/app_uninstall_dialog_view.cc
index e3916e22..632e052 100644
--- a/chrome/browser/ui/views/apps/app_dialog/app_uninstall_dialog_view.cc
+++ b/chrome/browser/ui/views/apps/app_dialog/app_uninstall_dialog_view.cc
@@ -191,27 +191,13 @@
 }
 
 void AppUninstallDialogView::InitializeCheckbox(const GURL& app_launch_url) {
-  std::unique_ptr<views::StyledLabel> checkbox_label;
   std::vector<base::string16> replacements;
-  size_t offset;
-  base::string16 learn_more_text =
-      l10n_util::GetStringUTF16(IDS_APP_UNINSTALL_PROMPT_LEARN_MORE);
-
   replacements.push_back(url_formatter::FormatUrlForSecurityDisplay(
       app_launch_url, url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC));
 
-  if (google_util::IsGoogleHostname(app_launch_url.host_piece(),
-                                    google_util::ALLOW_SUBDOMAIN)) {
-    replacements.push_back(learn_more_text);
-
-    checkbox_label = std::make_unique<views::StyledLabel>(this);
-    std::vector<size_t> offsets;
-    checkbox_label->SetText(l10n_util::GetStringFUTF16(
-        IDS_APP_UNINSTALL_PROMPT_REMOVE_DATA_CHECKBOX_FOR_GOOGLE, replacements,
-        &offsets));
-    DCHECK_EQ(replacements.size(), offsets.size());
-    offset = offsets.back();
-  } else {
+  const bool is_google = google_util::IsGoogleHostname(
+      app_launch_url.host_piece(), google_util::ALLOW_SUBDOMAIN);
+  if (!is_google) {
     auto domain = net::registry_controlled_domains::GetDomainAndRegistry(
         app_launch_url,
         net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
@@ -219,17 +205,21 @@
     domain[0] = base::ToUpperASCII(domain[0]);
 
     replacements.push_back(base::ASCIIToUTF16(domain));
-    replacements.push_back(learn_more_text);
-
-    checkbox_label = std::make_unique<views::StyledLabel>(this);
-    std::vector<size_t> offsets;
-    checkbox_label->SetText(l10n_util::GetStringFUTF16(
-        IDS_APP_UNINSTALL_PROMPT_REMOVE_DATA_CHECKBOX_FOR_NON_GOOGLE,
-        replacements, &offsets));
-    DCHECK_EQ(replacements.size(), offsets.size());
-    offset = offsets.back();
   }
 
+  base::string16 learn_more_text =
+      l10n_util::GetStringUTF16(IDS_APP_UNINSTALL_PROMPT_LEARN_MORE);
+  replacements.push_back(learn_more_text);
+
+  auto checkbox_label = std::make_unique<views::StyledLabel>(this);
+  std::vector<size_t> offsets;
+  checkbox_label->SetText(l10n_util::GetStringFUTF16(
+      is_google ? IDS_APP_UNINSTALL_PROMPT_REMOVE_DATA_CHECKBOX_FOR_GOOGLE
+                : IDS_APP_UNINSTALL_PROMPT_REMOVE_DATA_CHECKBOX_FOR_NON_GOOGLE,
+      replacements, &offsets));
+  DCHECK_EQ(replacements.size(), offsets.size());
+  const size_t offset = offsets.back();
+
   checkbox_label->AddStyleRange(
       gfx::Range(offset, offset + learn_more_text.length()),
       views::StyledLabel::RangeStyleInfo::CreateForLink());
diff --git a/chrome/browser/ui/views/apps/app_info_dialog/app_info_summary_panel.cc b/chrome/browser/ui/views/apps/app_info_dialog/app_info_summary_panel.cc
index 536151b..824ed57 100644
--- a/chrome/browser/ui/views/apps/app_info_dialog/app_info_summary_panel.cc
+++ b/chrome/browser/ui/views/apps/app_info_dialog/app_info_summary_panel.cc
@@ -200,7 +200,8 @@
       std::make_unique<views::Combobox>(launch_options_combobox_model_.get());
   launch_options_combobox->SetAccessibleName(
       l10n_util::GetStringUTF16(IDS_APPLICATION_INFO_LAUNCH_OPTIONS_ACCNAME));
-  launch_options_combobox->set_listener(this);
+  launch_options_combobox->set_callback(base::BindRepeating(
+      &AppInfoSummaryPanel::OnPerformAction, base::Unretained(this)));
   launch_options_combobox->SetSelectedIndex(
       launch_options_combobox_model_->GetIndexForLaunchType(GetLaunchType()));
 
@@ -224,12 +225,9 @@
 }
 
 void AppInfoSummaryPanel::OnPerformAction(views::Combobox* combobox) {
-  if (combobox == launch_options_combobox_) {
-    SetLaunchType(launch_options_combobox_model_->GetLaunchTypeAtIndex(
-        launch_options_combobox_->GetSelectedIndex()));
-  } else {
-    NOTREACHED();
-  }
+  DCHECK(combobox == launch_options_combobox_);
+  SetLaunchType(launch_options_combobox_model_->GetLaunchTypeAtIndex(
+      launch_options_combobox_->GetSelectedIndex()));
 }
 
 void AppInfoSummaryPanel::StartCalculatingAppSize() {
diff --git a/chrome/browser/ui/views/apps/app_info_dialog/app_info_summary_panel.h b/chrome/browser/ui/views/apps/app_info_dialog/app_info_summary_panel.h
index 78618f02..d57a5bf 100644
--- a/chrome/browser/ui/views/apps/app_info_dialog/app_info_summary_panel.h
+++ b/chrome/browser/ui/views/apps/app_info_dialog/app_info_summary_panel.h
@@ -13,7 +13,6 @@
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ui/views/apps/app_info_dialog/app_info_panel.h"
 #include "extensions/common/constants.h"
-#include "ui/views/controls/combobox/combobox_listener.h"
 
 class LaunchOptionsComboboxModel;
 class Profile;
@@ -31,7 +30,6 @@
 // The summary panel of the app info dialog, which provides basic information
 // and controls related to the app.
 class AppInfoSummaryPanel : public AppInfoPanel,
-                            public views::ComboboxListener,
                             public base::SupportsWeakPtr<AppInfoSummaryPanel> {
  public:
   AppInfoSummaryPanel(Profile* profile, const extensions::Extension* app);
@@ -45,8 +43,8 @@
   void AddLaunchOptionControl(views::View* vertical_stack);
   void AddSubviews();
 
-  // Overridden from views::ComboboxListener:
-  void OnPerformAction(views::Combobox* combobox) override;
+  // Called when the combobox selection changes.
+  void OnPerformAction(views::Combobox* combobox);
 
   // Called asynchronously to calculate and update the size of the app displayed
   // in the dialog.
diff --git a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
index a7f79db5..ca5d8e9 100644
--- a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
+++ b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
@@ -970,7 +970,7 @@
     AutofillPopupViewNativeViews* popup_view,
     int line_number)
     : popup_view_(popup_view), line_number_(line_number) {
-  set_notify_enter_exit_on_child(true);
+  SetNotifyEnterExitOnChild(true);
 }
 
 void AutofillPopupRowView::Init() {
diff --git a/chrome/browser/ui/views/autofill/payments/card_unmask_prompt_views.cc b/chrome/browser/ui/views/autofill/payments/card_unmask_prompt_views.cc
index 7d839d8..4f41556 100644
--- a/chrome/browser/ui/views/autofill/payments/card_unmask_prompt_views.cc
+++ b/chrome/browser/ui/views/autofill/payments/card_unmask_prompt_views.cc
@@ -360,12 +360,14 @@
 
   // Add the month and year comboboxes if the expiration date is needed.
   auto month_input = std::make_unique<views::Combobox>(&month_combobox_model_);
-  month_input->set_listener(this);
+  month_input->set_callback(base::BindRepeating(
+      &CardUnmaskPromptViews::OnPerformAction, base::Unretained(this)));
   month_input->SetAccessibleName(
       l10n_util::GetStringUTF16(IDS_AUTOFILL_CARD_UNMASK_EXPIRATION_MONTH));
   month_input_ = input_row->AddChildView(std::move(month_input));
   auto year_input = std::make_unique<views::Combobox>(&year_combobox_model_);
-  year_input->set_listener(this);
+  year_input->set_callback(base::BindRepeating(
+      &CardUnmaskPromptViews::OnPerformAction, base::Unretained(this)));
   year_input->SetAccessibleName(
       l10n_util::GetStringUTF16(IDS_AUTOFILL_CARD_UNMASK_EXPIRATION_YEAR));
   year_input_ = input_row->AddChildView(std::move(year_input));
diff --git a/chrome/browser/ui/views/autofill/payments/card_unmask_prompt_views.h b/chrome/browser/ui/views/autofill/payments/card_unmask_prompt_views.h
index ef01c5e..54c6c44d 100644
--- a/chrome/browser/ui/views/autofill/payments/card_unmask_prompt_views.h
+++ b/chrome/browser/ui/views/autofill/payments/card_unmask_prompt_views.h
@@ -11,16 +11,16 @@
 #include "chrome/browser/ui/autofill/payments/autofill_dialog_models.h"
 #include "components/autofill/core/browser/ui/payments/card_unmask_prompt_view.h"
 #include "ui/views/bubble/bubble_dialog_delegate_view.h"
-#include "ui/views/controls/combobox/combobox_listener.h"
 #include "ui/views/controls/textfield/textfield_controller.h"
 #include "ui/views/window/dialog_delegate.h"
 
 namespace content {
 class WebContents;
-}
+}  // namespace content
 
 namespace views {
 class Checkbox;
+class Combobox;
 class Label;
 class Textfield;
 class Throbber;
@@ -31,7 +31,6 @@
 class CardUnmaskPromptController;
 
 class CardUnmaskPromptViews : public CardUnmaskPromptView,
-                              public views::ComboboxListener,
                               public views::BubbleDialogDelegateView,
                               public views::TextfieldController {
  public:
@@ -39,7 +38,7 @@
                         content::WebContents* web_contents);
   ~CardUnmaskPromptViews() override;
 
-  // CardUnmaskPromptView
+  // CardUnmaskPromptView:
   void Show() override;
   void ControllerGone() override;
   void DisableAndWaitForVerification() override;
@@ -66,9 +65,6 @@
   void ContentsChanged(views::Textfield* sender,
                        const base::string16& new_contents) override;
 
-  // views::ComboboxListener
-  void OnPerformAction(views::Combobox* combobox) override;
-
  private:
   friend class CardUnmaskPromptViewTesterViews;
 
@@ -83,6 +79,8 @@
 
   void LinkClicked();
 
+  void OnPerformAction(views::Combobox* combobox);
+
   CardUnmaskPromptController* controller_;
   content::WebContents* web_contents_;
 
diff --git a/chrome/browser/ui/views/autofill/payments/local_card_migration_dialog_view.cc b/chrome/browser/ui/views/autofill/payments/local_card_migration_dialog_view.cc
index db1bfd38..98b4fe8 100644
--- a/chrome/browser/ui/views/autofill/payments/local_card_migration_dialog_view.cc
+++ b/chrome/browser/ui/views/autofill/payments/local_card_migration_dialog_view.cc
@@ -305,14 +305,13 @@
 
     AddChildView(new views::Separator());
 
-    legal_message_container_ = new LegalMessageView(
+    legal_message_container_ = AddChildView(std::make_unique<LegalMessageView>(
         controller->GetLegalMessageLines(),
         base::BindRepeating(
             &LocalCardMigrationDialogController::OnLegalMessageLinkClicked,
-            base::Unretained(controller_)));
+            base::Unretained(controller_))));
     legal_message_container_->SetBorder(
         views::CreateEmptyBorder(kMigrationDialogInsets));
-    AddChildView(legal_message_container_);
   }
 
   ~LocalCardMigrationOfferView() override {}
diff --git a/chrome/browser/ui/views/autofill/payments/payments_view_util.cc b/chrome/browser/ui/views/autofill/payments/payments_view_util.cc
index c45dc07..c7449ff8 100644
--- a/chrome/browser/ui/views/autofill/payments/payments_view_util.cc
+++ b/chrome/browser/ui/views/autofill/payments/payments_view_util.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/views/autofill/payments/payments_view_util.h"
 
+#include "base/util/ranges/algorithm.h"
 #include "build/branding_buildflags.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
@@ -148,26 +149,18 @@
   }
 }
 
-LegalMessageView::~LegalMessageView() {}
+LegalMessageView::~LegalMessageView() = default;
 
 void LegalMessageView::StyledLabelLinkClicked(views::StyledLabel* label,
                                               const gfx::Range& range,
                                               int event_flags) {
-  // Index of |label| within its parent's view hierarchy is the same as the
-  // legal message line index. DCHECK this assumption to guard against future
-  // layout changes.
-  DCHECK_EQ(label->parent()->children().size(), legal_message_lines_.size());
-
-  const std::vector<LegalMessageLine::Link>& links =
-      legal_message_lines_[label->parent()->GetIndexOf(label)].links();
-  for (const LegalMessageLine::Link& link : links) {
-    if (link.range == range) {
-      callback_.Run(link.url);
-      return;
-    }
-  }
-  // |range| was not found.
-  NOTREACHED();
+  const int label_index = GetIndexOf(label);
+  DCHECK_LT(size_t{label_index}, legal_message_lines_.size());
+  const auto& links = legal_message_lines_[label_index].links();
+  const auto it =
+      util::ranges::find(links, range, &LegalMessageLine::Link::range);
+  DCHECK(it != links.end());
+  callback_.Run(it->url);
 }
 
 PaymentsBubbleClosedReason GetPaymentsBubbleClosedReasonFromWidgetClosedReason(
diff --git a/chrome/browser/ui/views/autofill/payments/save_card_offer_bubble_views.cc b/chrome/browser/ui/views/autofill/payments/save_card_offer_bubble_views.cc
index c9f6f55a0ea..bfec965 100644
--- a/chrome/browser/ui/views/autofill/payments/save_card_offer_bubble_views.cc
+++ b/chrome/browser/ui/views/autofill/payments/save_card_offer_bubble_views.cc
@@ -127,11 +127,6 @@
   DialogModelChanged();
 }
 
-void SaveCardOfferBubbleViews::OnPerformAction(views::Combobox* sender) {
-  DCHECK(month_input_dropdown_ == sender || year_input_dropdown_ == sender);
-  DialogModelChanged();
-}
-
 SaveCardOfferBubbleViews::~SaveCardOfferBubbleViews() {}
 
 std::unique_ptr<views::View> SaveCardOfferBubbleViews::CreateMainContentView() {
@@ -231,7 +226,8 @@
 
   // Set up the month and year comboboxes.
   month_input_dropdown_ = new views::Combobox(&month_combobox_model_);
-  month_input_dropdown_->set_listener(this);
+  month_input_dropdown_->set_closure(base::BindRepeating(
+      &SaveCardOfferBubbleViews::DialogModelChanged, base::Unretained(this)));
   month_input_dropdown_->SetAccessibleName(
       l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_EXPIRY_MONTH));
   month_input_dropdown_->SetID(DialogViewId::EXPIRATION_DATE_DROPBOX_MONTH);
@@ -245,7 +241,8 @@
   }
 
   year_input_dropdown_ = new views::Combobox(&year_combobox_model_);
-  year_input_dropdown_->set_listener(this);
+  year_input_dropdown_->set_closure(base::BindRepeating(
+      &SaveCardOfferBubbleViews::DialogModelChanged, base::Unretained(this)));
   year_input_dropdown_->SetAccessibleName(
       l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_PLACEHOLDER_EXPIRY_YEAR));
   year_input_dropdown_->SetID(DialogViewId::EXPIRATION_DATE_DROPBOX_YEAR);
diff --git a/chrome/browser/ui/views/autofill/payments/save_card_offer_bubble_views.h b/chrome/browser/ui/views/autofill/payments/save_card_offer_bubble_views.h
index 8d8a458..16255f3 100644
--- a/chrome/browser/ui/views/autofill/payments/save_card_offer_bubble_views.h
+++ b/chrome/browser/ui/views/autofill/payments/save_card_offer_bubble_views.h
@@ -8,12 +8,15 @@
 #include "chrome/browser/ui/autofill/payments/autofill_dialog_models.h"
 #include "chrome/browser/ui/views/autofill/payments/payments_view_util.h"
 #include "chrome/browser/ui/views/autofill/payments/save_card_bubble_views.h"
-#include "ui/views/controls/combobox/combobox_listener.h"
 #include "ui/views/controls/textfield/textfield_controller.h"
 
 namespace content {
 class WebContents;
-}
+}  // namespace content
+
+namespace views {
+class Combobox;
+}  // namespace views
 
 namespace autofill {
 
@@ -22,7 +25,6 @@
 // previously saved. It includes a description of the card that is being saved
 // and an [Save] button. (Non-material UI's include a [No Thanks] button).
 class SaveCardOfferBubbleViews : public SaveCardBubbleViews,
-                                 public views::ComboboxListener,
                                  public views::TextfieldController {
  public:
   // Bubble will be anchored to |anchor_view|.
@@ -39,10 +41,9 @@
   void ContentsChanged(views::Textfield* sender,
                        const base::string16& new_contents) override;
 
-  // views::ComboboxListener:
-  void OnPerformAction(views::Combobox* combobox) override;
-
  private:
+  ~SaveCardOfferBubbleViews() override;
+
   std::unique_ptr<views::View> CreateMainContentView() override;
 
   std::unique_ptr<views::View> CreateRequestExpirationDateView();
@@ -50,8 +51,6 @@
 
   void LinkClicked(const GURL& url);
 
-  ~SaveCardOfferBubbleViews() override;
-
   views::Textfield* cardholder_name_textfield_ = nullptr;
 
   LegalMessageView* legal_message_view_ = nullptr;
diff --git a/chrome/browser/ui/views/content_setting_bubble_contents.cc b/chrome/browser/ui/views/content_setting_bubble_contents.cc
index 71d620e3..5fb0211 100644
--- a/chrome/browser/ui/views/content_setting_bubble_contents.cc
+++ b/chrome/browser/ui/views/content_setting_bubble_contents.cc
@@ -89,7 +89,7 @@
 // and/or camera).
 class MediaMenuBlock : public views::View {
  public:
-  MediaMenuBlock(views::ComboboxListener* listener,
+  MediaMenuBlock(views::Combobox::PerformActionCallback callback,
                  ContentSettingBubbleModel::MediaMenuMap media) {
     const ChromeLayoutProvider* provider = ChromeLayoutProvider::Get();
 
@@ -137,7 +137,7 @@
       auto combobox =
           std::make_unique<views::Combobox>(std::move(combobox_model));
       combobox->SetEnabled(combobox_enabled);
-      combobox->set_listener(listener);
+      combobox->set_callback(callback);
       combobox->SetSelectedIndex(combobox_selected_index);
       layout->AddView(std::move(combobox));
     }
@@ -517,7 +517,10 @@
   // Layout code for the media device menus.
   if (content_setting_bubble_model_->AsMediaStreamBubbleModel()) {
     rows.push_back(
-        {std::make_unique<MediaMenuBlock>(this, bubble_content.media_menus),
+        {std::make_unique<MediaMenuBlock>(
+             base::BindRepeating(&ContentSettingBubbleContents::OnPerformAction,
+                                 base::Unretained(this)),
+             bubble_content.media_menus),
          LayoutRowType::INDENTED});
   }
 
diff --git a/chrome/browser/ui/views/content_setting_bubble_contents.h b/chrome/browser/ui/views/content_setting_bubble_contents.h
index 13044feb..795c132 100644
--- a/chrome/browser/ui/views/content_setting_bubble_contents.h
+++ b/chrome/browser/ui/views/content_setting_bubble_contents.h
@@ -18,14 +18,14 @@
 #include "ui/views/controls/button/button.h"
 #include "ui/views/controls/button/checkbox.h"
 #include "ui/views/controls/button/radio_button.h"
-#include "ui/views/controls/combobox/combobox_listener.h"
 
 namespace views {
+class Combobox;
 class ImageButton;
 class RadioButton;
 class LabelButton;
 class Link;
-}
+}  // namespace views
 
 // ContentSettingBubbleContents is used when the user turns on different kinds
 // of content blocking (e.g. "block images").  When viewing a page with blocked
@@ -39,7 +39,6 @@
 class ContentSettingBubbleContents : public content::WebContentsObserver,
                                      public views::BubbleDialogDelegateView,
                                      public views::ButtonListener,
-                                     public views::ComboboxListener,
                                      public ContentSettingBubbleModel::Owner {
  public:
   ContentSettingBubbleContents(
@@ -81,6 +80,8 @@
   void LinkClicked(views::Link* source, int event_flags);
   void CustomLinkClicked();
 
+  void OnPerformAction(views::Combobox* combobox);
+
   // content::WebContentsObserver:
   void DidFinishNavigation(
       content::NavigationHandle* navigation_handle) override;
@@ -90,8 +91,6 @@
   // views::ButtonListener:
   void ButtonPressed(views::Button* sender, const ui::Event& event) override;
 
-  // views::ComboboxListener:
-  void OnPerformAction(views::Combobox* combobox) override;
 
   // Provides data for this bubble.
   std::unique_ptr<ContentSettingBubbleModel> content_setting_bubble_model_;
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_item_view.cc b/chrome/browser/ui/views/extensions/extensions_menu_item_view.cc
index de7a8b7..c7de8af 100644
--- a/chrome/browser/ui/views/extensions/extensions_menu_item_view.cc
+++ b/chrome/browser/ui/views/extensions/extensions_menu_item_view.cc
@@ -54,7 +54,7 @@
       model_(ToolbarActionsModel::Get(browser->profile())) {
   // Set so the extension button receives enter/exit on children to retain hover
   // status when hovering child views.
-  set_notify_enter_exit_on_child(true);
+  SetNotifyEnterExitOnChild(true);
 
   context_menu_controller_ = std::make_unique<ExtensionContextMenuController>(
       nullptr, controller_.get());
diff --git a/chrome/browser/ui/views/global_media_controls/media_notification_container_impl_view.cc b/chrome/browser/ui/views/global_media_controls/media_notification_container_impl_view.cc
index 1111ea9d..731fdec 100644
--- a/chrome/browser/ui/views/global_media_controls/media_notification_container_impl_view.cc
+++ b/chrome/browser/ui/views/global_media_controls/media_notification_container_impl_view.cc
@@ -80,7 +80,7 @@
   SetLayoutManager(std::make_unique<views::BoxLayout>(
       views::BoxLayout::Orientation::kVertical));
   SetPreferredSize(kNormalSize);
-  set_notify_enter_exit_on_child(true);
+  SetNotifyEnterExitOnChild(true);
   SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
   SetTooltipText(
       l10n_util::GetStringUTF16(IDS_GLOBAL_MEDIA_CONTROLS_BACK_TO_TAB));
diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
index 2ca68f51..8b91b74 100644
--- a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
+++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
@@ -148,7 +148,7 @@
 
   UpdateBorder();
 
-  set_notify_enter_exit_on_child(true);
+  SetNotifyEnterExitOnChild(true);
 
   // Flip the canvas in RTL so the separator is drawn on the correct side.
   separator_view_->EnableCanvasFlippingForRTLUI(true);
diff --git a/chrome/browser/ui/views/location_bar/zoom_bubble_view.cc b/chrome/browser/ui/views/location_bar/zoom_bubble_view.cc
index a8252d8..c296287 100644
--- a/chrome/browser/ui/views/location_bar/zoom_bubble_view.cc
+++ b/chrome/browser/ui/views/location_bar/zoom_bubble_view.cc
@@ -294,7 +294,7 @@
           chrome::FindBrowserWithWebContents(web_contents)->session_id()) {
   SetButtons(ui::DIALOG_BUTTON_NONE);
 
-  set_notify_enter_exit_on_child(true);
+  SetNotifyEnterExitOnChild(true);
   if (immersive_mode_controller_)
     immersive_mode_controller_->AddObserver(this);
   UseCompactMargins();
diff --git a/chrome/browser/ui/views/media_router/cast_dialog_sink_button.cc b/chrome/browser/ui/views/media_router/cast_dialog_sink_button.cc
index af665c7..9638e46 100644
--- a/chrome/browser/ui/views/media_router/cast_dialog_sink_button.cc
+++ b/chrome/browser/ui/views/media_router/cast_dialog_sink_button.cc
@@ -10,7 +10,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "build/branding_buildflags.h"
 #include "chrome/app/vector_icons/vector_icons.h"
-#include "chrome/browser/ui/views/chrome_layout_provider.h"
 #include "chrome/browser/ui/views/chrome_typography.h"
 #include "chrome/browser/ui/views/media_router/cast_dialog_helper.h"
 #include "chrome/grit/generated_resources.h"
@@ -21,11 +20,11 @@
 #include "ui/base/ui_base_types.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/paint_vector_icon.h"
+#include "ui/native_theme/native_theme.h"
 #include "ui/views/animation/ink_drop_impl.h"
+#include "ui/views/controls/color_tracking_icon_view.h"
 #include "ui/views/controls/styled_label.h"
 #include "ui/views/controls/throbber.h"
-#include "ui/views/layout/fill_layout.h"
-#include "ui/views/layout/layout_provider.h"
 #include "ui/views/vector_icons.h"
 
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
@@ -36,25 +35,6 @@
 
 namespace {
 
-// A view that represents the primary icon for a sink issue. This class is used
-// to ensure its color is kept in sync with current theme.
-class SinkIssueIconView : public views::ImageView {
- public:
-  SinkIssueIconView() {
-    SetBorder(views::CreateEmptyBorder(kPrimaryIconBorder));
-  }
-  ~SinkIssueIconView() override = default;
-
-  // views::ImageView:
-  void OnThemeChanged() override {
-    views::ImageView::OnThemeChanged();
-    const SkColor icon_color = GetNativeTheme()->GetSystemColor(
-        ui::NativeTheme::kColorId_DefaultIconColor);
-    SetImage(gfx::CreateVectorIcon(::vector_icons::kInfoOutlineIcon,
-                                   kPrimaryIconSize, icon_color));
-  }
-};
-
 gfx::ImageSkia CreateSinkIcon(SinkIconType icon_type, bool enabled = true) {
   const gfx::VectorIcon* vector_icon;
   switch (icon_type) {
@@ -112,7 +92,10 @@
     return CreatePrimaryIconView(gfx::CreateVectorIcon(
         kGenericStopIcon, kPrimaryIconSize, gfx::kGoogleBlue500));
   } else if (sink.issue) {
-    return std::make_unique<SinkIssueIconView>();
+    auto icon = std::make_unique<views::ColorTrackingIconView>(
+        ::vector_icons::kInfoOutlineIcon, kPrimaryIconSize);
+    icon->SetBorder(views::CreateEmptyBorder(kPrimaryIconBorder));
+    return icon;
   } else if (sink.state == UIMediaSinkState::CONNECTING ||
              sink.state == UIMediaSinkState::DISCONNECTING) {
     return CreateThrobber();
diff --git a/chrome/browser/ui/views/page_info/page_info_bubble_view.cc b/chrome/browser/ui/views/page_info/page_info_bubble_view.cc
index c46a47c6..e75f219 100644
--- a/chrome/browser/ui/views/page_info/page_info_bubble_view.cc
+++ b/chrome/browser/ui/views/page_info/page_info_bubble_view.cc
@@ -49,7 +49,6 @@
 #include "components/dom_distiller/core/url_constants.h"
 #include "components/dom_distiller/core/url_utils.h"
 #include "components/page_info/page_info.h"
-#include "components/password_manager/core/common/password_manager_features.h"
 #include "components/safe_browsing/buildflags.h"
 #include "components/strings/grit/components_chromium_strings.h"
 #include "components/strings/grit/components_strings.h"
@@ -60,6 +59,7 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/models/simple_menu_model.h"
 #include "ui/base/resource/resource_bundle.h"
+#include "ui/base/window_open_disposition.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/font_list.h"
 #include "ui/gfx/geometry/insets.h"
@@ -129,9 +129,9 @@
 
 }  // namespace
 
-// |BubbleHeaderView| is the UI element (view) that represents the header of the
-// |PageInfoBubbleView|. The header shows the status of the site's
-// identity check and the name of the site's identity.
+// BubbleHeaderView is the UI element (view) that represents the header of a
+// PageInfoBubbleView. The header shows the status of the site's identity check
+// and the name of the site's identity.
 class BubbleHeaderView : public views::View, public views::StyledLabelListener {
  public:
   BubbleHeaderView(PageInfoBubbleView* bubble, int side_margin);
@@ -238,7 +238,7 @@
                       views::GridLayout::FILL, views::GridLayout::LEADING);
 }
 
-BubbleHeaderView::~BubbleHeaderView() {}
+BubbleHeaderView::~BubbleHeaderView() = default;
 
 void BubbleHeaderView::StyledLabelLinkClicked(views::StyledLabel* label,
                                               const gfx::Range& range,
@@ -318,17 +318,9 @@
     password_reuse_button_container_->RemoveAllChildViews(true /* delete */);
   }
 
-  int change_password_template = 0;
-  if (is_saved_password && !base::FeatureList::IsEnabled(
-                               password_manager::features::kPasswordCheck)) {
-    change_password_template = 0;
-  } else {
-    change_password_template =
-        is_saved_password && base::FeatureList::IsEnabled(
-                                 password_manager::features::kPasswordCheck)
-            ? IDS_PAGE_INFO_CHECK_PASSWORDS_BUTTON
-            : IDS_PAGE_INFO_CHANGE_PASSWORD_BUTTON;
-  }
+  int change_password_template = is_saved_password
+                                     ? IDS_PAGE_INFO_CHECK_PASSWORDS_BUTTON
+                                     : IDS_PAGE_INFO_CHANGE_PASSWORD_BUTTON;
 
   std::unique_ptr<views::MdTextButton> change_password_button;
   if (change_password_template) {
@@ -481,8 +473,9 @@
   } else {
     web_contents()->OpenURL(content::OpenURLParams(
         GURL(chrome::kPageInfoHelpCenterURL), content::Referrer(),
-        WindowOpenDisposition::NEW_FOREGROUND_TAB, ui::PAGE_TRANSITION_LINK,
-        false));
+        ui::DispositionFromEventFlags(
+            event_flags, WindowOpenDisposition::NEW_FOREGROUND_TAB),
+        ui::PAGE_TRANSITION_LINK, false));
     presenter_->RecordPageInfoAction(
         PageInfo::PAGE_INFO_CONNECTION_HELP_OPENED);
   }
diff --git a/chrome/browser/ui/views/page_info/page_info_bubble_view_browsertest.cc b/chrome/browser/ui/views/page_info/page_info_bubble_view_browsertest.cc
index e9b53f3..f3289306 100644
--- a/chrome/browser/ui/views/page_info/page_info_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/page_info/page_info_bubble_view_browsertest.cc
@@ -7,7 +7,6 @@
 #include "base/run_loop.h"
 #include "base/scoped_observer.h"
 #include "base/test/metrics/histogram_tester.h"
-#include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
 #include "chrome/browser/safe_browsing/chrome_password_protection_service.h"
 #include "chrome/browser/ssl/security_state_tab_helper.h"
@@ -29,7 +28,6 @@
 #include "components/content_settings/core/common/content_settings_types.h"
 #include "components/page_info/page_info.h"
 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
-#include "components/password_manager/core/common/password_manager_features.h"
 #include "components/safe_browsing/content/password_protection/metrics_util.h"
 #include "components/safe_browsing/core/features.h"
 #include "components/strings/grit/components_strings.h"
@@ -130,11 +128,7 @@
 
 class PageInfoBubbleViewBrowserTest : public DialogBrowserTest {
  public:
-  PageInfoBubbleViewBrowserTest() {
-    feature_list_.InitAndEnableFeature(
-        password_manager::features::kPasswordCheck);
-  }
-
+  PageInfoBubbleViewBrowserTest() = default;
   // DialogBrowserTest:
   void ShowUi(const std::string& name) override {
     // Bubble dialogs' bounds may exceed the display's work area.
@@ -386,7 +380,6 @@
 
  private:
   std::vector<PageInfoBubbleView::PageInfoBubbleViewID> expected_identifiers_;
-  base::test::ScopedFeatureList feature_list_;
 
   DISALLOW_COPY_AND_ASSIGN(PageInfoBubbleViewBrowserTest);
 };
diff --git a/chrome/browser/ui/views/page_info/permission_selector_row.cc b/chrome/browser/ui/views/page_info/permission_selector_row.cc
index 2d043bc..c9a0cb3 100644
--- a/chrome/browser/ui/views/page_info/permission_selector_row.cc
+++ b/chrome/browser/ui/views/page_info/permission_selector_row.cc
@@ -23,7 +23,6 @@
 #include "ui/gfx/color_utils.h"
 #include "ui/gfx/image/image.h"
 #include "ui/views/controls/combobox/combobox.h"
-#include "ui/views/controls/combobox/combobox_listener.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/layout/grid_layout.h"
@@ -93,8 +92,7 @@
 }
 
 // The |PermissionCombobox| provides a combobox for selecting a permission type.
-class PermissionCombobox : public views::Combobox,
-                           public views::ComboboxListener {
+class PermissionCombobox : public views::Combobox {
  public:
   PermissionCombobox(ComboboxModelAdapter* model,
                      bool enabled,
@@ -109,8 +107,7 @@
   gfx::Size CalculatePreferredSize() const override;
 
  private:
-  // views::ComboboxListener:
-  void OnPerformAction(Combobox* combobox) override;
+  void OnPerformAction(Combobox* combobox);
 
   ComboboxModelAdapter* model_;
 
@@ -124,7 +121,8 @@
                                        bool enabled,
                                        bool use_default)
     : views::Combobox(model), model_(model) {
-  set_listener(this);
+  set_callback(base::BindRepeating(&PermissionCombobox::OnPerformAction,
+                                   base::Unretained(this)));
   SetEnabled(enabled);
   UpdateSelectedIndex(use_default);
   SetSizeToLargestLabel(false);
diff --git a/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view.cc b/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view.cc
index 3889bf3..b2a3e43d 100644
--- a/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view.cc
+++ b/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view.cc
@@ -260,6 +260,10 @@
     views::StyledLabel* label,
     const gfx::Range& range,
     int event_flags) {
+  OpenHelpCenter();
+}
+
+void SafetyTipPageInfoBubbleView::OpenHelpCenter() {
   action_taken_ = SafetyTipInteraction::kLearnMore;
   OpenHelpCenterFromSafetyTip(web_contents());
 }
diff --git a/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view.h b/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view.h
index 9892c4c..9cb8fcd 100644
--- a/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view.h
+++ b/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view.h
@@ -62,7 +62,8 @@
  private:
   friend class SafetyTipPageInfoBubbleViewBrowserTest;
 
-  views::StyledLabel* GetLearnMoreLinkForTesting() { return info_button_; }
+  void OpenHelpCenter();
+
   views::Button* GetLeaveButtonForTesting() { return leave_button_; }
 
   const security_state::SafetyTipStatus safety_tip_status_;
diff --git a/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc b/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc
index c4ff0b9..94632483ec 100644
--- a/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc
@@ -308,8 +308,7 @@
     // This class is a friend to SafetyTipPageInfoBubbleView.
     auto* bubble = static_cast<SafetyTipPageInfoBubbleView*>(
         PageInfoBubbleViewBase::GetPageInfoBubbleForTesting());
-    bubble->StyledLabelLinkClicked(bubble->GetLearnMoreLinkForTesting(),
-                                   gfx::Range(), 0);
+    bubble->OpenHelpCenter();
   }
 
   void CloseWarningLeaveSite(Browser* browser) {
diff --git a/chrome/browser/ui/views/passwords/credentials_item_view.cc b/chrome/browser/ui/views/passwords/credentials_item_view.cc
index e0d59ba9..121dfa23 100644
--- a/chrome/browser/ui/views/passwords/credentials_item_view.cc
+++ b/chrome/browser/ui/views/passwords/credentials_item_view.cc
@@ -64,7 +64,7 @@
     int upper_text_style,
     int lower_text_style)
     : Button(button_listener), form_(form) {
-  set_notify_enter_exit_on_child(true);
+  SetNotifyEnterExitOnChild(true);
   views::BoxLayout* layout =
       SetLayoutManager(std::make_unique<views::BoxLayout>(
           views::BoxLayout::Orientation::kHorizontal));
diff --git a/chrome/browser/ui/views/passwords/password_items_view.cc b/chrome/browser/ui/views/passwords/password_items_view.cc
index 09e83482..4e340564 100644
--- a/chrome/browser/ui/views/passwords/password_items_view.cc
+++ b/chrome/browser/ui/views/passwords/password_items_view.cc
@@ -36,6 +36,7 @@
 #include "ui/views/controls/button/image_button.h"
 #include "ui/views/controls/button/image_button_factory.h"
 #include "ui/views/controls/button/md_text_button.h"
+#include "ui/views/controls/color_tracking_icon_view.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/link.h"
@@ -61,23 +62,6 @@
   UNDO_COLUMN_SET
 };
 
-// And ImageView that holds a kGlobeIcon of gfx::kFaviconSize and adapts to
-// changes in theme color. Used as a fallback option when the page has no
-// favicon.
-class GlobeIconImageView : public views::ImageView {
- public:
-  GlobeIconImageView() = default;
-  ~GlobeIconImageView() override = default;
-
-  // views::View:
-  void OnThemeChanged() override {
-    views::ImageView::OnThemeChanged();
-    const SkColor icon_color = GetNativeTheme()->GetSystemColor(
-        ui::NativeTheme::kColorId_DefaultIconColor);
-    SetImage(gfx::CreateVectorIcon(kGlobeIcon, gfx::kFaviconSize, icon_color));
-  }
-};
-
 PasswordItemsViewColumnSetType InferColumnSetTypeFromCredentials(
     const std::vector<autofill::PasswordForm>& credentials) {
   if (std::any_of(credentials.begin(), credentials.end(),
@@ -310,7 +294,8 @@
 
   // Use a globe fallback until the actual favicon is loaded.
   if (parent_->favicon_.IsEmpty()) {
-    layout->AddView(std::make_unique<GlobeIconImageView>());
+    layout->AddView(std::make_unique<views::ColorTrackingIconView>(
+        kGlobeIcon, gfx::kFaviconSize));
   } else {
     auto favicon_view = std::make_unique<views::ImageView>();
     favicon_view->SetImage(parent_->favicon_.AsImageSkia());
diff --git a/chrome/browser/ui/views/passwords/password_save_update_with_account_store_view.cc b/chrome/browser/ui/views/passwords/password_save_update_with_account_store_view.cc
index fd35f04e..83b9c59 100644
--- a/chrome/browser/ui/views/passwords/password_save_update_with_account_store_view.cc
+++ b/chrome/browser/ui/views/passwords/password_save_update_with_account_store_view.cc
@@ -376,7 +376,9 @@
         controller_.GetPrimaryAccountEmail(),
         controller_.GetPrimaryAccountAvatar(ComboboxIconSize()),
         controller_.IsUsingAccountStore());
-    destination_dropdown->set_listener(this);
+    destination_dropdown->set_callback(base::BindRepeating(
+        &PasswordSaveUpdateWithAccountStoreView::OnPerformAction,
+        base::Unretained(this)));
     destination_dropdown_ = destination_dropdown.get();
   }
   const autofill::PasswordForm& password_form = controller_.pending_password();
diff --git a/chrome/browser/ui/views/passwords/password_save_update_with_account_store_view.h b/chrome/browser/ui/views/passwords/password_save_update_with_account_store_view.h
index 070d99f..f464c2f3 100644
--- a/chrome/browser/ui/views/passwords/password_save_update_with_account_store_view.h
+++ b/chrome/browser/ui/views/passwords/password_save_update_with_account_store_view.h
@@ -8,7 +8,6 @@
 #include "chrome/browser/ui/passwords/bubble_controllers/save_update_with_account_store_bubble_controller.h"
 #include "chrome/browser/ui/views/passwords/password_bubble_view_base.h"
 #include "ui/views/controls/button/button.h"
-#include "ui/views/controls/combobox/combobox_listener.h"
 #include "ui/views/layout/animating_layout_manager.h"
 #include "ui/views/view.h"
 
@@ -33,7 +32,6 @@
 class PasswordSaveUpdateWithAccountStoreView
     : public PasswordBubbleViewBase,
       public views::ButtonListener,
-      public views::ComboboxListener,
       public views::WidgetObserver,
       public views::AnimatingLayoutManager::Observer {
  public:
@@ -65,10 +63,6 @@
   // views::ButtonListener:
   void ButtonPressed(views::Button* sender, const ui::Event& event) override;
 
-  // views::ComboboxListener:
-  // Used for the destination combobox.
-  void OnPerformAction(views::Combobox* combobox) override;
-
   // views::WidgetObserver:
   void OnWidgetDestroying(views::Widget* widget) override;
 
@@ -91,6 +85,8 @@
   void UpdateUsernameAndPasswordInModel();
   void UpdateBubbleUIElements();
 
+  void OnPerformAction(views::Combobox* combobox);
+
   // Whether we should show the IPH informing the user about the destination
   // picker and that they can now select where to store the passwords. It
   // creates (if needed) and queries the |iph_tracker_|
diff --git a/chrome/browser/ui/views/payments/cvc_unmask_view_controller.cc b/chrome/browser/ui/views/payments/cvc_unmask_view_controller.cc
index 92acaa37..2c51a8e 100644
--- a/chrome/browser/ui/views/payments/cvc_unmask_view_controller.cc
+++ b/chrome/browser/ui/views/payments/cvc_unmask_view_controller.cc
@@ -189,14 +189,16 @@
   layout->StartRow(views::GridLayout::kFixedSize, 1);
   if (requesting_expiration) {
     auto month = std::make_unique<views::Combobox>(&month_combobox_model_);
-    month->set_listener(this);
+    month->set_closure(base::BindRepeating(
+        &CvcUnmaskViewController::OnPerformAction, base::Unretained(this)));
     month->SetID(static_cast<int>(DialogViewID::CVC_MONTH));
     month->SelectValue(credit_card_.Expiration2DigitMonthAsString());
     month->SetInvalid(true);
     layout->AddView(std::move(month));
 
     auto year = std::make_unique<views::Combobox>(&year_combobox_model_);
-    year->set_listener(this);
+    year->set_closure(base::BindRepeating(
+        &CvcUnmaskViewController::OnPerformAction, base::Unretained(this)));
     year->SetID(static_cast<int>(DialogViewID::CVC_YEAR));
     year->SelectValue(credit_card_.Expiration4DigitYearAsString());
     year->SetInvalid(true);
@@ -383,7 +385,7 @@
   UpdatePayButtonState();
 }
 
-void CvcUnmaskViewController::OnPerformAction(views::Combobox* combobox) {
+void CvcUnmaskViewController::OnPerformAction() {
   if (!dialog()->IsInteractive())
     return;
 
diff --git a/chrome/browser/ui/views/payments/cvc_unmask_view_controller.h b/chrome/browser/ui/views/payments/cvc_unmask_view_controller.h
index 76ec94c..d81e5f0 100644
--- a/chrome/browser/ui/views/payments/cvc_unmask_view_controller.h
+++ b/chrome/browser/ui/views/payments/cvc_unmask_view_controller.h
@@ -15,7 +15,6 @@
 #include "components/autofill/core/browser/payments/full_card_request.h"
 #include "components/autofill/core/browser/payments/payments_client.h"
 #include "components/autofill/core/browser/payments/risk_data_loader.h"
-#include "ui/views/controls/combobox/combobox_listener.h"
 #include "ui/views/controls/textfield/textfield_controller.h"
 
 namespace autofill {
@@ -40,7 +39,6 @@
     : public PaymentRequestSheetController,
       public autofill::RiskDataLoader,
       public autofill::payments::FullCardRequest::UIDelegate,
-      public views::ComboboxListener,
       public views::TextfieldController {
  public:
   CvcUnmaskViewController(
@@ -91,8 +89,7 @@
   void ContentsChanged(views::Textfield* sender,
                        const base::string16& new_contents) override;
 
-  // views::ComboboxListener:
-  void OnPerformAction(views::Combobox* combobox) override;
+  void OnPerformAction();
 
   autofill::MonthComboboxModel month_combobox_model_;
   autofill::YearComboboxModel year_combobox_model_;
diff --git a/chrome/browser/ui/views/payments/editor_view_controller.cc b/chrome/browser/ui/views/payments/editor_view_controller.cc
index 3473bb59..5305585d 100644
--- a/chrome/browser/ui/views/payments/editor_view_controller.cc
+++ b/chrome/browser/ui/views/payments/editor_view_controller.cc
@@ -214,7 +214,8 @@
 
   // Using autofill field type as a view ID.
   combobox->SetID(GetInputFieldViewId(field.type));
-  combobox->set_listener(this);
+  combobox->set_callback(base::BindRepeating(
+      &EditorViewController::OnPerformAction, base::Unretained(this)));
   comboboxes_.insert(std::make_pair(combobox.get(), field));
   return combobox;
 }
@@ -227,8 +228,7 @@
 }
 
 void EditorViewController::OnPerformAction(views::Combobox* sender) {
-  ValidatingCombobox* sender_cast = static_cast<ValidatingCombobox*>(sender);
-  sender_cast->OnContentsChanged();
+  static_cast<ValidatingCombobox*>(sender)->OnContentsChanged();
   primary_button()->SetEnabled(ValidateInputFields());
 }
 
diff --git a/chrome/browser/ui/views/payments/editor_view_controller.h b/chrome/browser/ui/views/payments/editor_view_controller.h
index 0bcb91a..ac7eec7 100644
--- a/chrome/browser/ui/views/payments/editor_view_controller.h
+++ b/chrome/browser/ui/views/payments/editor_view_controller.h
@@ -18,7 +18,6 @@
 #include "chrome/browser/ui/views/payments/payment_request_sheet_controller.h"
 #include "chrome/browser/ui/views/payments/validation_delegate.h"
 #include "components/autofill/core/browser/field_types.h"
-#include "ui/views/controls/combobox/combobox_listener.h"
 #include "ui/views/controls/textfield/textfield_controller.h"
 #include "ui/views/view.h"
 
@@ -77,8 +76,7 @@
 // The PaymentRequestSheetController subtype for the editor screens of the
 // Payment Request flow.
 class EditorViewController : public PaymentRequestSheetController,
-                             public views::TextfieldController,
-                             public views::ComboboxListener {
+                             public views::TextfieldController {
  public:
   using TextFieldsMap =
       std::unordered_map<ValidatingTextfield*, const EditorField>;
@@ -152,8 +150,8 @@
   bool ShouldShowSecondaryButton() override;
   void FillContentView(views::View* content_view) override;
 
-  // views::ComboboxListener:
-  void OnPerformAction(views::Combobox* combobox) override;
+  // Combobox callback.
+  virtual void OnPerformAction(views::Combobox* combobox);
 
   // Update the editor view by removing all it's child views and recreating
   // the input fields returned by GetFieldDefinitions. Note that
diff --git a/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc b/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
index b18ec56..41d72284 100644
--- a/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
+++ b/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
@@ -575,13 +575,10 @@
     views::StyledLabel* label,
     const gfx::Range& range,
     int event_flags) {
-  if (!dialog()->IsInteractive())
-    return;
-
-  // The only thing that can trigger this is the user clicking on the "settings"
-  // link in the data attribution text.
-  chrome::ShowSettingsSubPageForProfile(dialog()->GetProfile(),
-                                        chrome::kPaymentsSubPage);
+  if (dialog()->IsInteractive()) {
+    chrome::ShowSettingsSubPageForProfile(dialog()->GetProfile(),
+                                          chrome::kPaymentsSubPage);
+  }
 }
 
 void PaymentSheetViewController::UpdatePayButtonState(bool enabled) {
diff --git a/chrome/browser/ui/views/payments/payment_sheet_view_controller.h b/chrome/browser/ui/views/payments/payment_sheet_view_controller.h
index b51467e08..e7d29c2 100644
--- a/chrome/browser/ui/views/payments/payment_sheet_view_controller.h
+++ b/chrome/browser/ui/views/payments/payment_sheet_view_controller.h
@@ -13,10 +13,6 @@
 #include "components/payments/content/payment_request_state.h"
 #include "ui/views/controls/styled_label_listener.h"
 
-namespace views {
-class StyledLabel;
-}
-
 namespace payments {
 
 class PaymentRequestDialogView;
diff --git a/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.cc b/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.cc
index ccba3bf..387c357 100644
--- a/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.cc
+++ b/chrome/browser/ui/views/safe_browsing/password_reuse_modal_warning_dialog.cc
@@ -14,7 +14,6 @@
 #include "chrome/grit/theme_resources.h"
 #include "components/constrained_window/constrained_window_views.h"
 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
-#include "components/password_manager/core/common/password_manager_features.h"
 #include "components/safe_browsing/buildflags.h"
 #include "components/safe_browsing/content/password_protection/metrics_util.h"
 #include "components/strings/grit/components_strings.h"
@@ -88,11 +87,7 @@
     case safe_browsing::ReusedPasswordAccountType::NON_GAIA_ENTERPRISE:
       return l10n_util::GetStringUTF16(IDS_PAGE_INFO_CHANGE_PASSWORD_BUTTON);
     case safe_browsing::ReusedPasswordAccountType::SAVED_PASSWORD:
-      if (base::FeatureList::IsEnabled(
-              password_manager::features::kPasswordCheck)) {
-        return l10n_util::GetStringUTF16(IDS_PAGE_INFO_CHECK_PASSWORDS_BUTTON);
-      }
-      return l10n_util::GetStringUTF16(IDS_CLOSE);
+      return l10n_util::GetStringUTF16(IDS_PAGE_INFO_CHECK_PASSWORDS_BUTTON);
     default:
       return l10n_util::GetStringUTF16(IDS_PAGE_INFO_PROTECT_ACCOUNT_BUTTON);
   }
@@ -126,10 +121,8 @@
       password_type_(password_type) {
   bool show_check_passwords = false;
 #if BUILDFLAG(FULL_SAFE_BROWSING)
-  show_check_passwords = base::FeatureList::IsEnabled(
-                             password_manager::features::kPasswordCheck) &&
-                         password_type_.account_type() ==
-                             ReusedPasswordAccountType::SAVED_PASSWORD;
+  show_check_passwords = password_type_.account_type() ==
+                         ReusedPasswordAccountType::SAVED_PASSWORD;
 #endif
   SetShowIcon(true);
   if (password_type.account_type() !=
diff --git a/chrome/browser/ui/views/safe_browsing/prompt_for_scanning_modal_dialog.cc b/chrome/browser/ui/views/safe_browsing/prompt_for_scanning_modal_dialog.cc
index 13d0b312..8f20af1 100644
--- a/chrome/browser/ui/views/safe_browsing/prompt_for_scanning_modal_dialog.cc
+++ b/chrome/browser/ui/views/safe_browsing/prompt_for_scanning_modal_dialog.cc
@@ -123,7 +123,9 @@
     int event_flags) {
   web_contents_->OpenURL(content::OpenURLParams(
       GURL(chrome::kAdvancedProtectionDownloadLearnMoreURL),
-      content::Referrer(), WindowOpenDisposition::NEW_FOREGROUND_TAB,
+      content::Referrer(),
+      ui::DispositionFromEventFlags(event_flags,
+                                    WindowOpenDisposition::NEW_FOREGROUND_TAB),
       ui::PAGE_TRANSITION_LINK, /*is_renderer_initiated=*/false));
 }
 
diff --git a/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_device_button.cc b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_device_button.cc
index 470ee82..fce4014 100644
--- a/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_device_button.cc
+++ b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_device_button.cc
@@ -10,44 +10,29 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "chrome/app/vector_icons/vector_icons.h"
+#include "chrome/browser/ui/views/hover_button.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/send_tab_to_self/target_device_info.h"
 #include "components/sync/protocol/sync.pb.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/gfx/color_palette.h"
-#include "ui/gfx/paint_vector_icon.h"
-#include "ui/native_theme/native_theme.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/controls/color_tracking_icon_view.h"
 
 namespace send_tab_to_self {
 
 namespace {
 
-// IconView wraps the vector icon to track the color of the current Widget's
-// NativeTheme.
-class IconView : public views::ImageView {
- public:
-  explicit IconView(const sync_pb::SyncEnums::DeviceType device_type)
-      : vector_icon_{device_type == sync_pb::SyncEnums::TYPE_PHONE
-                         ? &kHardwareSmartphoneIcon
-                         : &kHardwareComputerIcon} {
-    constexpr auto kPrimaryIconBorder = gfx::Insets(6);
-    SetBorder(views::CreateEmptyBorder(kPrimaryIconBorder));
-  }
-  ~IconView() override = default;
-
-  // views::View:
-  void OnThemeChanged() override {
-    views::ImageView::OnThemeChanged();
-    const SkColor icon_color = GetNativeTheme()->GetSystemColor(
-        ui::NativeTheme::kColorId_DefaultIconColor);
-    SetImage(
-        gfx::CreateVectorIcon(*vector_icon_, kPrimaryIconSize, icon_color));
-  }
-
- private:
+std::unique_ptr<views::ColorTrackingIconView> CreateIcon(
+    const sync_pb::SyncEnums::DeviceType device_type) {
   static constexpr int kPrimaryIconSize = 20;
-  const gfx::VectorIcon* vector_icon_;
-};
+  auto icon = std::make_unique<views::ColorTrackingIconView>(
+      device_type == sync_pb::SyncEnums::TYPE_PHONE ? kHardwareSmartphoneIcon
+                                                    : kHardwareComputerIcon,
+      kPrimaryIconSize);
+  constexpr auto kPrimaryIconBorder = gfx::Insets(6);
+  icon->SetBorder(views::CreateEmptyBorder(kPrimaryIconBorder));
+  return icon;
+}
 
 base::string16 GetLastUpdatedTime(const TargetDeviceInfo& device_info) {
   int time_in_days =
@@ -72,7 +57,7 @@
     const TargetDeviceInfo& device_info,
     int button_tag)
     : HoverButton(button_listener,
-                  std::make_unique<IconView>(device_info.device_type),
+                  CreateIcon(device_info.device_type),
                   base::UTF8ToUTF16(device_info.device_name),
                   GetLastUpdatedTime(device_info)) {
   device_name_ = device_info.device_name;
diff --git a/chrome/browser/ui/views/session_crashed_bubble_view.cc b/chrome/browser/ui/views/session_crashed_bubble_view.cc
index 5c3b65f..7ff37ed 100644
--- a/chrome/browser/ui/views/session_crashed_bubble_view.cc
+++ b/chrome/browser/ui/views/session_crashed_bubble_view.cc
@@ -40,6 +40,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "ui/base/buildflags.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/window_open_disposition.h"
 #include "ui/views/controls/button/checkbox.h"
 #include "ui/views/controls/button/label_button_border.h"
 #include "ui/views/controls/button/menu_button.h"
@@ -294,7 +295,9 @@
                                                       int event_flags) {
   browser_->OpenURL(content::OpenURLParams(
       GURL("https://support.google.com/chrome/answer/96817"),
-      content::Referrer(), WindowOpenDisposition::NEW_FOREGROUND_TAB,
+      content::Referrer(),
+      ui::DispositionFromEventFlags(event_flags,
+                                    WindowOpenDisposition::NEW_FOREGROUND_TAB),
       ui::PAGE_TRANSITION_LINK, false));
   RecordBubbleHistogramValue(SESSION_CRASHED_BUBBLE_HELP);
 }
diff --git a/chrome/browser/ui/views/sharing/sharing_dialog_view.cc b/chrome/browser/ui/views/sharing/sharing_dialog_view.cc
index a0160ecb..72e6fde 100644
--- a/chrome/browser/ui/views/sharing/sharing_dialog_view.cc
+++ b/chrome/browser/ui/views/sharing/sharing_dialog_view.cc
@@ -26,10 +26,10 @@
 #include "ui/strings/grit/ui_strings.h"
 #include "ui/views/border.h"
 #include "ui/views/bubble/bubble_frame_view.h"
+#include "ui/views/controls/color_tracking_icon_view.h"
 #include "ui/views/controls/scroll_view.h"
 #include "ui/views/controls/styled_label.h"
 #include "ui/views/layout/box_layout.h"
-#include "ui/views/layout/fill_layout.h"
 #include "url/origin.h"
 
 #if defined(OS_CHROMEOS)
@@ -39,23 +39,6 @@
 
 namespace {
 
-class VectorIconView : public views::ImageView {
- public:
-  explicit VectorIconView(const gfx::VectorIcon& icon) : icon_(icon) {}
-
-  // views::ImageView
-  void OnThemeChanged() override {
-    ImageView::OnThemeChanged();
-    constexpr int kPrimaryIconSize = 20;
-    const SkColor color = GetNativeTheme()->GetSystemColor(
-        ui::NativeTheme::kColorId_DefaultIconColor);
-    SetImage(gfx::CreateVectorIcon(icon_, kPrimaryIconSize, color));
-  }
-
- private:
-  const gfx::VectorIcon& icon_;
-};
-
 class HeaderImageView : public NonAccessibleImageView {
  public:
   explicit HeaderImageView(const views::BubbleFrameView* frame_view,
@@ -283,6 +266,7 @@
 }
 
 void SharingDialogView::InitListView() {
+  constexpr int kPrimaryIconSize = 20;
   int tag = 0;
   const gfx::Insets device_border =
       gfx::Insets(kSharingDialogSpacing, kSharingDialogSpacing * 2,
@@ -297,10 +281,11 @@
   // Devices:
   LogSharingDevicesToShow(data_.prefix, kSharingUiDialog, data_.devices.size());
   for (const auto& device : data_.devices) {
-    auto icon = std::make_unique<VectorIconView>(
+    auto icon = std::make_unique<views::ColorTrackingIconView>(
         device->device_type() == sync_pb::SyncEnums::TYPE_TABLET
             ? kTabletIcon
-            : kHardwareSmartphoneIcon);
+            : kHardwareSmartphoneIcon,
+        kPrimaryIconSize);
 
     auto dialog_button = std::make_unique<HoverButton>(
         this, std::move(icon), base::UTF8ToUTF16(device->client_name()),
@@ -317,7 +302,8 @@
   for (const auto& app : data_.apps) {
     std::unique_ptr<views::ImageView> icon;
     if (app.vector_icon) {
-      icon = std::make_unique<VectorIconView>(*app.vector_icon);
+      icon = std::make_unique<views::ColorTrackingIconView>(*app.vector_icon,
+                                                            kPrimaryIconSize);
     } else {
       icon = std::make_unique<views::ImageView>();
       icon->SetImage(app.image.AsImageSkia());
diff --git a/chrome/browser/ui/views/sharing/sharing_dialog_view_unittest.cc b/chrome/browser/ui/views/sharing/sharing_dialog_view_unittest.cc
index cf4fdd0..7742249 100644
--- a/chrome/browser/ui/views/sharing/sharing_dialog_view_unittest.cc
+++ b/chrome/browser/ui/views/sharing/sharing_dialog_view_unittest.cc
@@ -21,6 +21,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/events/event_constants.h"
 #include "ui/events/event_utils.h"
 #include "ui/strings/grit/ui_strings.h"
 #include "ui/views/bubble/bubble_dialog_delegate_view.h"
@@ -180,8 +181,7 @@
   auto dialog_data = CreateDialogData(/*devices=*/0, /*apps=*/0);
   auto dialog = CreateDialogView(std::move(dialog_data));
 
-  dialog->StyledLabelLinkClicked(/*label=*/nullptr, /*range=*/{},
-                                 /*event_flags=*/0);
+  dialog->StyledLabelLinkClicked(nullptr, gfx::Range(), ui::EF_NONE);
 }
 
 TEST_F(SharingDialogViewTest, HelpTextClickedOnlyApps) {
@@ -191,8 +191,7 @@
   auto dialog_data = CreateDialogData(/*devices=*/0, /*apps=*/1);
   auto dialog = CreateDialogView(std::move(dialog_data));
 
-  dialog->StyledLabelLinkClicked(/*label=*/nullptr, /*range=*/{},
-                                 /*event_flags=*/0);
+  dialog->StyledLabelLinkClicked(nullptr, gfx::Range(), ui::EF_NONE);
 }
 
 TEST_F(SharingDialogViewTest, ThemeChangedEmptyList) {
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index 83651a9..80e5df4b 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -193,7 +193,7 @@
 
   // So we get don't get enter/exit on children and don't prematurely stop the
   // hover.
-  set_notify_enter_exit_on_child(true);
+  SetNotifyEnterExitOnChild(true);
 
   SetID(VIEW_ID_TAB);
 
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index b059df3..d262a0d6 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -2449,7 +2449,7 @@
 void TabStrip::Init() {
   SetID(VIEW_ID_TAB_STRIP);
   // So we get enter/exit on children to switch stacked layout on and off.
-  set_notify_enter_exit_on_child(true);
+  SetNotifyEnterExitOnChild(true);
 
   tab_controls_container_ =
       AddChildView(std::make_unique<TabControlsContainer>());
diff --git a/chrome/browser/ui/views/translate/translate_bubble_view.cc b/chrome/browser/ui/views/translate/translate_bubble_view.cc
index aef57f39..a8152b0e 100644
--- a/chrome/browser/ui/views/translate/translate_bubble_view.cc
+++ b/chrome/browser/ui/views/translate/translate_bubble_view.cc
@@ -834,7 +834,8 @@
   }
 
   source_language_combobox->SetID(COMBOBOX_ID_SOURCE_LANGUAGE);
-  source_language_combobox->set_listener(this);
+  source_language_combobox->set_callback(base::BindRepeating(
+      &TranslateBubbleView::OnPerformAction, base::Unretained(this)));
   source_language_combobox_ = source_language_combobox.get();
 
   auto advanced_done_button = std::make_unique<views::MdTextButton>(
@@ -866,7 +867,8 @@
       std::make_unique<views::Combobox>(target_language_combobox_model_.get());
 
   target_language_combobox->SetID(COMBOBOX_ID_TARGET_LANGUAGE);
-  target_language_combobox->set_listener(this);
+  target_language_combobox->set_callback(base::BindRepeating(
+      &TranslateBubbleView::OnPerformAction, base::Unretained(this)));
   target_language_combobox_ = target_language_combobox.get();
 
   auto advanced_done_button = std::make_unique<views::MdTextButton>(
diff --git a/chrome/browser/ui/views/translate/translate_bubble_view.h b/chrome/browser/ui/views/translate/translate_bubble_view.h
index 4766176..e328162 100644
--- a/chrome/browser/ui/views/translate/translate_bubble_view.h
+++ b/chrome/browser/ui/views/translate/translate_bubble_view.h
@@ -25,7 +25,6 @@
 #include "content/public/browser/web_contents_observer.h"
 #include "ui/base/models/simple_menu_model.h"
 #include "ui/views/controls/button/button.h"
-#include "ui/views/controls/combobox/combobox_listener.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/menu/menu_runner.h"
@@ -37,13 +36,13 @@
 
 namespace views {
 class Checkbox;
+class Combobox;
 class LabelButton;
 class View;
 }  // namespace views
 
 class TranslateBubbleView : public LocationBarBubbleDelegateView,
                             public views::ButtonListener,
-                            public views::ComboboxListener,
                             public ui::SimpleMenuModel::Delegate,
                             public views::TabbedPaneListener {
  public:
@@ -81,6 +80,8 @@
 
   TranslateBubbleModel* model() { return model_.get(); }
 
+  void OnPerformAction(views::Combobox* combobox);
+
   // LocationBarBubbleDelegateView:
   void Init() override;
   View* GetInitiallyFocusedView() override;
@@ -94,9 +95,6 @@
   // views::ButtonListener:
   void ButtonPressed(views::Button* source, const ui::Event& event) override;
 
-  // views::ComboboxListener:
-  void OnPerformAction(views::Combobox* combobox) override;
-
   // ui::SimpleMenuModel::Delegate:
   bool IsCommandIdChecked(int command_id) const override;
   bool IsCommandIdEnabled(int command_id) const override;
diff --git a/chrome/browser/ui/webui/settings/settings_ui.cc b/chrome/browser/ui/webui/settings/settings_ui.cc
index 95f4711b..920b416 100644
--- a/chrome/browser/ui/webui/settings/settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/settings_ui.cc
@@ -264,10 +264,6 @@
       base::FeatureList::IsEnabled(safe_browsing::kEnhancedProtection));
 
   html_source->AddBoolean(
-      "enablePasswordCheck",
-      base::FeatureList::IsEnabled(password_manager::features::kPasswordCheck));
-
-  html_source->AddBoolean(
       "passwordsWeaknessCheck",
       base::FeatureList::IsEnabled(
           password_manager::features::kPasswordsWeaknessCheck));
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index fcd99ee..45eead8 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-master-1595370378-ba0a034250ef2251ee8fa7ce722cfaaf39079474.profdata
+chrome-linux-master-1599738815-c7c05d9aad543471c0ca5060fdc90a37df9de6fc.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 13a4d46..c1b6510 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-master-1599716388-02eae1071f5b6fe6862d29aa135a2ecf5509f01d.profdata
+chrome-mac-master-1599738815-ff1bf13166c585a2e1282bb43357481f321e4e87.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index e9848f9b..35f8b78 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-master-1599651808-28c874736fb144e9b48a72308f081ee03ad277c7.profdata
+chrome-win64-master-1599738815-40f6ae90536e6d0f415f1d4a37e068148427b479.profdata
diff --git a/chrome/renderer/autofill/fake_mojo_password_manager_driver.cc b/chrome/renderer/autofill/fake_mojo_password_manager_driver.cc
index cb57ba1..710e810 100644
--- a/chrome/renderer/autofill/fake_mojo_password_manager_driver.cc
+++ b/chrome/renderer/autofill/fake_mojo_password_manager_driver.cc
@@ -67,16 +67,12 @@
   called_check_safe_browsing_reputation_cnt_++;
 }
 
-void FakeMojoPasswordManagerDriver::ShowManualFallbackForSaving(
+void FakeMojoPasswordManagerDriver::InformAboutUserInput(
     const autofill::FormData& form_data) {
-  called_show_manual_fallback_for_saving_count_++;
+  called_inform_about_user_input_count_++;
   form_data_maybe_submitted_ = form_data;
 }
 
-void FakeMojoPasswordManagerDriver::HideManualFallbackForSaving() {
-  called_show_manual_fallback_for_saving_count_ = 0;
-}
-
 void FakeMojoPasswordManagerDriver::FocusedInputChanged(
     autofill::mojom::FocusedFieldType focused_field_type) {
   last_focused_field_type_ = focused_field_type;
diff --git a/chrome/renderer/autofill/fake_mojo_password_manager_driver.h b/chrome/renderer/autofill/fake_mojo_password_manager_driver.h
index 0baa9b0d..30410ea7 100644
--- a/chrome/renderer/autofill/fake_mojo_password_manager_driver.h
+++ b/chrome/renderer/autofill/fake_mojo_password_manager_driver.h
@@ -111,8 +111,8 @@
     return called_check_safe_browsing_reputation_cnt_;
   }
 
-  int called_show_manual_fallback_for_saving_count() const {
-    return called_show_manual_fallback_for_saving_count_;
+  int called_inform_about_user_input_count() const {
+    return called_inform_about_user_input_count_;
   }
 
   autofill::mojom::FocusedFieldType last_focused_field_type() const {
@@ -143,9 +143,8 @@
   void CheckSafeBrowsingReputation(const GURL& form_action,
                                    const GURL& frame_url) override;
 
-  void ShowManualFallbackForSaving(
-      const autofill::FormData& form_data) override;
-  void HideManualFallbackForSaving() override;
+  void InformAboutUserInput(const autofill::FormData& form_data) override;
+
   void FocusedInputChanged(
       autofill::mojom::FocusedFieldType focused_field_type) override;
   void LogFirstFillingResult(autofill::FormRendererId form_renderer_id,
@@ -181,9 +180,8 @@
   // Records number of times CheckSafeBrowsingReputation() gets called.
   int called_check_safe_browsing_reputation_cnt_ = 0;
 
-  // Records the number of request to show manual fallback for password saving.
-  // If it is zero, the fallback is not available.
-  int called_show_manual_fallback_for_saving_count_ = 0;
+  // Records the number of request to inform about user input.
+  int called_inform_about_user_input_count_ = 0;
 
   // Records the last focused field type that FocusedInputChanged() was called
   // with.
diff --git a/chrome/renderer/autofill/password_autofill_agent_browsertest.cc b/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
index fcf5582ab..9fcfe54 100644
--- a/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
+++ b/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
@@ -56,6 +56,7 @@
 #include "third_party/blink/public/web/win/web_font_rendering.h"
 #endif
 
+using autofill::FormRendererId;
 using autofill::FormTracker;
 using autofill::mojom::FocusedFieldType;
 using autofill::mojom::PasswordFormFieldPredictionType;
@@ -461,8 +462,8 @@
         password_element_.UniqueRendererFormControlId());
     WebFormElement form = password_element_.Form();
     fill_data_.form_renderer_id =
-        form.IsNull() ? autofill::FormRendererId()
-                      : autofill::FormRendererId(form.UniqueRendererFormId());
+        form.IsNull() ? FormRendererId()
+                      : FormRendererId(form.UniqueRendererFormId());
   }
 
   void UpdateUsernameAndPasswordElements() {
@@ -674,18 +675,18 @@
         << "Some expected masks are missed in FormData";
   }
 
-  autofill::FormRendererId GetFormUniqueRendererId(const WebString& form_id) {
+  FormRendererId GetFormUniqueRendererId(const WebString& form_id) {
     WebLocalFrame* frame = GetMainFrame();
     if (!frame)
-      return autofill::FormRendererId();
+      return FormRendererId();
     WebFormElement web_form =
         frame->GetDocument().GetElementById(form_id).To<WebFormElement>();
-    return autofill::FormRendererId(web_form.UniqueRendererFormId());
+    return FormRendererId(web_form.UniqueRendererFormId());
   }
 
   void ExpectFormDataWithUsernameAndPasswordsAndEvent(
       const autofill::FormData& form_data,
-      autofill::FormRendererId form_renderer_id,
+      FormRendererId form_renderer_id,
       const std::string& username_value,
       const std::string& password_value,
       const std::string& new_password_value,
@@ -698,7 +699,7 @@
   }
 
   void ExpectFormSubmittedWithUsernameAndPasswords(
-      autofill::FormRendererId form_renderer_id,
+      FormRendererId form_renderer_id,
       const std::string& username_value,
       const std::string& password_value,
       const std::string& new_password_value) {
@@ -712,7 +713,7 @@
   }
 
   void ExpectSameDocumentNavigationWithUsernameAndPasswords(
-      autofill::FormRendererId form_renderer_id,
+      FormRendererId form_renderer_id,
       const std::string& username_value,
       const std::string& password_value,
       const std::string& new_password_value,
@@ -959,7 +960,7 @@
   WebFormElement form_element =
       document.GetElementById("LoginTestForm").To<WebFormElement>();
   fill_data_.form_renderer_id =
-      autofill::FormRendererId(form_element.UniqueRendererFormId());
+      FormRendererId(form_element.UniqueRendererFormId());
 
   SimulateOnFillPasswordForm(fill_data_);
   histogram_tester_.ExpectTotalCount(
@@ -1482,7 +1483,7 @@
   // Neither field should have been autocompleted.
   CheckTextFieldsDOMState("user1", false, std::string(), false);
   base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(0, fake_driver_.called_show_manual_fallback_for_saving_count());
+  EXPECT_EQ(0, fake_driver_.called_inform_about_user_input_count());
 
   // Only password field should be autocompleted.
   EXPECT_TRUE(password_autofill_agent_->FillSuggestion(
@@ -1490,7 +1491,7 @@
       ASCIIToUTF16(kAlicePassword)));
   CheckTextFieldsDOMState("user1", false, kAlicePassword, true);
   base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(1, fake_driver_.called_show_manual_fallback_for_saving_count());
+  EXPECT_EQ(1, fake_driver_.called_inform_about_user_input_count());
 
   // Try Filling with a different password. Only password should be changed.
   EXPECT_TRUE(password_autofill_agent_->FillSuggestion(
@@ -1498,7 +1499,7 @@
       ASCIIToUTF16(kCarolPassword)));
   CheckTextFieldsDOMState("user1", false, kCarolPassword, true);
   base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(2, fake_driver_.called_show_manual_fallback_for_saving_count());
+  EXPECT_EQ(2, fake_driver_.called_inform_about_user_input_count());
 }
 
 // Tests that |FillSuggestion| properly fills the password if the username field
@@ -1807,7 +1808,7 @@
   WebFormElement form_element =
       document.GetElementById("LoginTestForm").To<WebFormElement>();
   fill_data_.form_renderer_id =
-      autofill::FormRendererId(form_element.UniqueRendererFormId());
+      FormRendererId(form_element.UniqueRendererFormId());
 
   SimulateOnFillPasswordForm(fill_data_);
 
@@ -2100,7 +2101,7 @@
 // PasswordAutofillAgent can still remember the username and the password
 // typed by the user.
 TEST_F(PasswordAutofillAgentTest,
-       DISABLED_RememberLastNonEmptyUsernameAndPasswordOnSubmit_ScriptCleared) {
+       RememberLastNonEmptyUsernameAndPasswordOnSubmit_ScriptCleared) {
   LoadHTML(kSignupFormHTML);
   WebInputElement username_element = GetInputElementByID("random_info");
   ASSERT_FALSE(username_element.IsNull());
@@ -2128,8 +2129,9 @@
 
   // Observe that the PasswordAutofillAgent still remembered the last non-empty
   // username and password and sent that to the browser.
-  ExpectFormSubmittedWithUsernameAndPasswords(GetFormUniqueRendererId("form"),
-                                              "username", "", "random");
+  ExpectFormSubmittedWithUsernameAndPasswords(
+      FormRendererId(username_element.Form().UniqueRendererFormId()),
+      "username", "", "random");
   fake_driver_.form_data_submitted();
 }
 
@@ -2157,7 +2159,7 @@
 // Similar to RememberLastNonEmptyPasswordOnSubmit_ScriptCleared, but uses the
 // new password instead of the current password.
 TEST_F(PasswordAutofillAgentTest,
-       DISABLED_RememberLastNonEmptyUsernameAndPasswordOnSubmit_New) {
+       RememberLastNonEmptyUsernameAndPasswordOnSubmit_New) {
   const char kNewPasswordFormHTML[] =
       "<FORM name='LoginTestForm' action='http://www.bidule.com'>"
       "  <INPUT type='text' id='username' autocomplete='username'/>"
@@ -2180,7 +2182,8 @@
   // Observe that the PasswordAutofillAgent still remembered the last non-empty
   // password and sent that to the browser.
   ExpectFormSubmittedWithUsernameAndPasswords(
-      GetFormUniqueRendererId("LoginTestForm"), "temp", "", "random");
+      FormRendererId(username_element_.Form().UniqueRendererFormId()), "temp",
+      "", "random");
 }
 
 // The user first accepts a suggestion, but then overwrites the password. This
@@ -2812,7 +2815,7 @@
   FireAjaxSucceeded();
 
   ExpectSameDocumentNavigationWithUsernameAndPasswords(
-      autofill::FormRendererId(), "Bob", "mypassword", "",
+      FormRendererId(), "Bob", "mypassword", "",
       SubmissionIndicatorEvent::XHR_SUCCEEDED);
 }
 
@@ -2836,7 +2839,7 @@
   base::RunLoop().RunUntilIdle();
 
   ExpectSameDocumentNavigationWithUsernameAndPasswords(
-      autofill::FormRendererId(), "Bob", "mypassword", "",
+      FormRendererId(), "Bob", "mypassword", "",
       SubmissionIndicatorEvent::DOM_MUTATION_AFTER_XHR);
 }
 
@@ -2871,7 +2874,7 @@
        PromptForAJAXSubmitAfterDeletingParentElement) {
   LoadHTML(kDivWrappedFormHTML);
   UpdateUsernameAndPasswordElements();
-  autofill::FormRendererId renderer_id = GetFormUniqueRendererId("form");
+  FormRendererId renderer_id = GetFormUniqueRendererId("form");
 
   SimulateUsernameTyping("Bob");
   SimulatePasswordTyping("mypassword");
@@ -3304,7 +3307,7 @@
     FireAjaxSucceeded();
 
     ExpectSameDocumentNavigationWithUsernameAndPasswords(
-        autofill::FormRendererId(), "Alice", "mypassword", "",
+        FormRendererId(), "Alice", "mypassword", "",
         SubmissionIndicatorEvent::XHR_SUCCEEDED);
   }
 }
@@ -3330,7 +3333,7 @@
   base::RunLoop().RunUntilIdle();
 
   ExpectSameDocumentNavigationWithUsernameAndPasswords(
-      autofill::FormRendererId(), "Alice", "mypassword", "",
+      FormRendererId(), "Alice", "mypassword", "",
       SubmissionIndicatorEvent::DOM_MUTATION_AFTER_XHR);
 }
 
@@ -3468,8 +3471,7 @@
        SameDocumentNavigationSubmissionUsernameIsEmpty) {
   username_element_.SetValue(WebString());
   SimulatePasswordTyping("random");
-  autofill::FormRendererId renderer_id =
-      GetFormUniqueRendererId("LoginTestForm");
+  FormRendererId renderer_id = GetFormUniqueRendererId("LoginTestForm");
 
   // Simulate that JavaScript removes the submitted form from DOM. That means
   // that a submission was successful.
@@ -3557,42 +3559,41 @@
 
 TEST_F(PasswordAutofillAgentTest, ManualFallbackForSaving) {
   EXPECT_CALL(fake_pw_client_, PresaveGeneratedPassword(_, _)).Times(0);
-  // The users enters a username. No password - no fallback.
+  // The users enters a username. Inform the driver regardless.
   SimulateUsernameTyping(kUsernameName);
-  EXPECT_EQ(0, fake_driver_.called_show_manual_fallback_for_saving_count());
+  EXPECT_EQ(1, fake_driver_.called_inform_about_user_input_count());
 
   // The user enters a password.
   SimulatePasswordTyping(kPasswordName);
   // SimulateUsernameTyping/SimulatePasswordTyping calls
   // PasswordAutofillAgent::UpdateStateForTextChange only once.
-  EXPECT_EQ(1, fake_driver_.called_show_manual_fallback_for_saving_count());
+  EXPECT_EQ(2, fake_driver_.called_inform_about_user_input_count());
 
   // Remove one character from the password value.
   SimulateUserTypingASCIICharacter(ui::VKEY_BACK, true);
-  EXPECT_EQ(2, fake_driver_.called_show_manual_fallback_for_saving_count());
+  EXPECT_EQ(3, fake_driver_.called_inform_about_user_input_count());
 
   // Add one character to the username value.
   SetFocused(username_element_);
   SimulateUserTypingASCIICharacter('a', true);
-  EXPECT_EQ(3, fake_driver_.called_show_manual_fallback_for_saving_count());
+  EXPECT_EQ(4, fake_driver_.called_inform_about_user_input_count());
 
   // Remove username value.
   SimulateUsernameTyping("");
-  EXPECT_EQ(4, fake_driver_.called_show_manual_fallback_for_saving_count());
+  EXPECT_EQ(5, fake_driver_.called_inform_about_user_input_count());
 
-  // Change the password. Despite of empty username the fallback is still
-  // there.
+  // Change the password.
   SetFocused(password_element_);
   SimulateUserTypingASCIICharacter('a', true);
-  EXPECT_EQ(5, fake_driver_.called_show_manual_fallback_for_saving_count());
+  EXPECT_EQ(6, fake_driver_.called_inform_about_user_input_count());
 
-  // Remove password value. The fallback should be disabled.
+  // Remove password value. Inform the driver too.
   SimulatePasswordTyping("");
-  EXPECT_EQ(0, fake_driver_.called_show_manual_fallback_for_saving_count());
+  EXPECT_EQ(7, fake_driver_.called_inform_about_user_input_count());
 
-  // The user enters new password. Show the fallback again.
+  // The user enters new password.
   SimulateUserTypingASCIICharacter('a', true);
-  EXPECT_EQ(1, fake_driver_.called_show_manual_fallback_for_saving_count());
+  EXPECT_EQ(8, fake_driver_.called_inform_about_user_input_count());
 }
 
 TEST_F(PasswordAutofillAgentTest, ManualFallbackForSaving_PasswordChangeForm) {
@@ -3600,37 +3601,37 @@
   UpdateUrlForHTML(kPasswordChangeFormHTML);
   UpdateUsernameAndPasswordElements();
 
-  // No password to save yet - no fallback.
+  // No password to save yet - still we should inform the driver.
   SimulateUsernameTyping(kUsernameName);
-  EXPECT_EQ(0, fake_driver_.called_show_manual_fallback_for_saving_count());
+  EXPECT_EQ(1, fake_driver_.called_inform_about_user_input_count());
 
   // The user enters in the current password field. The fallback should be
   // available to save the entered value.
   SimulatePasswordTyping(kPasswordName);
   // SimulateUsernameTyping/SimulatePasswordTyping calls
   // PasswordAutofillAgent::UpdateStateForTextChange only once.
-  EXPECT_EQ(1, fake_driver_.called_show_manual_fallback_for_saving_count());
+  EXPECT_EQ(2, fake_driver_.called_inform_about_user_input_count());
 
-  // The user types into the new password field. The fallback should be updated.
+  // The user types into the new password field. Inform the driver.
   WebInputElement new_password = GetInputElementByID("newpassword");
   ASSERT_FALSE(new_password.IsNull());
   SetFocused(new_password);
   SimulateUserTypingASCIICharacter('a', true);
-  EXPECT_EQ(2, fake_driver_.called_show_manual_fallback_for_saving_count());
+  EXPECT_EQ(3, fake_driver_.called_inform_about_user_input_count());
 
-  // Edits of the confirmation password field trigger fallback updates.
+  // Edits of the confirmation password field trigger informing the driver.
   WebInputElement confirmation_password =
       GetInputElementByID("confirmpassword");
   ASSERT_FALSE(confirmation_password.IsNull());
   SetFocused(confirmation_password);
   SimulateUserTypingASCIICharacter('a', true);
-  EXPECT_EQ(3, fake_driver_.called_show_manual_fallback_for_saving_count());
+  EXPECT_EQ(4, fake_driver_.called_inform_about_user_input_count());
 
-  // Clear all password fields. The fallback should be disabled.
+  // Clear all password fields. The driver should be informed.
   SimulatePasswordTyping("");
   SimulateUserInputChangeForElement(&new_password, "");
   SimulateUserInputChangeForElement(&confirmation_password, "");
-  EXPECT_EQ(0, fake_driver_.called_show_manual_fallback_for_saving_count());
+  EXPECT_EQ(5, fake_driver_.called_inform_about_user_input_count());
 }
 
 // Tests that information about Gaia reauthentication form is sent to the
diff --git a/chrome/renderer/autofill/password_generation_agent_browsertest.cc b/chrome/renderer/autofill/password_generation_agent_browsertest.cc
index e7b7d736..4467efa 100644
--- a/chrome/renderer/autofill/password_generation_agent_browsertest.cc
+++ b/chrome/renderer/autofill/password_generation_agent_browsertest.cc
@@ -895,21 +895,20 @@
   LoadHTMLWithUserGesture(kAccountCreationFormHTML);
   SimulateElementRightClick("first_password");
   SelectGenerationFallbackAndExpect(true);
-  EXPECT_EQ(0, fake_driver_.called_show_manual_fallback_for_saving_count());
+  EXPECT_EQ(0, fake_driver_.called_inform_about_user_input_count());
   base::string16 password = base::ASCIIToUTF16("random_password");
   EXPECT_CALL(fake_pw_client_, PresaveGeneratedPassword(_, Eq(password)))
       .WillOnce(testing::InvokeWithoutArgs([this]() {
         // Make sure that generation event was propagated to the browser before
         // the fallback showing. Otherwise, the fallback for saving provides a
         // save bubble instead of a confirmation bubble.
-        EXPECT_EQ(0,
-                  fake_driver_.called_show_manual_fallback_for_saving_count());
+        EXPECT_EQ(0, fake_driver_.called_inform_about_user_input_count());
       }));
   password_generation_->GeneratedPasswordAccepted(password);
   fake_driver_.Flush();
   // Two fallback requests are expected because generation changes either new
   // password and confirmation fields.
-  EXPECT_EQ(2, fake_driver_.called_show_manual_fallback_for_saving_count());
+  EXPECT_EQ(2, fake_driver_.called_inform_about_user_input_count());
 }
 
 TEST_F(PasswordGenerationAgentTest, FormClassifierDisabled) {
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 1c415d2..93b8ed83 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -773,6 +773,7 @@
       "//mojo/public/cpp/system",
       "//net",
       "//net:test_support",
+      "//pdf:features",
       "//ppapi/buildflags",
       "//printing/buildflags",
       "//rlz/buildflags",
@@ -3258,6 +3259,7 @@
     "../browser/component_updater/autofill_states_component_installer_unittest.cc",
     "../browser/component_updater/chrome_component_updater_configurator_unittest.cc",
     "../browser/component_updater/crl_set_component_installer_unittest.cc",
+    "../browser/component_updater/first_party_sets_component_installer_unittest.cc",
     "../browser/component_updater/floc_blocklist_component_installer_unittest.cc",
     "../browser/component_updater/games_component_installer_unittest.cc",
     "../browser/component_updater/optimization_hints_component_installer_unittest.cc",
diff --git a/chrome/test/data/webui/settings/autofill_page_test.js b/chrome/test/data/webui/settings/autofill_page_test.js
index c5b81de2..853eeea 100644
--- a/chrome/test/data/webui/settings/autofill_page_test.js
+++ b/chrome/test/data/webui/settings/autofill_page_test.js
@@ -300,13 +300,6 @@
   let passwordManager;
   let pluralString;
 
-  suiteSetup(function() {
-    // Forces navigation to Google Password Manager to be off by default.
-    loadTimeData.overrideValues({
-      enablePasswordCheck: true,
-    });
-  });
-
   setup(function() {
     openWindowProxy = new TestOpenWindowProxy();
     OpenWindowProxyImpl.instance_ = openWindowProxy;
diff --git a/chrome/test/data/webui/settings/chromeos/os_about_page_tests.js b/chrome/test/data/webui/settings/chromeos/os_about_page_tests.js
index 10e6f55f..b8eac4f 100644
--- a/chrome/test/data/webui/settings/chromeos/os_about_page_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/os_about_page_tests.js
@@ -300,8 +300,7 @@
       async function checkReleaseNotesOnline(isShowing) {
         await aboutBrowserProxy.whenCalled('getEnabledReleaseNotes');
         const releaseNotesOnlineEl = page.$$('#releaseNotesOnline');
-        assertTrue(!!releaseNotesOnlineEl);
-        assertEquals(isShowing, !releaseNotesOnlineEl.hidden);
+        assertEquals(isShowing, !!releaseNotesOnlineEl);
       }
 
       /**
@@ -313,8 +312,7 @@
       async function checkReleaseNotesOffline(isShowing) {
         await aboutBrowserProxy.whenCalled('getEnabledReleaseNotes');
         const releaseNotesOfflineEl = page.$$('#releaseNotesOffline');
-        assertTrue(!!releaseNotesOfflineEl);
-        assertEquals(isShowing, !releaseNotesOfflineEl.hidden);
+        assertEquals(isShowing, !!releaseNotesOfflineEl);
       }
 
       /**
@@ -324,9 +322,9 @@
       async function checkReleaseNotesDisabled() {
         await aboutBrowserProxy.whenCalled('getEnabledReleaseNotes');
         const releaseNotesOnlineEl = page.$$('#releaseNotesOnline');
-        assertTrue(!releaseNotesOnlineEl);
+        assertFalse(!!releaseNotesOnlineEl);
         const releaseNotesOfflineEl = page.$$('#releaseNotesOffline');
-        assertTrue(!releaseNotesOfflineEl);
+        assertFalse(!!releaseNotesOfflineEl);
       }
 
       aboutBrowserProxy.setReleaseNotes(false);
diff --git a/chrome/test/data/webui/settings/cr_settings_v3_browsertest.js b/chrome/test/data/webui/settings/cr_settings_v3_browsertest.js
index dfbf541f..d350758 100644
--- a/chrome/test/data/webui/settings/cr_settings_v3_browsertest.js
+++ b/chrome/test/data/webui/settings/cr_settings_v3_browsertest.js
@@ -217,11 +217,6 @@
   get browsePreload() {
     return 'chrome://settings/test_loader.html?module=settings/passwords_section_test.js';
   }
-
-  /** @override */
-  get featureListInternal() {
-    return {enabled: ['password_manager::features::kPasswordCheck']};
-  }
 };
 
 // Flaky on Debug builds https://crbug.com/1090931
@@ -287,11 +282,6 @@
   get browsePreload() {
     return 'chrome://settings/test_loader.html?module=settings/password_check_test.js';
   }
-
-  /** @override */
-  get featureListInternal() {
-    return {enabled: ['password_manager::features::kPasswordCheck']};
-  }
 };
 
 TEST_F('CrSettingsPasswordsCheckV3Test', 'All', function() {
@@ -304,15 +294,6 @@
   get browsePreload() {
     return 'chrome://settings/test_loader.html?module=settings/safety_check_page_test.js';
   }
-
-  /** @override */
-  get featureListInternal() {
-    return {
-      enabled: [
-        'password_manager::features::kPasswordCheck',
-      ],
-    };
-  }
 };
 
 TEST_F('CrSettingsSafetyCheckPageV3Test', 'All', function() {
diff --git a/chrome/test/data/webui/settings/languages_page_tests.js b/chrome/test/data/webui/settings/languages_page_tests.js
index 116b558a..4ea94d99 100644
--- a/chrome/test/data/webui/settings/languages_page_tests.js
+++ b/chrome/test/data/webui/settings/languages_page_tests.js
@@ -631,27 +631,34 @@
 
       const list = languagesPage.$.spellCheckLanguagesList;
       assertFalse(list.hidden);
+      assertTrue(languagesPage.$$('#enableSpellcheckingToggle').checked);
+      assertDeepEquals(
+          ['en-US'], languageHelper.getPref('spellcheck.dictionaries').value);
 
-      languageHelper.setPrefValue('intl.accept_languages', 'en-US');
-      if (isChromeOS) {
-        languageHelper.setPrefValue(
-            'settings.language.preferred_languages', 'en-US');
-      }
-
-      // Update supported languages to just 1 language English with spell
-      // check disabled for that language
-      languageHelper.setPrefValue('spellcheck.dictionaries', []);
+      // Update supported languages to just 1 language should hide list.
+      languageHelper.setPrefValue(languagesPref, 'en-US');
+      flush();
       assertTrue(list.hidden);
-      assertFalse(languageHelper.getPref('browser.enable_spellchecking').value);
 
-      // Update supported languages to just 1 language English that finished
-      // downloading and is now ready
-      languageHelper.setPrefValue('spellcheck.dictionaries', ['en-US']);
-      languageHelper.set('languages.enabled.0.downloadDictionaryStatus', {
-        isReady: true,
-      });
+      // Disable spell check should keep list hidden and remove the single
+      // language from dictionaries.
+      languagesPage.$$('#enableSpellcheckingToggle').click();
+      flush();
+
       assertTrue(list.hidden);
-      assertTrue(languageHelper.getPref('browser.enable_spellchecking').value);
+      assertFalse(languagesPage.$$('#enableSpellcheckingToggle').checked);
+      assertDeepEquals(
+          [], languageHelper.getPref('spellcheck.dictionaries').value);
+
+      // Enable spell check should keep list hidden and add the single language
+      // to dictionaries.
+      languagesPage.$$('#enableSpellcheckingToggle').click();
+      flush();
+
+      assertTrue(list.hidden);
+      assertTrue(languagesPage.$$('#enableSpellcheckingToggle').checked);
+      assertDeepEquals(
+          ['en-US'], languageHelper.getPref('spellcheck.dictionaries').value);
     });
 
     test('no supported languages', () => {
diff --git a/chrome/test/data/webui/settings/password_check_test.js b/chrome/test/data/webui/settings/password_check_test.js
index b4a7ca5..0c1602d0 100644
--- a/chrome/test/data/webui/settings/password_check_test.js
+++ b/chrome/test/data/webui/settings/password_check_test.js
@@ -120,10 +120,6 @@
   /** @type {TestPasswordManagerProxy} */
   let passwordManager = null;
 
-  suiteSetup(function() {
-    loadTimeData.overrideValues({enablePasswordCheck: true});
-  });
-
   setup(function() {
     PolymerTest.clearBody();
     // Override the PasswordManagerImpl for testing.
diff --git a/chrome/test/data/webui/settings/passwords_section_test.js b/chrome/test/data/webui/settings/passwords_section_test.js
index 137d601..66de7a11 100644
--- a/chrome/test/data/webui/settings/passwords_section_test.js
+++ b/chrome/test/data/webui/settings/passwords_section_test.js
@@ -319,10 +319,6 @@
   /** @type {TestPluralStringProxy} */
   let pluralString = null;
 
-  suiteSetup(function() {
-    loadTimeData.overrideValues({enablePasswordCheck: true});
-  });
-
   setup(function() {
     PolymerTest.clearBody();
     // Override the PasswordManagerImpl for testing.
diff --git a/chrome/test/data/webui/settings/safety_check_page_test.js b/chrome/test/data/webui/settings/safety_check_page_test.js
index 9942d54..de8713d 100644
--- a/chrome/test/data/webui/settings/safety_check_page_test.js
+++ b/chrome/test/data/webui/settings/safety_check_page_test.js
@@ -551,7 +551,6 @@
       buttonClass: 'action-button',
     });
 
-    loadTimeData.overrideValues({enablePasswordCheck: true});
     const passwordManager = new TestPasswordManagerProxy();
     PasswordManagerImpl.instance_ = passwordManager;
 
diff --git a/chrome/updater/control_service_in_process.cc b/chrome/updater/control_service_in_process.cc
index 58a338eb..96eedb64 100644
--- a/chrome/updater/control_service_in_process.cc
+++ b/chrome/updater/control_service_in_process.cc
@@ -4,12 +4,19 @@
 
 #include "chrome/updater/control_service_in_process.h"
 
+#include <string>
+#include <vector>
+
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
 #include "base/logging.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/time/time.h"
 #include "chrome/updater/configurator.h"
+#include "chrome/updater/constants.h"
+#include "chrome/updater/persisted_data.h"
 #include "chrome/updater/prefs.h"
 #include "chrome/updater/update_service_in_process.h"
 #include "components/prefs/pref_service.h"
@@ -19,11 +26,18 @@
 ControlServiceInProcess::ControlServiceInProcess(
     scoped_refptr<updater::Configurator> config)
     : config_(config),
+      persisted_data_(
+          base::MakeRefCounted<PersistedData>(config_->GetPrefService())),
       main_task_runner_(base::SequencedTaskRunnerHandle::Get()) {}
 
 void ControlServiceInProcess::Run(base::OnceClosure callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
+  RemoveApps();
+  MaybeCheckForUpdates(std::move(callback));
+}
+
+void ControlServiceInProcess::MaybeCheckForUpdates(base::OnceClosure callback) {
   const base::Time lastUpdateTime =
       config_->GetPrefService()->GetTime(kPrefUpdateTime);
 
@@ -58,6 +72,20 @@
           base::BindOnce(std::move(callback)), config_));
 }
 
+void ControlServiceInProcess::RemoveApps() {
+  for (const auto& app_id : persisted_data_->GetAppIds()) {
+    // Skip if app_id is equal to updater app id.
+    if (app_id == kUpdaterAppId)
+      continue;
+
+    const base::FilePath ecp = persisted_data_->GetExistenceCheckerPath(app_id);
+    if (!ecp.empty() && base::PathExists(ecp)) {
+      if (!persisted_data_->RemoveApp(app_id))
+        VLOG(0) << "Could not remove registration of app " << app_id;
+    }
+  }
+}
+
 void ControlServiceInProcess::Uninitialize() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   PrefsCommitPendingWrites(config_->GetPrefService());
diff --git a/chrome/updater/control_service_in_process.h b/chrome/updater/control_service_in_process.h
index 1c1e9ce0..c5abd6a 100644
--- a/chrome/updater/control_service_in_process.h
+++ b/chrome/updater/control_service_in_process.h
@@ -17,6 +17,7 @@
 namespace updater {
 
 class Configurator;
+class PersistedData;
 
 // All functions and callbacks must be called on the same sequence.
 class ControlServiceInProcess : public ControlService {
@@ -33,7 +34,16 @@
 
   SEQUENCE_CHECKER(sequence_checker_);
 
+  // Checks for updates of all registered applications if it has been longer
+  // than the last check time by NextCheckDelay() amount defined in the config.
+  void MaybeCheckForUpdates(base::OnceClosure callback);
+
+  // Provides a way to remove apps from the persisted data if the app is no
+  // longer installed on the machine.
+  void RemoveApps();
+
   scoped_refptr<updater::Configurator> config_;
+  scoped_refptr<updater::PersistedData> persisted_data_;
   scoped_refptr<base::SequencedTaskRunner> main_task_runner_;
 };
 
diff --git a/chrome/updater/persisted_data.cc b/chrome/updater/persisted_data.cc
index 360ef2b..5d5e375 100644
--- a/chrome/updater/persisted_data.cc
+++ b/chrome/updater/persisted_data.cc
@@ -103,6 +103,17 @@
   SetTag(rq.app_id, rq.tag);
 }
 
+bool PersistedData::RemoveApp(const std::string& id) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (!pref_service_)
+    return false;
+
+  DictionaryPrefUpdate update(pref_service_, kPersistedDataPreference);
+  base::Value* apps = update->FindDictKey("apps");
+
+  return apps ? apps->RemoveKey(id) : false;
+}
+
 std::vector<std::string> PersistedData::GetAppIds() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
diff --git a/chrome/updater/persisted_data.h b/chrome/updater/persisted_data.h
index f0078e7..212ef5f 100644
--- a/chrome/updater/persisted_data.h
+++ b/chrome/updater/persisted_data.h
@@ -65,6 +65,9 @@
   // persistent data store.
   void RegisterApp(const RegistrationRequest& rq);
 
+  // This function removes a registered application from the persistent store.
+  bool RemoveApp(const std::string& id);
+
   // Returns the app ids of the applications registered in prefs, if the
   // application has a valid version.
   std::vector<std::string> GetAppIds() const;
@@ -83,7 +86,6 @@
   void SetString(const std::string& id,
                  const std::string& key,
                  const std::string& value);
-
   SEQUENCE_CHECKER(sequence_checker_);
 
   PrefService* pref_service_ = nullptr;  // Not owned by this class.
diff --git a/chrome/updater/persisted_data_unittest.cc b/chrome/updater/persisted_data_unittest.cc
index aee84bc..000114a 100644
--- a/chrome/updater/persisted_data_unittest.cc
+++ b/chrome/updater/persisted_data_unittest.cc
@@ -2,12 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/updater/persisted_data.h"
+
 #include <memory>
 #include <string>
 
+#include "base/files/file_path.h"
 #include "base/stl_util.h"
 #include "base/version.h"
-#include "chrome/updater/persisted_data.h"
 #include "chrome/updater/registration_data.h"
 #include "components/prefs/testing_pref_service.h"
 #include "components/update_client/update_client.h"
@@ -82,4 +84,36 @@
                metadata->GetProductVersion("someappid").GetString().c_str());
 }
 
+TEST(PersistedDataTest, RemoveAppId) {
+  auto pref = std::make_unique<TestingPrefServiceSimple>();
+  update_client::RegisterPrefs(pref->registry());
+  auto metadata = base::MakeRefCounted<PersistedData>(pref.get());
+
+  RegistrationRequest data;
+  data.app_id = "someappid";
+  data.brand_code = "somebrand";
+  data.tag = "arandom-tag=likethis";
+  data.version = base::Version("1.0");
+  data.existence_checker_path =
+      base::FilePath(FILE_PATH_LITERAL("some/file/path"));
+
+  metadata->RegisterApp(data);
+
+  data.app_id = "someappid2";
+  data.brand_code = "somebrand";
+  data.tag = "arandom-tag=likethis";
+  data.version = base::Version("2.0");
+  data.existence_checker_path =
+      base::FilePath(FILE_PATH_LITERAL("some/file/path"));
+
+  metadata->RegisterApp(data);
+  EXPECT_EQ(size_t{2}, metadata->GetAppIds().size());
+
+  metadata->RemoveApp("someappid");
+  EXPECT_EQ(size_t{1}, metadata->GetAppIds().size());
+
+  metadata->RemoveApp("someappid2");
+  EXPECT_TRUE(metadata->GetAppIds().empty());
+}
+
 }  // namespace updater
diff --git a/chromecast/BUILD.gn b/chromecast/BUILD.gn
index be67795..28f4caf4 100644
--- a/chromecast/BUILD.gn
+++ b/chromecast/BUILD.gn
@@ -94,6 +94,12 @@
     "//ui/base:ui_base_unittests",
   ]
 
+  if (enable_chromecast_extensions) {
+    tests += [
+      "//chromecast/browser/accessibility/flutter:cast_accessibility_unittests",
+    ]
+  }
+
   if (!is_cast_audio_only) {
     tests += [ "//gpu:gpu_unittests" ]
 
diff --git a/chromecast/browser/accessibility/flutter/BUILD.gn b/chromecast/browser/accessibility/flutter/BUILD.gn
new file mode 100644
index 0000000..88815d5c
--- /dev/null
+++ b/chromecast/browser/accessibility/flutter/BUILD.gn
@@ -0,0 +1,49 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//chromecast/build/tests/cast_test.gni")
+import("//chromecast/chromecast.gni")
+
+cast_source_set("accessibility") {
+  sources = [
+    "ax_tree_source_flutter.cc",
+    "ax_tree_source_flutter.h",
+    "flutter_accessibility_helper_bridge.cc",
+    "flutter_accessibility_helper_bridge.h",
+    "flutter_semantics_node.h",
+    "flutter_semantics_node_wrapper.cc",
+    "flutter_semantics_node_wrapper.h",
+  ]
+  public_deps = [ "//ui/accessibility" ]
+  deps = [
+    "//base",
+    "//chromecast/base",
+    "//chromecast/browser",
+    "//chromecast/browser/accessibility/proto:gallium_accessibility_proto",
+    "//chromecast/common",
+    "//components/exo",
+    "//content/public/browser",
+    "//extensions/browser/api",
+    "//skia",
+    "//third_party/grpc:grpcpp",
+    "//ui/views",
+  ]
+}
+
+test("cast_accessibility_unittests") {
+  sources = [ "ax_tree_source_flutter_unittest.cc" ]
+
+  deps = [
+    ":accessibility",
+    "//base",
+    "//base/test:run_all_unittests",
+    "//chromecast/browser",
+    "//extensions/browser/api",
+    "//skia",
+    "//testing/gmock",
+    "//testing/gtest",
+    "//third_party/protobuf:protobuf_lite",
+    "//ui/views",
+  ]
+}
diff --git a/chromecast/browser/accessibility/flutter/DEPS b/chromecast/browser/accessibility/flutter/DEPS
new file mode 100644
index 0000000..a1bbce47
--- /dev/null
+++ b/chromecast/browser/accessibility/flutter/DEPS
@@ -0,0 +1,13 @@
+include_rules = [
+  "+chromecast/browser",
+  "+chromecast/common/extensions_api",
+  "+components/exo",
+  "+content/browser",
+  "+content/public/browser",
+  "+extensions/browser",
+  '+third_party/grpc',
+  "+ui/accessibility",
+  "+ui/aura",
+  "+ui/gfx",
+  "+ui/views",
+]
diff --git a/chromecast/browser/accessibility/flutter/ax_tree_source_flutter.cc b/chromecast/browser/accessibility/flutter/ax_tree_source_flutter.cc
new file mode 100644
index 0000000..57105b9
--- /dev/null
+++ b/chromecast/browser/accessibility/flutter/ax_tree_source_flutter.cc
@@ -0,0 +1,641 @@
+// 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 "chromecast/browser/accessibility/flutter/ax_tree_source_flutter.h"
+
+#include <stack>
+
+#include "base/check_op.h"
+#include "base/strings/string_number_conversions.h"
+#include "chromecast/browser/accessibility/flutter/flutter_semantics_node_wrapper.h"
+#include "chromecast/browser/ui/aura/accessibility/automation_manager_aura.h"
+#include "content/public/browser/tts_controller.h"
+#include "content/public/browser/tts_utterance.h"
+#include "extensions/browser/api/automation_internal/automation_event_router.h"
+#include "extensions/browser/api/automation_internal/automation_event_router_interface.h"
+#include "ui/accessibility/aura/aura_window_properties.h"
+#include "ui/aura/window.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_delegate.h"
+
+namespace {
+ax::mojom::Event ToAXEvent(
+    gallium::castos::OnAccessibilityEventRequest_EventType flutter_event_type) {
+  switch (flutter_event_type) {
+    case gallium::castos::OnAccessibilityEventRequest_EventType_FOCUSED:
+      return ax::mojom::Event::kFocus;
+    case gallium::castos::OnAccessibilityEventRequest_EventType_CLICKED:
+    case gallium::castos::OnAccessibilityEventRequest_EventType_LONG_CLICKED:
+      return ax::mojom::Event::kClicked;
+    case gallium::castos::OnAccessibilityEventRequest_EventType_TEXT_CHANGED:
+      return ax::mojom::Event::kTextChanged;
+    case gallium::castos::
+        OnAccessibilityEventRequest_EventType_TEXT_SELECTION_CHANGED:
+      return ax::mojom::Event::kTextSelectionChanged;
+    case gallium::castos::OnAccessibilityEventRequest_EventType_HOVER_ENTER:
+      return ax::mojom::Event::kHover;
+    case gallium::castos::OnAccessibilityEventRequest_EventType_SCROLLED:
+      return ax::mojom::Event::kScrollPositionChanged;
+    case gallium::castos::OnAccessibilityEventRequest_EventType_CONTENT_CHANGED:
+      return ax::mojom::Event::kChildrenChanged;
+    case gallium::castos::
+        OnAccessibilityEventRequest_EventType_WINDOW_STATE_CHANGED:
+      return ax::mojom::Event::kLayoutComplete;
+    default:
+      return ax::mojom::Event::kNone;
+  }
+}
+}  // namespace
+
+namespace chromecast {
+namespace accessibility {
+
+AXTreeSourceFlutter::AXTreeWebContentsObserver::AXTreeWebContentsObserver(
+    content::WebContents* web_contents,
+    AXTreeSourceFlutter* ax_tree_source)
+    : WebContentsObserver(web_contents), ax_tree_source_(ax_tree_source) {}
+
+void AXTreeSourceFlutter::AXTreeWebContentsObserver::RenderFrameHostChanged(
+    content::RenderFrameHost* old_host,
+    content::RenderFrameHost* new_host) {
+  ax_tree_source_->UpdateTree();
+}
+
+constexpr int kInvalidId = -1;
+
+AXTreeSourceFlutter::AXTreeSourceFlutter(
+    Delegate* delegate,
+    content::BrowserContext* browser_context,
+    extensions::AutomationEventRouterInterface* event_router)
+    : current_tree_serializer_(std::make_unique<AXTreeFlutterSerializer>(this)),
+      root_id_(kInvalidId),
+      window_id_(kInvalidId),
+      focused_id_(kInvalidId),
+      delegate_(delegate),
+      browser_context_(browser_context),
+      event_router_(event_router
+                        ? event_router
+                        : extensions::AutomationEventRouter::GetInstance()) {
+  DCHECK(delegate_);
+}
+
+AXTreeSourceFlutter::~AXTreeSourceFlutter() {
+  Reset();
+}
+
+void AXTreeSourceFlutter::NotifyAccessibilityEvent(
+    const gallium::castos::OnAccessibilityEventRequest* event_data) {
+  DCHECK(event_data);
+
+  if (event_data->node_data_size() > 0) {
+    // Remember most recent tree in case we need to update parents
+    // of child trees with new ax tree ids (i.e. due to embedded webview
+    // navigation)
+    last_event_data_ = *event_data;
+  }
+
+  // First find out if we know what to do with this event type from flutter.
+  ax::mojom::Event translated_event = ToAXEvent(event_data->event_type());
+  if (translated_event == ax::mojom::Event::kNone) {
+    LOG(INFO) << "Ignoring unknown flutter ax event "
+              << event_data->event_type() << ". No mapping available.";
+    return;
+  }
+
+  // b/150992421 - We sometimes get nodes that have been reparented.
+  // Any node that is reparented must first be deleted from its old
+  // parent before appearing under a new one. The tree serializer
+  // should be handling this case for us but isn't so the tree
+  // update fails. As a workaround until this is fixed upstream, we
+  // will identify these nodes ourselves and provide a separate update
+  // that will delete them prior to the full update.
+  reparented_children_.clear();
+  std::vector<int32_t> parents_with_deleted_children;
+  for (int i = 0; i < event_data->node_data_size(); ++i) {
+    const SemanticsNode& node = event_data->node_data(i);
+    for (int j = 0; j < node.child_node_ids_size(); ++j) {
+      int child_id = node.child_node_ids(j);
+      auto it = parent_map_.find(child_id);
+      if (it != parent_map_.end()) {
+        if (node.node_id() != it->second) {
+          // Remember this child and who its parent was.
+          reparented_children_.push_back(child_id);
+          parents_with_deleted_children.push_back(it->second);
+        }
+      }
+    }
+  }
+
+  if (event_data->node_data_size() > 0) {
+    // Unless there are new nodes, don't clear previous maps so we
+    // can detect reparenting above.
+    tree_map_.clear();
+    parent_map_.clear();
+    cached_computed_bounds_.clear();
+  }
+
+  window_id_ = event_data->window_id();
+
+  // The following loops perform caching to prepare for AXTreeSerializer.
+  // First, we need to cache parent links, which are implied by a node's child
+  // ids. Next, we cache the nodes by id. During this process, we can detect
+  // the root node based upon the parent links we cached above. Finally, we
+  // cache each node's computed bounds, based on its descendants.
+  std::map<int32_t, int32_t> all_parent_map;
+  std::map<int32_t, std::vector<int32_t>> all_children_map;
+  for (int i = 0; i < event_data->node_data_size(); ++i) {
+    const SemanticsNode& node = event_data->node_data(i);
+    for (int j = 0; j < node.child_node_ids_size(); ++j) {
+      all_children_map[node.node_id()].push_back(node.child_node_ids(j));
+      all_parent_map[node.child_node_ids(j)] = node.node_id();
+    }
+  }
+
+  // Now copy just the relevant subtree containing the source_id into the
+  // |parent_map_|.
+  root_id_ = event_data->source_id();
+  // Walk up to the root from the source_id.
+  for (auto it = all_parent_map.find(root_id_); it != all_parent_map.end();
+       it = all_parent_map.find(root_id_)) {
+    root_id_ = it->second;
+  }
+
+  // Walk back down through children map to populate parent_map_.
+  std::stack<int32_t> stack;
+  stack.push(root_id_);
+  while (!stack.empty()) {
+    int32_t parent = stack.top();
+    stack.pop();
+    for (int32_t child_id : all_children_map[parent]) {
+      parent_map_[child_id] = parent;
+      stack.push(child_id);
+    }
+  }
+
+  std::vector<std::string> new_child_trees;
+  for (int i = 0; i < event_data->node_data_size(); ++i) {
+    int32_t id = event_data->node_data(i).node_id();
+    // Only map nodes in the parent_map and the root.
+    // This avoids adding other subtrees that are not interesting.
+    if (parent_map_.find(id) == parent_map_.end() && id != root_id_)
+      continue;
+    const SemanticsNode& node = event_data->node_data(i);
+    tree_map_[id] = std::make_unique<FlutterSemanticsNodeWrapper>(this, &node);
+    if (tree_map_[id]->IsFocused()) {
+      focused_id_ = id;
+    }
+    // Place focus on the node that holds a child tree. When the
+    // child tree is removed, focus will be placed back on the root.
+    if (node.has_plugin_id()) {
+      std::string ax_tree_id = node.plugin_id();
+      new_child_trees.push_back(ax_tree_id);
+
+      if (std::find(child_trees_.begin(), child_trees_.end(), ax_tree_id) ==
+          child_trees_.end()) {
+        if (ax_tree_id.rfind("T:", 0) == 0) {
+          int web_contents_id;
+          base::StringToInt(ax_tree_id.substr(2), &web_contents_id);
+          std::vector<CastWebContents*> all_contents =
+              CastWebContents::GetAll();
+          for (CastWebContents* contents : all_contents) {
+            if (contents->id() == web_contents_id &&
+                child_tree_observers_.find(web_contents_id) ==
+                    child_tree_observers_.end()) {
+              child_tree_observers_[contents->id()] = std::make_unique<
+                  AXTreeSourceFlutter::AXTreeWebContentsObserver>(
+                  contents->web_contents(), this);
+              contents->AddObserver(this);
+              break;
+            }
+          }
+        }
+      }
+
+      focused_id_ = node.node_id();
+    }
+  }
+
+  // Do we need to put focus back on the root after a child tree
+  // has been removed?
+  bool need_focus_clear = false;
+  for (std::string id : child_trees_) {
+    // Is this old child tree still known?
+    if (std::find(new_child_trees.begin(), new_child_trees.end(), id) ==
+        new_child_trees.end()) {
+      // No, clear focus.
+      need_focus_clear = true;
+      focused_id_ = root_id_;
+      break;
+    }
+  }
+  child_trees_ = new_child_trees;
+
+  // Assuming |nodeData| is in pre-order, compute cached bounds in post-order to
+  // avoid an O(n^2) amount of work as the computed bounds uses descendant
+  // bounds.
+  for (int i = 0; i < event_data->node_data_size(); ++i) {
+    int32_t id = event_data->node_data(i).node_id();
+    if (parent_map_.find(id) == parent_map_.end() && id != root_id_)
+      continue;
+    cached_computed_bounds_[id] = ComputeEnclosingBounds(tree_map_[id].get());
+  }
+
+  // If focus was not set from above, set it now on the root node.
+  if (focused_id_ < 0 && root_id_ >= 0) {
+    focused_id_ = root_id_;
+  }
+
+  ExtensionMsg_AccessibilityEventBundleParams event_bundle;
+  event_bundle.tree_id = ax_tree_id();
+
+  event_bundle.events.emplace_back();
+  ui::AXEvent& event = event_bundle.events.back();
+  event.event_type = translated_event;
+  event.id = event_data->source_id();
+
+  if (event_data->event_type() ==
+      gallium::castos::OnAccessibilityEventRequest_EventType_CONTENT_CHANGED) {
+    current_tree_serializer_->InvalidateSubtree(GetFromId(event.id));
+  }
+
+  if (event_data->event_type() !=
+          gallium::castos::OnAccessibilityEventRequest_EventType_HOVER_ENTER &&
+      event_data->event_type() !=
+          gallium::castos::OnAccessibilityEventRequest_EventType_HOVER_EXIT) {
+    // For every parent whose child has been moved, serialize an update.
+    // This update will filter all the children that have moved.
+    for (int32_t nid : parents_with_deleted_children) {
+      event_bundle.updates.emplace_back();
+      current_tree_serializer_->SerializeChanges(GetFromId(nid),
+                                                 &event_bundle.updates.back());
+    }
+
+    // If there were any children that were reparented, invalidate the entire
+    // tree so the new parents get the children.
+    if (reparented_children_.size() > 0) {
+      current_tree_serializer_->InvalidateSubtree(GetFromId(root_id_));
+    }
+
+    // Clear reparented children.
+    reparented_children_.clear();
+
+    event_bundle.updates.emplace_back();
+    current_tree_serializer_->SerializeChanges(GetFromId(event.id),
+                                               &event_bundle.updates.back());
+
+    HandleLiveRegions(&event_bundle.events);
+
+    // b/162311902: For nodes that have scroll extents, rapidly changing the
+    // value will result in queueing up the values and speak out one by one.
+    // Here we handle the tts natively.
+    HandleNativeTTS();
+  }
+
+  // Place focus back on the root if a child tree has disappeared
+  if (need_focus_clear) {
+    event_bundle.events.emplace_back();
+    ui::AXEvent& focus_event = event_bundle.events.back();
+    focus_event.event_type = ax::mojom::Event::kFocus;
+    focus_event.id = root_id_;
+    focus_event.event_from = ax::mojom::EventFrom::kNone;
+  }
+
+  if (event_router_)
+    event_router_->DispatchAccessibilityEvents(event_bundle);
+}
+
+void AXTreeSourceFlutter::NotifyActionResult(const ui::AXActionData& data,
+                                             bool result) {
+  if (!event_router_)
+    return;
+
+  event_router_->DispatchActionResult(data, result, browser_context_);
+}
+
+bool AXTreeSourceFlutter::GetTreeData(ui::AXTreeData* data) const {
+  DCHECK(data);
+  data->tree_id = ax_tree_id();
+  if (focused_id_ >= 0) {
+    data->focus_id = focused_id_;
+  } else if (root_id_ >= 0) {
+    data->focus_id = root_id_;
+  }
+  return true;
+}
+
+FlutterSemanticsNode* AXTreeSourceFlutter::GetRoot() const {
+  return GetFromId(root_id_);
+}
+
+FlutterSemanticsNode* AXTreeSourceFlutter::GetFromId(int32_t id) const {
+  auto it = tree_map_.find(id);
+  if (it == tree_map_.end())
+    return nullptr;
+  return it->second.get();
+}
+
+int32_t AXTreeSourceFlutter::GetId(FlutterSemanticsNode* info_data) const {
+  if (!info_data)
+    return kInvalidId;
+  return info_data->GetId();
+}
+
+void AXTreeSourceFlutter::GetChildren(
+    FlutterSemanticsNode* info_data,
+    std::vector<FlutterSemanticsNode*>* out_children) const {
+  if (!info_data)
+    return;
+
+  info_data->GetChildren(out_children);
+  if (out_children->empty())
+    return;
+
+  // Filter out any reparented children so the update doesn't see them.
+  auto it = out_children->begin();
+  while (it != out_children->end()) {
+    if (std::find(reparented_children_.begin(), reparented_children_.end(),
+                  (*it)->GetId()) != reparented_children_.end()) {
+      it = out_children->erase(it);
+    } else {
+      ++it;
+    }
+  }
+
+  std::map<int32_t, size_t> id_to_index;
+  for (size_t i = 0; i < out_children->size(); i++)
+    id_to_index[(*out_children)[i]->GetId()] = i;
+
+  // Sort children based on their enclosing bounding rectangles, based on their
+  // descendants.
+  std::sort(
+      out_children->begin(), out_children->end(),
+      [this, id_to_index](auto left, auto right) {
+        auto left_bounds = ComputeEnclosingBounds(left);
+        auto right_bounds = ComputeEnclosingBounds(right);
+
+        if (left_bounds.IsEmpty() || right_bounds.IsEmpty()) {
+          return id_to_index.at(left->GetId()) < id_to_index.at(right->GetId());
+        }
+
+        // Left to right sort (non-overlapping).
+        if (!left_bounds.Intersects(right_bounds)) {
+          return left_bounds.x() < right_bounds.x();
+        }
+
+        // Overlapping
+        // Left to right.
+        int left_difference = left_bounds.x() - right_bounds.x();
+        if (left_difference != 0) {
+          return left_difference < 0;
+        }
+
+        // Top to bottom.
+        int top_difference = left_bounds.y() - right_bounds.y();
+        if (top_difference != 0) {
+          return top_difference < 0;
+        }
+
+        // Larger to smaller.
+        int height_difference = left_bounds.height() - right_bounds.height();
+        if (height_difference != 0) {
+          return height_difference > 0;
+        }
+
+        int width_difference = left_bounds.width() - right_bounds.width();
+        if (width_difference != 0) {
+          return width_difference > 0;
+        }
+
+        // The rects are equal.
+        return id_to_index.at(left->GetId()) < id_to_index.at(right->GetId());
+      });
+}
+
+FlutterSemanticsNode* AXTreeSourceFlutter::GetParent(
+    FlutterSemanticsNode* info_data) const {
+  if (!info_data)
+    return nullptr;
+  auto it = parent_map_.find(info_data->GetId());
+  if (it != parent_map_.end())
+    return GetFromId(it->second);
+  return nullptr;
+}
+
+bool AXTreeSourceFlutter::IsValid(FlutterSemanticsNode* info_data) const {
+  return info_data;
+}
+
+bool AXTreeSourceFlutter::IsIgnored(FlutterSemanticsNode* info_data) const {
+  return false;
+}
+
+bool AXTreeSourceFlutter::IsEqual(FlutterSemanticsNode* info_data1,
+                                  FlutterSemanticsNode* info_data2) const {
+  if (!info_data1 || !info_data2)
+    return false;
+  return info_data1->GetId() == info_data2->GetId();
+}
+
+FlutterSemanticsNode* AXTreeSourceFlutter::GetNull() const {
+  return nullptr;
+}
+
+void AXTreeSourceFlutter::SerializeNode(FlutterSemanticsNode* info_data,
+                                        ui::AXNodeData* out_data) const {
+  if (!info_data)
+    return;
+
+  int32_t id = info_data->GetId();
+  out_data->id = id;
+  if (id == root_id_) {
+    out_data->role = ax::mojom::Role::kRootWebArea;
+  } else {
+    info_data->PopulateAXRole(out_data);
+  }
+
+  info_data->Serialize(out_data);
+}
+
+const gfx::Rect AXTreeSourceFlutter::GetBounds(
+    FlutterSemanticsNode* info_data) const {
+  DCHECK(info_data);
+  DCHECK_NE(root_id_, kInvalidId);
+
+  gfx::Rect node_bounds = info_data->GetBounds();
+
+  // TODO(rmrossi): If embedded flutter is ever not full screen, we will have
+  // to pass in the embedded object tag's screen coordinates to this function
+  // and set the offset of the root node here separately from other nodes.
+  // The bounds of the root node are supposed to be relative to its container
+  // but since we are full screen, we leave them alone.  See
+  // ax_tree_source_arc.cc for an example.
+  if (info_data->GetId() == root_id_) {
+    gfx::Rect root_bounds = GetFromId(root_id_)->GetBounds();
+    // No offset applied since we are full screen.  See TODO above.
+    return root_bounds;
+  }
+  // Bounds of non-root node is relative to its tree's root.
+  gfx::Rect root_bounds = GetFromId(root_id_)->GetBounds();
+  node_bounds.Offset(-1 * root_bounds.x(), -1 * root_bounds.y());
+  return node_bounds;
+}
+
+gfx::Rect AXTreeSourceFlutter::ComputeEnclosingBounds(
+    FlutterSemanticsNode* info_data) const {
+  gfx::Rect computed_bounds;
+  // Exit early if the node or window is invisible.
+  if (!info_data->IsVisibleToUser())
+    return computed_bounds;
+
+  ComputeEnclosingBoundsInternal(info_data, &computed_bounds);
+  return computed_bounds;
+}
+
+void AXTreeSourceFlutter::ComputeEnclosingBoundsInternal(
+    FlutterSemanticsNode* info_data,
+    gfx::Rect* computed_bounds) const {
+  auto cached_bounds = cached_computed_bounds_.find(info_data->GetId());
+  if (cached_bounds != cached_computed_bounds_.end()) {
+    computed_bounds->Union(cached_bounds->second);
+    return;
+  }
+
+  if (!info_data->IsVisibleToUser())
+    return;
+
+  if (info_data->CanBeAccessibilityFocused()) {
+    // Only consider nodes that can possibly be accessibility focused.
+    computed_bounds->Union(info_data->GetBounds());
+    return;
+  }
+
+  std::vector<FlutterSemanticsNode*> children;
+  info_data->GetChildren(&children);
+  if (children.empty())
+    return;
+
+  for (FlutterSemanticsNode* child : children)
+    ComputeEnclosingBoundsInternal(child, computed_bounds);
+}
+
+void AXTreeSourceFlutter::PerformAction(const ui::AXActionData& data) {
+  delegate_->OnAction(data);
+}
+
+void AXTreeSourceFlutter::Reset() {
+  tree_map_.clear();
+  parent_map_.clear();
+  cached_computed_bounds_.clear();
+  current_tree_serializer_ = std::make_unique<AXTreeFlutterSerializer>(this);
+  root_id_ = kInvalidId;
+  focused_id_ = kInvalidId;
+  if (!event_router_)
+    return;
+  event_router_->DispatchTreeDestroyedEvent(ax_tree_id(), browser_context_);
+}
+
+void AXTreeSourceFlutter::HandleNativeTTS() {
+  std::map<int32_t, std::string> new_native_tts_name_cache;
+
+  // Cache current native tts name cache.
+  for (const auto& it : tree_map_) {
+    FlutterSemanticsNode* node_info = it.second.get();
+    if (!node_info->IsRapidChangingSlider())
+      continue;
+
+    std::vector<std::string> names;
+    if (node_info->HasLabelHint()) {
+      names.push_back(node_info->GetLabelHint());
+    }
+    if (node_info->HasValue()) {
+      names.push_back(node_info->GetValue());
+    }
+
+    new_native_tts_name_cache[node_info->GetId()] =
+        base::JoinString(names, " ");
+  }
+
+  // Compare to the previous one, and send out TTS if needed.
+  for (const auto& it : new_native_tts_name_cache) {
+    auto prev_it = native_tts_name_cache_.find(it.first);
+    if (prev_it != native_tts_name_cache_.end() &&
+        prev_it->second != it.second) {
+      // Send to TTS controller.
+      std::unique_ptr<content::TtsUtterance> utterance =
+          content::TtsUtterance::Create(browser_context_);
+      utterance->SetText(it.second);
+
+      auto* tts_controller = content::TtsController::GetInstance();
+      tts_controller->Stop();
+      tts_controller->SpeakOrEnqueue(std::move(utterance));
+    }
+  }
+
+  std::swap(native_tts_name_cache_, new_native_tts_name_cache);
+}
+
+void AXTreeSourceFlutter::HandleLiveRegions(std::vector<ui::AXEvent>* events) {
+  std::map<int32_t, std::string> new_live_region_map;
+
+  // Cache current live region's name.
+  for (const auto& it : tree_map_) {
+    FlutterSemanticsNode* node_info = it.second.get();
+    if (!node_info->IsLiveRegion())
+      continue;
+
+    std::stack<FlutterSemanticsNode*> stack;
+    stack.push(node_info);
+    while (!stack.empty()) {
+      FlutterSemanticsNode* node = stack.top();
+      stack.pop();
+      DCHECK(node);
+
+      ui::AXNodeData data;
+      SerializeNode(node, &data);
+      std::string name;
+      data.GetStringAttribute(ax::mojom::StringAttribute::kName, &name);
+      new_live_region_map[node->GetId()] = name;
+
+      std::vector<FlutterSemanticsNode*> children;
+      node->GetChildren(&children);
+      for (FlutterSemanticsNode* child : children)
+        stack.push(child);
+    }
+  }
+
+  // Compare to the previous one, and add an event if needed.
+  for (const auto& it : new_live_region_map) {
+    auto prev_it = live_region_name_cache_.find(it.first);
+    if (prev_it == live_region_name_cache_.end())
+      continue;
+
+    if (prev_it->second != it.second) {
+      events->emplace_back();
+      ui::AXEvent& event = events->back();
+      event.event_type = ax::mojom::Event::kLiveRegionChanged;
+      event.id = it.first;
+    }
+  }
+
+  std::swap(live_region_name_cache_, new_live_region_map);
+}
+
+void AXTreeSourceFlutter::UpdateTree() {
+  // Update the tree with last known flutter nodes.
+  // TODO: A more efficient update would be to isolate just the parent node
+  // whose child has changed. Consider giving the node to the observer
+  // class on creation and passing through here.
+  NotifyAccessibilityEvent(&last_event_data_);
+}
+
+void AXTreeSourceFlutter::OnPageStopped(CastWebContents* cast_web_contents,
+                                        int error_code) {
+  // Webview is gone. Stop observing.
+  cast_web_contents->RemoveObserver(this);
+  child_tree_observers_.erase(cast_web_contents->id());
+}
+
+}  // namespace accessibility
+}  // namespace chromecast
diff --git a/chromecast/browser/accessibility/flutter/ax_tree_source_flutter.h b/chromecast/browser/accessibility/flutter/ax_tree_source_flutter.h
new file mode 100644
index 0000000..1d1e8ad
--- /dev/null
+++ b/chromecast/browser/accessibility/flutter/ax_tree_source_flutter.h
@@ -0,0 +1,202 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMECAST_BROWSER_ACCESSIBILITY_FLUTTER_AX_TREE_SOURCE_FLUTTER_H_
+#define CHROMECAST_BROWSER_ACCESSIBILITY_FLUTTER_AX_TREE_SOURCE_FLUTTER_H_
+
+#include <stdint.h>
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/containers/flat_map.h"
+#include "chromecast/browser/accessibility/proto/cast_server_accessibility.pb.h"
+#include "chromecast/browser/cast_web_contents.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "ui/accessibility/ax_action_handler.h"
+#include "ui/accessibility/ax_node.h"
+#include "ui/accessibility/ax_node_data.h"
+#include "ui/accessibility/ax_tree_data.h"
+#include "ui/accessibility/ax_tree_serializer.h"
+#include "ui/accessibility/ax_tree_source.h"
+
+namespace aura {
+class Window;
+}  // namespace aura
+
+namespace content {
+class BrowserContext;
+}  // namespace content
+
+namespace extensions {
+class AutomationEventRouterInterface;
+}  // namespace extensions
+
+namespace ui {
+struct AXEvent;
+}  // namespace ui
+
+namespace chromecast {
+namespace accessibility {
+
+class FlutterSemanticsNode;
+
+// This class translates accessibility trees found in the gallium accessibility
+// OnAccessibilityEventRequest proto into a tree update Chrome's accessibility
+// API can work with.
+class AXTreeSourceFlutter : public ui::AXTreeSource<FlutterSemanticsNode*,
+                                                    ui::AXNodeData,
+                                                    ui::AXTreeData>,
+                            public CastWebContents::Observer,
+                            public ui::AXActionHandler {
+ public:
+  class Delegate {
+   public:
+    virtual ~Delegate() {}
+    virtual void OnAction(const ui::AXActionData& data) = 0;
+  };
+
+  AXTreeSourceFlutter(
+      Delegate* delegate,
+      content::BrowserContext* browser_context,
+      extensions::AutomationEventRouterInterface* event_router = nullptr);
+  AXTreeSourceFlutter(const AXTreeSourceFlutter&) = delete;
+  ~AXTreeSourceFlutter() override;
+  AXTreeSourceFlutter& operator=(const AXTreeSourceFlutter&) = delete;
+
+  // AXTreeSource implementation.
+  bool GetTreeData(ui::AXTreeData* data) const override;
+
+  // AXTreeSource implementation used by FlutterAccessibilityInfoData
+  // subclasses.
+  FlutterSemanticsNode* GetRoot() const override;
+  FlutterSemanticsNode* GetFromId(int32_t id) const override;
+  void SerializeNode(FlutterSemanticsNode* node,
+                     ui::AXNodeData* out_data) const override;
+  FlutterSemanticsNode* GetParent(FlutterSemanticsNode* node) const override;
+
+  // Notifies automation of an accessibility event.
+  void NotifyAccessibilityEvent(
+      const ::gallium::castos::OnAccessibilityEventRequest* event_data);
+
+  // Notifies automation of a result to an action.
+  void NotifyActionResult(const ui::AXActionData& data, bool result);
+
+  // Attaches tree to an aura window and gives it system focus.
+  void Focus(aura::Window* window);
+
+  // Gets the window id of this tree.
+  int32_t window_id() const { return window_id_; }
+
+  // Returns bounds of a node which can be passed to AXNodeData.location. Bounds
+  // are returned in the following coordinates depending on whether it's root or
+  // not.
+  // - Root node is relative to its container.
+  // - Non-root node is relative to the root node of this tree.
+  const gfx::Rect GetBounds(FlutterSemanticsNode* node) const;
+
+  void UpdateTree();
+
+  // CastWebContents::Observer
+  void OnPageStopped(CastWebContents* cast_web_contents,
+                     int error_code) override;
+
+ private:
+  class AXTreeWebContentsObserver : public content::WebContentsObserver {
+   public:
+    AXTreeWebContentsObserver(
+        content::WebContents* web_contents,
+        chromecast::accessibility::AXTreeSourceFlutter* ax_tree_source);
+
+    void RenderFrameHostChanged(content::RenderFrameHost* old_host,
+                                content::RenderFrameHost* new_host) override;
+
+   private:
+    chromecast::accessibility::AXTreeSourceFlutter* ax_tree_source_;
+
+    DISALLOW_COPY_AND_ASSIGN(AXTreeWebContentsObserver);
+  };
+
+  using AXTreeFlutterSerializer = ui::
+      AXTreeSerializer<FlutterSemanticsNode*, ui::AXNodeData, ui::AXTreeData>;
+
+  friend class AXTreeSourceFlutterTest;
+
+  // AXTreeSource overrides.
+  int32_t GetId(FlutterSemanticsNode* node) const override;
+  void GetChildren(
+      FlutterSemanticsNode* node,
+      std::vector<FlutterSemanticsNode*>* out_children) const override;
+  bool IsValid(FlutterSemanticsNode* node) const override;
+  bool IsIgnored(FlutterSemanticsNode* node) const override;
+  bool IsEqual(FlutterSemanticsNode* node1,
+               FlutterSemanticsNode* node2) const override;
+  FlutterSemanticsNode* GetNull() const override;
+
+  // Computes the smallest rect that encloses all of the descendants of |node|.
+  gfx::Rect ComputeEnclosingBounds(FlutterSemanticsNode* node) const;
+
+  // Helper to recursively compute bounds for |node|. Returns true if non-empty
+  // bounds were encountered.
+  void ComputeEnclosingBoundsInternal(FlutterSemanticsNode* node,
+                                      gfx::Rect* computed_bounds) const;
+
+  // AXHostDelegate implementation.
+  void PerformAction(const ui::AXActionData& data) override;
+
+  // Resets tree state.
+  void Reset();
+
+  // Detects live region changes and generates events for them.
+  void HandleLiveRegions(std::vector<ui::AXEvent>* events);
+
+  // Detects rapidly changing nodes and use native TTS instead.
+  void HandleNativeTTS();
+
+  std::unique_ptr<AXTreeFlutterSerializer> current_tree_serializer_;
+  int32_t root_id_;
+  int32_t window_id_;
+  int32_t focused_id_;
+
+  // A delegate that handles accessibility actions on behalf of this tree. The
+  // delegate is valid during the lifetime of this tree.
+  Delegate* delegate_;
+  content::BrowserContext* const browser_context_;
+  extensions::AutomationEventRouterInterface* const event_router_;
+
+  // Maps a node id to its tree data.
+  base::flat_map<int32_t /* node_id */, std::unique_ptr<FlutterSemanticsNode>>
+      tree_map_;
+
+  // Maps a node id to its parent.
+  base::flat_map<int32_t /* node_id */, int32_t /* parent_node_id */>
+      parent_map_;
+
+  // Mapping from ArcAccessibilityInfoData ID to its cached computed bounds.
+  // This simplifies bounds calculations.
+  base::flat_map<int32_t, gfx::Rect> cached_computed_bounds_;
+
+  // Cache from node id to computed name for live region.
+  std::map<int32_t, std::string> live_region_name_cache_;
+
+  // Cache form node id to tts string for native tts components.
+  std::map<int32_t, std::string> native_tts_name_cache_;
+
+  std::vector<int32_t> reparented_children_;
+  std::vector<std::string> child_trees_;
+
+  // Maps web contents id to the web contents observer
+  base::flat_map<int32_t, std::unique_ptr<AXTreeWebContentsObserver>>
+      child_tree_observers_;
+
+  // Copy of most recent tree data
+  gallium::castos::OnAccessibilityEventRequest last_event_data_;
+};
+
+}  // namespace accessibility
+}  // namespace chromecast
+
+#endif  // CHROMECAST_BROWSER_ACCESSIBILITY_FLUTTER_AX_TREE_SOURCE_FLUTTER_H_
diff --git a/chromecast/browser/accessibility/flutter/ax_tree_source_flutter_unittest.cc b/chromecast/browser/accessibility/flutter/ax_tree_source_flutter_unittest.cc
new file mode 100644
index 0000000..168344f0
--- /dev/null
+++ b/chromecast/browser/accessibility/flutter/ax_tree_source_flutter_unittest.cc
@@ -0,0 +1,636 @@
+// 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 "chromecast/browser/accessibility/flutter/ax_tree_source_flutter.h"
+
+#include <string>
+
+#include "chromecast/browser/accessibility/flutter/flutter_semantics_node_wrapper.h"
+#include "extensions/browser/api/automation_internal/automation_event_router_interface.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/accessibility/ax_action_data.h"
+
+using ::testing::StrictMock;
+
+using ::gallium::castos::ActionProperties;
+using ::gallium::castos::BooleanProperties;
+using ::gallium::castos::OnAccessibilityEventRequest;
+using ::gallium::castos::OnAccessibilityEventRequest_EventType_FOCUSED;
+using ::gallium::castos::Rect;
+
+namespace chromecast {
+namespace accessibility {
+
+class MockAutomationEventRouter
+    : public extensions::AutomationEventRouterInterface {
+ public:
+  MockAutomationEventRouter() {}
+  ~MockAutomationEventRouter() override = default;
+  void DispatchAccessibilityEvents(
+      const ExtensionMsg_AccessibilityEventBundleParams& events) override {
+    for (const auto& event : events.events)
+      event_count_[event.event_type]++;
+  }
+  MOCK_METHOD(void,
+              DispatchAccessibilityLocationChange,
+              (const ExtensionMsg_AccessibilityLocationChangeParams&),
+              (override));
+  MOCK_METHOD(void,
+              DispatchTreeDestroyedEvent,
+              (ui::AXTreeID, content::BrowserContext*),
+              (override));
+  MOCK_METHOD(void,
+              DispatchActionResult,
+              (const ui::AXActionData&, bool, content::BrowserContext*),
+              (override));
+  std::map<ax::mojom::Event, int> event_count_;
+};
+
+class AXTreeSourceFlutterTest : public testing::Test,
+                                public AXTreeSourceFlutter::Delegate {
+ public:
+  AXTreeSourceFlutterTest()
+      : tree_(
+            std::make_unique<AXTreeSourceFlutter>(this,
+                                                  nullptr /* browser_context */,
+                                                  &router_)) {}
+  AXTreeSourceFlutterTest(const AXTreeSourceFlutterTest&) = delete;
+  ~AXTreeSourceFlutterTest() override {
+    EXPECT_CALL(router_, DispatchTreeDestroyedEvent).Times(1);
+  }
+  AXTreeSourceFlutterTest& operator=(const AXTreeSourceFlutterTest&) = delete;
+
+ protected:
+  void CallNotifyAccessibilityEvent(OnAccessibilityEventRequest* event_data) {
+    tree_->NotifyAccessibilityEvent(event_data);
+  }
+
+  void CallGetChildren(SemanticsNode* node,
+                       std::vector<FlutterSemanticsNode*>* out_children) const {
+    FlutterSemanticsNodeWrapper node_data(tree_.get(), node);
+    tree_->GetChildren(&node_data, out_children);
+  }
+
+  void CallSerializeNode(SemanticsNode* node,
+                         std::unique_ptr<ui::AXNodeData>* out_data) const {
+    ASSERT_TRUE(out_data);
+    FlutterSemanticsNodeWrapper node_data(tree_.get(), node);
+    *out_data = std::make_unique<ui::AXNodeData>();
+    tree_->SerializeNode(&node_data, out_data->get());
+  }
+
+  FlutterSemanticsNode* CallGetFromId(int32_t id) const {
+    return tree_->GetFromId(id);
+  }
+
+  bool CallGetTreeData(ui::AXTreeData* data) {
+    return tree_->GetTreeData(data);
+  }
+
+  int GetDispatchedEventCount(ax::mojom::Event type) {
+    return router_.event_count_[type];
+  }
+
+  void SetRect(Rect* rect, int left, int top, int right, int bottom) {
+    rect->set_left(left);
+    rect->set_top(top);
+    rect->set_right(right);
+    rect->set_bottom(bottom);
+  }
+
+  SemanticsNode* AddChild(OnAccessibilityEventRequest* event,
+                          SemanticsNode* parent,
+                          int id,
+                          int x,
+                          int y,
+                          int w,
+                          int h,
+                          bool click) {
+    BooleanProperties* boolean_properties;
+    ActionProperties* action_properties;
+
+    SemanticsNode* new_node = event->add_node_data();
+    new_node->set_node_id(id);
+    Rect* bounds = new_node->mutable_bounds_in_screen();
+    SetRect(bounds, x, y, x + w, y + h);
+    boolean_properties = new_node->mutable_boolean_properties();
+    boolean_properties->set_is_button(click);
+    if (click) {
+      new_node->set_label("Button");
+    }
+    action_properties = new_node->mutable_action_properties();
+    action_properties->set_tap(click);
+
+    parent->add_child_node_ids(id);
+    return new_node;
+  }
+
+ private:
+  void OnAction(const ui::AXActionData& data) override {}
+
+  MockAutomationEventRouter router_;
+  std::unique_ptr<AXTreeSourceFlutter> tree_;
+};
+
+TEST_F(AXTreeSourceFlutterTest, ReorderChildrenByLayout) {
+  BooleanProperties* boolean_properties;
+  ActionProperties* action_properties;
+
+  OnAccessibilityEventRequest event;
+  event.set_source_id(0);
+  event.set_window_id(1);
+  event.set_event_type(OnAccessibilityEventRequest_EventType_FOCUSED);
+
+  //     0
+  //    / \
+  //   1   2
+  SemanticsNode* root = event.add_node_data();
+  root->set_node_id(0);
+  root->add_child_node_ids(1);
+  root->add_child_node_ids(2);
+
+  // Child button 1.
+  SemanticsNode* button1 = event.add_node_data();
+  button1->set_node_id(1);
+  button1->set_label("Button");
+  boolean_properties = button1->mutable_boolean_properties();
+  boolean_properties->set_is_button(true);
+  boolean_properties->set_is_hidden(false);
+  action_properties = button1->mutable_action_properties();
+  action_properties->set_tap(true);
+
+  // Another child button.
+  SemanticsNode* button2 = event.add_node_data();
+  button2->set_node_id(2);
+  button2->set_label("Button");
+  boolean_properties = button2->mutable_boolean_properties();
+  boolean_properties->set_is_button(true);
+  boolean_properties->set_is_hidden(false);
+  action_properties = button2->mutable_action_properties();
+  action_properties->set_tap(true);
+
+  // Non-overlapping: 2
+  //                   1
+  // Expect left(2) to right(1)
+  Rect* bounds1 = button1->mutable_bounds_in_screen();
+  Rect* bounds2 = button2->mutable_bounds_in_screen();
+  SetRect(bounds1, 100, 100, 200, 200);
+  SetRect(bounds2, 0, 0, 50, 50);
+
+  // Trigger an update which refreshes the computed bounds used for reordering.
+  CallNotifyAccessibilityEvent(&event);
+  EXPECT_EQ(1, GetDispatchedEventCount(ax::mojom::Event::kFocus));
+  std::vector<FlutterSemanticsNode*> order;
+  order.clear();
+  CallGetChildren(root, &order);
+  ASSERT_EQ(2U, order.size());
+  EXPECT_EQ(2, order[0]->GetId());
+  EXPECT_EQ(1, order[1]->GetId());
+
+  // Non-overlapping:  2
+  //                  1
+  // Expect left(1) to right(2)
+  SetRect(bounds1, 0, 50, 50, 50);
+  SetRect(bounds2, 100, 0, 200, 200);
+  CallNotifyAccessibilityEvent(&event);
+  EXPECT_EQ(2, GetDispatchedEventCount(ax::mojom::Event::kFocus));
+  order.clear();
+  CallGetChildren(root, &order);
+  ASSERT_EQ(2U, order.size());
+  EXPECT_EQ(1, order[0]->GetId());
+  EXPECT_EQ(2, order[1]->GetId());
+
+  // Non-overlapping: 1
+  //                   2
+  // Expect left(1) to right(2)
+  SetRect(bounds1, 0, 0, 50, 50);
+  SetRect(bounds2, 100, 100, 200, 200);
+  CallNotifyAccessibilityEvent(&event);
+  EXPECT_EQ(3, GetDispatchedEventCount(ax::mojom::Event::kFocus));
+  order.clear();
+  CallGetChildren(root, &order);
+  ASSERT_EQ(2U, order.size());
+  EXPECT_EQ(1, order[0]->GetId());
+  EXPECT_EQ(2, order[1]->GetId());
+
+  // Non-overlapping:  1
+  //                  2
+  // Expect left(2) to right(1)
+  SetRect(bounds1, 100, 0, 200, 50);
+  SetRect(bounds2, 0, 100, 50, 200);
+  CallNotifyAccessibilityEvent(&event);
+  EXPECT_EQ(4, GetDispatchedEventCount(ax::mojom::Event::kFocus));
+  order.clear();
+  CallGetChildren(root, &order);
+  ASSERT_EQ(2U, order.size());
+  EXPECT_EQ(2, order[0]->GetId());
+  EXPECT_EQ(1, order[1]->GetId());
+
+  // Overlapping: Same y, 2_x < 1_x
+  // Expect left(2) to right(1)
+  SetRect(bounds1, 101, 100, 200, 200);
+  SetRect(bounds2, 100, 100, 200, 200);
+  CallNotifyAccessibilityEvent(&event);
+  EXPECT_EQ(5, GetDispatchedEventCount(ax::mojom::Event::kFocus));
+  order.clear();
+  CallGetChildren(root, &order);
+  ASSERT_EQ(2U, order.size());
+  EXPECT_EQ(2, order[0]->GetId());
+  EXPECT_EQ(1, order[1]->GetId());
+
+  // Overlapping: Same y, 1_x < 2_x
+  // Expect left(1) to right(2)
+  SetRect(bounds1, 100, 100, 200, 200);
+  SetRect(bounds2, 101, 100, 200, 200);
+  CallNotifyAccessibilityEvent(&event);
+  EXPECT_EQ(6, GetDispatchedEventCount(ax::mojom::Event::kFocus));
+  order.clear();
+  CallGetChildren(root, &order);
+  ASSERT_EQ(2U, order.size());
+  EXPECT_EQ(1, order[0]->GetId());
+  EXPECT_EQ(2, order[1]->GetId());
+
+  // Overlapping, 1st_x == 2nd_x
+  // Expect top(2) to bottom(1)
+  SetRect(bounds1, 100, 100, 200, 200);
+  SetRect(bounds2, 100, 99, 200, 199);
+  CallNotifyAccessibilityEvent(&event);
+  EXPECT_EQ(7, GetDispatchedEventCount(ax::mojom::Event::kFocus));
+  order.clear();
+  CallGetChildren(root, &order);
+  ASSERT_EQ(2U, order.size());
+  EXPECT_EQ(2, order[0]->GetId());
+  EXPECT_EQ(1, order[1]->GetId());
+
+  // Overlapping, 1st_x > 2nd_x
+  // Expect left(1) to right(2)
+  SetRect(bounds1, 100, 100, 200, 200);
+  SetRect(bounds2, 99, 100, 200, 199);
+  CallNotifyAccessibilityEvent(&event);
+  EXPECT_EQ(8, GetDispatchedEventCount(ax::mojom::Event::kFocus));
+  order.clear();
+  CallGetChildren(root, &order);
+  ASSERT_EQ(2U, order.size());
+  EXPECT_EQ(2, order[0]->GetId());
+  EXPECT_EQ(1, order[1]->GetId());
+
+  // Same top,left,x
+  // Expect larger(2) to smaller(1)
+  SetRect(bounds1, 100, 100, 200, 110);
+  SetRect(bounds2, 100, 100, 200, 200);
+  CallNotifyAccessibilityEvent(&event);
+  EXPECT_EQ(9, GetDispatchedEventCount(ax::mojom::Event::kFocus));
+  order.clear();
+  CallGetChildren(root, &order);
+  ASSERT_EQ(2U, order.size());
+  EXPECT_EQ(2, order[0]->GetId());
+  EXPECT_EQ(1, order[1]->GetId());
+
+  // Same top,left,y
+  // Expect larger(2) to smaller(1)
+  SetRect(bounds1, 100, 100, 110, 200);
+  SetRect(bounds2, 100, 100, 200, 200);
+  CallNotifyAccessibilityEvent(&event);
+  EXPECT_EQ(10, GetDispatchedEventCount(ax::mojom::Event::kFocus));
+  order.clear();
+  CallGetChildren(root, &order);
+  ASSERT_EQ(2U, order.size());
+  EXPECT_EQ(2, order[0]->GetId());
+  EXPECT_EQ(1, order[1]->GetId());
+
+  // Same top,left,x
+  // Expect larger(1) to smaller(2)
+  SetRect(bounds1, 100, 100, 200, 200);
+  SetRect(bounds2, 100, 100, 200, 110);
+  CallNotifyAccessibilityEvent(&event);
+  EXPECT_EQ(11, GetDispatchedEventCount(ax::mojom::Event::kFocus));
+  order.clear();
+  CallGetChildren(root, &order);
+  ASSERT_EQ(2U, order.size());
+  EXPECT_EQ(1, order[0]->GetId());
+  EXPECT_EQ(2, order[1]->GetId());
+
+  // Same top,left,y
+  // Expect larger(1) to smaller(2)
+  SetRect(bounds1, 100, 100, 200, 200);
+  SetRect(bounds2, 100, 100, 110, 200);
+  CallNotifyAccessibilityEvent(&event);
+  EXPECT_EQ(12, GetDispatchedEventCount(ax::mojom::Event::kFocus));
+  order.clear();
+  CallGetChildren(root, &order);
+  ASSERT_EQ(2U, order.size());
+  EXPECT_EQ(1, order[0]->GetId());
+  EXPECT_EQ(2, order[1]->GetId());
+}
+
+// This tree was taken from real tree data. When the enclosing
+// bounds have been computed for children and they don't overlap,
+// we should prefer left to right ordering as it aligns
+// better with the way the UI is laid out. Preferring top
+// to bottom usually results in a strange ordering which
+// may make sense if you knew what the enclosing bounds were
+// but does not behave with what you would expect visually.
+TEST_F(AXTreeSourceFlutterTest, ReorderChildrenByLayoutPreferLeftToRight) {
+  OnAccessibilityEventRequest event;
+
+  event.set_source_id(0);
+  event.set_window_id(1);
+  event.set_event_type(OnAccessibilityEventRequest_EventType_FOCUSED);
+
+  SemanticsNode* root = event.add_node_data();
+  root->set_node_id(0);
+  Rect* bounds = root->mutable_bounds_in_screen();
+  SetRect(bounds, 0, 0, 1280, 800);
+
+  SemanticsNode* child;
+  AddChild(&event, root, 17, 0, 0, 422, 800, true);
+
+  child = AddChild(&event, root, 29, 1022, 0, 257, 800, false);
+  child = AddChild(&event, child, 30, 1022, 55, 257, 690, true);
+  AddChild(&event, child, 31, 1232, 165, 47, 150, false);
+  AddChild(&event, child, 32, 1232, 165, 47, 150, false);
+
+  child = AddChild(&event, root, 18, 422, 0, 600, 800, false);
+  child = AddChild(&event, child, 19, 422, 55, 570, 690, false);
+  AddChild(&event, child, 20, 507, 95, 445, 40, false);
+  AddChild(&event, child, 21, 463, 186, 488, 70, true);
+  AddChild(&event, child, 22, 463, 283, 488, 70, true);
+  AddChild(&event, child, 23, 463, 381, 488, 70, true);
+  AddChild(&event, child, 24, 463, 478, 488, 70, true);
+
+  // Enclosing bounds for 29 end up being smaller y
+  // than enclosing bounds for 18 but 18 is left of 29
+  // so order should be 17,18,29
+
+  CallNotifyAccessibilityEvent(&event);
+  EXPECT_EQ(1, GetDispatchedEventCount(ax::mojom::Event::kFocus));
+  std::vector<FlutterSemanticsNode*> ordered;
+  CallGetChildren(root, &ordered);
+  ASSERT_EQ(3U, ordered.size());
+  EXPECT_EQ(17, ordered[0]->GetId());
+  EXPECT_EQ(18, ordered[1]->GetId());
+  EXPECT_EQ(29, ordered[2]->GetId());
+}
+
+TEST_F(AXTreeSourceFlutterTest, AccessibleNameComputation) {
+  ActionProperties* action_properties;
+
+  OnAccessibilityEventRequest event;
+  event.set_source_id(0);
+  event.set_window_id(1);
+  event.set_event_type(OnAccessibilityEventRequest_EventType_FOCUSED);
+
+  //     0
+  //    / \
+  //   1   2
+  SemanticsNode* root = event.add_node_data();
+  root->set_node_id(0);
+  root->add_child_node_ids(1);
+  root->add_child_node_ids(2);
+
+  // Child.
+  SemanticsNode* child1 = event.add_node_data();
+  child1->set_node_id(1);
+
+  // Another child.
+  SemanticsNode* child2 = event.add_node_data();
+  child2->set_node_id(2);
+
+  // Populate the tree source with the data.
+  CallNotifyAccessibilityEvent(&event);
+  EXPECT_EQ(1, GetDispatchedEventCount(ax::mojom::Event::kFocus));
+
+  // No attributes.
+  std::unique_ptr<ui::AXNodeData> data;
+  CallSerializeNode(root, &data);
+  std::string name;
+  ASSERT_FALSE(
+      data->GetStringAttribute(ax::mojom::StringAttribute::kName, &name));
+  EXPECT_EQ("", name);
+
+  // Label (empty).
+  root->set_label("");
+  CallSerializeNode(root, &data);
+  ASSERT_TRUE(
+      data->GetStringAttribute(ax::mojom::StringAttribute::kName, &name));
+  EXPECT_EQ("", name);
+
+  // Label (non-empty).
+  root->set_label("label text");
+  CallSerializeNode(root, &data);
+  ASSERT_TRUE(
+      data->GetStringAttribute(ax::mojom::StringAttribute::kName, &name));
+  EXPECT_EQ("label text", name);
+
+  // Hint (empty), Label (non-empty).
+  root->set_hint("");
+  CallSerializeNode(root, &data);
+  ASSERT_TRUE(
+      data->GetStringAttribute(ax::mojom::StringAttribute::kName, &name));
+  EXPECT_EQ("label text", name);
+
+  // Hint (non-empty), Label (empty).
+  root->set_hint("hint");
+  root->clear_label();
+  CallSerializeNode(root, &data);
+  ASSERT_TRUE(
+      data->GetStringAttribute(ax::mojom::StringAttribute::kName, &name));
+  EXPECT_EQ("hint", name);
+
+  // Name from contents.
+
+  // Root node has no name, but has descendants with name.
+  root->clear_hint();
+  root->clear_label();
+  // Name from contents only happens if a node is clickable.
+  action_properties = root->mutable_action_properties();
+  action_properties->set_tap(true);
+  child1->set_label("child1 label text");
+  child2->set_label("child2 label text");
+  CallSerializeNode(root, &data);
+  ASSERT_TRUE(
+      data->GetStringAttribute(ax::mojom::StringAttribute::kName, &name));
+  ASSERT_EQ("child1 label text child2 label text", name);
+
+  // If the node has a name, it should override the contents.
+  root->set_label("root label text");
+  CallSerializeNode(root, &data);
+  ASSERT_TRUE(
+      data->GetStringAttribute(ax::mojom::StringAttribute::kName, &name));
+  ASSERT_EQ("root label text", name);
+
+  // Clearing both clickable and name from root, the name should not be
+  // populated.
+  root->clear_label();
+  action_properties->clear_tap();
+  CallSerializeNode(root, &data);
+  ASSERT_FALSE(
+      data->GetStringAttribute(ax::mojom::StringAttribute::kName, &name));
+}
+
+// Flutter's 'hidden' attribute should not translate to the node being
+// ignored or in any way not a11y focusable.
+TEST_F(AXTreeSourceFlutterTest, NeverHidden) {
+  OnAccessibilityEventRequest event;
+  event.set_source_id(0);
+  event.set_window_id(1);
+  event.set_event_type(OnAccessibilityEventRequest_EventType_FOCUSED);
+
+  BooleanProperties* boolean_properties;
+  SemanticsNode* root = event.add_node_data();
+  root->add_child_node_ids(1);
+  SemanticsNode* child1 = event.add_node_data();
+  child1->set_node_id(1);
+  child1->set_label("some label text");
+  boolean_properties = child1->mutable_boolean_properties();
+  boolean_properties->set_is_hidden(true);
+
+  CallNotifyAccessibilityEvent(&event);
+  EXPECT_EQ(1, GetDispatchedEventCount(ax::mojom::Event::kFocus));
+
+  std::unique_ptr<ui::AXNodeData> data;
+  CallSerializeNode(child1, &data);
+
+  ASSERT_TRUE(data->role == ax::mojom::Role::kStaticText);
+  ASSERT_FALSE(data->HasState(ax::mojom::State::kInvisible));
+}
+
+TEST_F(AXTreeSourceFlutterTest, GetTreeDataAppliesFocus) {
+  OnAccessibilityEventRequest event;
+  event.set_source_id(5);
+  event.set_window_id(1);
+  event.set_event_type(OnAccessibilityEventRequest_EventType_FOCUSED);
+
+  SemanticsNode* root = event.add_node_data();
+  root->set_node_id(5);
+
+  CallNotifyAccessibilityEvent(&event);
+  EXPECT_EQ(1, GetDispatchedEventCount(ax::mojom::Event::kFocus));
+  ui::AXTreeData data;
+
+  // If no node claimed focus, the root node should get it.
+  EXPECT_TRUE(CallGetTreeData(&data));
+  EXPECT_EQ(5, data.focus_id);
+
+  // Add a child node with focus.
+  root->add_child_node_ids(6);
+  SemanticsNode* child = event.add_node_data();
+  child->set_node_id(6);
+  child->mutable_boolean_properties()->set_is_focused(true);
+
+  CallNotifyAccessibilityEvent(&event);
+  EXPECT_EQ(2, GetDispatchedEventCount(ax::mojom::Event::kFocus));
+
+  EXPECT_TRUE(CallGetTreeData(&data));
+  EXPECT_EQ(6, data.focus_id);
+}
+
+TEST_F(AXTreeSourceFlutterTest, LiveRegion) {
+  OnAccessibilityEventRequest event;
+  event.set_source_id(1);
+  event.set_window_id(1);
+  event.set_event_type(OnAccessibilityEventRequest_EventType_FOCUSED);
+
+  SemanticsNode* root = event.add_node_data();
+  root->set_node_id(10);
+  root->add_child_node_ids(1);
+  root->add_child_node_ids(2);
+  BooleanProperties* boolean_properties = root->mutable_boolean_properties();
+  boolean_properties->set_is_live_region(true);
+
+  // Add child nodes.
+  SemanticsNode* node1 = event.add_node_data();
+  node1->set_node_id(1);
+  node1->set_label("text 1");
+
+  SemanticsNode* node2 = event.add_node_data();
+  node2->set_node_id(2);
+  node2->set_label("text 2");
+
+  CallNotifyAccessibilityEvent(&event);
+  EXPECT_EQ(1, GetDispatchedEventCount(ax::mojom::Event::kFocus));
+
+  std::unique_ptr<ui::AXNodeData> data;
+  CallSerializeNode(root, &data);
+  std::string status;
+  ASSERT_TRUE(data->GetStringAttribute(
+      ax::mojom::StringAttribute::kContainerLiveStatus, &status));
+  ASSERT_EQ(status, "polite");
+
+  EXPECT_EQ(0, GetDispatchedEventCount(ax::mojom::Event::kLiveRegionChanged));
+
+  // Modify text of node1.
+  node1->set_label("modified text 1");
+  CallNotifyAccessibilityEvent(&event);
+
+  EXPECT_EQ(1, GetDispatchedEventCount(ax::mojom::Event::kLiveRegionChanged));
+}
+
+TEST_F(AXTreeSourceFlutterTest, ResetFocus) {
+  //
+  // tree 1: no child tree
+  //
+  OnAccessibilityEventRequest event;
+
+  event.set_source_id(0);
+  event.set_window_id(1);
+  event.set_event_type(OnAccessibilityEventRequest_EventType_FOCUSED);
+
+  SemanticsNode* root = event.add_node_data();
+  root->set_node_id(0);
+  Rect* bounds = root->mutable_bounds_in_screen();
+  SetRect(bounds, 0, 0, 1280, 800);
+
+  SemanticsNode* child;
+  AddChild(&event, root, 1, 0, 0, 800, 600, false);
+
+  child = AddChild(&event, root, 2, 0, 0, 400, 600, false);
+  child = AddChild(&event, root, 3, 400, 0, 400, 600, false);
+
+  CallNotifyAccessibilityEvent(&event);
+
+  // initial focus on root
+  ui::AXTreeData tree_data;
+  CallGetTreeData(&tree_data);
+  ASSERT_EQ(0, tree_data.focus_id);
+
+  //
+  // tree 2: add a node with a child tree id
+  //
+  OnAccessibilityEventRequest event2;
+
+  event2.set_source_id(0);
+  event2.set_window_id(1);
+  event2.set_event_type(OnAccessibilityEventRequest_EventType_FOCUSED);
+
+  SemanticsNode* root2 = event2.add_node_data();
+  root2->set_node_id(0);
+  Rect* bounds2 = root2->mutable_bounds_in_screen();
+  SetRect(bounds2, 0, 0, 1280, 800);
+
+  AddChild(&event2, root2, 1, 0, 0, 800, 600, false);
+
+  child = AddChild(&event2, root2, 2, 0, 0, 400, 600, false);
+  child = AddChild(&event2, root2, 3, 400, 0, 400, 600, false);
+  child = AddChild(&event2, root2, 4, 0, 0, 200, 200, false);
+  child->set_plugin_id("1234");
+
+  // focus should move to node with child tree
+  CallNotifyAccessibilityEvent(&event2);
+  CallGetTreeData(&tree_data);
+  ASSERT_EQ(4, tree_data.focus_id);
+
+  //
+  // tree 2: back to initial tree
+  //
+  CallNotifyAccessibilityEvent(&event);
+  CallGetTreeData(&tree_data);
+
+  // focus back to root
+  ASSERT_EQ(0, tree_data.focus_id);
+}
+
+}  // namespace accessibility
+}  // namespace chromecast
diff --git a/chromecast/browser/accessibility/flutter/flutter_accessibility_helper_bridge.cc b/chromecast/browser/accessibility/flutter/flutter_accessibility_helper_bridge.cc
new file mode 100644
index 0000000..b166f61e
--- /dev/null
+++ b/chromecast/browser/accessibility/flutter/flutter_accessibility_helper_bridge.cc
@@ -0,0 +1,196 @@
+// 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 "chromecast/browser/accessibility/flutter/flutter_accessibility_helper_bridge.h"
+
+#include <utility>
+
+#include "base/task/post_task.h"
+#include "chromecast/browser/accessibility/accessibility_manager.h"
+#include "chromecast/browser/accessibility/proto/gallium_server_accessibility.grpc.pb.h"
+#include "chromecast/browser/cast_browser_process.h"
+#include "components/exo/fullscreen_shell_surface.h"
+#include "components/exo/shell_surface_util.h"
+#include "components/exo/surface.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "ui/accessibility/aura/aura_window_properties.h"
+#include "ui/accessibility/ax_action_data.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
+
+namespace chromecast {
+namespace gallium {
+namespace accessibility {
+
+using ::gallium::castos::
+    OnAccessibilityActionRequest_AccessibilityActionType_CUSTOM_ACTION;
+using ::gallium::castos::
+    // NOLINTNEXTLINE(whitespace/line_length)
+    OnAccessibilityActionRequest_AccessibilityActionType_DID_GAIN_ACCESSIBILITY_FOCUS;
+using ::gallium::castos::
+    // NOLINTNEXTLINE(whitespace/line_length)
+    OnAccessibilityActionRequest_AccessibilityActionType_DID_LOSE_ACCESSIBILITY_FOCUS;
+using ::gallium::castos::
+    OnAccessibilityActionRequest_AccessibilityActionType_SCROLL_DOWN;
+using ::gallium::castos::
+    OnAccessibilityActionRequest_AccessibilityActionType_SCROLL_LEFT;
+using ::gallium::castos::
+    OnAccessibilityActionRequest_AccessibilityActionType_SCROLL_RIGHT;
+using ::gallium::castos::
+    OnAccessibilityActionRequest_AccessibilityActionType_SCROLL_UP;
+using ::gallium::castos::
+    OnAccessibilityActionRequest_AccessibilityActionType_SET_SELECTION;
+using ::gallium::castos::
+    OnAccessibilityActionRequest_AccessibilityActionType_SHOW_ON_SCREEN;
+using ::gallium::castos::
+    OnAccessibilityActionRequest_AccessibilityActionType_TAP;
+
+FlutterAccessibilityHelperBridge::FlutterAccessibilityHelperBridge(
+    Delegate* bridge_delegate,
+    content::BrowserContext* browser_context)
+    : tree_source_(
+          std::make_unique<AXTreeSourceFlutter>(this, browser_context)),
+      bridge_delegate_(bridge_delegate) {}
+
+FlutterAccessibilityHelperBridge::~FlutterAccessibilityHelperBridge() = default;
+
+void FlutterAccessibilityHelperBridge::AccessibilityStateChanged(bool value) {
+  if (value) {
+    aura::Window* window = chromecast::shell::CastBrowserProcess::GetInstance()
+                               ->accessibility_manager()
+                               ->window_tree_host()
+                               ->window();
+
+    // Find the full screen shell surface for the exo::Surface representing
+    // the ui.  We must ensure our tree id is the child ax tree id for
+    // that view so when the root window is serialized, the flutter ax tree
+    // will be parented by that view.
+    bool found = false;
+    if (window) {
+      for (aura::Window* child : window->children()) {
+        exo::Surface* surface = exo::GetShellMainSurface(child);
+        if (surface) {
+          views::Widget* widget =
+              views::Widget::GetWidgetForNativeWindow(child);
+          if (widget) {
+            exo::FullscreenShellSurface* full_screen_shell_surface =
+                static_cast<exo::FullscreenShellSurface*>(
+                    widget->widget_delegate());
+            full_screen_shell_surface->SetChildAxTreeId(
+                tree_source_->ax_tree_id());
+            full_screen_shell_surface->GetContentsView()
+                ->NotifyAccessibilityEvent(ax::mojom::Event::kChildrenChanged,
+                                           false);
+            child->Focus();
+            found = true;
+          }
+          break;
+        }
+      }
+    }
+
+    if (!found) {
+      LOG(ERROR) << "Could not find full screen shell surface for ax tree.";
+    }
+  }
+}
+
+void FlutterAccessibilityHelperBridge::OnAccessibilityEventRequestInternal(
+    std::unique_ptr<::gallium::castos::OnAccessibilityEventRequest>
+        event_data) {
+  // Tell the tree source to serialize these changes.
+  tree_source_->NotifyAccessibilityEvent(event_data.get());
+}
+
+bool FlutterAccessibilityHelperBridge::OnAccessibilityEventRequest(
+    const ::gallium::castos::OnAccessibilityEventRequest* event_data) {
+  std::unique_ptr<::gallium::castos::OnAccessibilityEventRequest> event =
+      std::make_unique<::gallium::castos::OnAccessibilityEventRequest>(
+          *event_data);
+
+  base::PostTask(FROM_HERE, {content::BrowserThread::UI},
+                 base::BindOnce(&FlutterAccessibilityHelperBridge::
+                                    OnAccessibilityEventRequestInternal,
+                                base::Unretained(this), std::move(event)));
+  return true;
+}
+
+void FlutterAccessibilityHelperBridge::OnAction(const ui::AXActionData& data) {
+  // Called by tree source to dispatch ax action to flutter. Translate this
+  // to gallium accessibility proto and forward to the delegate for
+  // dispatching.
+  ::gallium::castos::OnAccessibilityActionRequest request;
+  request.set_node_id(data.target_node_id);
+
+  switch (data.action) {
+    case ax::mojom::Action::kDoDefault:
+      request.set_action_type(
+          OnAccessibilityActionRequest_AccessibilityActionType_TAP);
+      break;
+    case ax::mojom::Action::kScrollToMakeVisible:
+      request.set_action_type(
+          OnAccessibilityActionRequest_AccessibilityActionType_SHOW_ON_SCREEN);
+      break;
+    case ax::mojom::Action::kScrollBackward:
+      request.set_action_type(
+          OnAccessibilityActionRequest_AccessibilityActionType_SCROLL_LEFT);
+      break;
+    case ax::mojom::Action::kScrollForward:
+      request.set_action_type(
+          OnAccessibilityActionRequest_AccessibilityActionType_SCROLL_RIGHT);
+      break;
+    case ax::mojom::Action::kScrollUp:
+      request.set_action_type(
+          OnAccessibilityActionRequest_AccessibilityActionType_SCROLL_UP);
+      break;
+    case ax::mojom::Action::kScrollDown:
+      request.set_action_type(
+          OnAccessibilityActionRequest_AccessibilityActionType_SCROLL_DOWN);
+      break;
+    case ax::mojom::Action::kScrollLeft:
+      request.set_action_type(
+          OnAccessibilityActionRequest_AccessibilityActionType_SCROLL_LEFT);
+      break;
+    case ax::mojom::Action::kScrollRight:
+      request.set_action_type(
+          OnAccessibilityActionRequest_AccessibilityActionType_SCROLL_RIGHT);
+      break;
+    case ax::mojom::Action::kCustomAction:
+      request.set_action_type(
+          OnAccessibilityActionRequest_AccessibilityActionType_CUSTOM_ACTION);
+      request.set_custom_action_id(data.custom_action_id);
+      break;
+    case ax::mojom::Action::kSetAccessibilityFocus:
+      request.set_action_type(
+          // NOLINTNEXTLINE(whitespace/line_length)
+          OnAccessibilityActionRequest_AccessibilityActionType_DID_GAIN_ACCESSIBILITY_FOCUS);
+      break;
+    case ax::mojom::Action::kClearAccessibilityFocus:
+      request.set_action_type(
+          // NOLINTNEXTLINE(whitespace/line_length)
+          OnAccessibilityActionRequest_AccessibilityActionType_DID_LOSE_ACCESSIBILITY_FOCUS);
+      break;
+    case ax::mojom::Action::kGetTextLocation:
+      request.set_action_type(
+          OnAccessibilityActionRequest_AccessibilityActionType_SET_SELECTION);
+      request.set_start_index(data.start_index);
+      request.set_end_index(data.end_index);
+      break;
+    default:
+      LOG(WARNING) << "Cast ax action " << data.action
+                   << " not mapped to flutter action - dropped.";
+
+      return;
+  }
+
+  bridge_delegate_->SendAccessibilityAction(request);
+}
+
+}  // namespace accessibility
+}  // namespace gallium
+}  // namespace chromecast
diff --git a/chromecast/browser/accessibility/flutter/flutter_accessibility_helper_bridge.h b/chromecast/browser/accessibility/flutter/flutter_accessibility_helper_bridge.h
new file mode 100644
index 0000000..8b902cba
--- /dev/null
+++ b/chromecast/browser/accessibility/flutter/flutter_accessibility_helper_bridge.h
@@ -0,0 +1,74 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMECAST_BROWSER_ACCESSIBILITY_FLUTTER_FLUTTER_ACCESSIBILITY_HELPER_BRIDGE_H_
+#define CHROMECAST_BROWSER_ACCESSIBILITY_FLUTTER_FLUTTER_ACCESSIBILITY_HELPER_BRIDGE_H_
+
+#include <memory>
+
+#include "chromecast/browser/accessibility/flutter/ax_tree_source_flutter.h"
+
+using chromecast::accessibility::AXTreeSourceFlutter;
+
+namespace content {
+class BrowserContext;
+}  // namespace content
+
+namespace gallium {
+namespace castos {
+class OnAccessibilityEventRequest;
+class OnAccessibilityActionRequest;
+}  // namespace castos
+}  // namespace gallium
+
+namespace chromecast {
+namespace gallium {
+namespace accessibility {
+
+// FlutterAccessibilityHelperBridge receives Flutter accessibility
+// events from gallium, translates them to chrome tree updates and dispatches
+// them to chromecast accessibility services.
+class FlutterAccessibilityHelperBridge : public AXTreeSourceFlutter::Delegate {
+ public:
+  class Delegate {
+   public:
+    virtual void SendAccessibilityAction(
+        ::gallium::castos::OnAccessibilityActionRequest request) = 0;
+
+   protected:
+    virtual ~Delegate() = default;
+  };
+
+  FlutterAccessibilityHelperBridge(Delegate* bridge_delegate,
+                                   content::BrowserContext* browser_context);
+  FlutterAccessibilityHelperBridge(const FlutterAccessibilityHelperBridge&) =
+      delete;
+  ~FlutterAccessibilityHelperBridge() override;
+  FlutterAccessibilityHelperBridge& operator=(
+      const FlutterAccessibilityHelperBridge&) = delete;
+
+  // Receive an accessibility event from flutter.
+  bool OnAccessibilityEventRequest(
+      const ::gallium::castos::OnAccessibilityEventRequest* event_data);
+
+  // AXTreeSourceArc::Delegate implementation:
+  // Dispatch a chrome accessibility action to flutter.
+  void OnAction(const ui::AXActionData& data) override;
+
+  void AccessibilityStateChanged(bool value);
+
+ private:
+  void OnAccessibilityEventRequestInternal(
+      std::unique_ptr<::gallium::castos::OnAccessibilityEventRequest>
+          event_data);
+
+  std::unique_ptr<AXTreeSourceFlutter> tree_source_;
+  Delegate* bridge_delegate_;
+};
+
+}  // namespace accessibility
+}  // namespace gallium
+}  // namespace chromecast
+
+#endif  // CHROMECAST_BROWSER_ACCESSIBILITY_FLUTTER_FLUTTER_ACCESSIBILITY_HELPER_BRIDGE_H_
diff --git a/chromecast/browser/accessibility/flutter/flutter_semantics_node.h b/chromecast/browser/accessibility/flutter/flutter_semantics_node.h
new file mode 100644
index 0000000..e140adca
--- /dev/null
+++ b/chromecast/browser/accessibility/flutter/flutter_semantics_node.h
@@ -0,0 +1,50 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMECAST_BROWSER_ACCESSIBILITY_FLUTTER_FLUTTER_SEMANTICS_NODE_H_
+#define CHROMECAST_BROWSER_ACCESSIBILITY_FLUTTER_FLUTTER_SEMANTICS_NODE_H_
+
+#include <ui/gfx/geometry/rect.h>
+
+#include <string>
+#include <vector>
+
+namespace ui {
+struct AXNodeData;
+}  // namespace ui
+
+namespace chromecast {
+namespace accessibility {
+
+// FlutterSemanticsNode represents a single flutter semantics object from
+// flutter. This class is used by AXTreeSourceFlutter to encapsulate
+// flutter information which maps to a single AXNodeData.
+class FlutterSemanticsNode {
+ public:
+  virtual ~FlutterSemanticsNode() = default;
+
+  virtual int32_t GetId() const = 0;
+  virtual const gfx::Rect GetBounds() const = 0;
+  virtual bool IsVisibleToUser() const = 0;
+  virtual bool IsFocused() const = 0;
+  virtual bool IsLiveRegion() const = 0;
+  virtual bool IsRapidChangingSlider() const = 0;
+  virtual bool CanBeAccessibilityFocused() const = 0;
+  virtual void PopulateAXRole(ui::AXNodeData* out_data) const = 0;
+  virtual void PopulateAXState(ui::AXNodeData* out_data) const = 0;
+  virtual void Serialize(ui::AXNodeData* out_data) const = 0;
+  virtual void GetChildren(
+      std::vector<FlutterSemanticsNode*>* children) const = 0;
+  virtual void ComputeNameFromContents(
+      std::vector<std::string>* names) const = 0;
+  virtual bool HasLabelHint() const = 0;
+  virtual std::string GetLabelHint() const = 0;
+  virtual bool HasValue() const = 0;
+  virtual std::string GetValue() const = 0;
+};
+
+}  // namespace accessibility
+}  // namespace chromecast
+
+#endif  // CHROMECAST_BROWSER_ACCESSIBILITY_FLUTTER_FLUTTER_SEMANTICS_NODE_H_
diff --git a/chromecast/browser/accessibility/flutter/flutter_semantics_node_wrapper.cc b/chromecast/browser/accessibility/flutter/flutter_semantics_node_wrapper.cc
new file mode 100644
index 0000000..e08501a8
--- /dev/null
+++ b/chromecast/browser/accessibility/flutter/flutter_semantics_node_wrapper.cc
@@ -0,0 +1,594 @@
+// 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 "chromecast/browser/accessibility/flutter/flutter_semantics_node_wrapper.h"
+
+#include "base/check.h"
+#include "base/strings/string_util.h"
+#include "chromecast/browser/accessibility/flutter/ax_tree_source_flutter.h"
+#include "chromecast/browser/cast_web_contents.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
+#include "ui/accessibility/ax_tree_id_registry.h"
+
+using gallium::castos::ActionProperties;
+using gallium::castos::BooleanProperties;
+
+namespace chromecast {
+namespace accessibility {
+
+FlutterSemanticsNodeWrapper::FlutterSemanticsNodeWrapper(
+    AXTreeSourceFlutter* tree_source,
+    const SemanticsNode* node)
+    : tree_source_(tree_source), node_ptr_(node) {
+  DCHECK(tree_source_);
+  DCHECK(node_ptr_);
+}
+
+int32_t FlutterSemanticsNodeWrapper::GetId() const {
+  return node_ptr_->node_id();
+}
+
+const gfx::Rect FlutterSemanticsNodeWrapper::GetBounds() const {
+  if (node_ptr_->has_bounds_in_screen()) {
+    return gfx::Rect(node_ptr_->bounds_in_screen().left(),
+                     node_ptr_->bounds_in_screen().top(),
+                     node_ptr_->bounds_in_screen().right() -
+                         node_ptr_->bounds_in_screen().left(),
+                     node_ptr_->bounds_in_screen().bottom() -
+                         node_ptr_->bounds_in_screen().top());
+  }
+  return gfx::Rect(0, 0, 0, 0);
+}
+
+bool FlutterSemanticsNodeWrapper::IsVisibleToUser() const {
+  if (node_ptr_->has_boolean_properties()) {
+    const BooleanProperties& boolean_properties =
+        node_ptr_->boolean_properties();
+    return !boolean_properties.is_hidden();
+  }
+  return true;
+}
+
+bool FlutterSemanticsNodeWrapper::IsFocused() const {
+  if (node_ptr_->has_boolean_properties()) {
+    const BooleanProperties& boolean_properties =
+        node_ptr_->boolean_properties();
+    return boolean_properties.is_focused();
+  }
+  return false;
+}
+
+bool FlutterSemanticsNodeWrapper::IsLiveRegion() const {
+  const BooleanProperties& boolean_properties = node_ptr_->boolean_properties();
+  return boolean_properties.is_live_region();
+}
+
+bool FlutterSemanticsNodeWrapper::CanBeAccessibilityFocused() const {
+  // In Chrome, this means:
+  // a node with a non-generic role and:
+  // actionable nodes or top level scrollables with a name
+  ui::AXNodeData data;
+  PopulateAXRole(&data);
+  bool non_generic_role = data.role != ax::mojom::Role::kGenericContainer &&
+                          data.role != ax::mojom::Role::kGroup;
+  bool actionable = node_ptr_->action_properties().tap() ||
+                    node_ptr_->action_properties().long_press();
+  bool top_level_scrollable =
+      HasLabelHint() && (node_ptr_->action_properties().scroll_up() ||
+                         node_ptr_->action_properties().scroll_down() ||
+                         node_ptr_->action_properties().scroll_left() ||
+                         node_ptr_->action_properties().scroll_right());
+  return non_generic_role && (actionable || top_level_scrollable);
+}
+
+void FlutterSemanticsNodeWrapper::PopulateAXRole(
+    ui::AXNodeData* out_data) const {
+  const BooleanProperties& boolean_properties = node_ptr_->boolean_properties();
+  const ActionProperties& action_properties = node_ptr_->action_properties();
+
+  if (boolean_properties.is_text_field()) {
+    out_data->role = ax::mojom::Role::kTextField;
+    return;
+  }
+
+  if (boolean_properties.is_header()) {
+    out_data->role = ax::mojom::Role::kHeading;
+    return;
+  }
+
+  // b/148808637: Flutter allows buttons to be containers but ChromeVox
+  // expects buttons to be atomic.  If we allow this node to be marked a
+  // button and it contains other clickable nodes, none of those nodes will
+  // be focusable by the user. This means no button that is also a
+  // container of other actionable items will ever be read as 'button'
+  // by the screen reader.  However, buttons that have no actionable
+  // descendants will still say 'Button' as expected.
+  if (boolean_properties.is_button() && !AnyChildIsActionable() &&
+      HasLabelHint() && GetLabelHint().length() > 0) {
+    out_data->role = ax::mojom::Role::kButton;
+    return;
+  }
+
+  if (boolean_properties.is_image() &&
+      node_ptr_->child_node_ids().size() == 0) {
+    out_data->role = ax::mojom::Role::kImage;
+    return;
+  }
+
+  if (action_properties.increase() || action_properties.decrease()) {
+    out_data->role = ax::mojom::Role::kSlider;
+    return;
+  }
+
+  bool has_checked_state = boolean_properties.has_checked_state();
+  bool has_toggled_state = boolean_properties.has_toggled_state();
+
+  if (has_checked_state) {
+    if (boolean_properties.is_in_mutually_exclusive_group()) {
+      out_data->role = ax::mojom::Role::kRadioButton;
+    } else {
+      out_data->role = ax::mojom::Role::kCheckBox;
+    }
+    return;
+  }
+  if (has_toggled_state) {
+    out_data->role = ax::mojom::Role::kSwitch;
+    return;
+  }
+
+  // b/149934151 : Flutter sends us nodes with labels that
+  // have children. Don't mark these as static text or
+  // no children will ever be focused properly via swipe
+  // navigation. Only nodes that have labels with no children
+  // should get the static text role. Use kHeader role
+  // instead as it is allowed to be a container.
+  if (HasLabelHint() && GetLabelHint().length() > 0) {
+    if (node_ptr_->child_node_ids().size() == 0) {
+      if (HasTapOrPress()) {
+        out_data->role = ax::mojom::Role::kButton;
+      } else {
+        out_data->role = ax::mojom::Role::kStaticText;
+      }
+    } else {
+      if (IsListItem()) {
+        out_data->role = ax::mojom::Role::kListBoxOption;
+      } else {
+        out_data->role = ax::mojom::Role::kHeader;
+      }
+    }
+    return;
+  }
+
+  if (node_ptr_->scroll_children() > 0) {
+    out_data->role = ax::mojom::Role::kList;
+    return;
+  }
+
+  out_data->role = ax::mojom::Role::kGenericContainer;
+}
+
+FlutterSemanticsNodeWrapper* FlutterSemanticsNodeWrapper::IsListItem() const {
+  // To consider it a list item, the node has to have a ancestor that has scroll
+  // children.
+  std::vector<FlutterSemanticsNodeWrapper*> ancestors;
+  FlutterSemanticsNodeWrapper* node = static_cast<FlutterSemanticsNodeWrapper*>(
+      tree_source_->GetFromId(GetId()));
+
+  while (node) {
+    FlutterSemanticsNodeWrapper* parent =
+        static_cast<FlutterSemanticsNodeWrapper*>(
+            tree_source_->GetParent(node));
+    if (parent)
+      ancestors.push_back(parent);
+    node = parent;
+  }
+
+  // |ancestors| is with order from closest ancestor to root. Find the closest
+  // ancestor that has scroll children and in between there is no actionable
+  // nodes.
+  for (FlutterSemanticsNodeWrapper* ancestor : ancestors) {
+    if (!ancestor->IsActionable()) {
+      if (ancestor->node()->scroll_children() > 0) {
+        return ancestor;
+      }
+    } else {
+      break;
+    }
+  }
+
+  return nullptr;
+}
+
+void FlutterSemanticsNodeWrapper::GetActionableChildren(
+    std::vector<FlutterSemanticsNodeWrapper*>* out_children) const {
+  std::vector<FlutterSemanticsNode*> children;
+  GetChildren(&children);
+
+  for (FlutterSemanticsNode* child : children) {
+    FlutterSemanticsNodeWrapper* child_wrapper =
+        static_cast<FlutterSemanticsNodeWrapper*>(child);
+
+    if (child_wrapper->HasTapOrPress() ||
+        child_wrapper->AnyChildIsActionable()) {
+      out_children->push_back(child_wrapper);
+    }
+  }
+}
+
+bool FlutterSemanticsNodeWrapper::IsDescendant(
+    FlutterSemanticsNodeWrapper* ancestor) const {
+  FlutterSemanticsNodeWrapper* parent =
+      static_cast<FlutterSemanticsNodeWrapper*>(
+          tree_source_->GetParent(tree_source_->GetFromId(GetId())));
+
+  while (parent) {
+    if (parent == ancestor)
+      return true;
+    parent = static_cast<FlutterSemanticsNodeWrapper*>(
+        tree_source_->GetParent(parent));
+  }
+
+  return false;
+}
+
+bool FlutterSemanticsNodeWrapper::IsRapidChangingSlider() const {
+  return (node_ptr_->scroll_extent_min() || node_ptr_->scroll_extent_min() ||
+          node_ptr_->action_properties().increase() ||
+          node_ptr_->action_properties().decrease());
+}
+
+void FlutterSemanticsNodeWrapper::PopulateAXState(
+    ui::AXNodeData* out_data) const {
+  const BooleanProperties& boolean_properties = node_ptr_->boolean_properties();
+
+  if (boolean_properties.is_obscured()) {
+    out_data->AddState(ax::mojom::State::kProtected);
+  }
+
+  if (boolean_properties.is_text_field()) {
+    out_data->AddState(ax::mojom::State::kEditable);
+  }
+
+  if (IsFocusable()) {
+    out_data->AddState(ax::mojom::State::kFocusable);
+  }
+
+  if (boolean_properties.has_checked_state()) {
+    out_data->SetCheckedState(boolean_properties.is_checked()
+                                  ? ax::mojom::CheckedState::kTrue
+                                  : ax::mojom::CheckedState::kFalse);
+  }
+
+  if (boolean_properties.has_toggled_state()) {
+    out_data->SetCheckedState(boolean_properties.is_toggled()
+                                  ? ax::mojom::CheckedState::kTrue
+                                  : ax::mojom::CheckedState::kFalse);
+  }
+
+  // Put this back after b/148875421 is resolved. Flutter is sending
+  // many elements with a disabled flag which causes the reader to
+  // speak 'Disabled' even though it is not.
+  // if (!boolean_properties.is_enabled()) {
+  // out_data->SetRestriction(ax::mojom::Restriction::kDisabled);
+  //}
+}
+
+void FlutterSemanticsNodeWrapper::Serialize(ui::AXNodeData* out_data) const {
+  PopulateAXState(out_data);
+
+  const BooleanProperties& boolean_properties = node_ptr_->boolean_properties();
+  const ActionProperties& action_properties = node_ptr_->action_properties();
+
+  // b/162311902: For nodes that have scroll extents and can be changed rapidly,
+  // set the name as empty so that ChromeVox will skip speaking them.
+  if (IsRapidChangingSlider()) {
+    out_data->SetName("");
+  } else if (HasLabelHint()) {
+    out_data->SetName(GetLabelHint());
+  } else if (IsActionable()) {
+    // Compute the name by joining all nodes with names.
+    std::vector<std::string> names;
+    ComputeNameFromContents(&names);
+    if (!names.empty())
+      out_data->SetName(base::JoinString(names, " "));
+  }
+
+  if (HasValue()) {
+    out_data->SetValue(GetValue());
+  }
+
+  out_data->AddBoolAttribute(ax::mojom::BoolAttribute::kClickable,
+                             IsActionable());
+  out_data->AddBoolAttribute(ax::mojom::BoolAttribute::kScrollable,
+                             IsScrollable());
+
+  if (boolean_properties.is_selected()) {
+    out_data->AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+  }
+
+  if (node_ptr_->has_hint()) {
+    out_data->AddStringAttribute(ax::mojom::StringAttribute::kPlaceholder,
+                                 node_ptr_->hint());
+  }
+
+  // Set bounds
+  if (tree_source_->GetRoot()->GetId() != -1) {
+    // TODO(rmrossi) Pass in nullptr for now for active window. Root node will
+    // get bounds relative to 0,0 anyway since we are full screen.  This may
+    // change if flutter is ever not full screen in which case we will have
+    // to pass in the bounds of whatever container it resides in.
+    const gfx::Rect& local_bounds =
+        tree_source_->GetBounds(tree_source_->GetFromId(GetId()));
+    out_data->relative_bounds.bounds.SetRect(local_bounds.x(), local_bounds.y(),
+                                             local_bounds.width(),
+                                             local_bounds.height());
+  }
+
+  if (node_ptr_->has_text_selection_base()) {
+    out_data->AddIntAttribute(ax::mojom::IntAttribute::kTextSelStart,
+                              node_ptr_->text_selection_base());
+  }
+
+  if (node_ptr_->has_text_selection_extent()) {
+    out_data->AddIntAttribute(ax::mojom::IntAttribute::kTextSelEnd,
+                              node_ptr_->text_selection_extent());
+  }
+
+  if (action_properties.has_scroll_left() ||
+      action_properties.has_scroll_up()) {
+    out_data->AddAction(ax::mojom::Action::kScrollBackward);
+  }
+
+  if (action_properties.has_scroll_right() ||
+      action_properties.has_scroll_down()) {
+    out_data->AddAction(ax::mojom::Action::kScrollForward);
+  }
+
+  if (action_properties.set_selection()) {
+    out_data->AddAction(ax::mojom::Action::kSetSelection);
+  }
+
+  if (action_properties.increase()) {
+    out_data->AddAction(ax::mojom::Action::kIncrement);
+  }
+
+  if (action_properties.decrease()) {
+    out_data->AddAction(ax::mojom::Action::kDecrement);
+  }
+
+  if (IsScrollable()) {
+    const float position = node_ptr_->scroll_position();
+    const float min = node_ptr_->scroll_extent_min();
+    const float max = node_ptr_->scroll_extent_max();
+    if (node_ptr_->action_properties().scroll_up() ||
+        node_ptr_->action_properties().scroll_down()) {
+      out_data->AddIntAttribute(ax::mojom::IntAttribute::kScrollY, position);
+      out_data->AddIntAttribute(ax::mojom::IntAttribute::kScrollYMin, min);
+      out_data->AddIntAttribute(ax::mojom::IntAttribute::kScrollYMax, max);
+    } else if (node_ptr_->action_properties().scroll_left() ||
+               node_ptr_->action_properties().scroll_right()) {
+      out_data->AddIntAttribute(ax::mojom::IntAttribute::kScrollX, position);
+      out_data->AddIntAttribute(ax::mojom::IntAttribute::kScrollXMin, min);
+      out_data->AddIntAttribute(ax::mojom::IntAttribute::kScrollXMax, max);
+    }
+  }
+
+  if (node_ptr_->custom_actions_size() > 0) {
+    std::vector<int32_t> ids;
+    std::vector<std::string> labels;
+    for (int i = 0; i < node_ptr_->custom_actions_size(); i++) {
+      ids.push_back(node_ptr_->custom_actions(i).id());
+      labels.push_back(node_ptr_->custom_actions(i).label());
+    }
+    out_data->AddAction(ax::mojom::Action::kCustomAction);
+    out_data->AddIntListAttribute(ax::mojom::IntListAttribute::kCustomActionIds,
+                                  ids);
+    out_data->AddStringListAttribute(
+        ax::mojom::StringListAttribute::kCustomActionDescriptions, labels);
+  }
+
+  if (node_ptr_->has_plugin_id()) {
+    std::string ax_tree_id = node_ptr_->plugin_id();
+    if (ax_tree_id.rfind("T:", 0) == 0) {
+      // This is a cast web contents id. Find the matching
+      // CastWebContents and find the ax tree id from there.
+      int web_contents_id;
+      base::StringToInt(ax_tree_id.substr(2), &web_contents_id);
+      std::vector<CastWebContents*> all_contents = CastWebContents::GetAll();
+      // There will likely only ever be one active at any time.
+      for (CastWebContents* contents : all_contents) {
+        if (contents->id() == web_contents_id) {
+          content::WebContents* web_contents = contents->web_contents();
+          out_data->AddStringAttribute(
+              ax::mojom::StringAttribute::kChildTreeId,
+              web_contents->GetMainFrame()->GetAXTreeID().ToString());
+          break;
+        }
+      }
+    } else {
+      // Use the value as a tree id.
+      out_data->AddStringAttribute(ax::mojom::StringAttribute::kChildTreeId,
+                                   ax_tree_id);
+    }
+  }
+
+  if (boolean_properties.is_live_region()) {
+    out_data->AddStringAttribute(
+        ax::mojom::StringAttribute::kContainerLiveStatus, "polite");
+    out_data->AddStringAttribute(
+        ax::mojom::StringAttribute::kContainerLiveRelevant, "text");
+  }
+
+  if (out_data->role == ax::mojom::Role::kListBoxOption) {
+    // Find the ancestor whose role is kList.
+    FlutterSemanticsNodeWrapper* ancestor = IsListItem();
+
+    std::vector<FlutterSemanticsNodeWrapper*> ancestor_actionable_children;
+    ancestor->GetActionableChildren(&ancestor_actionable_children);
+
+    // kSetSize should be the number of actionable children that the scrollable
+    // ancestor has.
+    out_data->AddIntAttribute(ax::mojom::IntAttribute::kSetSize,
+                              ancestor_actionable_children.size());
+
+    // Find which children tree that this node is in.
+    for (size_t i = 0; i < ancestor_actionable_children.size(); ++i) {
+      if (IsDescendant(ancestor_actionable_children[i])) {
+        out_data->AddIntAttribute(ax::mojom::IntAttribute::kPosInSet, i + 1);
+        break;
+      }
+    }
+  }
+
+  if (out_data->role == ax::mojom::Role::kList) {
+    // Find the size of actionable children.
+    std::vector<FlutterSemanticsNodeWrapper*> actionable_children;
+    GetActionableChildren(&actionable_children);
+
+    out_data->AddIntAttribute(ax::mojom::IntAttribute::kSetSize,
+                              actionable_children.size());
+  }
+}
+
+void FlutterSemanticsNodeWrapper::GetChildren(
+    std::vector<FlutterSemanticsNode*>* children) const {
+  for (auto id : node_ptr_->child_node_ids()) {
+    FlutterSemanticsNode* node = tree_source_->GetFromId(id);
+    if (node) {
+      children->push_back(tree_source_->GetFromId(id));
+    } else {
+      LOG(ERROR) << "Node id present for which there is no child node given";
+    }
+  }
+}
+
+bool FlutterSemanticsNodeWrapper::AnyChildIsActionable() const {
+  // b/156940104 - If this node is host to a child tree, we
+  // can assume at least one of it's child nodes is actionable.
+  // Otherwise, none of it's descendants will be traversed by
+  // the reader.
+  if (node_ptr_->has_plugin_id()) {
+    return true;
+  }
+  for (auto child_id : node_ptr_->child_node_ids()) {
+    FlutterSemanticsNodeWrapper* child =
+        static_cast<FlutterSemanticsNodeWrapper*>(
+            tree_source_->GetFromId(child_id));
+    if (child->HasTapOrPress()) {
+      return true;
+    }
+    if (child->AnyChildIsActionable()) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool FlutterSemanticsNodeWrapper::HasTapOrPress() const {
+  return node_ptr_->boolean_properties().is_button() ||
+         node_ptr_->action_properties().tap() ||
+         node_ptr_->action_properties().long_press();
+}
+
+bool FlutterSemanticsNodeWrapper::IsActionable() const {
+  // When flutter tells us a generic container is actionable, do not allow this
+  // unless all children of this node are NOT actionable.  Otherwise, the
+  // tree walker will consider this node a leaf and it will not navigate to
+  // any actionable children.
+  bool actionable = HasTapOrPress();
+
+  ui::AXNodeData data;
+  PopulateAXRole(&data);
+  if (actionable && data.role == ax::mojom::Role::kGenericContainer &&
+      AnyChildIsActionable()) {
+    actionable = false;
+  }
+  // If this node is actionable but is also the host for a child tree,
+  // don't make it actionable or else chromevox won't traverse into
+  // any child.
+  if (node_ptr_->has_plugin_id()) {
+    actionable = false;
+  }
+  return actionable;
+}
+
+bool FlutterSemanticsNodeWrapper::IsScrollable() const {
+  return node_ptr_->action_properties().scroll_up() ||
+         node_ptr_->action_properties().scroll_down() ||
+         node_ptr_->action_properties().scroll_left() ||
+         node_ptr_->action_properties().scroll_right();
+}
+
+bool FlutterSemanticsNodeWrapper::IsFocusable() const {
+  const BooleanProperties& boolean_properties = node_ptr_->boolean_properties();
+  if (boolean_properties.scopes_route())
+    return false;
+
+  bool focusable_flags =
+      boolean_properties.has_checked_state() ||
+      boolean_properties.is_checked() || boolean_properties.is_selected() ||
+      HasTapOrPress() || boolean_properties.is_text_field() ||
+      boolean_properties.is_focused() ||
+      boolean_properties.has_enabled_state() ||
+      boolean_properties.is_enabled() ||
+      boolean_properties.is_in_mutually_exclusive_group() ||
+      boolean_properties.is_header() || boolean_properties.is_obscured() ||
+      boolean_properties.names_route() ||
+      (boolean_properties.is_image() &&
+       node_ptr_->child_node_ids().size() == 0) ||
+      boolean_properties.is_live_region() ||
+      boolean_properties.has_toggled_state() || boolean_properties.is_toggled();
+
+  // b/149934151 : If a node has a label but also has children, don't
+  // mark it focusable, otherwise none of its children will be navigable
+  // via swipe nav. It's role wlil be a generic container (see above).
+  return focusable_flags || (HasLabelHint() && !GetLabelHint().empty() &&
+                             node_ptr_->child_node_ids().size() == 0);
+}
+
+bool FlutterSemanticsNodeWrapper::HasLabelHint() const {
+  return node_ptr_->has_label() || node_ptr_->has_hint();
+}
+
+std::string FlutterSemanticsNodeWrapper::GetLabelHint() const {
+  // TODO(rmrossi): Find out whether this order of precedence makes sense
+  if (node_ptr_->has_label() && node_ptr_->label().length() > 0) {
+    return node_ptr_->label();
+  }
+  if (node_ptr_->has_hint() && node_ptr_->hint().length() > 0) {
+    return node_ptr_->hint();
+  }
+  return "";
+}
+
+void FlutterSemanticsNodeWrapper::ComputeNameFromContents(
+    std::vector<std::string>* names) const {
+  DCHECK(names);
+  std::string name;
+  if (HasLabelHint()) {
+    name = GetLabelHint();
+    if (!name.empty()) {
+      names->push_back(name);
+      return;
+    }
+  }
+
+  std::vector<FlutterSemanticsNode*> children;
+  GetChildren(&children);
+  for (const FlutterSemanticsNode* child : children) {
+    child->ComputeNameFromContents(names);
+  }
+}
+
+bool FlutterSemanticsNodeWrapper::HasValue() const {
+  return node_ptr_->has_value();
+}
+
+std::string FlutterSemanticsNodeWrapper::GetValue() const {
+  return node_ptr_->value();
+}
+
+}  // namespace accessibility
+}  // namespace chromecast
diff --git a/chromecast/browser/accessibility/flutter/flutter_semantics_node_wrapper.h b/chromecast/browser/accessibility/flutter/flutter_semantics_node_wrapper.h
new file mode 100644
index 0000000..658f588f
--- /dev/null
+++ b/chromecast/browser/accessibility/flutter/flutter_semantics_node_wrapper.h
@@ -0,0 +1,74 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMECAST_BROWSER_ACCESSIBILITY_FLUTTER_FLUTTER_SEMANTICS_NODE_WRAPPER_H_
+#define CHROMECAST_BROWSER_ACCESSIBILITY_FLUTTER_FLUTTER_SEMANTICS_NODE_WRAPPER_H_
+
+#include <string>
+#include <vector>
+
+#include "chromecast/browser/accessibility/flutter/flutter_semantics_node.h"
+#include "chromecast/browser/accessibility/proto/cast_server_accessibility.pb.h"
+#include "ui/accessibility/ax_enum_util.h"
+#include "ui/accessibility/ax_node_data.h"
+
+namespace chromecast {
+namespace accessibility {
+
+using gallium::castos::SemanticsNode;
+
+class AXTreeSourceFlutter;
+
+// A wrapper class for a SemanticsNode proto object.
+// This is used by AXTreeSourceFlutter to create accessibility tree updates
+// from semantics trees sent to us from the flutter process.
+class FlutterSemanticsNodeWrapper : public FlutterSemanticsNode {
+ public:
+  FlutterSemanticsNodeWrapper(AXTreeSourceFlutter* tree_source,
+                              const SemanticsNode* node);
+  FlutterSemanticsNodeWrapper(const FlutterSemanticsNodeWrapper&) = delete;
+  FlutterSemanticsNodeWrapper& operator=(const FlutterSemanticsNodeWrapper&) =
+      delete;
+
+  // FlutterSemanticsNode implementation:
+  int32_t GetId() const override;
+  const gfx::Rect GetBounds() const override;
+  bool IsVisibleToUser() const override;
+  bool IsFocused() const override;
+  bool IsLiveRegion() const override;
+  bool IsRapidChangingSlider() const override;
+  bool CanBeAccessibilityFocused() const override;
+  void PopulateAXRole(ui::AXNodeData* out_data) const override;
+  void PopulateAXState(ui::AXNodeData* out_data) const override;
+  void Serialize(ui::AXNodeData* out_data) const override;
+  void GetChildren(std::vector<FlutterSemanticsNode*>* children) const override;
+  bool HasLabelHint() const override;
+  std::string GetLabelHint() const override;
+  bool HasValue() const override;
+  std::string GetValue() const override;
+
+  const SemanticsNode* node() { return node_ptr_; }
+
+ private:
+  bool AnyChildIsActionable() const;
+  bool HasTapOrPress() const;
+  bool IsActionable() const;
+  bool IsScrollable() const;
+  bool IsFocusable() const;
+  void ComputeNameFromContents(std::vector<std::string>* names) const override;
+  void GetActionableChildren(
+      std::vector<FlutterSemanticsNodeWrapper*>* out_children) const;
+  // Check if this is a list item and return the node of its ancestor whose role
+  // is kList
+  FlutterSemanticsNodeWrapper* IsListItem() const;
+  bool IsDescendant(FlutterSemanticsNodeWrapper* ancestor) const;
+
+  AXTreeSourceFlutter* const tree_source_;
+  const SemanticsNode* const node_ptr_;
+};
+
+}  // namespace accessibility
+}  // namespace chromecast
+
+#endif  // CHROMECAST_BROWSER_ACCESSIBILITY_FLUTTER_FLUTTER_SEMANTICS_NODE_WRAPPER_H_
diff --git a/chromecast/browser/accessibility/proto/BUILD.gn b/chromecast/browser/accessibility/proto/BUILD.gn
new file mode 100644
index 0000000..e1e606b
--- /dev/null
+++ b/chromecast/browser/accessibility/proto/BUILD.gn
@@ -0,0 +1,16 @@
+import("//third_party/protobuf/proto_library.gni")
+
+proto_library("gallium_accessibility_proto") {
+  sources = [
+    "cast_server_accessibility.proto",
+    "gallium_server_accessibility.proto",
+  ]
+
+  deps = [
+    "//third_party/grpc:grpcpp",
+    "//third_party/protobuf:protobuf_lite",
+  ]
+
+  generator_plugin_label = "//third_party/grpc:grpc_cpp_plugin"
+  generator_plugin_suffix = ".grpc.pb"
+}
diff --git a/chromecast/browser/accessibility/proto/cast_server_accessibility.proto b/chromecast/browser/accessibility/proto/cast_server_accessibility.proto
new file mode 100644
index 0000000..25dfe56
--- /dev/null
+++ b/chromecast/browser/accessibility/proto/cast_server_accessibility.proto
@@ -0,0 +1,116 @@
+syntax = "proto2";
+
+package gallium.castos;
+
+option optimize_for = LITE_RUNTIME;
+
+message Rect {
+  optional int32 left = 1;
+  optional int32 top = 2;
+  optional int32 right = 3;
+  optional int32 bottom = 4;
+}
+
+message BooleanProperties {
+  optional bool has_checked_state = 1;
+  optional bool is_checked = 2;
+  optional bool is_selected = 3;
+  optional bool is_button = 4;
+  optional bool is_text_field = 5;
+  optional bool is_focused = 6;
+  optional bool has_enabled_state = 7;
+  optional bool is_enabled = 8;
+  optional bool is_in_mutually_exclusive_group = 9;
+  optional bool is_header = 10;
+  optional bool is_obscured = 11;
+  optional bool scopes_route = 12;
+  optional bool names_route = 13;
+  optional bool is_hidden = 14;
+  optional bool is_image = 15;
+  optional bool is_live_region = 16;
+  optional bool has_toggled_state = 17;
+  optional bool is_toggled = 18;
+  optional bool has_implicit_scrolling = 19;
+}
+
+message ActionProperties {
+  optional bool tap = 1;
+  optional bool long_press = 2;
+  optional bool scroll_left = 3;
+  optional bool scroll_right = 4;
+  optional bool scroll_up = 5;
+  optional bool scroll_down = 6;
+  optional bool increase = 7;
+  optional bool decrease = 8;
+  optional bool show_on_screen = 9;
+  optional bool move_cursor_forward_by_character = 10;
+  optional bool move_cursor_backward_by_character = 11;
+  optional bool set_selection = 12;
+  optional bool copy = 13;
+  optional bool cut = 14;
+  optional bool paste = 15;
+  optional bool did_gain_accessibility_focus = 16;
+  optional bool did_lose_accessibility_focus = 17;
+  optional bool custom_action = 18;
+  optional bool dismiss = 19;
+  optional bool move_cursor_forward_by_word = 20;
+  optional bool move_cursor_backward_by_word = 21;
+};
+
+message CustomAction {
+  optional int32 id = 1;
+  optional string label = 2;
+}
+
+message SemanticsNode {
+  optional int32 node_id = 1;
+  optional Rect bounds_in_screen = 2;
+  optional int32 window_id = 3;
+  repeated int32 child_node_ids = 4;
+  optional BooleanProperties boolean_properties = 5;
+  optional ActionProperties action_properties = 6;
+  optional string value = 7;
+  optional string label = 8;
+  optional string hint = 9;
+  optional string text_direction = 10;
+  optional int32 resource_id = 11;
+  optional int32 text_selection_base = 12;
+  optional int32 text_selection_extent = 13;
+  optional int32 scroll_children = 14;
+  optional int32 scroll_index = 15;
+  optional float scroll_position = 16;
+  optional int32 scroll_extent_max = 17;
+  optional int32 scroll_extent_min = 18;
+  repeated CustomAction custom_actions = 19;
+  // If set, indicates the semantics information for this node
+  // is provided by a platform plugin or some other native backed
+  // entity.
+  optional string plugin_id = 20;
+}
+
+message OnAccessibilityEventRequest {
+  enum EventType {
+    UNSPECIFIED = 0;
+    FOCUSED = 1;
+    FOCUS_CLEARED = 2;
+    HOVER_ENTER = 3;
+    HOVER_EXIT = 4;
+    CLICKED = 5;
+    LONG_CLICKED = 6;
+    WINDOW_STATE_CHANGED = 7;
+    TEXT_CHANGED = 8;
+    TEXT_SELECTION_CHANGED = 9;
+    CONTENT_CHANGED = 10;
+    SCROLLED = 11;
+  }
+  // Type of event this represents.
+  optional EventType event_type = 1;
+  // The node responsible for triggering this event.
+  optional int32 source_id = 2;
+  // Unique identifier for flutter window.
+  optional int32 window_id = 3;
+  // The 'flattened' semantic tree nodes.
+  repeated SemanticsNode node_data = 4;
+}
+
+message OnAccessibilityEventResponse {}
diff --git a/chromecast/browser/accessibility/proto/gallium_server_accessibility.proto b/chromecast/browser/accessibility/proto/gallium_server_accessibility.proto
new file mode 100644
index 0000000..04918fe
--- /dev/null
+++ b/chromecast/browser/accessibility/proto/gallium_server_accessibility.proto
@@ -0,0 +1,54 @@
+syntax = "proto2";
+
+package gallium.castos;
+
+option optimize_for = LITE_RUNTIME;
+
+message OnAccessibilityStateChangedRequest {
+  optional bool enabled = 1;
+}
+
+message OnAccessibilityStateChangedResponse {}
+
+message OnAccessibilityActionRequest {
+  enum AccessibilityActionType {
+    UNSPECIFIED = 0;
+    TAP = 1;
+    LONG_PRESS = 2;
+    SCROLL_LEFT = 3;
+    SCROLL_RIGHT = 4;
+    SCROLL_UP = 5;
+    SCROLL_DOWN = 6;
+    INCREASE = 7;
+    DECREASE = 8;
+    SHOW_ON_SCREEN = 9;
+    MOVE_CURSOR_FORWARD_BY_CHARACTER = 10;
+    MOVE_CURSOR_BACKWARD_BY_CHARACTER = 11;
+    SET_SELECTION = 12;
+    COPY = 13;
+    CUT = 14;
+    PASTE = 15;
+    DID_GAIN_ACCESSIBILITY_FOCUS = 16;
+    DID_LOSE_ACCESSIBILITY_FOCUS = 17;
+    CUSTOM_ACTION = 18;
+    DISMISS = 19;
+    MOVE_CURSOR_FORWARD_BY_WORD = 20;
+    MOVE_CURSOR_BACKWARD_BY_WORD = 21;
+  }
+
+  optional int32 node_id = 1;
+
+  optional AccessibilityActionType action_type = 2;
+
+  // custom_action_id must be set if action_type is CUSTOM_ACTION.
+  optional int32 custom_action_id = 3;
+
+  // window_id where the action is performed.
+  optional int32 window_id = 4;
+
+  // Parameters specifying indices to get text location of node.
+  optional int32 start_index = 5;
+  optional int32 end_index = 6;
+}
+
+message OnAccessibilityActionResponse {}
diff --git a/chromeos/components/telemetry_extension_ui/diagnostics_service.cc b/chromeos/components/telemetry_extension_ui/diagnostics_service.cc
index 567cce9..161e6b76 100644
--- a/chromeos/components/telemetry_extension_ui/diagnostics_service.cc
+++ b/chromeos/components/telemetry_extension_ui/diagnostics_service.cc
@@ -148,4 +148,18 @@
           std::move(callback)));
 }
 
+void DiagnosticsService::RunFloatingPointAccuracyRoutine(
+    uint32_t length_seconds,
+    RunFloatingPointAccuracyRoutineCallback callback) {
+  GetService()->RunFloatingPointAccuracyRoutine(
+      length_seconds,
+      base::BindOnce(
+          [](health::mojom::DiagnosticsService::
+                 RunFloatingPointAccuracyRoutineCallback callback,
+             cros_healthd::mojom::RunRoutineResponsePtr ptr) {
+            std::move(callback).Run(converters::ConvertPtr(std::move(ptr)));
+          },
+          std::move(callback)));
+}
+
 }  // namespace chromeos
diff --git a/chromeos/components/telemetry_extension_ui/diagnostics_service.h b/chromeos/components/telemetry_extension_ui/diagnostics_service.h
index e6d72ec..38a3da7 100644
--- a/chromeos/components/telemetry_extension_ui/diagnostics_service.h
+++ b/chromeos/components/telemetry_extension_ui/diagnostics_service.h
@@ -48,6 +48,9 @@
                           RunCpuCacheRoutineCallback callback) override;
   void RunCpuStressRoutine(uint32_t length_seconds,
                            RunCpuStressRoutineCallback callback) override;
+  void RunFloatingPointAccuracyRoutine(
+      uint32_t length_seconds,
+      RunFloatingPointAccuracyRoutineCallback callback) override;
 
   // Ensures that |service_| created and connected to the
   // CrosHealthdProbeService.
diff --git a/chromeos/components/telemetry_extension_ui/mojom/diagnostics_service.mojom b/chromeos/components/telemetry_extension_ui/mojom/diagnostics_service.mojom
index bc439965..b158a9e 100644
--- a/chromeos/components/telemetry_extension_ui/mojom/diagnostics_service.mojom
+++ b/chromeos/components/telemetry_extension_ui/mojom/diagnostics_service.mojom
@@ -134,6 +134,25 @@
   //                routine.
   RunCpuStressRoutine(uint32 length_seconds)
       => (RunRoutineResponse response);
+
+  // Requests that the FloatingPointAccuracy routine is created and started
+  // on the platform. This routine executes millions of floating-point
+  // operations by SSE instructions for a specified amount of time. The routine
+  // will pass if the result values of the operations and known accurate result
+  // are the same.
+  //
+  // The request:
+  // * |length_seconds| - length of time, in seconds, to run the floating-point
+  //                      routine for. Test will executes millions of
+  //                      floating-point operations in length seconds and get
+  //                      the result to compare with known accurate results.
+  //                      This parameter needs to be strictly greater than zero.
+  //
+  // The response:
+  // * |response| - contains a unique identifier and status for the created
+  //                routine.
+  RunFloatingPointAccuracyRoutine(uint32 length_seconds)
+      => (RunRoutineResponse response);
 };
 
 // Enumeration of each of the diagnostics routines the platform may support.
diff --git a/chromeos/components/telemetry_extension_ui/resources/message_types.js b/chromeos/components/telemetry_extension_ui/resources/message_types.js
index d4da227..78607db 100644
--- a/chromeos/components/telemetry_extension_ui/resources/message_types.js
+++ b/chromeos/components/telemetry_extension_ui/resources/message_types.js
@@ -29,6 +29,8 @@
   DIAGNOSTICS_RUN_AC_POWER_ROUTINE: 'DiagnosticsService.RunAcPowerRoutine',
   DIAGNOSTICS_RUN_CPU_CACHE_ROUTINE: 'DiagnosticsService.RunCpuCacheRoutine',
   DIAGNOSTICS_RUN_CPU_STRESS_ROUTINE: 'DiagnosticsService.RunCpuStressRoutine',
+  DIAGNOSTICS_RUN_FP_ACCURACY_ROUTINE:
+      'DiagnosticsService.RunFloatingPointAccuraryRoutine',
   PROBE_TELEMETRY_INFO: 'ProbeService.ProbeTelemetryInfo',
 };
 
@@ -112,6 +114,13 @@
 dpsl_internal.DiagnosticsRunCpuStressRoutineRequest;
 
 /**
+ * Request message sent by the unprivileged context to the privileged
+ * context to run floating point accuracy routine.
+ * @typedef {{ duration: !number }}
+ */
+dpsl_internal.DiagnosticsRunFPAccuracyRoutineRequest;
+
+/**
  * Response message sent by the privileged context containing routine
  * information.
  * @typedef { !Object | !Error }
diff --git a/chromeos/components/telemetry_extension_ui/resources/trusted.js b/chromeos/components/telemetry_extension_ui/resources/trusted.js
index cf3c7fec..03e1cb2be 100644
--- a/chromeos/components/telemetry_extension_ui/resources/trusted.js
+++ b/chromeos/components/telemetry_extension_ui/resources/trusted.js
@@ -406,6 +406,20 @@
     return await getOrCreateDiagnosticsService().runCpuStressRoutine(
         request.duration);
   };
+
+  /**
+   * Runs floating point accuracy routine.
+   * @param { !Object } message
+   * @return { !RunRoutineResponsePromise }
+   */
+  async handleRunFloatingPointAccuracyRoutine(message) {
+    const request =
+        /** @type {!dpsl_internal.DiagnosticsRunFPAccuracyRoutineRequest} */
+        (message);
+    this.assertNumberIsPositive(request.duration);
+    return await getOrCreateDiagnosticsService()
+        .runFloatingPointAccuracyRoutine(request.duration);
+  };
 };
 
 const diagnosticsProxy = new DiagnosticsProxy();
@@ -722,5 +736,12 @@
         message));
 
 untrustedMessagePipe.registerHandler(
+    dpsl_internal.Message.DIAGNOSTICS_RUN_FP_ACCURACY_ROUTINE,
+    (message) => diagnosticsProxy.genericRunRoutineHandler(
+        (message) =>
+            diagnosticsProxy.handleRunFloatingPointAccuracyRoutine(message),
+        message));
+
+untrustedMessagePipe.registerHandler(
     dpsl_internal.Message.PROBE_TELEMETRY_INFO,
     (message) => telemetryProxy.handleProbeTelemetryInfo(message));
diff --git a/chromeos/components/telemetry_extension_ui/resources/untrusted.js b/chromeos/components/telemetry_extension_ui/resources/untrusted.js
index 1ac484a..0ed8e7c 100644
--- a/chromeos/components/telemetry_extension_ui/resources/untrusted.js
+++ b/chromeos/components/telemetry_extension_ui/resources/untrusted.js
@@ -202,6 +202,26 @@
       }
       return response;
     }
+
+    /**
+     * Requests floating point accuracy routine to be run for duration seconds.
+     * @param { !number } duration
+     * @return { !Promise<!Object> }
+     * @public
+     */
+    async runFloatingPointAccuracyRoutine(duration) {
+      const message =
+          /** @type {!dpsl_internal.DiagnosticsRunFPAccuracyRoutineRequest} */
+          ({duration: duration});
+      const response =
+          /** @type {!Object} */ (await messagePipe.sendMessage(
+              dpsl_internal.Message.DIAGNOSTICS_RUN_FP_ACCURACY_ROUTINE,
+              message));
+      if (response instanceof Error) {
+        throw response;
+      }
+      return response;
+    }
   };
 
   /**
diff --git a/chromeos/components/telemetry_extension_ui/test/telemetry_extension_ui_browsertest.js b/chromeos/components/telemetry_extension_ui/test/telemetry_extension_ui_browsertest.js
index abf952e..a18a63fe 100644
--- a/chromeos/components/telemetry_extension_ui/test/telemetry_extension_ui_browsertest.js
+++ b/chromeos/components/telemetry_extension_ui/test/telemetry_extension_ui_browsertest.js
@@ -425,6 +425,22 @@
 
 TEST_F(
     'TelemetryExtensionUIBrowserTest',
+    'UntrustedDiagnosticsRequestRunFPAccuracyRoutineInvalidInput', async () => {
+      await runTestInUntrusted(
+          'UntrustedDiagnosticsRequestRunFPAccuracyRoutineInvalidInput');
+      testDone();
+    });
+
+TEST_F(
+    'TelemetryExtensionUIBrowserTest',
+    'UntrustedDiagnosticsRequestRunFPAccuracyRoutine', async () => {
+      await runTestInUntrusted(
+          'UntrustedDiagnosticsRequestRunFPAccuracyRoutine');
+      testDone();
+    });
+
+TEST_F(
+    'TelemetryExtensionUIBrowserTest',
     'UntrustedRequestTelemetryInfoUnknownCategory', async () => {
       await runTestInUntrusted('UntrustedRequestTelemetryInfoUnknownCategory');
       testDone();
diff --git a/chromeos/components/telemetry_extension_ui/test/untrusted_browsertest.js b/chromeos/components/telemetry_extension_ui/test/untrusted_browsertest.js
index 34c62944..4371279 100644
--- a/chromeos/components/telemetry_extension_ui/test/untrusted_browsertest.js
+++ b/chromeos/components/telemetry_extension_ui/test/untrusted_browsertest.js
@@ -226,6 +226,38 @@
   assertDeepEquals(response, {id: 123456789, status: 'ready'});
 });
 
+// Tests that runFloatingPointAccuracyRoutine throws the correct error when
+// invalid number is passed as input.
+UNTRUSTED_TEST(
+    'UntrustedDiagnosticsRequestRunFPAccuracyRoutineInvalidInput', async () => {
+      let caughtError1;
+      try {
+        await chromeos.diagnostics.runFloatingPointAccuracyRoutine(0);
+      } catch (error) {
+        caughtError1 = error;
+      }
+
+      assertEquals(caughtError1.name, 'RangeError');
+      assertEquals(caughtError1.message, `Parameter must be positive.`);
+
+      let caughtError2;
+      try {
+        await chromeos.diagnostics.runFloatingPointAccuracyRoutine(-2147483648);
+      } catch (error) {
+        caughtError2 = error;
+      }
+
+      assertEquals(caughtError2.name, 'RangeError');
+      assertEquals(caughtError2.message, `Parameter must be positive.`);
+    });
+
+// Tests that runFloatingPointAccuracyRoutine returns the correct Object.
+UNTRUSTED_TEST('UntrustedDiagnosticsRequestRunFPAccuracyRoutine', async () => {
+  const response =
+      await chromeos.diagnostics.runFloatingPointAccuracyRoutine(5);
+  assertDeepEquals(response, {id: 123456789, status: 'ready'});
+});
+
 // Tests that TelemetryInfo can be successfully requested from
 // from chrome-untrusted://.
 UNTRUSTED_TEST('UntrustedRequestTelemetryInfo', async () => {
diff --git a/chromeos/constants/chromeos_features.cc b/chromeos/constants/chromeos_features.cc
index 9a50d937..b874314 100644
--- a/chromeos/constants/chromeos_features.cc
+++ b/chromeos/constants/chromeos_features.cc
@@ -518,6 +518,11 @@
 const base::Feature kUseBrowserSyncConsent{"UseBrowserSyncConsent",
                                            base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Use the staging server as part of the Wallpaper App to verify
+// additions/removals of wallpapers.
+const base::Feature kUseWallpaperStagingUrl{"UseWallpaperStagingUrl",
+                                            base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Use the staging URL as part of the "Messages" feature under "Connected
 // Devices" settings.
 const base::Feature kUseMessagesStagingUrl{"UseMessagesStagingUrl",
diff --git a/chromeos/constants/chromeos_features.h b/chromeos/constants/chromeos_features.h
index 159f8c15..3b7d1da4 100644
--- a/chromeos/constants/chromeos_features.h
+++ b/chromeos/constants/chromeos_features.h
@@ -224,6 +224,8 @@
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
 extern const base::Feature kUseBrowserSyncConsent;
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
+extern const base::Feature kUseWallpaperStagingUrl;
+COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
 extern const base::Feature kUseMessagesStagingUrl;
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
 extern const base::Feature kUserActivityPrediction;
diff --git a/chromeos/services/secure_channel/ble_connection_manager_impl.cc b/chromeos/services/secure_channel/ble_connection_manager_impl.cc
index ca99a2b..5450228 100644
--- a/chromeos/services/secure_channel/ble_connection_manager_impl.cc
+++ b/chromeos/services/secure_channel/ble_connection_manager_impl.cc
@@ -16,7 +16,6 @@
 #include "chromeos/services/secure_channel/ble_initiator_failure_type.h"
 #include "chromeos/services/secure_channel/ble_listener_failure_type.h"
 #include "chromeos/services/secure_channel/ble_scanner_impl.h"
-#include "chromeos/services/secure_channel/ble_synchronizer.h"
 #include "chromeos/services/secure_channel/ble_weave_client_connection.h"
 #include "chromeos/services/secure_channel/latency_metrics_logger.h"
 #include "chromeos/services/secure_channel/public/mojom/secure_channel.mojom.h"
@@ -59,15 +58,19 @@
 std::unique_ptr<BleConnectionManager> BleConnectionManagerImpl::Factory::Create(
     scoped_refptr<device::BluetoothAdapter> bluetooth_adapter,
     BleServiceDataHelper* ble_service_data_helper,
+    BleSynchronizerBase* ble_synchronizer,
+    BleScanner* ble_scanner,
     TimerFactory* timer_factory,
     base::Clock* clock) {
   if (test_factory_) {
     return test_factory_->CreateInstance(
-        bluetooth_adapter, ble_service_data_helper, timer_factory, clock);
+        bluetooth_adapter, ble_service_data_helper, ble_synchronizer,
+        ble_scanner, timer_factory, clock);
   }
 
   return base::WrapUnique(new BleConnectionManagerImpl(
-      bluetooth_adapter, ble_service_data_helper, timer_factory, clock));
+      bluetooth_adapter, ble_service_data_helper, ble_synchronizer, ble_scanner,
+      timer_factory, clock));
 }
 
 // static
@@ -204,20 +207,18 @@
 BleConnectionManagerImpl::BleConnectionManagerImpl(
     scoped_refptr<device::BluetoothAdapter> bluetooth_adapter,
     BleServiceDataHelper* ble_service_data_helper,
+    BleSynchronizerBase* ble_synchronizer,
+    BleScanner* ble_scanner,
     TimerFactory* timer_factory,
     base::Clock* clock)
     : bluetooth_adapter_(bluetooth_adapter),
-      ble_service_data_helper_(ble_service_data_helper),
       clock_(clock),
-      ble_synchronizer_(BleSynchronizer::Factory::Create(bluetooth_adapter)),
+      ble_scanner_(ble_scanner),
       ble_advertiser_(
           BleAdvertiserImpl::Factory::Create(this /* delegate */,
-                                             ble_service_data_helper_,
-                                             ble_synchronizer_.get(),
+                                             ble_service_data_helper,
+                                             ble_synchronizer,
                                              timer_factory)),
-      ble_scanner_(BleScannerImpl::Factory::Create(ble_service_data_helper_,
-                                                   ble_synchronizer_.get(),
-                                                   bluetooth_adapter)),
       secure_channel_disconnector_(
           SecureChannelDisconnectorImpl::Factory::Create()) {
   ble_scanner_->AddObserver(this);
diff --git a/chromeos/services/secure_channel/ble_connection_manager_impl.h b/chromeos/services/secure_channel/ble_connection_manager_impl.h
index 60e6cf3..e7e3328 100644
--- a/chromeos/services/secure_channel/ble_connection_manager_impl.h
+++ b/chromeos/services/secure_channel/ble_connection_manager_impl.h
@@ -49,6 +49,8 @@
     static std::unique_ptr<BleConnectionManager> Create(
         scoped_refptr<device::BluetoothAdapter> bluetooth_adapter,
         BleServiceDataHelper* ble_service_data_helper,
+        BleSynchronizerBase* ble_synchronizer,
+        BleScanner* ble_scanner,
         TimerFactory* timer_factory,
         base::Clock* clock = base::DefaultClock::GetInstance());
     static void SetFactoryForTesting(Factory* test_factory);
@@ -58,6 +60,8 @@
     virtual std::unique_ptr<BleConnectionManager> CreateInstance(
         scoped_refptr<device::BluetoothAdapter> bluetooth_adapter,
         BleServiceDataHelper* ble_service_data_helper,
+        BleSynchronizerBase* ble_synchronizer,
+        BleScanner* ble_scanner,
         TimerFactory* timer_factory,
         base::Clock* clock = base::DefaultClock::GetInstance()) = 0;
 
@@ -103,6 +107,8 @@
   BleConnectionManagerImpl(
       scoped_refptr<device::BluetoothAdapter> bluetooth_adapter,
       BleServiceDataHelper* ble_service_data_helper,
+      BleSynchronizerBase* ble_synchronizer,
+      BleScanner* ble_scanner,
       TimerFactory* timer_factory,
       base::Clock* clock);
 
@@ -197,12 +203,10 @@
       const std::string& remote_device_id);
 
   scoped_refptr<device::BluetoothAdapter> bluetooth_adapter_;
-  BleServiceDataHelper* ble_service_data_helper_;
   base::Clock* clock_;
+  BleScanner* ble_scanner_;
 
-  std::unique_ptr<BleSynchronizerBase> ble_synchronizer_;
   std::unique_ptr<BleAdvertiser> ble_advertiser_;
-  std::unique_ptr<BleScanner> ble_scanner_;
   std::unique_ptr<SecureChannelDisconnector> secure_channel_disconnector_;
 
   using SecureChannelWithRole =
diff --git a/chromeos/services/secure_channel/ble_connection_manager_impl_unittest.cc b/chromeos/services/secure_channel/ble_connection_manager_impl_unittest.cc
index 8e6a726a..7fb883a 100644
--- a/chromeos/services/secure_channel/ble_connection_manager_impl_unittest.cc
+++ b/chromeos/services/secure_channel/ble_connection_manager_impl_unittest.cc
@@ -22,8 +22,6 @@
 #include "chromeos/services/secure_channel/ble_constants.h"
 #include "chromeos/services/secure_channel/ble_initiator_failure_type.h"
 #include "chromeos/services/secure_channel/ble_listener_failure_type.h"
-#include "chromeos/services/secure_channel/ble_scanner_impl.h"
-#include "chromeos/services/secure_channel/ble_synchronizer.h"
 #include "chromeos/services/secure_channel/ble_weave_client_connection.h"
 #include "chromeos/services/secure_channel/fake_authenticated_channel.h"
 #include "chromeos/services/secure_channel/fake_ble_advertiser.h"
@@ -56,46 +54,15 @@
 constexpr base::TimeDelta kConnectionToAuthenticationTime =
     base::TimeDelta::FromSeconds(1);
 
-class FakeBleSynchronizerFactory : public BleSynchronizer::Factory {
- public:
-  FakeBleSynchronizerFactory(
-      scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>>
-          expected_mock_adapter)
-      : expected_mock_adapter_(expected_mock_adapter) {}
-
-  ~FakeBleSynchronizerFactory() override = default;
-
-  FakeBleSynchronizer* instance() { return instance_; }
-
- private:
-  // BleSynchronizer::Factory:
-  std::unique_ptr<BleSynchronizerBase> CreateInstance(
-      scoped_refptr<device::BluetoothAdapter> bluetooth_adapter) override {
-    EXPECT_EQ(expected_mock_adapter_, bluetooth_adapter);
-    EXPECT_FALSE(instance_);
-
-    auto instance = std::make_unique<FakeBleSynchronizer>();
-    instance_ = instance.get();
-    return instance;
-  }
-
-  FakeBleSynchronizer* instance_ = nullptr;
-
-  scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>>
-      expected_mock_adapter_;
-
-  DISALLOW_COPY_AND_ASSIGN(FakeBleSynchronizerFactory);
-};
-
 class FakeBleAdvertiserFactory : public BleAdvertiserImpl::Factory {
  public:
   FakeBleAdvertiserFactory(
       FakeBleServiceDataHelper* expected_fake_ble_service_data_helper,
-      FakeBleSynchronizerFactory* fake_ble_synchronizer_factory,
+      FakeBleSynchronizer* expected_fake_ble_synchronizer,
       FakeTimerFactory* expected_fake_timer_factory)
       : expected_fake_ble_service_data_helper_(
             expected_fake_ble_service_data_helper),
-        fake_ble_synchronizer_factory_(fake_ble_synchronizer_factory),
+        expected_fake_ble_synchronizer_(expected_fake_ble_synchronizer),
         expected_fake_timer_factory_(expected_fake_timer_factory) {}
 
   ~FakeBleAdvertiserFactory() override = default;
@@ -111,8 +78,7 @@
       TimerFactory* timer_factory,
       scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner) override {
     EXPECT_EQ(expected_fake_ble_service_data_helper_, ble_service_data_helper);
-    EXPECT_EQ(fake_ble_synchronizer_factory_->instance(),
-              ble_synchronizer_base);
+    EXPECT_EQ(expected_fake_ble_synchronizer_, ble_synchronizer_base);
     EXPECT_EQ(expected_fake_timer_factory_, timer_factory);
     EXPECT_FALSE(instance_);
 
@@ -124,55 +90,12 @@
   FakeBleAdvertiser* instance_ = nullptr;
 
   FakeBleServiceDataHelper* expected_fake_ble_service_data_helper_;
-  FakeBleSynchronizerFactory* fake_ble_synchronizer_factory_;
+  FakeBleSynchronizer* expected_fake_ble_synchronizer_;
   FakeTimerFactory* expected_fake_timer_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(FakeBleAdvertiserFactory);
 };
 
-class FakeBleScannerFactory : public BleScannerImpl::Factory {
- public:
-  FakeBleScannerFactory(
-      scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>>
-          expected_mock_adapter,
-      FakeBleServiceDataHelper* expected_fake_ble_service_data_helper,
-      FakeBleSynchronizerFactory* fake_ble_synchronizer_factory)
-      : expected_mock_adapter_(expected_mock_adapter),
-        expected_fake_ble_service_data_helper_(
-            expected_fake_ble_service_data_helper),
-        fake_ble_synchronizer_factory_(fake_ble_synchronizer_factory) {}
-
-  ~FakeBleScannerFactory() override = default;
-
-  FakeBleScanner* instance() { return instance_; }
-
- private:
-  // BleScannerImpl::Factory:
-  std::unique_ptr<BleScanner> CreateInstance(
-      BleServiceDataHelper* service_data_helper,
-      BleSynchronizerBase* ble_synchronizer_base,
-      scoped_refptr<device::BluetoothAdapter> adapter) override {
-    EXPECT_EQ(expected_fake_ble_service_data_helper_, service_data_helper);
-    EXPECT_EQ(fake_ble_synchronizer_factory_->instance(),
-              ble_synchronizer_base);
-    EXPECT_EQ(expected_mock_adapter_, adapter);
-    EXPECT_FALSE(instance_);
-
-    auto instance = std::make_unique<FakeBleScanner>();
-    instance_ = instance.get();
-    return instance;
-  }
-
-  FakeBleScanner* instance_ = nullptr;
-
-  scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>>
-      expected_mock_adapter_;
-  FakeBleServiceDataHelper* expected_fake_ble_service_data_helper_;
-  FakeBleSynchronizerFactory* fake_ble_synchronizer_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(FakeBleScannerFactory);
-};
-
 class FakeSecureChannelDisconnectorFactory
     : public SecureChannelDisconnectorImpl::Factory {
  public:
@@ -338,29 +261,20 @@
 
     fake_ble_service_data_helper_ =
         std::make_unique<FakeBleServiceDataHelper>();
+    fake_ble_synchronizer_ = std::make_unique<FakeBleSynchronizer>();
+    fake_ble_scanner_ = std::make_unique<FakeBleScanner>();
 
     fake_timer_factory_ = std::make_unique<FakeTimerFactory>();
 
     test_clock_ = std::make_unique<base::SimpleTestClock>();
     test_clock_->SetNow(base::Time::UnixEpoch());
 
-    fake_ble_synchronizer_factory_ =
-        std::make_unique<FakeBleSynchronizerFactory>(mock_adapter_);
-    BleSynchronizer::Factory::SetFactoryForTesting(
-        fake_ble_synchronizer_factory_.get());
-
     fake_ble_advertiser_factory_ = std::make_unique<FakeBleAdvertiserFactory>(
-        fake_ble_service_data_helper_.get(),
-        fake_ble_synchronizer_factory_.get(), fake_timer_factory_.get());
+        fake_ble_service_data_helper_.get(), fake_ble_synchronizer_.get(),
+        fake_timer_factory_.get());
     BleAdvertiserImpl::Factory::SetFactoryForTesting(
         fake_ble_advertiser_factory_.get());
 
-    fake_ble_scanner_factory_ = std::make_unique<FakeBleScannerFactory>(
-        mock_adapter_, fake_ble_service_data_helper_.get(),
-        fake_ble_synchronizer_factory_.get());
-    BleScannerImpl::Factory::SetFactoryForTesting(
-        fake_ble_scanner_factory_.get());
-
     fake_secure_channel_disconnector_factory_ =
         std::make_unique<FakeSecureChannelDisconnectorFactory>();
     SecureChannelDisconnectorImpl::Factory::SetFactoryForTesting(
@@ -383,13 +297,12 @@
 
     manager_ = BleConnectionManagerImpl::Factory::Create(
         mock_adapter_, fake_ble_service_data_helper_.get(),
+        fake_ble_synchronizer_.get(), fake_ble_scanner_.get(),
         fake_timer_factory_.get(), test_clock_.get());
   }
 
   void TearDown() override {
-    BleSynchronizer::Factory::SetFactoryForTesting(nullptr);
     BleAdvertiserImpl::Factory::SetFactoryForTesting(nullptr);
-    BleScannerImpl::Factory::SetFactoryForTesting(nullptr);
     SecureChannelDisconnectorImpl::Factory::SetFactoryForTesting(nullptr);
     weave::BluetoothLowEnergyWeaveClientConnection::Factory::
         SetFactoryForTesting(nullptr);
@@ -420,13 +333,13 @@
     if (expected_to_add_request) {
       EXPECT_EQ(connection_priority,
                 *fake_ble_advertiser()->GetPriorityForRequest(device_id_pair));
-      EXPECT_TRUE(fake_ble_scanner()->HasScanRequest(ConnectionAttemptDetails(
+      EXPECT_TRUE(fake_ble_scanner_->HasScanRequest(ConnectionAttemptDetails(
           device_id_pair, ConnectionMedium::kBluetoothLowEnergy,
           ConnectionRole::kInitiatorRole)));
     } else {
       EXPECT_FALSE(
           fake_ble_advertiser()->GetPriorityForRequest(device_id_pair));
-      EXPECT_FALSE(fake_ble_scanner()->HasScanRequest(ConnectionAttemptDetails(
+      EXPECT_FALSE(fake_ble_scanner_->HasScanRequest(ConnectionAttemptDetails(
           device_id_pair, ConnectionMedium::kBluetoothLowEnergy,
           ConnectionRole::kInitiatorRole)));
     }
@@ -445,13 +358,13 @@
     if (expected_to_update_priority) {
       EXPECT_EQ(connection_priority,
                 *fake_ble_advertiser()->GetPriorityForRequest(device_id_pair));
-      EXPECT_TRUE(fake_ble_scanner()->HasScanRequest(ConnectionAttemptDetails(
+      EXPECT_TRUE(fake_ble_scanner_->HasScanRequest(ConnectionAttemptDetails(
           device_id_pair, ConnectionMedium::kBluetoothLowEnergy,
           ConnectionRole::kInitiatorRole)));
     } else {
       EXPECT_FALSE(
           fake_ble_advertiser()->GetPriorityForRequest(device_id_pair));
-      EXPECT_FALSE(fake_ble_scanner()->HasScanRequest(ConnectionAttemptDetails(
+      EXPECT_FALSE(fake_ble_scanner_->HasScanRequest(ConnectionAttemptDetails(
           device_id_pair, ConnectionMedium::kBluetoothLowEnergy,
           ConnectionRole::kInitiatorRole)));
     }
@@ -462,7 +375,7 @@
                                           ConnectionRole::kInitiatorRole);
     manager_->CancelBleInitiatorConnectionAttempt(device_id_pair);
     EXPECT_FALSE(fake_ble_advertiser()->GetPriorityForRequest(device_id_pair));
-    EXPECT_FALSE(fake_ble_scanner()->HasScanRequest(ConnectionAttemptDetails(
+    EXPECT_FALSE(fake_ble_scanner_->HasScanRequest(ConnectionAttemptDetails(
         device_id_pair, ConnectionMedium::kBluetoothLowEnergy,
         ConnectionRole::kInitiatorRole)));
   }
@@ -486,11 +399,11 @@
             should_cancel_attempt_on_failure));
 
     if (expected_to_add_request) {
-      EXPECT_TRUE(fake_ble_scanner()->HasScanRequest(ConnectionAttemptDetails(
+      EXPECT_TRUE(fake_ble_scanner_->HasScanRequest(ConnectionAttemptDetails(
           device_id_pair, ConnectionMedium::kBluetoothLowEnergy,
           ConnectionRole::kListenerRole)));
     } else {
-      EXPECT_FALSE(fake_ble_scanner()->HasScanRequest(ConnectionAttemptDetails(
+      EXPECT_FALSE(fake_ble_scanner_->HasScanRequest(ConnectionAttemptDetails(
           device_id_pair, ConnectionMedium::kBluetoothLowEnergy,
           ConnectionRole::kListenerRole)));
     }
@@ -507,11 +420,11 @@
                                                   connection_priority);
 
     if (expected_to_update_priority) {
-      EXPECT_TRUE(fake_ble_scanner()->HasScanRequest(ConnectionAttemptDetails(
+      EXPECT_TRUE(fake_ble_scanner_->HasScanRequest(ConnectionAttemptDetails(
           device_id_pair, ConnectionMedium::kBluetoothLowEnergy,
           ConnectionRole::kListenerRole)));
     } else {
-      EXPECT_FALSE(fake_ble_scanner()->HasScanRequest(ConnectionAttemptDetails(
+      EXPECT_FALSE(fake_ble_scanner_->HasScanRequest(ConnectionAttemptDetails(
           device_id_pair, ConnectionMedium::kBluetoothLowEnergy,
           ConnectionRole::kListenerRole)));
     }
@@ -521,7 +434,7 @@
     RemoveFromRemoteDeviceIdToMetadataMap(device_id_pair,
                                           ConnectionRole::kListenerRole);
     manager_->CancelBleListenerConnectionAttempt(device_id_pair);
-    EXPECT_FALSE(fake_ble_scanner()->HasScanRequest(ConnectionAttemptDetails(
+    EXPECT_FALSE(fake_ble_scanner_->HasScanRequest(ConnectionAttemptDetails(
         device_id_pair, ConnectionMedium::kBluetoothLowEnergy,
         ConnectionRole::kListenerRole)));
   }
@@ -562,7 +475,7 @@
     fake_weave_client_connection_factory_->set_expected_bluetooth_device(
         mock_bluetooth_device.get());
 
-    fake_ble_scanner()->NotifyReceivedAdvertisementFromDevice(
+    fake_ble_scanner_->NotifyReceivedAdvertisementFromDevice(
         remote_device, mock_bluetooth_device.get(),
         ConnectionMedium::kBluetoothLowEnergy, connection_role);
 
@@ -572,7 +485,7 @@
                     ->GetAllRequestsForRemoteDevice(remote_device.GetDeviceId())
                     .empty());
     EXPECT_TRUE(
-        fake_ble_scanner()
+        fake_ble_scanner_
             ->GetAllScanRequestsForRemoteDevice(remote_device.GetDeviceId())
             .empty());
 
@@ -649,7 +562,7 @@
                     *fake_ble_advertiser()->GetPriorityForRequest(
                         std::get<0>(tuple)));
           EXPECT_TRUE(
-              fake_ble_scanner()->HasScanRequest(ConnectionAttemptDetails(
+              fake_ble_scanner_->HasScanRequest(ConnectionAttemptDetails(
                   std::get<0>(tuple), ConnectionMedium::kBluetoothLowEnergy,
                   ConnectionRole::kInitiatorRole)));
           break;
@@ -657,7 +570,7 @@
 
         case ConnectionRole::kListenerRole: {
           EXPECT_TRUE(
-              fake_ble_scanner()->HasScanRequest(ConnectionAttemptDetails(
+              fake_ble_scanner_->HasScanRequest(ConnectionAttemptDetails(
                   std::get<0>(tuple), ConnectionMedium::kBluetoothLowEnergy,
                   ConnectionRole::kListenerRole)));
           break;
@@ -696,7 +609,7 @@
                     *fake_ble_advertiser()->GetPriorityForRequest(
                         std::get<0>(tuple)));
           EXPECT_TRUE(
-              fake_ble_scanner()->HasScanRequest(ConnectionAttemptDetails(
+              fake_ble_scanner_->HasScanRequest(ConnectionAttemptDetails(
                   std::get<0>(tuple), ConnectionMedium::kBluetoothLowEnergy,
                   ConnectionRole::kInitiatorRole)));
           break;
@@ -704,7 +617,7 @@
 
         case ConnectionRole::kListenerRole: {
           EXPECT_TRUE(
-              fake_ble_scanner()->HasScanRequest(ConnectionAttemptDetails(
+              fake_ble_scanner_->HasScanRequest(ConnectionAttemptDetails(
                   std::get<0>(tuple), ConnectionMedium::kBluetoothLowEnergy,
                   ConnectionRole::kListenerRole)));
           break;
@@ -851,10 +764,6 @@
     return fake_ble_advertiser_factory_->instance();
   }
 
-  FakeBleScanner* fake_ble_scanner() {
-    return fake_ble_scanner_factory_->instance();
-  }
-
   FakeSecureChannelDisconnector* fake_secure_channel_disconnector() {
     return fake_secure_channel_disconnector_factory_->instance();
   }
@@ -876,9 +785,7 @@
   std::vector<std::pair<DeviceIdPair, BleListenerFailureType>>
       ble_listener_failures_;
 
-  std::unique_ptr<FakeBleSynchronizerFactory> fake_ble_synchronizer_factory_;
   std::unique_ptr<FakeBleAdvertiserFactory> fake_ble_advertiser_factory_;
-  std::unique_ptr<FakeBleScannerFactory> fake_ble_scanner_factory_;
   std::unique_ptr<FakeSecureChannelDisconnectorFactory>
       fake_secure_channel_disconnector_factory_;
   std::unique_ptr<FakeWeaveClientConnectionFactory>
@@ -889,6 +796,8 @@
 
   scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>> mock_adapter_;
   std::unique_ptr<FakeBleServiceDataHelper> fake_ble_service_data_helper_;
+  std::unique_ptr<FakeBleSynchronizer> fake_ble_synchronizer_;
+  std::unique_ptr<FakeBleScanner> fake_ble_scanner_;
   std::unique_ptr<FakeTimerFactory> fake_timer_factory_;
   std::unique_ptr<base::SimpleTestClock> test_clock_;
 
diff --git a/chromeos/services/secure_channel/secure_channel_impl.cc b/chromeos/services/secure_channel/secure_channel_impl.cc
index 126c35f1..e190178 100644
--- a/chromeos/services/secure_channel/secure_channel_impl.cc
+++ b/chromeos/services/secure_channel/secure_channel_impl.cc
@@ -13,7 +13,9 @@
 #include "chromeos/services/secure_channel/active_connection_manager_impl.h"
 #include "chromeos/services/secure_channel/authenticated_channel.h"
 #include "chromeos/services/secure_channel/ble_connection_manager_impl.h"
+#include "chromeos/services/secure_channel/ble_scanner_impl.h"
 #include "chromeos/services/secure_channel/ble_service_data_helper_impl.h"
+#include "chromeos/services/secure_channel/ble_synchronizer.h"
 #include "chromeos/services/secure_channel/client_connection_parameters_impl.h"
 #include "chromeos/services/secure_channel/device_id_pair.h"
 #include "chromeos/services/secure_channel/pending_connection_manager_impl.h"
@@ -68,9 +70,16 @@
       remote_device_cache_(multidevice::RemoteDeviceCache::Factory::Create()),
       ble_service_data_helper_(BleServiceDataHelperImpl::Factory::Create(
           remote_device_cache_.get())),
+      ble_synchronizer_(BleSynchronizer::Factory::Create(bluetooth_adapter_)),
+      ble_scanner_(
+          BleScannerImpl::Factory::Create(ble_service_data_helper_.get(),
+                                          ble_synchronizer_.get(),
+                                          bluetooth_adapter_)),
       ble_connection_manager_(BleConnectionManagerImpl::Factory::Create(
           bluetooth_adapter_,
           ble_service_data_helper_.get(),
+          ble_synchronizer_.get(),
+          ble_scanner_.get(),
           timer_factory_.get())),
       pending_connection_manager_(PendingConnectionManagerImpl::Factory::Create(
           this /* delegate */,
diff --git a/chromeos/services/secure_channel/secure_channel_impl.h b/chromeos/services/secure_channel/secure_channel_impl.h
index 0214dfde..4b3d2aa 100644
--- a/chromeos/services/secure_channel/secure_channel_impl.h
+++ b/chromeos/services/secure_channel/secure_channel_impl.h
@@ -29,7 +29,9 @@
 namespace secure_channel {
 
 class BleConnectionManager;
+class BleScanner;
 class BleServiceDataHelper;
+class BleSynchronizerBase;
 class TimerFactory;
 
 // Concrete SecureChannelImpl implementation, which contains three pieces:
@@ -173,6 +175,8 @@
   std::unique_ptr<TimerFactory> timer_factory_;
   std::unique_ptr<multidevice::RemoteDeviceCache> remote_device_cache_;
   std::unique_ptr<BleServiceDataHelper> ble_service_data_helper_;
+  std::unique_ptr<BleSynchronizerBase> ble_synchronizer_;
+  std::unique_ptr<BleScanner> ble_scanner_;
   std::unique_ptr<BleConnectionManager> ble_connection_manager_;
   std::unique_ptr<PendingConnectionManager> pending_connection_manager_;
   std::unique_ptr<ActiveConnectionManager> active_connection_manager_;
diff --git a/chromeos/services/secure_channel/secure_channel_service_unittest.cc b/chromeos/services/secure_channel/secure_channel_service_unittest.cc
index 9e9f834..68274fd 100644
--- a/chromeos/services/secure_channel/secure_channel_service_unittest.cc
+++ b/chromeos/services/secure_channel/secure_channel_service_unittest.cc
@@ -16,12 +16,16 @@
 #include "chromeos/components/multidevice/remote_device_test_util.h"
 #include "chromeos/services/secure_channel/active_connection_manager_impl.h"
 #include "chromeos/services/secure_channel/ble_connection_manager_impl.h"
+#include "chromeos/services/secure_channel/ble_scanner_impl.h"
 #include "chromeos/services/secure_channel/ble_service_data_helper_impl.h"
+#include "chromeos/services/secure_channel/ble_synchronizer.h"
 #include "chromeos/services/secure_channel/client_connection_parameters_impl.h"
 #include "chromeos/services/secure_channel/fake_active_connection_manager.h"
 #include "chromeos/services/secure_channel/fake_authenticated_channel.h"
 #include "chromeos/services/secure_channel/fake_ble_connection_manager.h"
+#include "chromeos/services/secure_channel/fake_ble_scanner.h"
 #include "chromeos/services/secure_channel/fake_ble_service_data_helper.h"
+#include "chromeos/services/secure_channel/fake_ble_synchronizer.h"
 #include "chromeos/services/secure_channel/fake_client_connection_parameters.h"
 #include "chromeos/services/secure_channel/fake_connection_delegate.h"
 #include "chromeos/services/secure_channel/fake_pending_connection_manager.h"
@@ -123,16 +127,81 @@
   DISALLOW_COPY_AND_ASSIGN(FakeBleServiceDataHelperFactory);
 };
 
+class FakeBleSynchronizerFactory : public BleSynchronizer::Factory {
+ public:
+  FakeBleSynchronizerFactory() = default;
+  ~FakeBleSynchronizerFactory() override = default;
+
+  FakeBleSynchronizer* instance() { return instance_; }
+
+ private:
+  // BleSynchronizer::Factory:
+  std::unique_ptr<BleSynchronizerBase> CreateInstance(
+      scoped_refptr<device::BluetoothAdapter> bluetooth_adapter) override {
+    EXPECT_FALSE(instance_);
+
+    auto instance = std::make_unique<FakeBleSynchronizer>();
+    instance_ = instance.get();
+    return instance;
+  }
+
+  FakeBleSynchronizer* instance_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeBleSynchronizerFactory);
+};
+
+class FakeBleScannerFactory : public BleScannerImpl::Factory {
+ public:
+  FakeBleScannerFactory(
+      FakeBleServiceDataHelperFactory* fake_ble_service_data_helper_factory,
+      FakeBleSynchronizerFactory* fake_ble_synchronizer_factory)
+      : fake_ble_service_data_helper_factory_(
+            fake_ble_service_data_helper_factory),
+        fake_ble_synchronizer_factory_(fake_ble_synchronizer_factory) {}
+
+  ~FakeBleScannerFactory() override = default;
+
+  FakeBleScanner* instance() { return instance_; }
+
+ private:
+  // BleScannerImpl::Factory:
+  std::unique_ptr<BleScanner> CreateInstance(
+      BleServiceDataHelper* service_data_helper,
+      BleSynchronizerBase* ble_synchronizer_base,
+      scoped_refptr<device::BluetoothAdapter> adapter) override {
+    EXPECT_EQ(fake_ble_service_data_helper_factory_->instance(),
+              service_data_helper);
+    EXPECT_EQ(fake_ble_synchronizer_factory_->instance(),
+              ble_synchronizer_base);
+    EXPECT_FALSE(instance_);
+
+    auto instance = std::make_unique<FakeBleScanner>();
+    instance_ = instance.get();
+    return instance;
+  }
+
+  FakeBleScanner* instance_ = nullptr;
+
+  FakeBleServiceDataHelperFactory* fake_ble_service_data_helper_factory_;
+  FakeBleSynchronizerFactory* fake_ble_synchronizer_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeBleScannerFactory);
+};
+
 class FakeBleConnectionManagerFactory
     : public BleConnectionManagerImpl::Factory {
  public:
   FakeBleConnectionManagerFactory(
       device::BluetoothAdapter* expected_bluetooth_adapter,
       FakeBleServiceDataHelperFactory* fake_ble_service_data_helper_factory,
+      FakeBleSynchronizerFactory* fake_ble_synchronizer_factory,
+      FakeBleScannerFactory* fake_ble_scanner_factory,
       FakeTimerFactoryFactory* fake_timer_factory_factory)
       : expected_bluetooth_adapter_(expected_bluetooth_adapter),
         fake_ble_service_data_helper_factory_(
             fake_ble_service_data_helper_factory),
+        fake_ble_synchronizer_factory_(fake_ble_synchronizer_factory),
+        fake_ble_scanner_factory_(fake_ble_scanner_factory),
         fake_timer_factory_factory_(fake_timer_factory_factory) {}
 
   ~FakeBleConnectionManagerFactory() override = default;
@@ -144,12 +213,16 @@
   std::unique_ptr<BleConnectionManager> CreateInstance(
       scoped_refptr<device::BluetoothAdapter> bluetooth_adapter,
       BleServiceDataHelper* ble_service_data_helper,
+      BleSynchronizerBase* ble_synchronizer,
+      BleScanner* ble_scanner,
       TimerFactory* timer_factory,
       base::Clock* clock) override {
     EXPECT_FALSE(instance_);
     EXPECT_EQ(expected_bluetooth_adapter_, bluetooth_adapter.get());
     EXPECT_EQ(fake_ble_service_data_helper_factory_->instance(),
               ble_service_data_helper);
+    EXPECT_EQ(fake_ble_synchronizer_factory_->instance(), ble_synchronizer);
+    EXPECT_EQ(fake_ble_scanner_factory_->instance(), ble_scanner);
     EXPECT_EQ(fake_timer_factory_factory_->instance(), timer_factory);
 
     auto instance = std::make_unique<FakeBleConnectionManager>();
@@ -159,6 +232,8 @@
 
   device::BluetoothAdapter* expected_bluetooth_adapter_;
   FakeBleServiceDataHelperFactory* fake_ble_service_data_helper_factory_;
+  FakeBleSynchronizerFactory* fake_ble_synchronizer_factory_;
+  FakeBleScannerFactory* fake_ble_scanner_factory_;
   FakeTimerFactoryFactory* fake_timer_factory_factory_;
 
   FakeBleConnectionManager* instance_ = nullptr;
@@ -358,10 +433,22 @@
     BleServiceDataHelperImpl::Factory::SetFactoryForTesting(
         fake_ble_service_data_helper_factory_.get());
 
+    fake_ble_synchronizer_factory_ =
+        std::make_unique<FakeBleSynchronizerFactory>();
+    BleSynchronizer::Factory::SetFactoryForTesting(
+        fake_ble_synchronizer_factory_.get());
+
+    fake_ble_scanner_factory_ = std::make_unique<FakeBleScannerFactory>(
+        fake_ble_service_data_helper_factory_.get(),
+        fake_ble_synchronizer_factory_.get());
+    BleScannerImpl::Factory::SetFactoryForTesting(
+        fake_ble_scanner_factory_.get());
+
     fake_ble_connection_manager_factory_ =
         std::make_unique<FakeBleConnectionManagerFactory>(
             mock_adapter_.get(), fake_ble_service_data_helper_factory_.get(),
-            fake_timer_factory_factory_.get());
+            fake_ble_synchronizer_factory_.get(),
+            fake_ble_scanner_factory_.get(), fake_timer_factory_factory_.get());
     BleConnectionManagerImpl::Factory::SetFactoryForTesting(
         fake_ble_connection_manager_factory_.get());
 
@@ -396,6 +483,8 @@
     TimerFactoryImpl::Factory::SetFactoryForTesting(nullptr);
     multidevice::RemoteDeviceCache::Factory::SetFactoryForTesting(nullptr);
     BleServiceDataHelperImpl::Factory::SetFactoryForTesting(nullptr);
+    BleSynchronizer::Factory::SetFactoryForTesting(nullptr);
+    BleScannerImpl::Factory::SetFactoryForTesting(nullptr);
     BleConnectionManagerImpl::Factory::SetFactoryForTesting(nullptr);
     PendingConnectionManagerImpl::Factory::SetFactoryForTesting(nullptr);
     ActiveConnectionManagerImpl::Factory::SetFactoryForTesting(nullptr);
@@ -870,6 +959,8 @@
       test_remote_device_cache_factory_;
   std::unique_ptr<FakeBleServiceDataHelperFactory>
       fake_ble_service_data_helper_factory_;
+  std::unique_ptr<FakeBleSynchronizerFactory> fake_ble_synchronizer_factory_;
+  std::unique_ptr<FakeBleScannerFactory> fake_ble_scanner_factory_;
   std::unique_ptr<FakeBleConnectionManagerFactory>
       fake_ble_connection_manager_factory_;
   std::unique_ptr<FakePendingConnectionManagerFactory>
diff --git a/components/autofill/content/common/mojom/autofill_driver.mojom b/components/autofill/content/common/mojom/autofill_driver.mojom
index 48c32fa8..6807ea2 100644
--- a/components/autofill/content/common/mojom/autofill_driver.mojom
+++ b/components/autofill/content/common/mojom/autofill_driver.mojom
@@ -96,13 +96,10 @@
   // Notification that this password form was submitted by the user.
   PasswordFormSubmitted(FormData form_data);
 
-  // Notification that a user starts typing in password fields and the omnibox
-  // icon with anchored save/update prompt should be available.
-  ShowManualFallbackForSaving(FormData form_data);
-
-  // Notification that there is no user input in password fields and the
-  // save/update prompt anchored to the omnibox icon should be removed.
-  HideManualFallbackForSaving();
+  // Notification that a user has modified a password field. This is fired both
+  // when typing new characters and deleting characters, so the password field
+  // in `form_data` may or may not be empty
+  InformAboutUserInput(FormData form_data);
 
   // Notification that same-document navigation happened. We use this as a
   // signal for successful login.
diff --git a/components/autofill/content/renderer/form_tracker.h b/components/autofill/content/renderer/form_tracker.h
index 899f98d..7498871 100644
--- a/components/autofill/content/renderer/form_tracker.h
+++ b/components/autofill/content/renderer/form_tracker.h
@@ -33,6 +33,7 @@
       SELECT_CHANGED,
     };
 
+    // TODO(crbug.com/1126017): Find a better name for this method.
     // Invoked when form needs to be saved because of |source|, |element| is
     // valid if the callback caused by source other than
     // WILL_SEND_SUBMIT_EVENT, |form| is valid for the callback caused by
diff --git a/components/autofill/content/renderer/password_autofill_agent.cc b/components/autofill/content/renderer/password_autofill_agent.cc
index a5e0a581..7e4b315 100644
--- a/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/components/autofill/content/renderer/password_autofill_agent.cc
@@ -356,17 +356,6 @@
   return false;
 }
 
-// Whether any of the fields in |form| is a non-empty password field.
-bool FormHasNonEmptyPasswordField(const FormData& form) {
-  for (const auto& field : form.fields) {
-    if (field.IsPasswordInputElement()) {
-      if (!field.value.empty() || !field.typed_value.empty())
-        return true;
-    }
-  }
-  return false;
-}
-
 void AnnotateFieldWithParsingResult(WebDocument doc,
                                     FieldRendererId renderer_id,
                                     const std::string& text) {
@@ -564,7 +553,7 @@
   field_data_manager_->UpdateFieldDataMap(element_id, element_value,
                                           FieldPropertiesFlags::kUserTyped);
 
-  ProvisionallySavePassword(element.Form(), element, RESTRICTION_NONE);
+  InformBrowserAboutUserInput(element.Form(), element);
 
   if (element.IsPasswordFieldForAutofill()) {
     auto iter = password_to_username_.find(element);
@@ -659,8 +648,7 @@
   DCHECK(password_input);
   DCHECK(password_input->IsPasswordFieldForAutofill());
   FillField(password_input, credential);
-  ProvisionallySavePassword(password_input->Form(), *password_input,
-                            RESTRICTION_NONE);
+  InformBrowserAboutUserInput(password_input->Form(), *password_input);
 }
 
 bool PasswordAutofillAgent::PreviewSuggestion(
@@ -1454,29 +1442,23 @@
     password->SetAutofillState(password_autofill_state_);
   }
 }
-void PasswordAutofillAgent::ProvisionallySavePassword(
+void PasswordAutofillAgent::InformBrowserAboutUserInput(
     const WebFormElement& form,
-    const WebInputElement& element,
-    ProvisionallySaveRestriction restriction) {
+    const WebInputElement& element) {
   DCHECK(!form.IsNull() || !element.IsNull());
+  if (!FrameCanAccessPasswordManager())
+    return;
   SetLastUpdatedFormAndField(form, element);
   std::unique_ptr<FormData> form_data =
-      (form.IsNull() ? GetFormDataFromUnownedInputElements()
-                     : GetFormDataFromWebForm(form));
+      form.IsNull() ? GetFormDataFromUnownedInputElements()
+                    : GetFormDataFromWebForm(form);
   if (!form_data)
     return;
 
-  bool has_password = FormHasNonEmptyPasswordField(*form_data);
-  if (restriction == RESTRICTION_NON_EMPTY_PASSWORD && !has_password)
+  if (!FormHasPasswordField(*form_data))
     return;
 
-  if (!FrameCanAccessPasswordManager())
-    return;
-
-  if (has_password)
-    GetPasswordManagerDriver()->ShowManualFallbackForSaving(*form_data);
-  else
-    GetPasswordManagerDriver()->HideManualFallbackForSaving();
+  GetPasswordManagerDriver()->InformAboutUserInput(*form_data);
 
   browser_has_form_to_process_ = true;
 }
@@ -1639,8 +1621,7 @@
   }
 
   DCHECK_EQ(ElementChangeSource::WILL_SEND_SUBMIT_EVENT, source);
-  ProvisionallySavePassword(form, input_element,
-                            RESTRICTION_NON_EMPTY_PASSWORD);
+  InformBrowserAboutUserInput(form, input_element);
 }
 
 void PasswordAutofillAgent::OnFormSubmitted(const WebFormElement& form) {
diff --git a/components/autofill/content/renderer/password_autofill_agent.h b/components/autofill/content/renderer/password_autofill_agent.h
index 31268fa..3738a1f 100644
--- a/components/autofill/content/renderer/password_autofill_agent.h
+++ b/components/autofill/content/renderer/password_autofill_agent.h
@@ -243,12 +243,6 @@
  private:
   using OnPasswordField = util::StrongAlias<class OnPasswordFieldTag, bool>;
 
-  // Ways to restrict which passwords are saved in ProvisionallySavePassword.
-  enum ProvisionallySaveRestriction {
-    RESTRICTION_NONE,
-    RESTRICTION_NON_EMPTY_PASSWORD
-  };
-
   // Enumeration representing possible Touch To Fill states. This is used to
   // make sure that Touch To Fill will only be shown in response to the first
   // password form focus during a frame's life time and to suppress the soft
@@ -397,14 +391,12 @@
   void FillPasswordFieldAndSave(blink::WebInputElement* password_input,
                                 const base::string16& credential);
 
-  // Saves |form| and |input| in |provisionally_saved_form_|, as long as it
-  // satisfies |restriction|. |form| and |input| are the elements user has just
-  // been interacting with before the form save. |form| or |input| can be null
-  // but not both at the same time. For example: if the form is unowned, |form|
-  // will be null; if the user has submitted the form, |input| will be null.
-  void ProvisionallySavePassword(const blink::WebFormElement& form,
-                                 const blink::WebInputElement& input,
-                                 ProvisionallySaveRestriction restriction);
+  // |form| and |input| are the elements user has just been interacting with
+  // before the form save. |form| or |input| can be null but not both at the
+  // same time. For example: if the form is unowned, |form| will be null; if the
+  // user has submitted the form, |input| will be null.
+  void InformBrowserAboutUserInput(const blink::WebFormElement& form,
+                                   const blink::WebInputElement& input);
 
   // This function attempts to fill |username_element| and |password_element|
   // with values from |fill_data|. The |username_element| and |password_element|
diff --git a/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc b/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc
index 9b45786f..6c76bdbd 100644
--- a/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc
+++ b/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc
@@ -50,10 +50,7 @@
 
   void PasswordFormSubmitted(const autofill::FormData& form_data) override {}
 
-  void ShowManualFallbackForSaving(
-      const autofill::FormData& form_data) override {}
-
-  void HideManualFallbackForSaving() override {}
+  void InformAboutUserInput(const autofill::FormData& form_data) override {}
 
   void SameDocumentNavigation(autofill::mojom::SubmissionIndicatorEvent
                                   submission_indication_event) override {}
diff --git a/components/autofill/core/browser/autofill_metrics.cc b/components/autofill/core/browser/autofill_metrics.cc
index f102f93e..67bedb21 100644
--- a/components/autofill/core/browser/autofill_metrics.cc
+++ b/components/autofill/core/browser/autofill_metrics.cc
@@ -49,6 +49,11 @@
   GROUP_ADDRESS_STATE,
   GROUP_ADDRESS_ZIP,
   GROUP_ADDRESS_COUNTRY,
+  GROUP_ADDRESS_HOME_STREET_NAME,
+  GROUP_ADDRESS_HOME_DEPENDENT_STREET_NAME,
+  GROUP_ADDRESS_HOME_HOUSE_NUMBER,
+  GROUP_ADDRESS_HOME_PREMISE_NAME,
+  GROUP_ADDRESS_HOME_SUBPREMISE,
   GROUP_PHONE,
   GROUP_FAX,  // Deprecated.
   GROUP_EMAIL,
@@ -158,6 +163,21 @@
         case ADDRESS_HOME_COUNTRY:
           group = GROUP_ADDRESS_COUNTRY;
           break;
+        case ADDRESS_HOME_STREET_NAME:
+          group = GROUP_ADDRESS_HOME_STREET_NAME;
+          break;
+        case ADDRESS_HOME_DEPENDENT_STREET_NAME:
+          group = GROUP_ADDRESS_HOME_DEPENDENT_STREET_NAME;
+          break;
+        case ADDRESS_HOME_HOUSE_NUMBER:
+          group = GROUP_ADDRESS_HOME_HOUSE_NUMBER;
+          break;
+        case ADDRESS_HOME_PREMISE_NAME:
+          group = GROUP_ADDRESS_HOME_PREMISE_NAME;
+          break;
+        case ADDRESS_HOME_SUBPREMISE:
+          group = GROUP_ADDRESS_HOME_SUBPREMISE;
+          break;
         default:
           NOTREACHED() << field_type << " has no group assigned (ambiguous)";
           group = GROUP_AMBIGUOUS;
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc
index 3b7b0ea1c..b108c47 100644
--- a/components/autofill/core/browser/form_structure.cc
+++ b/components/autofill/core/browser/form_structure.cc
@@ -1115,6 +1115,30 @@
         cached_field = it->second;
     }
 
+    // If the unique renderer id (or the name) is not stable due to some Java
+    // Script magic in the website, use the field signature as a fallback
+    // solution to find the field in the cached form.
+    // TODO(crbug.com/1125624): Remove feature check once trial ended.
+    if (!cached_field &&
+        base::FeatureList::IsEnabled(
+            features::kAutofillRetrieveFromCacheWithFieldSignatureAsFallback)) {
+      // Iterates over the fields to find the field with the same form
+      // signature.
+      for (size_t i = 0; i < cached_form.field_count(); ++i) {
+        auto* const cfield = cached_form.field(i);
+        if (field->GetFieldSignature() == cfield->GetFieldSignature()) {
+          // If there are multiple matches, do not retrieve the field and stop
+          // the process.
+          if (cached_field) {
+            cached_field = nullptr;
+            break;
+          } else {
+            cached_field = cfield;
+          }
+        }
+      }
+    }
+
     if (cached_field) {
       if (!only_server_and_autofill_state) {
         // Transfer attributes of the cached AutofillField to the newly created
diff --git a/components/autofill/core/browser/payments/legal_message_line.h b/components/autofill/core/browser/payments/legal_message_line.h
index 4d9f2659..e99a588b 100644
--- a/components/autofill/core/browser/payments/legal_message_line.h
+++ b/components/autofill/core/browser/payments/legal_message_line.h
@@ -33,6 +33,7 @@
     gfx::Range range;
     GURL url;
   };
+  using Links = std::vector<Link>;
 
   LegalMessageLine();
   LegalMessageLine(const LegalMessageLine& other);
@@ -75,7 +76,7 @@
                     bool escape_apostrophes = false);
 
   const base::string16& text() const { return text_; }
-  const std::vector<Link>& links() const { return links_; }
+  const Links& links() const { return links_; }
 
  private:
   friend class TestLegalMessageLine;
@@ -83,7 +84,7 @@
   bool ParseLine(const base::Value& line, bool escape_apostrophes);
 
   base::string16 text_;
-  std::vector<Link> links_;
+  Links links_;
 };
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/payments/test_legal_message_line.h b/components/autofill/core/browser/payments/test_legal_message_line.h
index 1fdfcd66..111e904 100644
--- a/components/autofill/core/browser/payments/test_legal_message_line.h
+++ b/components/autofill/core/browser/payments/test_legal_message_line.h
@@ -21,8 +21,7 @@
 
   TestLegalMessageLine(const std::string& ascii_text) { set_text(ascii_text); }
 
-  TestLegalMessageLine(const std::string& ascii_text,
-                       const std::vector<Link>& links) {
+  TestLegalMessageLine(const std::string& ascii_text, const Links& links) {
     set_text(ascii_text);
     set_links(links);
   }
@@ -33,7 +32,7 @@
     text_ = base::ASCIIToUTF16(ascii_text);
   }
 
-  void set_links(const std::vector<Link>& links) { links_ = links; }
+  void set_links(const Links& links) { links_ = links; }
 
  private:
   DISALLOW_COPY_AND_ASSIGN(TestLegalMessageLine);
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc
index fae996c..55747282 100644
--- a/components/autofill/core/common/autofill_features.cc
+++ b/components/autofill/core/common/autofill_features.cc
@@ -159,6 +159,13 @@
     "AutofillRetrieveFromCacheWithRendererIds",
     base::FEATURE_DISABLED_BY_DEFAULT};
 
+// When enabled, Autofill will try to retrieve cached fields by signatures as a
+// fallback that is useful if unique renderer ids are unstable.
+// TODO(crbug.com/1125624): Remove experiment once trial ended.
+const base::Feature kAutofillRetrieveFromCacheWithFieldSignatureAsFallback{
+    "AutofillRetrieveFromCacheWithFieldSignatureAsFallback",
+    base::FEATURE_DISABLED_BY_DEFAULT};
+
 // When enabled, autofill suggestions are displayed in the keyboard accessory
 // instead of the regular popup.
 const base::Feature kAutofillKeyboardAccessory{
diff --git a/components/autofill/core/common/autofill_features.h b/components/autofill/core/common/autofill_features.h
index 37457fb..adcfb2e 100644
--- a/components/autofill/core/common/autofill_features.h
+++ b/components/autofill/core/common/autofill_features.h
@@ -45,6 +45,8 @@
 extern const base::Feature kAutofillImportPrefilledCountryAndStateValues;
 extern const base::Feature kAutofillKeepInitialFormValuesInCache;
 extern const base::Feature kAutofillRetrieveFromCacheWithRendererIds;
+extern const base::Feature
+    kAutofillRetrieveFromCacheWithFieldSignatureAsFallback;
 extern const base::Feature kAutofillKeyboardAccessory;
 extern const base::Feature kAutofillLabelAffixRemoval;
 extern const base::Feature kAutofillPruneSuggestions;
diff --git a/components/autofill/core/common/form_data.cc b/components/autofill/core/common/form_data.cc
index e2199e3..0861134 100644
--- a/components/autofill/core/common/form_data.cc
+++ b/components/autofill/core/common/form_data.cc
@@ -142,6 +142,16 @@
                                       FormFieldData::IdentityComparator());
 }
 
+bool FormHasNonEmptyPasswordField(const FormData& form) {
+  for (const auto& field : form.fields) {
+    if (field.IsPasswordInputElement()) {
+      if (!field.value.empty() || !field.typed_value.empty())
+        return true;
+    }
+  }
+  return false;
+}
+
 std::ostream& operator<<(std::ostream& os, const FormData& form) {
   os << base::UTF16ToUTF8(form.name) << " " << form.url << " " << form.action
      << " " << form.main_frame_origin << " " << form.is_form_tag << " "
diff --git a/components/autofill/core/common/form_data.h b/components/autofill/core/common/form_data.h
index 9b59194..b57d18df 100644
--- a/components/autofill/core/common/form_data.h
+++ b/components/autofill/core/common/form_data.h
@@ -120,6 +120,9 @@
 #endif
 };
 
+// Whether any of the fields in |form| is a non-empty password field.
+bool FormHasNonEmptyPasswordField(const FormData& form);
+
 // For testing.
 std::ostream& operator<<(std::ostream& os, const FormData& form);
 
diff --git a/components/page_info/android/BUILD.gn b/components/page_info/android/BUILD.gn
index 45a865ffe..e8a135a 100644
--- a/components/page_info/android/BUILD.gn
+++ b/components/page_info/android/BUILD.gn
@@ -51,9 +51,9 @@
     "java/res/layout/connection_info.xml",
     "java/res/layout/cookie_controls_view.xml",
     "java/res/layout/page_info.xml",
+    "java/res/layout/page_info_container.xml",
     "java/res/layout/page_info_permission_row.xml",
     "java/res/layout/page_info_row.xml",
-    "java/res/layout/page_info_subpage.xml",
     "java/res/layout/page_info_v2.xml",
     "java/res/values/colors.xml",
     "java/res/values/dimens.xml",
@@ -77,16 +77,16 @@
     "java/src/org/chromium/components/page_info/ConnectionInfoView.java",
     "java/src/org/chromium/components/page_info/CookieControlsView.java",
     "java/src/org/chromium/components/page_info/PageInfoConnectionController.java",
+    "java/src/org/chromium/components/page_info/PageInfoContainer.java",
     "java/src/org/chromium/components/page_info/PageInfoController.java",
     "java/src/org/chromium/components/page_info/PageInfoControllerDelegate.java",
     "java/src/org/chromium/components/page_info/PageInfoCookiesController.java",
     "java/src/org/chromium/components/page_info/PageInfoCookiesPreference.java",
     "java/src/org/chromium/components/page_info/PageInfoDialog.java",
     "java/src/org/chromium/components/page_info/PageInfoFeatureList.java",
-    "java/src/org/chromium/components/page_info/PageInfoMainPageController.java",
+    "java/src/org/chromium/components/page_info/PageInfoMainController.java",
     "java/src/org/chromium/components/page_info/PageInfoPermissionsController.java",
     "java/src/org/chromium/components/page_info/PageInfoRowView.java",
-    "java/src/org/chromium/components/page_info/PageInfoSubpage.java",
     "java/src/org/chromium/components/page_info/PageInfoSubpageController.java",
     "java/src/org/chromium/components/page_info/PageInfoView.java",
     "java/src/org/chromium/components/page_info/PageInfoViewV2.java",
diff --git a/components/page_info/android/java/res/layout/page_info_subpage.xml b/components/page_info/android/java/res/layout/page_info_container.xml
similarity index 75%
rename from components/page_info/android/java/res/layout/page_info_subpage.xml
rename to components/page_info/android/java/res/layout/page_info_container.xml
index a7afe4f..b70ba73 100644
--- a/components/page_info/android/java/res/layout/page_info_subpage.xml
+++ b/components/page_info/android/java/res/layout/page_info_container.xml
@@ -14,14 +14,26 @@
     android:background="@color/sheet_bg_color"
     android:orientation="vertical">
 
+    <TextView
+        android:id="@+id/page_info_truncated_url"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal"
+        android:ellipsize="end"
+        android:layout_marginVertical="16dp"
+        android:lineSpacingExtra="6dp"
+        android:textAlignment="center"
+        android:textAppearance="@style/TextAppearance.TextLarge.Primary" />
+
     <view
-        android:id="@+id/subpage_url"
+        android:id="@+id/page_info_url"
         class="org.chromium.components.page_info.PageInfoView$ElidedUrlTextView"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:ellipsize="end"
         android:lineSpacingExtra="6dp"
         android:paddingVertical="16dp"
+        android:visibility="gone"
         android:textAlignment="center"
         android:textAppearance="@style/TextAppearance.TextLarge.Primary" />
 
@@ -30,7 +42,8 @@
         android:layout_height="wrap_content"
         android:orientation="horizontal"
         android:gravity="center_vertical"
-        android:paddingHorizontal="16dp">
+        android:paddingHorizontal="16dp"
+        android:id="@+id/page_info_subpage_header">
 
         <org.chromium.ui.widget.ChromeImageButton
             android:id="@+id/subpage_back_button"
@@ -45,7 +58,7 @@
             app:tint="@color/default_icon_color" />
 
         <TextView
-            android:id="@+id/subpage_title"
+            android:id="@+id/page_info_subpage_title"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_marginVertical="12dp"
@@ -54,7 +67,7 @@
 
     <!-- Programmatically add page specific inner view here -->
     <FrameLayout
-        android:id="@+id/placeholder"
+        android:id="@+id/page_info_content"
         android:layout_width="match_parent"
         android:layout_height="match_parent" />
 
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 e8c05c6..c068351 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
@@ -17,32 +17,7 @@
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:orientation="vertical"
-        android:paddingBottom="12dp"
-        android:paddingEnd="@dimen/page_info_popup_padding_sides"
-        android:paddingStart="@dimen/page_info_popup_padding_sides" >
-
-        <TextView
-            android:id="@+id/page_info_truncated_url"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center_horizontal"
-            android:ellipsize="end"
-            android:layout_marginTop="16dp"
-            android:lineSpacingExtra="6dp"
-            android:textAlignment="center"
-            android:textAppearance="@style/TextAppearance.TextLarge.Primary" />
-
-        <view class="org.chromium.components.page_info.PageInfoView$ElidedUrlTextView"
-            android:id="@+id/page_info_url"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:ellipsize="end"
-            android:lineSpacingExtra="6dp"
-            android:layout_marginTop="16dp"
-            android:textAlignment="viewStart"
-            android:textAppearance="@style/TextAppearance.TextLarge.Primary" />
-
+        android:orientation="vertical">
         <View
             android:id="@+id/page_info_preview_separator"
             android:layout_marginTop="16dp"
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoConnectionController.java b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoConnectionController.java
index 624e480..2ed3af89 100644
--- a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoConnectionController.java
+++ b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoConnectionController.java
@@ -17,7 +17,7 @@
  */
 public class PageInfoConnectionController
         implements PageInfoSubpageController, ConnectionInfoView.ConnectionInfoDelegate {
-    private PageInfoMainPageController mMainController;
+    private PageInfoMainController mMainController;
     private final WebContents mWebContents;
     private final VrHandler mVrHandler;
     private PageInfoRowView mRowView;
@@ -25,8 +25,8 @@
     private ConnectionInfoView mInfoView;
     private ViewGroup mContainer;
 
-    public PageInfoConnectionController(PageInfoMainPageController mainController,
-            PageInfoRowView view, WebContents webContents, VrHandler vrHandler) {
+    public PageInfoConnectionController(PageInfoMainController mainController, PageInfoRowView view,
+            WebContents webContents, VrHandler vrHandler) {
         mMainController = mainController;
         mWebContents = webContents;
         mVrHandler = vrHandler;
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoContainer.java b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoContainer.java
new file mode 100644
index 0000000..070bf76
--- /dev/null
+++ b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoContainer.java
@@ -0,0 +1,103 @@
+// 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.components.page_info;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+
+import org.chromium.ui.widget.ChromeImageButton;
+
+/**
+ * Represents the url, a sub page header and container for page info content.
+ */
+public class PageInfoContainer extends FrameLayout {
+    /**  Parameters to configure the view of page info subpage. */
+    public static class Params {
+        // Whether the URL title should be shown.
+        public boolean urlTitleShown;
+        // The URL to be shown at the top of the page.
+        public CharSequence url;
+        // The length of the URL's origin in number of characters.
+        public int urlOriginLength;
+        // The URL to show in truncated state.
+        public String truncatedUrl;
+
+        public Runnable urlTitleClickCallback;
+        public Runnable urlTitleLongClickCallback;
+        public Runnable backButtonClickCallback;
+    }
+    private PageInfoView.ElidedUrlTextView mUrlTitle;
+    private TextView mTruncatedUrlTitle;
+
+    private final View mSubpageHeader;
+    private TextView mSubpageTitle;
+    private final FrameLayout mContent;
+
+    public PageInfoContainer(Context context) {
+        super(context);
+        LayoutInflater.from(context).inflate(R.layout.page_info_container, this, true);
+        mSubpageHeader = findViewById(R.id.page_info_subpage_header);
+        mSubpageTitle = findViewById(R.id.page_info_subpage_title);
+        mContent = findViewById(R.id.page_info_content);
+    }
+
+    public void setParams(Params params) {
+        mUrlTitle = findViewById(R.id.page_info_url);
+        initializeUrlView(mUrlTitle, params);
+        mUrlTitle.setUrl(params.url, params.urlOriginLength);
+        // Adjust the mUrlTitle for displaying the non-truncated URL.
+        mUrlTitle.toggleTruncation();
+
+        mTruncatedUrlTitle = findViewById(R.id.page_info_truncated_url);
+        // Use a separate view for truncated URL display.
+        initializeUrlView(mTruncatedUrlTitle, params);
+        mTruncatedUrlTitle = findViewById(R.id.page_info_truncated_url);
+        mTruncatedUrlTitle.setText(params.truncatedUrl);
+
+        ChromeImageButton backButton = findViewById(R.id.subpage_back_button);
+        backButton.setOnClickListener(v -> params.backButtonClickCallback.run());
+    }
+
+    private void initializeUrlView(View view, Params params) {
+        if (!params.urlTitleShown) {
+            view.setVisibility(GONE);
+        }
+        if (params.urlTitleClickCallback != null) {
+            view.setOnClickListener(v -> { params.urlTitleClickCallback.run(); });
+        }
+        if (params.urlTitleLongClickCallback != null) {
+            view.setOnLongClickListener(v -> {
+                params.urlTitleLongClickCallback.run();
+                return true;
+            });
+        }
+    }
+
+    public void toggleUrlTruncation() {
+        mUrlTitle.setVisibility(mTruncatedUrlTitle.getVisibility());
+        mTruncatedUrlTitle.setVisibility(mUrlTitle.getVisibility() == VISIBLE ? GONE : VISIBLE);
+    }
+
+    public void setFavicon(Drawable favicon) {
+        int padding =
+                getResources().getDimensionPixelSize(R.dimen.page_info_popup_button_padding_sides);
+        int size = getResources().getDimensionPixelSize(R.dimen.page_info_favicon_size);
+
+        favicon.setBounds(0, 0, size, size);
+        mTruncatedUrlTitle.setCompoundDrawablePadding(padding);
+        mTruncatedUrlTitle.setCompoundDrawablesRelative(favicon, null, null, null);
+    }
+
+    public void showPage(View view, CharSequence title, boolean isMainPage) {
+        mContent.removeAllViews();
+        mContent.addView(view);
+        mSubpageHeader.setVisibility(isMainPage ? GONE : VISIBLE);
+        mSubpageTitle.setText(title);
+    }
+}
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoController.java b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoController.java
index a7a1355..459c4db 100644
--- a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoController.java
+++ b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoController.java
@@ -18,9 +18,7 @@
 import android.text.style.ForegroundColorSpan;
 import android.text.style.TextAppearanceSpan;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.Window;
-import android.widget.FrameLayout;
 
 import androidx.annotation.IntDef;
 import androidx.annotation.VisibleForTesting;
@@ -66,9 +64,9 @@
 /**
  * Java side of Android implementation of the page info UI.
  */
-public class PageInfoController
-        implements PageInfoMainPageController, ModalDialogProperties.Controller,
-                   SystemSettingsActivityRequiredListener, CookieControlsObserver {
+public class PageInfoController implements PageInfoMainController, ModalDialogProperties.Controller,
+                                           SystemSettingsActivityRequiredListener,
+                                           CookieControlsObserver {
     @IntDef({OpenedFromSource.MENU, OpenedFromSource.TOOLBAR, OpenedFromSource.VR})
     @Retention(RetentionPolicy.SOURCE)
     public @interface OpenedFromSource {
@@ -85,9 +83,12 @@
     // A pointer to the C++ object for this UI.
     private long mNativePageInfoController;
 
-    // The view inside the popup.
+    // The view inside the popup or the main PageInfo view.
     private PageInfoView mView;
 
+    // The view inside the popup (V2).
+    private PageInfoContainer mContainer;
+
     // The dialog the view is placed in.
     private PageInfoDialog mDialog;
 
@@ -95,12 +96,6 @@
     // URL'.
     private String mFullUrl;
 
-    // The URL to be shown at the top of the page info views.
-    private SpannableStringBuilder mDisplayUrlBuilder;
-
-    // The length of the URL's origin in number of characters.
-    private int mUrlOriginLength;
-
     // Whether or not this page is an internal chrome page (e.g. the
     // chrome://settings page).
     private boolean mIsInternalPage;
@@ -123,15 +118,13 @@
 
     // Whether Version 2 of the PageInfoView is enabled.
     private boolean mIsV2Enabled;
+
     // Used to show Site settings from Page Info UI.
     private final PermissionParamsListBuilder mPermissionParamsListBuilder;
 
     // Delegate used by PermissionParamsListBuilder.
     private final PermissionParamsListBuilderDelegate mPermissionParamsListBuilderDelegate;
 
-    // The specific subpage being shown at any time, if any.
-    private PageInfoSubpage mSubpage;
-
     // The current page info subpage controller, if any.
     private PageInfoSubpageController mSubpageController;
 
@@ -197,33 +190,29 @@
         if (mDelegate.isShowingOfflinePage()) {
             displayUrl = UrlUtilities.stripScheme(mFullUrl);
         }
-        mDisplayUrlBuilder = new SpannableStringBuilder(displayUrl);
+        SpannableStringBuilder displayUrlBuilder = new SpannableStringBuilder(displayUrl);
         AutocompleteSchemeClassifier autocompleteSchemeClassifier =
                 delegate.createAutocompleteSchemeClassifier();
         if (mSecurityLevel == ConnectionSecurityLevel.SECURE) {
             OmniboxUrlEmphasizer.EmphasizeComponentsResponse emphasizeResponse =
                     OmniboxUrlEmphasizer.parseForEmphasizeComponents(
-                            mDisplayUrlBuilder.toString(), autocompleteSchemeClassifier);
+                            displayUrlBuilder.toString(), autocompleteSchemeClassifier);
             if (emphasizeResponse.schemeLength > 0) {
-                mDisplayUrlBuilder.setSpan(
+                displayUrlBuilder.setSpan(
                         new TextAppearanceSpan(mContext, R.style.TextAppearance_RobotoMediumStyle),
                         0, emphasizeResponse.schemeLength, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
             }
         }
 
         boolean useDarkText = !ColorUtils.inNightMode(mContext);
-        OmniboxUrlEmphasizer.emphasizeUrl(mDisplayUrlBuilder, mContext.getResources(),
+        OmniboxUrlEmphasizer.emphasizeUrl(displayUrlBuilder, mContext.getResources(),
                 autocompleteSchemeClassifier, mSecurityLevel, mIsInternalPage, useDarkText,
                 /*emphasizeScheme=*/true);
-        viewParams.url = mDisplayUrlBuilder;
-        mUrlOriginLength = OmniboxUrlEmphasizer.getOriginEndIndex(
-                mDisplayUrlBuilder.toString(), autocompleteSchemeClassifier);
-        viewParams.urlOriginLength = mUrlOriginLength;
+        viewParams.url = displayUrlBuilder;
+        viewParams.urlOriginLength = OmniboxUrlEmphasizer.getOriginEndIndex(
+                displayUrlBuilder.toString(), autocompleteSchemeClassifier);
         autocompleteSchemeClassifier.destroy();
 
-        viewParams.truncatedUrl =
-                UrlFormatter.formatUrlForSecurityDisplay(url, SchemeDisplay.OMIT_HTTP_AND_HTTPS);
-
         if (mDelegate.isSiteSettingsAvailable()) {
             viewParams.siteSettingsButtonClickCallback = () -> {
                 // Delay while the dialog closes.
@@ -265,20 +254,30 @@
                              : new PageInfoView(mContext, viewParams);
         if (isSheet(mContext)) mView.setBackgroundColor(Color.WHITE);
         if (mIsV2Enabled) {
-            mSubpage = new PageInfoSubpage(mContext);
-            mSubpage.setBackButtonOnClickListener(view -> exitSubpage());
+            mContainer = new PageInfoContainer(mContext);
+            PageInfoContainer.Params containerParams = new PageInfoContainer.Params();
+            containerParams.url = viewParams.url;
+            containerParams.urlOriginLength = viewParams.urlOriginLength;
+            containerParams.truncatedUrl = UrlFormatter.formatUrlForSecurityDisplay(
+                    url, SchemeDisplay.OMIT_HTTP_AND_HTTPS);
+            containerParams.backButtonClickCallback = this::exitSubpage;
+            containerParams.urlTitleClickCallback = mContainer::toggleUrlTruncation;
+            containerParams.urlTitleLongClickCallback = viewParams.urlTitleLongClickCallback;
+            containerParams.urlTitleShown = viewParams.urlTitleShown;
+            mContainer.setParams(containerParams);
+            mContainer.showPage(mView, "", true);
             PageInfoViewV2 view2 = (PageInfoViewV2) mView;
             mConnectionController = new PageInfoConnectionController(
                     this, view2.getConnectionRowView(), mWebContents, mDelegate.getVrHandler());
             mPermissionsController = new PageInfoPermissionsController(
-                    this, view2.getPermissionsRowView(), mDelegate, mDisplayUrlBuilder.toString());
+                    this, view2.getPermissionsRowView(), mDelegate, mFullUrl);
             mCookiesController = new PageInfoCookiesController(this, view2.getCookiesRowView(),
                     mDelegate, viewParams.cookieControlsShown, mFullUrl);
             mDelegate.getFavicon(mFullUrl, favicon -> {
                 if (favicon != null) {
-                    mView.setFavicon(favicon);
+                    mContainer.setFavicon(favicon);
                 } else {
-                    mView.setFavicon(
+                    mContainer.setFavicon(
                             SettingsUtils.getTintedIcon(mContext, R.drawable.ic_globe_24dp));
                 }
             });
@@ -336,7 +335,7 @@
             }
         };
 
-        mDialog = new PageInfoDialog(mContext, mView, mSubpage,
+        mDialog = new PageInfoDialog(mContext, mView, mContainer,
                 webContents.getViewAndroidDelegate().getContainerView(), isSheet(mContext),
                 delegate.getModalDialogManager(), this);
         mDialog.show();
@@ -503,9 +502,8 @@
     }
 
     @VisibleForTesting
-    public PageInfoView getPageInfoViewForTesting() {
-        // Check that this view is active.
-        assert mView.getParent() != null;
+    public View getPageInfoViewForTesting() {
+        if (mContainer != null) return mContainer;
         return mView;
     }
 
@@ -584,33 +582,16 @@
     @Override
     public void launchSubpage(PageInfoSubpageController controller) {
         mSubpageController = controller;
-        PageInfoSubpage.Params subpageParams = new PageInfoSubpage.Params();
-        subpageParams.url = mDisplayUrlBuilder;
-        subpageParams.urlOriginLength = mUrlOriginLength;
-        subpageParams.subpageTitle = mSubpageController.getSubpageTitle();
-        mSubpage.updateSubpage(subpageParams);
-        View subview = mSubpageController.createViewForSubpage(mSubpage);
-
-        ((FrameLayout) mSubpage.findViewById(R.id.placeholder)).addView(subview);
-        replaceView(mView, mSubpage);
+        CharSequence title = mSubpageController.getSubpageTitle();
+        View subview = mSubpageController.createViewForSubpage(mContainer);
+        mContainer.showPage(subview, title, false);
         controller.onSubPageAttached();
     }
 
     @Override
     public void exitSubpage() {
-        replaceView(mSubpage, mView);
-        ((FrameLayout) mSubpage.findViewById(R.id.placeholder)).removeAllViews();
+        mContainer.showPage(mView, "", true);
         mSubpageController.onSubpageRemoved();
         mSubpageController = null;
     }
-
-    private void replaceView(View currentView, View newView) {
-        assert currentView.getParent() != null;
-        assert newView.getParent() == null;
-
-        ViewGroup parent = (ViewGroup) currentView.getParent();
-        final int index = parent.indexOfChild(currentView);
-        parent.removeView(currentView);
-        parent.addView(newView, index);
-    }
 }
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoCookiesController.java b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoCookiesController.java
index 759e2eb..e07aca3 100644
--- a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoCookiesController.java
+++ b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoCookiesController.java
@@ -23,7 +23,7 @@
  */
 public class PageInfoCookiesController
         implements PageInfoSubpageController, CookieControlsObserver {
-    private PageInfoMainPageController mMainController;
+    private PageInfoMainController mMainController;
     private PageInfoRowView mRowView;
     private CookieControlsBridge mBridge;
     private PageInfoControllerDelegate mDelegate;
@@ -36,9 +36,8 @@
     private int mStatus;
     private boolean mIsEnforced;
 
-    public PageInfoCookiesController(PageInfoMainPageController mainController,
-            PageInfoRowView rowView, PageInfoControllerDelegate delegate, boolean isVisible,
-            String fullUrl) {
+    public PageInfoCookiesController(PageInfoMainController mainController, PageInfoRowView rowView,
+            PageInfoControllerDelegate delegate, boolean isVisible, String fullUrl) {
         mMainController = mainController;
         mRowView = rowView;
         mDelegate = delegate;
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoDialog.java b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoDialog.java
index e88e7b4..81c64885 100644
--- a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoDialog.java
+++ b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoDialog.java
@@ -39,7 +39,7 @@
 
     @NonNull
     private final PageInfoView mView;
-    private final PageInfoSubpage mSubpageView;
+    private final PageInfoContainer mContainerView;
     private final boolean mIsSheet;
     // The dialog implementation.
     // mSheetDialog is set if the dialog appears as a sheet. Otherwise, mModalDialog is set.
@@ -68,11 +68,11 @@
      *
      */
     public PageInfoDialog(Context context, @NonNull PageInfoView view,
-            @Nullable PageInfoSubpage subpageView, View containerView, boolean isSheet,
+            @Nullable PageInfoContainer subpageView, View containerView, boolean isSheet,
             @NonNull ModalDialogManager manager,
             @NonNull ModalDialogProperties.Controller controller) {
         mView = view;
-        mSubpageView = subpageView;
+        mContainerView = subpageView;
         mIsSheet = isSheet;
         mManager = manager;
         mController = controller;
@@ -99,7 +99,7 @@
             container = new ScrollView(context);
         }
 
-        container.addView(mView);
+        container.addView(mContainerView != null ? mContainerView : mView);
 
         if (isSheet) {
             mSheetDialog = createSheetDialog(context, container);
@@ -163,8 +163,8 @@
                         // Delay the cleanup by a tiny amount to give this frame a chance to
                         // be displayed before we destroy the dialog.
                         mView.postDelayed(this::superDismiss, CLOSE_CLEANUP_DELAY_MS);
-                        if (mSubpageView != null) {
-                            mSubpageView.postDelayed(this::superDismiss, CLOSE_CLEANUP_DELAY_MS);
+                        if (mContainerView != null) {
+                            mContainerView.postDelayed(this::superDismiss, CLOSE_CLEANUP_DELAY_MS);
                         }
                     }).start();
                 }
@@ -238,8 +238,8 @@
     private Animator createAllAnimations(boolean isEnter, Runnable onAnimationEnd) {
         Animator dialogAnimation =
                 mIsSheet ? createDialogSlideAnimaton(isEnter, mView) : new AnimatorSet();
-        Animator subpageDialogAnimation = mIsSheet && mSubpageView != null
-                ? createDialogSlideAnimaton(isEnter, mSubpageView)
+        Animator subpageDialogAnimation = mIsSheet && mContainerView != null
+                ? createDialogSlideAnimaton(isEnter, mContainerView)
                 : new AnimatorSet();
         Animator viewAnimation = mView.createEnterExitAnimation(isEnter);
         AnimatorSet allAnimations = new AnimatorSet();
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoMainPageController.java b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoMainController.java
similarity index 95%
rename from components/page_info/android/java/src/org/chromium/components/page_info/PageInfoMainPageController.java
rename to components/page_info/android/java/src/org/chromium/components/page_info/PageInfoMainController.java
index 8e5a4b2..72ccc1b 100644
--- a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoMainPageController.java
+++ b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoMainController.java
@@ -9,7 +9,7 @@
 /**
  * Interface for a page info main page controller.
  */
-public interface PageInfoMainPageController {
+public interface PageInfoMainController {
     /**
      * Launches the PageInfoSubpage provided by |pageInfoCookiesController|.
      * @param controller The controller providing a PageInfoSubpage.
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoPermissionsController.java b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoPermissionsController.java
index ff93fdd..3bf0d7fb 100644
--- a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoPermissionsController.java
+++ b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoPermissionsController.java
@@ -17,14 +17,14 @@
  * Class for controlling the page info permissions section.
  */
 public class PageInfoPermissionsController implements PageInfoSubpageController {
-    private PageInfoMainPageController mMainController;
+    private PageInfoMainController mMainController;
     private PageInfoRowView mRowView;
     private PageInfoControllerDelegate mDelegate;
     private String mTitle;
     private String mPageUrl;
     private SingleWebsiteSettings mSubpageFragment;
 
-    public PageInfoPermissionsController(PageInfoMainPageController mainController,
+    public PageInfoPermissionsController(PageInfoMainController mainController,
             PageInfoRowView view, PageInfoControllerDelegate delegate, String pageUrl) {
         mMainController = mainController;
         mRowView = view;
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoSubpage.java b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoSubpage.java
deleted file mode 100644
index 5fff064..0000000
--- a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoSubpage.java
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.page_info;
-
-import android.content.Context;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.TextView;
-
-import org.chromium.ui.widget.ChromeImageButton;
-
-/**
- * Represents a particular page info subpage.
- */
-public class PageInfoSubpage extends FrameLayout {
-    /**  Parameters to configure the view of page info subpage. */
-    public static class Params {
-        // The URL to be shown at the top of the page.
-        public CharSequence url;
-        // The length of the URL's origin in number of characters.
-        public int urlOriginLength;
-        // The name of the subpage to be displayed.
-        public String subpageTitle;
-    }
-
-    private PageInfoView.ElidedUrlTextView mUrlTitle;
-    private TextView mSubpageTitle;
-
-    public PageInfoSubpage(Context context) {
-        super(context);
-        LayoutInflater.from(context).inflate(R.layout.page_info_subpage, this, true);
-        mUrlTitle = findViewById(R.id.subpage_url);
-        mSubpageTitle = findViewById(R.id.subpage_title);
-    }
-
-    public void updateSubpage(Params params) {
-        mUrlTitle.setUrl(params.url, params.urlOriginLength);
-        mSubpageTitle.setText(params.subpageTitle);
-    }
-
-    public void setBackButtonOnClickListener(View.OnClickListener listener) {
-        ChromeImageButton backButton = findViewById(R.id.subpage_back_button);
-        backButton.setOnClickListener(listener);
-    }
-}
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoView.java b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoView.java
index 580477c..1c9186a 100644
--- a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoView.java
+++ b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoView.java
@@ -8,7 +8,6 @@
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.content.Context;
-import android.graphics.drawable.Drawable;
 import android.text.Layout;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
@@ -174,7 +173,6 @@
         public CharSequence url;
         public CharSequence previewLoadOriginalMessage;
         public int urlOriginLength;
-        public CharSequence truncatedUrl;
     }
 
     /** Parameters to configure the permission info section */
@@ -344,13 +342,6 @@
         mOnUiClosingCallback.run();
     }
 
-    /**
-     * Sets a favicon for the current page.
-     */
-    public void setFavicon(Drawable favicon) {
-        // Not implemented.
-    }
-
     public void setPermissions(PermissionParams params) {
         mPermissionsList.removeAllViews();
         // If we have at least one permission show the lower permissions area.
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoViewV2.java b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoViewV2.java
index 57d52f2..eefa728 100644
--- a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoViewV2.java
+++ b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoViewV2.java
@@ -5,11 +5,9 @@
 package org.chromium.components.page_info;
 
 import android.content.Context;
-import android.graphics.drawable.Drawable;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.LinearLayout;
-import android.widget.TextView;
 
 import java.util.Arrays;
 import java.util.List;
@@ -23,7 +21,6 @@
     private PageInfoRowView mConnectionRow;
     private PageInfoRowView mPermissionsRow;
     private PageInfoRowView mCookiesRow;
-    private TextView mTruncatedUrlTitle;
 
     public PageInfoViewV2(Context context, PageInfoView.PageInfoViewParams params) {
         super(context);
@@ -32,17 +29,6 @@
     }
 
     @Override
-    public void setFavicon(Drawable favicon) {
-        int padding =
-                getResources().getDimensionPixelSize(R.dimen.page_info_popup_button_padding_sides);
-        int size = getResources().getDimensionPixelSize(R.dimen.page_info_favicon_size);
-
-        favicon.setBounds(0, 0, size, size);
-        mTruncatedUrlTitle.setCompoundDrawablePadding(padding);
-        mTruncatedUrlTitle.setCompoundDrawablesRelative(favicon, null, null, null);
-    }
-
-    @Override
     protected void init(PageInfoView.PageInfoViewParams params) {
         super.init(params);
         mRowWrapper = findViewById(R.id.page_info_row_wrapper);
@@ -51,23 +37,7 @@
 
     @Override
     protected void initUrlTitle(PageInfoView.PageInfoViewParams params) {
-        super.initUrlTitle(params);
-        // Adjust the mUrlTitle for displaying the non-truncated URL.
-        mUrlTitle.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
-        mUrlTitle.setAlpha(1.0f);
-        mUrlTitle.setVisibility(GONE);
-        mUrlTitle.toggleTruncation();
-        // Use a separate view for truncated URL display.
-        mTruncatedUrlTitle = findViewById(R.id.page_info_truncated_url);
-        mTruncatedUrlTitle.setText(params.truncatedUrl);
-        if (params.urlTitleLongClickCallback != null) {
-            mTruncatedUrlTitle.setOnLongClickListener(v -> {
-                params.urlTitleLongClickCallback.run();
-                return true;
-            });
-        }
-        initializePageInfoViewChild(
-                mTruncatedUrlTitle, params.urlTitleShown, 0f, params.urlTitleClickCallback);
+        // URL is initialized in PageInfoContainer.
     }
 
     @Override
@@ -108,8 +78,7 @@
 
     @Override
     public void toggleUrlTruncation() {
-        mUrlTitle.setVisibility(mTruncatedUrlTitle.getVisibility());
-        mTruncatedUrlTitle.setVisibility(mUrlTitle.getVisibility() == VISIBLE ? GONE : VISIBLE);
+        throw new RuntimeException();
     }
 
     /**
@@ -118,7 +87,7 @@
     @Override
     protected List<View> collectAnimatableViews() {
         // TODO(crbug.com/1077766): Sort and use rows instead of the rowWrapper.
-        return Arrays.asList(mTruncatedUrlTitle, mPreviewMessage, mPreviewLoadOriginal,
-                mPreviewSeparator, mInstantAppButton, mRowWrapper, mSiteSettingsButton);
+        return Arrays.asList(mPreviewMessage, mPreviewLoadOriginal, mPreviewSeparator,
+                mInstantAppButton, mRowWrapper, mSiteSettingsButton);
     }
 }
diff --git a/components/paint_preview/browser/BUILD.gn b/components/paint_preview/browser/BUILD.gn
index fe905fd1..3712dfe 100644
--- a/components/paint_preview/browser/BUILD.gn
+++ b/components/paint_preview/browser/BUILD.gn
@@ -26,8 +26,6 @@
     "paint_preview_compositor_service_impl.h",
     "paint_preview_policy.h",
     "service_sandbox_type.h",
-    "warm_compositor.cc",
-    "warm_compositor.h",
   ]
 
   deps = [
diff --git a/components/paint_preview/browser/paint_preview_compositor_service_impl.cc b/components/paint_preview/browser/paint_preview_compositor_service_impl.cc
index f1489dd..9a58136 100644
--- a/components/paint_preview/browser/paint_preview_compositor_service_impl.cc
+++ b/components/paint_preview/browser/paint_preview_compositor_service_impl.cc
@@ -101,12 +101,6 @@
   return !active_clients_.empty();
 }
 
-void PaintPreviewCompositorServiceImpl::SetDisconnectHandler(
-    base::OnceClosure disconnect_handler) {
-  DCHECK(default_task_runner_->RunsTasksInCurrentSequence());
-  user_disconnect_closure_ = std::move(disconnect_handler);
-}
-
 void PaintPreviewCompositorServiceImpl::MarkCompositorAsDeleted(
     const base::UnguessableToken& token) {
   DCHECK(default_task_runner_->RunsTasksInCurrentSequence());
@@ -127,8 +121,7 @@
 
 void PaintPreviewCompositorServiceImpl::DisconnectHandler() {
   DCHECK(default_task_runner_->RunsTasksInCurrentSequence());
-  if (user_disconnect_closure_)
-    std::move(user_disconnect_closure_).Run();
+  std::move(user_disconnect_closure_).Run();
   compositor_service_.reset();
 }
 
diff --git a/components/paint_preview/browser/paint_preview_compositor_service_impl.h b/components/paint_preview/browser/paint_preview_compositor_service_impl.h
index 590e6360..8ca3b2010 100644
--- a/components/paint_preview/browser/paint_preview_compositor_service_impl.h
+++ b/components/paint_preview/browser/paint_preview_compositor_service_impl.h
@@ -38,9 +38,6 @@
   CreateCompositor(base::OnceClosure connected_closure) override;
 
   bool HasActiveClients() const override;
-  // NOTE: this is set by the constructor. However, in some cases it may need to
-  // be changed.
-  void SetDisconnectHandler(base::OnceClosure disconnect_handler) override;
 
   // Marks the compositor associated with |token| as deleted in the
   // |active_clients_| set.
diff --git a/components/paint_preview/browser/warm_compositor.cc b/components/paint_preview/browser/warm_compositor.cc
deleted file mode 100644
index f5c1d22..0000000
--- a/components/paint_preview/browser/warm_compositor.cc
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/paint_preview/browser/warm_compositor.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/memory/singleton.h"
-#include "components/paint_preview/browser/compositor_utils.h"
-
-namespace paint_preview {
-
-WarmCompositor::WarmCompositor()
-    : compositor_service_(nullptr, base::OnTaskRunnerDeleter(nullptr)) {}
-WarmCompositor::~WarmCompositor() = default;
-
-// static
-WarmCompositor* WarmCompositor::GetInstance() {
-  return base::Singleton<WarmCompositor,
-                         base::LeakySingletonTraits<WarmCompositor>>::get();
-}
-
-void WarmCompositor::WarmupCompositor() {
-  if (compositor_service_)
-    return;
-
-  compositor_service_ = StartCompositorService(base::BindOnce(
-      &WarmCompositor::OnDisconnect, weak_ptr_factory_.GetWeakPtr()));
-}
-
-bool WarmCompositor::StopCompositor() {
-  if (!compositor_service_)
-    return false;
-
-  compositor_service_.reset();
-  return true;
-}
-
-std::unique_ptr<PaintPreviewCompositorService, base::OnTaskRunnerDeleter>
-WarmCompositor::GetOrStartCompositorService(
-    base::OnceClosure disconnect_handler) {
-  if (!compositor_service_)
-    return StartCompositorService(std::move(disconnect_handler));
-
-  compositor_service_->SetDisconnectHandler(std::move(disconnect_handler));
-  return std::move(compositor_service_);
-}
-
-void WarmCompositor::OnDisconnect() {
-  compositor_service_.reset();
-}
-
-}  // namespace paint_preview
diff --git a/components/paint_preview/browser/warm_compositor.h b/components/paint_preview/browser/warm_compositor.h
deleted file mode 100644
index defeebe..0000000
--- a/components/paint_preview/browser/warm_compositor.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_PAINT_PREVIEW_BROWSER_WARM_COMPOSITOR_H_
-#define COMPONENTS_PAINT_PREVIEW_BROWSER_WARM_COMPOSITOR_H_
-
-#include <memory>
-
-#include "base/task_runner.h"
-#include "components/paint_preview/public/paint_preview_compositor_service.h"
-
-namespace base {
-template <typename T>
-struct DefaultSingletonTraits;
-}
-
-namespace paint_preview {
-
-// A class that can hold a pre-warmed compositor service for use.
-class WarmCompositor {
- public:
-  ~WarmCompositor();
-
-  WarmCompositor(const WarmCompositor&) = delete;
-  WarmCompositor& operator=(const WarmCompositor&) = delete;
-
-  static WarmCompositor* GetInstance();
-
-  // Warms up the compositor service.
-  void WarmupCompositor();
-
-  // Releases the warmed compositor service if there is one. Returns true if a
-  // compositor was released.
-  bool StopCompositor();
-
-  // Passes the pre-warmed compositor to the caller if one is present.
-  // Otherwise starts a new compositor.
-  std::unique_ptr<PaintPreviewCompositorService, base::OnTaskRunnerDeleter>
-  GetOrStartCompositorService(base::OnceClosure disconnect_handler);
-
- private:
-  WarmCompositor();
-  friend struct base::DefaultSingletonTraits<WarmCompositor>;
-
-  void OnDisconnect();
-
-  std::unique_ptr<PaintPreviewCompositorService, base::OnTaskRunnerDeleter>
-      compositor_service_;
-
-  base::WeakPtrFactory<WarmCompositor> weak_ptr_factory_{this};
-};
-
-}  // namespace paint_preview
-
-#endif  // COMPONENTS_PAINT_PREVIEW_BROWSER_WARM_COMPOSITOR_H_
diff --git a/components/paint_preview/player/player_compositor_delegate.cc b/components/paint_preview/player/player_compositor_delegate.cc
index 3f14d43..8ac4e61 100644
--- a/components/paint_preview/player/player_compositor_delegate.cc
+++ b/components/paint_preview/player/player_compositor_delegate.cc
@@ -21,8 +21,8 @@
 #include "base/trace_event/common/trace_event_common.h"
 #include "base/trace_event/trace_event.h"
 #include "base/unguessable_token.h"
+#include "components/paint_preview/browser/compositor_utils.h"
 #include "components/paint_preview/browser/paint_preview_base_service.h"
-#include "components/paint_preview/browser/warm_compositor.h"
 #include "components/paint_preview/common/proto/paint_preview.pb.h"
 #include "components/paint_preview/common/recording_map.h"
 #include "components/paint_preview/common/serialized_recording.h"
@@ -120,10 +120,9 @@
   TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("paint_preview",
                                     "PlayerCompositorDelegate CreateCompositor",
                                     TRACE_ID_LOCAL(this));
-  paint_preview_compositor_service_ =
-      WarmCompositor::GetInstance()->GetOrStartCompositorService(base::BindOnce(
-          &PlayerCompositorDelegate::OnCompositorServiceDisconnected,
-          weak_factory_.GetWeakPtr()));
+  paint_preview_compositor_service_ = StartCompositorService(
+      base::BindOnce(&PlayerCompositorDelegate::OnCompositorServiceDisconnected,
+                     weak_factory_.GetWeakPtr()));
 
   paint_preview_compositor_client_ =
       paint_preview_compositor_service_->CreateCompositor(
diff --git a/components/paint_preview/public/paint_preview_compositor_service.h b/components/paint_preview/public/paint_preview_compositor_service.h
index ab934d2..10be79ce 100644
--- a/components/paint_preview/public/paint_preview_compositor_service.h
+++ b/components/paint_preview/public/paint_preview_compositor_service.h
@@ -35,9 +35,6 @@
   // check if killing this service is safe (i.e. won't drop messages).
   virtual bool HasActiveClients() const = 0;
 
-  // Sets the disconnect handler for this service.
-  virtual void SetDisconnectHandler(base::OnceClosure disconnect_handler) = 0;
-
   PaintPreviewCompositorService(const PaintPreviewCompositorService&) = delete;
   PaintPreviewCompositorService& operator=(
       const PaintPreviewCompositorService&) = delete;
diff --git a/components/password_manager/content/browser/bad_message.h b/components/password_manager/content/browser/bad_message.h
index 5d9a0384..5d1a692f 100644
--- a/components/password_manager/content/browser/bad_message.h
+++ b/components/password_manager/content/browser/bad_message.h
@@ -34,7 +34,7 @@
   CPMD_BAD_ORIGIN_PASSWORD_NO_LONGER_GENERATED = 6,
   CPMD_BAD_ORIGIN_PRESAVE_GENERATED_PASSWORD = 7,
   CPMD_BAD_ORIGIN_SAVE_GENERATION_FIELD_DETECTED_BY_CLASSIFIER = 8,
-  CPMD_BAD_ORIGIN_SHOW_FALLBACK_FOR_SAVING = 9,
+  CPMD_BAD_ORIGIN_UPON_USER_INPUT_CHANGE = 9,
   CPMD_BAD_ORIGIN_AUTOMATIC_GENERATION_STATUS_CHANGED = 10,
   CPMD_BAD_ORIGIN_SHOW_MANUAL_PASSWORD_GENERATION_POPUP = 11,
   CPMD_BAD_ORIGIN_SHOW_PASSWORD_EDITING_POPUP = 12,
diff --git a/components/password_manager/content/browser/content_password_manager_driver.cc b/components/password_manager/content/browser/content_password_manager_driver.cc
index 60599057c..3a015aa 100644
--- a/components/password_manager/content/browser/content_password_manager_driver.cc
+++ b/components/password_manager/content/browser/content_password_manager_driver.cc
@@ -246,15 +246,16 @@
   LogSiteIsolationMetricsForSubmittedForm(render_frame_host_);
 }
 
-void ContentPasswordManagerDriver::ShowManualFallbackForSaving(
+void ContentPasswordManagerDriver::InformAboutUserInput(
     const autofill::FormData& form_data) {
   if (!password_manager::bad_message::CheckChildProcessSecurityPolicyForURL(
           render_frame_host_, form_data.url,
-          BadMessageReason::CPMD_BAD_ORIGIN_SHOW_FALLBACK_FOR_SAVING))
+          BadMessageReason::CPMD_BAD_ORIGIN_UPON_USER_INPUT_CHANGE))
     return;
-  GetPasswordManager()->ShowManualFallbackForSaving(this, form_data);
+  GetPasswordManager()->OnInformAboutUserInput(this, form_data);
 
-  if (client_->IsIsolationForPasswordSitesEnabled()) {
+  if (FormHasNonEmptyPasswordField(form_data) &&
+      client_->IsIsolationForPasswordSitesEnabled()) {
     // This function signals that a password field has been filled (whether by
     // the user, JS, autofill, or some other means) or a password form has been
     // submitted. Use this as a heuristic to start site-isolating the form's
@@ -266,10 +267,6 @@
   }
 }
 
-void ContentPasswordManagerDriver::HideManualFallbackForSaving() {
-  GetPasswordManager()->HideManualFallbackForSaving();
-}
-
 void ContentPasswordManagerDriver::SameDocumentNavigation(
     autofill::mojom::SubmissionIndicatorEvent submission_indication_event) {
   GetPasswordManager()->OnPasswordFormSubmittedNoChecks(
diff --git a/components/password_manager/content/browser/content_password_manager_driver.h b/components/password_manager/content/browser/content_password_manager_driver.h
index 5aa51d0..0d6354c 100644
--- a/components/password_manager/content/browser/content_password_manager_driver.h
+++ b/components/password_manager/content/browser/content_password_manager_driver.h
@@ -100,9 +100,7 @@
       const std::vector<autofill::FormData>& visible_forms_data,
       bool did_stop_loading) override;
   void PasswordFormSubmitted(const autofill::FormData& form_data) override;
-  void ShowManualFallbackForSaving(
-      const autofill::FormData& form_data) override;
-  void HideManualFallbackForSaving() override;
+  void InformAboutUserInput(const autofill::FormData& form_data) override;
   void SameDocumentNavigation(autofill::mojom::SubmissionIndicatorEvent
                                   submission_indication_event) override;
   void RecordSavePasswordProgress(const std::string& log) override;
diff --git a/components/password_manager/core/browser/BUILD.gn b/components/password_manager/core/browser/BUILD.gn
index 0c9fbb3c..4d48c57 100644
--- a/components/password_manager/core/browser/BUILD.gn
+++ b/components/password_manager/core/browser/BUILD.gn
@@ -242,6 +242,8 @@
     "ui/post_save_compromised_helper.h",
     "ui/saved_passwords_presenter.cc",
     "ui/saved_passwords_presenter.h",
+    "ui/weak_check_utility.cc",
+    "ui/weak_check_utility.h",
     "votes_uploader.cc",
     "votes_uploader.h",
     "well_known_change_password_state.cc",
@@ -312,6 +314,7 @@
     "//third_party/abseil-cpp:absl",
     "//third_party/protobuf:protobuf_lite",
     "//third_party/re2",
+    "//third_party/zxcvbn-cpp",
     "//ui/base",
     "//ui/gfx",
     "//ui/gfx/range",
@@ -635,6 +638,7 @@
     "ui/insecure_credentials_manager_unittest.cc",
     "ui/post_save_compromised_helper_unittest.cc",
     "ui/saved_passwords_presenter_unittest.cc",
+    "ui/weak_check_utility_unittest.cc",
     "vote_uploads_test_matchers.h",
     "votes_uploader_unittest.cc",
     "well_known_change_password_state_unittest.cc",
diff --git a/components/password_manager/core/browser/DEPS b/components/password_manager/core/browser/DEPS
index 7bd83f9f..bed33b2 100644
--- a/components/password_manager/core/browser/DEPS
+++ b/components/password_manager/core/browser/DEPS
@@ -26,6 +26,7 @@
   "+services/network/public/cpp",
   "+services/network/public/mojom",
   "+services/network/test",
+  "+third_party/zxcvbn-cpp",
 ]
 
 specific_include_rules = {
diff --git a/components/password_manager/core/browser/password_manager.cc b/components/password_manager/core/browser/password_manager.cc
index 64fd26fb..b25db13 100644
--- a/components/password_manager/core/browser/password_manager.cc
+++ b/components/password_manager/core/browser/password_manager.cc
@@ -488,8 +488,8 @@
                              renderer_id, value, base::Time::Now(), driver_id);
 }
 
-void PasswordManager::ShowManualFallbackForSaving(PasswordManagerDriver* driver,
-                                                  const FormData& form_data) {
+void PasswordManager::OnInformAboutUserInput(PasswordManagerDriver* driver,
+                                             const FormData& form_data) {
   PasswordFormManager* manager = ProvisionallySaveForm(form_data, driver, true);
 
   if (manager && form_data.is_gaia_with_skip_save_password_form) {
@@ -504,7 +504,7 @@
   if (client_ && client_->GetMetricsRecorder())
     client_->GetMetricsRecorder()->RecordFormManagerAvailable(availability);
 
-  ShowManualFallbackForSavingImpl(manager, form_data);
+  ShowManualFallbackForSaving(manager, form_data);
 }
 
 void PasswordManager::HideManualFallbackForSaving() {
@@ -724,8 +724,7 @@
     if (manager->UpdateStateOnUserInput(form_id, field_id, field_value)) {
       ProvisionallySaveForm(*manager->observed_form(), driver, true);
       if (manager->is_submitted() && !manager->HasGeneratedPassword()) {
-        ShowManualFallbackForSavingImpl(manager.get(),
-                                        *manager->observed_form());
+        ShowManualFallbackForSaving(manager.get(), *manager->observed_form());
       } else {
         HideManualFallbackForSaving();
       }
@@ -1197,10 +1196,19 @@
   }
 }
 
-void PasswordManager::ShowManualFallbackForSavingImpl(
+void PasswordManager::ShowManualFallbackForSaving(
     PasswordFormManager* form_manager,
     const FormData& form_data) {
-  if (!form_manager || !form_manager->is_submitted())
+  // Where `form_manager` is nullptr, make sure the manual fallback isn't
+  // shown. One scenario where this is relevant is when the user inputs some
+  // password and then removes it. Upon removing the password, the
+  // `form_manager` will become nullptr.
+  if (!form_manager) {
+    HideManualFallbackForSaving();
+    return;
+  }
+
+  if (!form_manager->is_submitted())
     return;
 
   if (!client_->GetProfilePasswordStore()->IsAbleToSavePasswords() ||
diff --git a/components/password_manager/core/browser/password_manager.h b/components/password_manager/core/browser/password_manager.h
index c600643cc..e815839 100644
--- a/components/password_manager/core/browser/password_manager.h
+++ b/components/password_manager/core/browser/password_manager.h
@@ -166,10 +166,10 @@
                                       autofill::FieldRendererId renderer_id,
                                       const base::string16& value);
 
-  // Handles a request to show manual fallback for password saving, i.e. the
-  // omnibox icon with the anchored hidden prompt.
-  void ShowManualFallbackForSaving(PasswordManagerDriver* driver,
-                                   const autofill::FormData& form_data);
+  // Handles user input and decides whether to show manual fallback for password
+  // saving, i.e. the omnibox icon with the anchored hidden prompt.
+  void OnInformAboutUserInput(PasswordManagerDriver* driver,
+                              const autofill::FormData& form_data);
 
   // Handles a request to hide manual fallback for password saving.
   void HideManualFallbackForSaving();
@@ -320,8 +320,8 @@
 
   // Handles a request to show manual fallback for password saving, i.e. the
   // omnibox icon with the anchored hidden prompt. todo
-  void ShowManualFallbackForSavingImpl(PasswordFormManager* form_manager,
-                                       const autofill::FormData& form_data);
+  void ShowManualFallbackForSaving(PasswordFormManager* form_manager,
+                                   const autofill::FormData& form_data);
 
   // Returns the timeout for the disabling Password Manager's prompts.
   base::TimeDelta GetTimeoutForDisablingPrompts();
diff --git a/components/password_manager/core/browser/password_manager_unittest.cc b/components/password_manager/core/browser/password_manager_unittest.cc
index 3a18c20..87ec364 100644
--- a/components/password_manager/core/browser/password_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_manager_unittest.cc
@@ -913,7 +913,7 @@
   std::unique_ptr<PasswordFormManagerForUI> form_manager_to_save;
   EXPECT_CALL(client_, ShowManualFallbackForSavingPtr(_, false, true))
       .WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
-  manager()->ShowManualFallbackForSaving(&driver_, incomplete_match.form_data);
+  manager()->OnInformAboutUserInput(&driver_, incomplete_match.form_data);
   ASSERT_TRUE(form_manager_to_save);
   EXPECT_THAT(form_manager_to_save->GetPendingCredentials(),
               FormMatches(incomplete_match));
@@ -924,7 +924,7 @@
   // because the credential is already in the store.
   EXPECT_CALL(client_, ShowManualFallbackForSavingPtr(_, false, true)).Times(0);
   EXPECT_CALL(client_, HideManualFallbackForSaving());
-  manager()->ShowManualFallbackForSaving(&driver_, form.form_data);
+  manager()->OnInformAboutUserInput(&driver_, form.form_data);
 
   // The user submits the form. No prompt should pop up. The credential is
   // updated in background.
@@ -939,6 +939,42 @@
             user_action_tester.GetActionCount("PasswordManager_LoginPassed"));
 }
 
+TEST_P(PasswordManagerTest, DoNotSaveWhenUserDeletesPassword) {
+  PasswordForm form(MakeSimpleForm());
+  PasswordForm stored_form = form;
+  stored_form.password_value = ASCIIToUTF16("old_password");
+  EXPECT_CALL(*store_, GetLogins(_, _))
+      .WillRepeatedly(WithArg<1>(InvokeConsumer(store_.get(), stored_form)));
+
+  ON_CALL(client_, IsSavingAndFillingEnabled(form.url))
+      .WillByDefault(Return(true));
+
+  std::vector<FormData> observed = {form.form_data};
+  manager()->OnPasswordFormsParsed(&driver_, observed);
+
+  // The user is typing a credential manually, the fallback should be available.
+  std::unique_ptr<PasswordFormManagerForUI> form_manager_to_save;
+  EXPECT_CALL(client_, ShowManualFallbackForSavingPtr(_, false, true))
+      .WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
+  manager()->OnInformAboutUserInput(&driver_, form.form_data);
+  ASSERT_TRUE(form_manager_to_save);
+
+  // The user deletes the password, no manuall fallback should be shown.
+  PasswordForm empty_password_form(form);
+  empty_password_form.password_value.clear();
+  empty_password_form.form_data.fields[1].value.clear();
+  EXPECT_CALL(client_, ShowManualFallbackForSavingPtr).Times(0);
+  EXPECT_CALL(client_, HideManualFallbackForSaving());
+  manager()->OnInformAboutUserInput(&driver_, empty_password_form.form_data);
+
+  // The user submits the form. No prompt should pop up.
+  OnPasswordFormSubmitted(empty_password_form.form_data);
+  EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr).Times(0);
+  observed.clear();
+  manager()->DidNavigateMainFrame(true);
+  manager()->OnPasswordFormsParsed(&driver_, observed);
+}
+
 // Tests that on Chrome sign-in form credentials are not saved.
 TEST_P(PasswordManagerTest, DoNotSaveOnChromeSignInForm) {
   FormData form_data(MakeSimpleFormData());
@@ -957,7 +993,7 @@
   FormData typed_credentials(form_data);
   typed_credentials.fields[1].value = ASCIIToUTF16("pw");
   EXPECT_CALL(client_, ShowManualFallbackForSavingPtr(_, _, _)).Times(0);
-  manager()->ShowManualFallbackForSaving(&driver_, form_data);
+  manager()->OnInformAboutUserInput(&driver_, form_data);
 
   // The user submits the form. No prompt should pop up.
   OnPasswordFormSubmitted(form_data);
@@ -992,7 +1028,7 @@
   EXPECT_CALL(client_, HideManualFallbackForSaving());
   // The call to manual fallback with |form| equal to already saved should close
   // the fallback, but it should not prevent sending metrics.
-  manager()->ShowManualFallbackForSaving(&driver_, form.form_data);
+  manager()->OnInformAboutUserInput(&driver_, form.form_data);
   EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_)).Times(0);
   EXPECT_CALL(*store_, UpdateLogin(_));
 
@@ -1812,7 +1848,7 @@
       .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store_.get())));
   manager()->OnPasswordFormsParsed(&driver_, observed);
   manager()->OnPasswordFormsRendered(&driver_, observed, true);
-  manager()->ShowManualFallbackForSaving(&driver_, form.form_data);
+  manager()->OnInformAboutUserInput(&driver_, form.form_data);
 
   std::unique_ptr<PasswordFormManagerForUI> form_manager_to_save;
   EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_))
@@ -1843,7 +1879,7 @@
       .WillRepeatedly(Return(true));
   manager()->OnPasswordFormsParsed(&driver_, observed);
   manager()->OnPasswordFormsRendered(&driver_, observed, true);
-  manager()->ShowManualFallbackForSaving(&driver_, form.form_data);
+  manager()->OnInformAboutUserInput(&driver_, form.form_data);
 
   std::unique_ptr<PasswordFormManagerForUI> form_manager_to_save;
   EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_))
@@ -2466,7 +2502,7 @@
   std::unique_ptr<PasswordFormManagerForUI> form_manager_to_save;
   EXPECT_CALL(client_, ShowManualFallbackForSavingPtr(_, false, true))
       .WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
-  manager()->ShowManualFallbackForSaving(&driver_, form.form_data);
+  manager()->OnInformAboutUserInput(&driver_, form.form_data);
   ASSERT_TRUE(form_manager_to_save);
   EXPECT_THAT(form_manager_to_save->GetPendingCredentials(), FormMatches(form));
 
@@ -2476,7 +2512,7 @@
   new_form.form_data.fields[0].value = new_form.username_value;
   EXPECT_CALL(client_, ShowManualFallbackForSavingPtr(_, false, false))
       .WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
-  manager()->ShowManualFallbackForSaving(&driver_, new_form.form_data);
+  manager()->OnInformAboutUserInput(&driver_, new_form.form_data);
   ASSERT_TRUE(form_manager_to_save);
   EXPECT_THAT(form_manager_to_save->GetPendingCredentials(),
               FormMatches(new_form));
@@ -2516,7 +2552,7 @@
 
   // There is no response from the store. Don't show the fallback.
   EXPECT_CALL(client_, ShowManualFallbackForSavingPtr(_, _, _)).Times(0);
-  manager()->ShowManualFallbackForSaving(&driver_, form_data);
+  manager()->OnInformAboutUserInput(&driver_, form_data);
 
   // The storage responded. The fallback can be shown.
   ASSERT_TRUE(store_consumer);
@@ -2525,7 +2561,7 @@
   std::unique_ptr<PasswordFormManagerForUI> form_manager_to_save;
   EXPECT_CALL(client_, ShowManualFallbackForSavingPtr(_, false, false))
       .WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
-  manager()->ShowManualFallbackForSaving(&driver_, form_data);
+  manager()->OnInformAboutUserInput(&driver_, form_data);
 }
 
 TEST_P(PasswordManagerTest, ManualFallbackForSaving_GeneratedPassword) {
@@ -2549,7 +2585,7 @@
       .WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
   manager()->OnPresaveGeneratedPassword(&driver_, form.form_data,
                                         form.password_value);
-  manager()->ShowManualFallbackForSaving(&driver_, form.form_data);
+  manager()->OnInformAboutUserInput(&driver_, form.form_data);
   ASSERT_TRUE(form_manager_to_save);
   EXPECT_THAT(form_manager_to_save->GetPendingCredentials(), FormMatches(form));
 
@@ -2560,7 +2596,7 @@
       .WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
   manager()->OnPresaveGeneratedPassword(&driver_, form.form_data,
                                         form.password_value);
-  manager()->ShowManualFallbackForSaving(&driver_, form.form_data);
+  manager()->OnInformAboutUserInput(&driver_, form.form_data);
 
   // A user removes the generated password. The presaved password is removed,
   // the fallback is disabled.
@@ -2829,7 +2865,7 @@
   observed.push_back(form_data);
   manager()->OnPasswordFormsParsed(&driver_, observed);
   manager()->OnPasswordFormsRendered(&driver_, observed, true);
-  manager()->ShowManualFallbackForSaving(&driver_, form_data);
+  manager()->OnInformAboutUserInput(&driver_, form_data);
 
   auto submitted_form_data = form_data;
   submitted_form_data.fields[0].value = ASCIIToUTF16("username");
@@ -2915,7 +2951,7 @@
   std::unique_ptr<PasswordFormManagerForUI> form_manager_to_save;
   EXPECT_CALL(client_, ShowManualFallbackForSavingPtr(_, false, true))
       .WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
-  manager()->ShowManualFallbackForSaving(&driver_, form.form_data);
+  manager()->OnInformAboutUserInput(&driver_, form.form_data);
   ASSERT_TRUE(form_manager_to_save);
   EXPECT_THAT(form_manager_to_save->GetPendingCredentials(), FormMatches(form));
 
@@ -2925,7 +2961,7 @@
   new_form.form_data.fields[0].value = new_form.username_value;
   EXPECT_CALL(client_, ShowManualFallbackForSavingPtr(_, false, false))
       .WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
-  manager()->ShowManualFallbackForSaving(&driver_, new_form.form_data);
+  manager()->OnInformAboutUserInput(&driver_, new_form.form_data);
   ASSERT_TRUE(form_manager_to_save);
   EXPECT_THAT(form_manager_to_save->GetPendingCredentials(),
               FormMatches(new_form));
@@ -3066,7 +3102,7 @@
     std::unique_ptr<PasswordFormManagerForUI> form_manager_to_save;
     EXPECT_CALL(client_, ShowManualFallbackForSavingPtr(_, false, false))
         .WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
-    manager()->ShowManualFallbackForSaving(&driver_, form.form_data);
+    manager()->OnInformAboutUserInput(&driver_, form.form_data);
     ASSERT_TRUE(form_manager_to_save);
     EXPECT_THAT(form_manager_to_save->GetPendingCredentials(),
                 FormMatches(form));
@@ -3245,7 +3281,7 @@
           manager()->OnPasswordFormSubmitted(nullptr, form_data);
           break;
         case MissingFormManagerTestCase::Signal::Manual:
-          manager()->ShowManualFallbackForSaving(nullptr, form_data);
+          manager()->OnInformAboutUserInput(nullptr, form_data);
           break;
         case MissingFormManagerTestCase::Signal::None:
           break;
@@ -3355,7 +3391,7 @@
   std::unique_ptr<PasswordFormManagerForUI> form_manager_to_save;
   EXPECT_CALL(client_, ShowManualFallbackForSavingPtr(_, false, false))
       .WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
-  manager()->ShowManualFallbackForSaving(&driver_, credit_card_form.form_data);
+  manager()->OnInformAboutUserInput(&driver_, credit_card_form.form_data);
   ASSERT_TRUE(form_manager_to_save);
   EXPECT_THAT(form_manager_to_save->GetPendingCredentials(),
               FormMatches(credit_card_form));
@@ -3677,7 +3713,7 @@
   for (size_t i = 0; i < 2; i++) {
     PasswordForm form(MakeSimpleForm());
     manager()->OnPasswordFormsParsed(&driver_, {form.form_data});
-    manager()->ShowManualFallbackForSaving(&driver_, form.form_data);
+    manager()->OnInformAboutUserInput(&driver_, form.form_data);
 
     manager()->DidNavigateMainFrame(true /* form_may_be_submitted */);
     manager()->OnPasswordFormsRendered(&driver_, {} /* observed */,
@@ -3708,8 +3744,8 @@
     PasswordForm form2(MakeSimpleForm());
     manager()->OnPasswordFormsParsed(&driver_,
                                      {form1.form_data, form2.form_data});
-    manager()->ShowManualFallbackForSaving(&driver_, form1.form_data);
-    manager()->ShowManualFallbackForSaving(&driver_, form2.form_data);
+    manager()->OnInformAboutUserInput(&driver_, form1.form_data);
+    manager()->OnInformAboutUserInput(&driver_, form2.form_data);
 
     // Simulate submission in different ways depending on whether
     // |owned_submitted_form_manager_| should be set and |form_managers_| should
diff --git a/components/password_manager/core/browser/ui/insecure_credentials_manager.cc b/components/password_manager/core/browser/ui/insecure_credentials_manager.cc
index e55f03da..313695e7 100644
--- a/components/password_manager/core/browser/ui/insecure_credentials_manager.cc
+++ b/components/password_manager/core/browser/ui/insecure_credentials_manager.cc
@@ -8,13 +8,16 @@
 #include <iterator>
 #include <set>
 
+#include "base/bind.h"
 #include "base/containers/flat_set.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/task/post_task.h"
 #include "components/autofill/core/common/password_form.h"
 #include "components/password_manager/core/browser/compromised_credentials_table.h"
 #include "components/password_manager/core/browser/ui/credential_utils.h"
 #include "components/password_manager/core/browser/ui/saved_passwords_presenter.h"
+#include "components/password_manager/core/browser/ui/weak_check_utility.h"
 #include "components/password_manager/core/common/password_manager_features.h"
 
 namespace password_manager {
@@ -64,12 +67,13 @@
   NOTREACHED();
 }
 
-// This function takes two lists of insecure credentials and saved passwords and
-// joins them, producing a map that contains CredentialWithPassword as keys and
-// vector<autofill::PasswordForm> as values with InsecureCredentialTypeFlags as
-// values.
+// This function takes three lists of compromised credentials, weak passwords
+// and saved passwords and joins them, producing a map that contains
+// CredentialWithPassword as keys and vector<autofill::PasswordForm> as values
+// with InsecureCredentialTypeFlags as values.
 CredentialPasswordsMap JoinInsecureCredentialsWithSavedPasswords(
-    const std::vector<CompromisedCredentials>& credentials,
+    const std::vector<CompromisedCredentials>& compromised_credentials,
+    const base::flat_set<base::string16>& weak_passwords,
     SavedPasswordsPresenter::SavedPasswordsView saved_passwords) {
   CredentialPasswordsMap credentials_to_forms;
 
@@ -96,7 +100,7 @@
   // size of 1, however.
   std::multiset<autofill::PasswordForm, CredentialWithoutPasswordLess>
       password_forms(saved_passwords.begin(), saved_passwords.end());
-  for (const auto& credential : credentials) {
+  for (const auto& credential : compromised_credentials) {
     auto range = password_forms.equal_range(credential);
     // Make use of a set to only filter out repeated passwords, if any.
     std::for_each(
@@ -106,8 +110,7 @@
               credentials_to_forms[compromised_credential];
 
           // Using |= operator to save in a bit mask both Leaked and Phished.
-          credential_to_form.type =
-              credential_to_form.type |
+          credential_to_form.type |=
               ConvertCompromiseType(credential.compromise_type);
 
           // Use the latest time. Relevant when the same credential is both
@@ -122,18 +125,35 @@
         });
   }
 
+  for (const auto& form : saved_passwords) {
+    if (weak_passwords.contains(form.password_value)) {
+      CredentialView weak_credential(form);
+      auto& credential_to_form = credentials_to_forms[weak_credential];
+      credential_to_form.type |= InsecureCredentialTypeFlags::kWeakCredential;
+
+      // This helps not to create a copy of the |form| in case the credential
+      // has also been compromised. This is important because we don't want to
+      // delete the form twice in the RemoveCredential.
+      if (!IsCompromised(credential_to_form.type)) {
+        credential_to_form.forms.push_back(form);
+      }
+    }
+  }
+
   return credentials_to_forms;
 }
 
-std::vector<CredentialWithPassword> ExtractCompromisedCredentials(
-    const CredentialPasswordsMap& credentials_to_forms) {
+std::vector<CredentialWithPassword> ExtractInsecureCredentials(
+    const CredentialPasswordsMap& credentials_to_forms,
+    bool (*condition)(const InsecureCredentialTypeFlags&)) {
   std::vector<CredentialWithPassword> credentials;
-  credentials.reserve(credentials_to_forms.size());
   for (const auto& credential_to_forms : credentials_to_forms) {
-    CredentialWithPassword credential(credential_to_forms.first);
-    credential.insecure_type = credential_to_forms.second.type;
-    credential.create_time = credential_to_forms.second.latest_time;
-    credentials.push_back(std::move(credential));
+    if (condition(credential_to_forms.second.type)) {
+      CredentialWithPassword credential(credential_to_forms.first);
+      credential.insecure_type = credential_to_forms.second.type;
+      credential.create_time = credential_to_forms.second.latest_time;
+      credentials.push_back(std::move(credential));
+    }
   }
   return credentials;
 }
@@ -205,6 +225,14 @@
   compromised_credentials_reader_.Init();
 }
 
+void InsecureCredentialsManager::StartWeakCheck() {
+  base::ThreadPool::PostTaskAndReplyWithResult(
+      FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
+      base::BindOnce(&BulkWeakCheck, presenter_->GetSavedPasswords()),
+      base::BindOnce(&InsecureCredentialsManager::OnWeakCheckDone,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+
 void InsecureCredentialsManager::SaveCompromisedCredential(
     const LeakCheckCredential& credential) {
   // Iterate over all currently saved credentials and mark those as compromised
@@ -265,7 +293,12 @@
 
 std::vector<CredentialWithPassword>
 InsecureCredentialsManager::GetCompromisedCredentials() const {
-  return ExtractCompromisedCredentials(credentials_to_forms_);
+  return ExtractInsecureCredentials(credentials_to_forms_, &IsCompromised);
+}
+
+std::vector<CredentialWithPassword>
+InsecureCredentialsManager::GetWeakCredentials() const {
+  return ExtractInsecureCredentials(credentials_to_forms_, &IsWeak);
 }
 
 SavedPasswordsPresenter::SavedPasswordsView
@@ -285,29 +318,51 @@
   observers_.RemoveObserver(observer);
 }
 
+void InsecureCredentialsManager::OnWeakCheckDone(
+    base::flat_set<base::string16> weak_passwords) {
+  weak_passwords_ = std::move(weak_passwords);
+
+  credentials_to_forms_ = JoinInsecureCredentialsWithSavedPasswords(
+      compromised_credentials_, weak_passwords_,
+      presenter_->GetSavedPasswords());
+  NotifyWeakCredentialsChanged();
+}
+
 // Re-computes the list of compromised credentials with passwords after
 // obtaining a new list of compromised credentials.
 void InsecureCredentialsManager::OnCompromisedCredentialsChanged(
     const std::vector<CompromisedCredentials>& compromised_credentials) {
   compromised_credentials_ = compromised_credentials;
-  UpdateCachedDataAndNotifyObservers(presenter_->GetSavedPasswords());
+
+  credentials_to_forms_ = JoinInsecureCredentialsWithSavedPasswords(
+      compromised_credentials_, weak_passwords_,
+      presenter_->GetSavedPasswords());
+  NotifyCompromisedCredentialsChanged();
 }
 
 // Re-computes the list of insecure credentials with passwords after obtaining a
 // new list of saved passwords.
 void InsecureCredentialsManager::OnSavedPasswordsChanged(
     SavedPasswordsPresenter::SavedPasswordsView saved_passwords) {
-  UpdateCachedDataAndNotifyObservers(saved_passwords);
+  credentials_to_forms_ = JoinInsecureCredentialsWithSavedPasswords(
+      compromised_credentials_, weak_passwords_, saved_passwords);
+  NotifyCompromisedCredentialsChanged();
+  NotifyWeakCredentialsChanged();
 }
 
-void InsecureCredentialsManager::UpdateCachedDataAndNotifyObservers(
-    SavedPasswordsPresenter::SavedPasswordsView saved_passwords) {
-  credentials_to_forms_ = JoinInsecureCredentialsWithSavedPasswords(
-      compromised_credentials_, saved_passwords);
-  std::vector<CredentialWithPassword> credentials =
-      ExtractCompromisedCredentials(credentials_to_forms_);
+void InsecureCredentialsManager::NotifyCompromisedCredentialsChanged() {
+  std::vector<CredentialWithPassword> compromised_credentials =
+      ExtractInsecureCredentials(credentials_to_forms_, &IsCompromised);
   for (auto& observer : observers_) {
-    observer.OnCompromisedCredentialsChanged(credentials);
+    observer.OnCompromisedCredentialsChanged(compromised_credentials);
+  }
+}
+
+void InsecureCredentialsManager::NotifyWeakCredentialsChanged() {
+  std::vector<CredentialWithPassword> weak_credentials =
+      ExtractInsecureCredentials(credentials_to_forms_, &IsWeak);
+  for (auto& observer : observers_) {
+    observer.OnWeakCredentialsChanged(weak_credentials);
   }
 }
 
diff --git a/components/password_manager/core/browser/ui/insecure_credentials_manager.h b/components/password_manager/core/browser/ui/insecure_credentials_manager.h
index 9a823daa..b0a3817 100644
--- a/components/password_manager/core/browser/ui/insecure_credentials_manager.h
+++ b/components/password_manager/core/browser/ui/insecure_credentials_manager.h
@@ -8,6 +8,7 @@
 #include <map>
 #include <vector>
 
+#include "base/containers/flat_set.h"
 #include "base/containers/span.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/observer_list.h"
@@ -37,6 +38,13 @@
   kWeakCredential = 1 << 2,
 };
 
+constexpr InsecureCredentialTypeFlags operator&(
+    InsecureCredentialTypeFlags lhs,
+    InsecureCredentialTypeFlags rhs) {
+  return static_cast<InsecureCredentialTypeFlags>(static_cast<int>(lhs) &
+                                                  static_cast<int>(rhs));
+}
+
 constexpr InsecureCredentialTypeFlags operator|(
     InsecureCredentialTypeFlags lhs,
     InsecureCredentialTypeFlags rhs) {
@@ -44,6 +52,26 @@
                                                   static_cast<int>(rhs));
 }
 
+constexpr InsecureCredentialTypeFlags& operator|=(
+    InsecureCredentialTypeFlags& lhs,
+    InsecureCredentialTypeFlags rhs) {
+  lhs = lhs | rhs;
+  return lhs;
+}
+
+// Checks that |flag| contains at least one of compromised types.
+constexpr bool IsCompromised(const InsecureCredentialTypeFlags& flag) {
+  return (flag & (InsecureCredentialTypeFlags::kCredentialLeaked |
+                  InsecureCredentialTypeFlags::kCredentialPhished)) !=
+         InsecureCredentialTypeFlags::kSecure;
+}
+
+// Checks that |flag| contains weak type.
+constexpr bool IsWeak(const InsecureCredentialTypeFlags& flag) {
+  return (flag & InsecureCredentialTypeFlags::kWeakCredential) !=
+         InsecureCredentialTypeFlags::kSecure;
+}
+
 // Simple struct that augments key values of InsecureCredentials and a password.
 struct CredentialView {
   CredentialView(std::string signon_realm,
@@ -125,6 +153,10 @@
 
   void Init();
 
+  // Computes weak credentials in a separate thread and then passes the result
+  // to OnWeakCheckDone.
+  void StartWeakCheck();
+
   // Marks all saved credentials which have same username & password as
   // compromised.
   void SaveCompromisedCredential(const LeakCheckCredential& credential);
@@ -141,6 +173,9 @@
   // Returns a vector of currently compromised credentials.
   std::vector<CredentialWithPassword> GetCompromisedCredentials() const;
 
+  // Returns a vector of currently weak credentials.
+  std::vector<CredentialWithPassword> GetWeakCredentials() const;
+
   // Returns password forms which map to provided insecure credential.
   // In most of the cases vector will have 1 element only.
   SavedPasswordsPresenter::SavedPasswordsView GetSavedPasswordsFor(
@@ -154,6 +189,10 @@
   using CredentialPasswordsMap =
       std::map<CredentialView, CredentialMetadata, PasswordCredentialLess>;
 
+  // Updates |weak_passwords| set and notifies observers that weak credentials
+  // were changed.
+  void OnWeakCheckDone(base::flat_set<base::string16> weak_passwords);
+
   // CompromisedCredentialsReader::Observer:
   void OnCompromisedCredentialsChanged(
       const std::vector<CompromisedCredentials>& compromised_credentials)
@@ -163,9 +202,11 @@
   void OnSavedPasswordsChanged(
       SavedPasswordsPresenter::SavedPasswordsView passwords) override;
 
-  // Function to update |credentials_to_forms_| and notify observers.
-  void UpdateCachedDataAndNotifyObservers(
-      SavedPasswordsPresenter::SavedPasswordsView saved_passwords);
+  // Notifies observers when compromised credentials have changed.
+  void NotifyCompromisedCredentialsChanged();
+
+  // Notifies observers when weak credentials have changed.
+  void NotifyWeakCredentialsChanged();
 
   // Returns the `profile_store_` or `account_store_` if `form` is stored in the
   // profile store of the account store accordingly.
@@ -186,6 +227,9 @@
   // Cache of the most recently obtained compromised credentials.
   std::vector<CompromisedCredentials> compromised_credentials_;
 
+  // Cache of the most recently obtained weak passwords.
+  base::flat_set<base::string16> weak_passwords_;
+
   // A map that matches CredentialView to corresponding PasswordForms, latest
   // create_type and combined insecure type.
   CredentialPasswordsMap credentials_to_forms_;
@@ -201,6 +245,8 @@
       observed_saved_password_presenter_{this};
 
   base::ObserverList<Observer, /*check_empty=*/true> observers_;
+
+  base::WeakPtrFactory<InsecureCredentialsManager> weak_ptr_factory_{this};
 };
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/ui/insecure_credentials_manager_unittest.cc b/components/password_manager/core/browser/ui/insecure_credentials_manager_unittest.cc
index 170a752..22fa6c1 100644
--- a/components/password_manager/core/browser/ui/insecure_credentials_manager_unittest.cc
+++ b/components/password_manager/core/browser/ui/insecure_credentials_manager_unittest.cc
@@ -29,6 +29,11 @@
 constexpr char kPassword2[] = "s3cr3t";
 constexpr char kPassword3[] = "484her";
 
+constexpr char kWeakPassword1[] = "123456";
+constexpr char kWeakPassword2[] = "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcda";
+constexpr char kStrongPassword1[] = "fnlsr4@cm^mdls@fkspnsg3d";
+constexpr char kStrongPassword2[] = "pmsFlsnoab4nsl#losb@skpfnsbkjb^klsnbs!cns";
+
 using autofill::PasswordForm;
 using ::testing::ElementsAre;
 using ::testing::ElementsAreArray;
@@ -84,11 +89,11 @@
   return credential_with_password;
 }
 
-class CompromisedCredentialsManagerTest : public ::testing::Test {
+class InsecureCredentialsManagerTest : public ::testing::Test {
  protected:
-  CompromisedCredentialsManagerTest() { store_->Init(/*prefs=*/nullptr); }
+  InsecureCredentialsManagerTest() { store_->Init(/*prefs=*/nullptr); }
 
-  ~CompromisedCredentialsManagerTest() override {
+  ~InsecureCredentialsManagerTest() override {
     store_->ShutdownOnUIThread();
     task_env_.RunUntilIdle();
   }
@@ -99,8 +104,8 @@
   void RunUntilIdle() { task_env_.RunUntilIdle(); }
 
  private:
-  base::test::SingleThreadTaskEnvironment task_env_{
-      base::test::SingleThreadTaskEnvironment::TimeSource::MOCK_TIME};
+  base::test::TaskEnvironment task_env_{
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
   scoped_refptr<TestPasswordStore> store_ =
       base::MakeRefCounted<TestPasswordStore>();
   SavedPasswordsPresenter presenter_{store_};
@@ -127,7 +132,7 @@
 }
 
 // Tests whether adding and removing an observer works as expected.
-TEST_F(CompromisedCredentialsManagerTest,
+TEST_F(InsecureCredentialsManagerTest,
        NotifyObserversAboutCompromisedCredentialChanges) {
   std::vector<CompromisedCredentials> credentials = {
       MakeCompromised(kExampleCom, kUsername1)};
@@ -172,7 +177,7 @@
 
 // Tests removing a compromised credentials by compromise type triggers an
 // observer works as expected.
-TEST_F(CompromisedCredentialsManagerTest,
+TEST_F(InsecureCredentialsManagerTest,
        NotifyObserversAboutRemovingCompromisedCredentialsByCompromisedType) {
   CompromisedCredentials phished_credentials =
       MakeCompromised(kExampleCom, kUsername1, CompromiseType::kPhished);
@@ -206,7 +211,7 @@
 }
 
 // Tests whether adding and removing an observer works as expected.
-TEST_F(CompromisedCredentialsManagerTest,
+TEST_F(InsecureCredentialsManagerTest,
        NotifyObserversAboutSavedPasswordsChanges) {
   StrictMockInsecureCredentialsManagerObserver observer;
   provider().AddObserver(&observer);
@@ -239,7 +244,7 @@
 
 // Tests that the provider is able to join a single password with a compromised
 // credential.
-TEST_F(CompromisedCredentialsManagerTest, JoinSingleCredentials) {
+TEST_F(InsecureCredentialsManagerTest, JoinSingleCredentials) {
   PasswordForm password =
       MakeSavedPassword(kExampleCom, kUsername1, kPassword1);
   CompromisedCredentials credential = MakeCompromised(kExampleCom, kUsername1);
@@ -256,7 +261,7 @@
 
 // Tests that the provider is able to join a password with a credential that was
 // compromised in multiple ways.
-TEST_F(CompromisedCredentialsManagerTest, JoinPhishedAndLeaked) {
+TEST_F(InsecureCredentialsManagerTest, JoinPhishedAndLeaked) {
   PasswordForm password =
       MakeSavedPassword(kExampleCom, kUsername1, kPassword1);
   CompromisedCredentials leaked =
@@ -279,7 +284,7 @@
 
 // Tests that the provider reacts whenever the saved passwords or the
 // compromised credentials change.
-TEST_F(CompromisedCredentialsManagerTest, ReactToChangesInBothTables) {
+TEST_F(InsecureCredentialsManagerTest, ReactToChangesInBothTables) {
   std::vector<PasswordForm> passwords = {
       MakeSavedPassword(kExampleCom, kUsername1, kPassword1),
       MakeSavedPassword(kExampleCom, kUsername2, kPassword2)};
@@ -320,7 +325,7 @@
 
 // Tests that the provider is able to join multiple passwords with compromised
 // credentials.
-TEST_F(CompromisedCredentialsManagerTest, JoinMultipleCredentials) {
+TEST_F(InsecureCredentialsManagerTest, JoinMultipleCredentials) {
   std::vector<PasswordForm> passwords = {
       MakeSavedPassword(kExampleCom, kUsername1, kPassword1),
       MakeSavedPassword(kExampleCom, kUsername2, kPassword2)};
@@ -346,7 +351,7 @@
 
 // Tests that joining a compromised credential with saved passwords with a
 // different username results in an empty list.
-TEST_F(CompromisedCredentialsManagerTest, JoinWitDifferentUsername) {
+TEST_F(InsecureCredentialsManagerTest, JoinWitDifferentUsername) {
   std::vector<PasswordForm> passwords = {
       MakeSavedPassword(kExampleCom, kUsername2, kPassword1),
       MakeSavedPassword(kExampleCom, kUsername2, kPassword2)};
@@ -363,7 +368,7 @@
 
 // Tests that joining a compromised credential with saved passwords with a
 // matching username but different signon_realm results in an empty list.
-TEST_F(CompromisedCredentialsManagerTest, JoinWitDifferentSignonRealm) {
+TEST_F(InsecureCredentialsManagerTest, JoinWitDifferentSignonRealm) {
   std::vector<PasswordForm> passwords = {
       MakeSavedPassword(kExampleOrg, kUsername1, kPassword1),
       MakeSavedPassword(kExampleOrg, kUsername1, kPassword2)};
@@ -381,7 +386,7 @@
 // Tests that joining a compromised credential with multiple saved passwords for
 // the same signon_realm and username combination results in multiple entries
 // when the passwords are distinct.
-TEST_F(CompromisedCredentialsManagerTest, JoinWithMultipleDistinctPasswords) {
+TEST_F(InsecureCredentialsManagerTest, JoinWithMultipleDistinctPasswords) {
   std::vector<PasswordForm> passwords = {
       MakeSavedPassword(kExampleCom, kUsername1, kPassword1, "element_1"),
       MakeSavedPassword(kExampleCom, kUsername1, kPassword2, "element_2")};
@@ -405,7 +410,7 @@
 // Tests that joining a compromised credential with multiple saved passwords for
 // the same signon_realm and username combination results in a single entry
 // when the passwords are the same.
-TEST_F(CompromisedCredentialsManagerTest, JoinWithMultipleRepeatedPasswords) {
+TEST_F(InsecureCredentialsManagerTest, JoinWithMultipleRepeatedPasswords) {
   CompromisedCredentials credential = MakeCompromised(kExampleCom, kUsername1);
   std::vector<PasswordForm> passwords = {
       MakeSavedPassword(kExampleCom, kUsername1, kPassword1, "element_1"),
@@ -424,7 +429,7 @@
 
 // Tests that verifies mapping compromised credentials to passwords works
 // correctly.
-TEST_F(CompromisedCredentialsManagerTest, MapCompromisedPasswordsToPasswords) {
+TEST_F(InsecureCredentialsManagerTest, MapCompromisedPasswordsToPasswords) {
   std::vector<PasswordForm> passwords = {
       MakeSavedPassword(kExampleCom, kUsername1, kPassword1, "element_1"),
       MakeSavedPassword(kExampleCom, kUsername1, kPassword1, "element_2"),
@@ -456,9 +461,159 @@
               ElementsAreArray(store().stored_passwords().at(kExampleOrg)));
 }
 
+TEST_F(InsecureCredentialsManagerTest, WeakCredentialsNotFound) {
+  std::vector<PasswordForm> passwords = {
+      MakeSavedPassword(kExampleCom, kUsername1, kStrongPassword1),
+      MakeSavedPassword(kExampleCom, kUsername2, kStrongPassword2)};
+
+  store().AddLogin(passwords[0]);
+  store().AddLogin(passwords[1]);
+
+  RunUntilIdle();
+  provider().StartWeakCheck();
+  RunUntilIdle();
+
+  EXPECT_THAT(provider().GetWeakCredentials(), IsEmpty());
+}
+
+TEST_F(InsecureCredentialsManagerTest, DetectedWeakCredential) {
+  std::vector<PasswordForm> passwords = {
+      MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1),
+      MakeSavedPassword(kExampleCom, kUsername2, kStrongPassword1)};
+
+  store().AddLogin(passwords[0]);
+  store().AddLogin(passwords[1]);
+
+  RunUntilIdle();
+  provider().StartWeakCheck();
+  RunUntilIdle();
+
+  std::vector<CredentialWithPassword> weak_credentials =
+      provider().GetWeakCredentials();
+
+  ASSERT_EQ(weak_credentials.size(), 1u);
+  EXPECT_EQ(base::UTF16ToUTF8(weak_credentials[0].password), kWeakPassword1);
+  EXPECT_TRUE(IsWeak(weak_credentials[0].insecure_type));
+}
+
+// Tests that credentials with the same signon_realm and username, but different
+// passwords will be both returned by GetWeakCredentials().
+TEST_F(InsecureCredentialsManagerTest,
+       FindBothWeakCredentialsWithDifferentPasswords) {
+  std::vector<PasswordForm> passwords = {
+      MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1, "element_1"),
+      MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword2, "element_2")};
+
+  store().AddLogin(passwords[0]);
+  store().AddLogin(passwords[1]);
+
+  RunUntilIdle();
+  provider().StartWeakCheck();
+  RunUntilIdle();
+
+  std::vector<CredentialWithPassword> weak_credentials =
+      provider().GetWeakCredentials();
+
+  ASSERT_EQ(weak_credentials.size(), 2u);
+  EXPECT_TRUE(IsWeak(weak_credentials[0].insecure_type));
+  EXPECT_TRUE(IsWeak(weak_credentials[1].insecure_type));
+}
+
+// Tests that credentials with the same signon_realm, username and passwords
+// will be joind and GetWeakCredentials() will return one credential.
+TEST_F(InsecureCredentialsManagerTest,
+       JoinWeakCredentialsWithTheSamePasswords) {
+  std::vector<PasswordForm> passwords = {
+      MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1, "element_1"),
+      MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1, "element_2")};
+
+  store().AddLogin(passwords[0]);
+  store().AddLogin(passwords[1]);
+
+  RunUntilIdle();
+  provider().StartWeakCheck();
+  RunUntilIdle();
+
+  std::vector<CredentialWithPassword> weak_credentials =
+      provider().GetWeakCredentials();
+
+  ASSERT_EQ(weak_credentials.size(), 1u);
+  EXPECT_EQ(base::UTF16ToUTF8(weak_credentials[0].password), kWeakPassword1);
+  EXPECT_TRUE(IsWeak(weak_credentials[0].insecure_type));
+}
+
+TEST_F(InsecureCredentialsManagerTest, BothWeakAndCompromisedCredentialsExist) {
+  std::vector<PasswordForm> passwords = {
+      MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1),
+      MakeSavedPassword(kExampleCom, kUsername2, kStrongPassword1)};
+  std::vector<CompromisedCredentials> compromised_credentials = {
+      MakeCompromised(kExampleCom, kUsername1),
+      MakeCompromised(kExampleCom, kUsername2)};
+
+  store().AddLogin(passwords[0]);
+  store().AddLogin(passwords[1]);
+  store().AddCompromisedCredentials(compromised_credentials[0]);
+  store().AddCompromisedCredentials(compromised_credentials[1]);
+
+  RunUntilIdle();
+  provider().StartWeakCheck();
+  RunUntilIdle();
+
+  std::vector<CredentialWithPassword> returned_weak_credentials =
+      provider().GetWeakCredentials();
+  std::vector<CredentialWithPassword> returned_compromised_credentials =
+      provider().GetCompromisedCredentials();
+
+  ASSERT_EQ(returned_weak_credentials.size(), 1u);
+  EXPECT_EQ(base::UTF16ToUTF8(returned_weak_credentials[0].password),
+            kWeakPassword1);
+  EXPECT_TRUE(IsWeak(returned_weak_credentials[0].insecure_type));
+
+  ASSERT_EQ(returned_compromised_credentials.size(), 2u);
+  EXPECT_TRUE(IsCompromised(returned_compromised_credentials[0].insecure_type));
+  EXPECT_TRUE(IsCompromised(returned_compromised_credentials[1].insecure_type));
+}
+
+// Checks that for a credential that is both weak and compromised,
+// getWeakCredentials and GetCompromisedCredentials will return this credential
+// in one instance.
+TEST_F(InsecureCredentialsManagerTest, SingleCredentialIsWeakAndCompromised) {
+  std::vector<PasswordForm> passwords = {
+      MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1)};
+  std::vector<CompromisedCredentials> compromised_credentials = {
+      MakeCompromised(kExampleCom, kUsername1)};
+
+  store().AddLogin(passwords[0]);
+  store().AddCompromisedCredentials(compromised_credentials[0]);
+
+  RunUntilIdle();
+  provider().StartWeakCheck();
+  RunUntilIdle();
+
+  std::vector<CredentialWithPassword> returned_weak_credentials =
+      provider().GetWeakCredentials();
+  std::vector<CredentialWithPassword> returned_compromised_credentials =
+      provider().GetCompromisedCredentials();
+
+  // Since the credential is weak and compromised, the |insecure_type| should be
+  // weak and compromised for elements from |returned_weak_credentials| and
+  // |returned_compromised_credentials|.
+  ASSERT_EQ(returned_weak_credentials.size(), 1u);
+  EXPECT_EQ(base::UTF16ToUTF8(returned_weak_credentials[0].password),
+            kWeakPassword1);
+  EXPECT_TRUE(IsWeak(returned_weak_credentials[0].insecure_type));
+  EXPECT_TRUE(IsCompromised(returned_weak_credentials[0].insecure_type));
+
+  ASSERT_EQ(returned_compromised_credentials.size(), 1u);
+  EXPECT_EQ(base::UTF16ToUTF8(returned_compromised_credentials[0].password),
+            kWeakPassword1);
+  EXPECT_TRUE(IsWeak(returned_compromised_credentials[0].insecure_type));
+  EXPECT_TRUE(IsCompromised(returned_compromised_credentials[0].insecure_type));
+}
+
 // Test verifies that saving LeakCheckCredential via provider adds expected
 // compromised credential.
-TEST_F(CompromisedCredentialsManagerTest, SaveCompromisedPassword) {
+TEST_F(InsecureCredentialsManagerTest, SaveCompromisedPassword) {
   PasswordForm password_form =
       MakeSavedPassword(kExampleCom, kUsername1, kPassword1);
   LeakCheckCredential credential = MakeLeakCredential(kUsername1, kPassword1);
@@ -480,7 +635,7 @@
 
 // Test verifies that editing Compromised Credential via provider change the
 // original password form.
-TEST_F(CompromisedCredentialsManagerTest, UpdateCompromisedPassword) {
+TEST_F(InsecureCredentialsManagerTest, UpdateCompromisedPassword) {
   PasswordForm password_form =
       MakeSavedPassword(kExampleCom, kUsername1, kPassword1);
   CompromisedCredentials credential = MakeCompromised(kExampleCom, kUsername1);
@@ -499,7 +654,7 @@
   EXPECT_THAT(provider().GetCompromisedCredentials(), ElementsAre(expected));
 }
 
-TEST_F(CompromisedCredentialsManagerTest, RemoveCompromisedCredential) {
+TEST_F(InsecureCredentialsManagerTest, RemoveCompromisedCredential) {
   CompromisedCredentials credential = MakeCompromised(kExampleCom, kUsername1);
   PasswordForm password =
       MakeSavedPassword(kExampleCom, kUsername1, kPassword1);
@@ -520,14 +675,14 @@
 }
 
 namespace {
-class CompromisedCredentialsManagerWithTwoStoresTest : public ::testing::Test {
+class InsecureCredentialsManagerWithTwoStoresTest : public ::testing::Test {
  protected:
-  CompromisedCredentialsManagerWithTwoStoresTest() {
+  InsecureCredentialsManagerWithTwoStoresTest() {
     profile_store_->Init(/*prefs=*/nullptr);
     account_store_->Init(/*prefs=*/nullptr);
   }
 
-  ~CompromisedCredentialsManagerWithTwoStoresTest() override {
+  ~InsecureCredentialsManagerWithTwoStoresTest() override {
     account_store_->ShutdownOnUIThread();
     profile_store_->ShutdownOnUIThread();
     task_env_.RunUntilIdle();
@@ -553,7 +708,7 @@
 
 // Tests that verifies mapping compromised credentials to passwords works
 // correctly.
-TEST_F(CompromisedCredentialsManagerWithTwoStoresTest,
+TEST_F(InsecureCredentialsManagerWithTwoStoresTest,
        MapCompromisedPasswordsToPasswords) {
   // Add credentials for both `kExampleCom` and `kExampleOrg` in both stores
   // with the same username and difference passwords. For `kUsername1`, the
@@ -607,8 +762,7 @@
 
 // Test verifies that saving LeakCheckCredential via provider adds expected
 // compromised credential to the correct store.
-TEST_F(CompromisedCredentialsManagerWithTwoStoresTest,
-       SaveCompromisedPassword) {
+TEST_F(InsecureCredentialsManagerWithTwoStoresTest, SaveCompromisedPassword) {
   ASSERT_TRUE(profile_store().compromised_credentials().empty());
   ASSERT_TRUE(account_store().compromised_credentials().empty());
   // Add `kUsername1`,`kPassword1` to both stores.
@@ -642,7 +796,7 @@
   EXPECT_EQ(2U, account_store().compromised_credentials().size());
 }
 
-TEST_F(CompromisedCredentialsManagerWithTwoStoresTest,
+TEST_F(InsecureCredentialsManagerWithTwoStoresTest,
        RemoveCompromisedCredential) {
   // Add `kUsername1`,`kPassword1` to both stores.
   profile_store().AddLogin(
diff --git a/components/password_manager/core/browser/ui/weak_check_utility.cc b/components/password_manager/core/browser/ui/weak_check_utility.cc
new file mode 100644
index 0000000..7401c3c
--- /dev/null
+++ b/components/password_manager/core/browser/ui/weak_check_utility.cc
@@ -0,0 +1,73 @@
+// 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/password_manager/core/browser/ui/weak_check_utility.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "third_party/zxcvbn-cpp/native-src/zxcvbn/matching.hpp"
+#include "third_party/zxcvbn-cpp/native-src/zxcvbn/scoring.hpp"
+#include "third_party/zxcvbn-cpp/native-src/zxcvbn/time_estimates.hpp"
+
+namespace password_manager {
+
+namespace {
+
+// Passwords longer than this constant should not be checked for weakness using
+// the zxcvbn-cpp library. This is because the runtime grows extremely, starting
+// at a password length of 40.
+// See https://github.com/dropbox/zxcvbn#runtime-latency
+// Needs to stay in sync with google3 constant: http://shortn/_1ufIF61G4X
+constexpr int kZxcvbnLengthCap = 40;
+
+// If the password has a score of 2 or less, this password should be marked as
+// weak. The lower the password score, the weaker it is.
+constexpr int kHighSeverityScore = 0;
+constexpr int kLowSeverityScore = 2;
+
+constexpr int kStrongPasswordScore = 4;
+
+// Very rough, extremely simplified strength check that only makes sense for
+// long passwords.
+int SimpleLongPasswordStrengthEstimate(const base::string16& password) {
+  base::flat_set<base::char16> chars;
+
+  for (auto character : password) {
+    chars.insert(character);
+    if (chars.size() > 4) {
+      return kStrongPasswordScore;
+    }
+  }
+  return kHighSeverityScore;
+}
+
+// Returns the |password| score.
+int PasswordWeakCheck(const base::string16& password) {
+  // zxcvbn's computation time explodes for long passwords, so don't use it for
+  // those.
+  if (password.size() > kZxcvbnLengthCap) {
+    return SimpleLongPasswordStrengthEstimate(password);
+  }
+  std::vector<zxcvbn::Match> matches =
+      zxcvbn::omnimatch(base::UTF16ToUTF8(password));
+  zxcvbn::ScoringResult result = zxcvbn::most_guessable_match_sequence(
+      base::UTF16ToUTF8(password), matches);
+  return zxcvbn::estimate_attack_times(result.guesses).score;
+}
+
+}  // namespace
+
+base::flat_set<base::string16> BulkWeakCheck(
+    SavedPasswordsPresenter::SavedPasswordsView saved_passwords) {
+  std::vector<base::string16> weak_passwords;
+
+  for (const auto& password : saved_passwords) {
+    if (PasswordWeakCheck(password.password_value) <= kLowSeverityScore) {
+      weak_passwords.push_back(password.password_value);
+    }
+  }
+
+  return base::flat_set<base::string16>(std::move(weak_passwords));
+}
+
+}  // namespace password_manager
diff --git a/components/password_manager/core/browser/ui/weak_check_utility.h b/components/password_manager/core/browser/ui/weak_check_utility.h
new file mode 100644
index 0000000..c976b88
--- /dev/null
+++ b/components/password_manager/core/browser/ui/weak_check_utility.h
@@ -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.
+
+#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_UI_WEAK_CHECK_UTILITY_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_UI_WEAK_CHECK_UTILITY_H_
+
+#include "base/containers/flat_set.h"
+#include "base/strings/string16.h"
+#include "components/password_manager/core/browser/ui/saved_passwords_presenter.h"
+
+namespace password_manager {
+
+// Checks each password for weakness.
+base::flat_set<base::string16> BulkWeakCheck(
+    SavedPasswordsPresenter::SavedPasswordsView passwords);
+
+}  // namespace password_manager
+
+#endif  // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_UI_WEAK_CHECK_UTILITY_H_
diff --git a/components/password_manager/core/browser/ui/weak_check_utility_unittest.cc b/components/password_manager/core/browser/ui/weak_check_utility_unittest.cc
new file mode 100644
index 0000000..8352a150
--- /dev/null
+++ b/components/password_manager/core/browser/ui/weak_check_utility_unittest.cc
@@ -0,0 +1,74 @@
+// 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/password_manager/core/browser/ui/weak_check_utility.h"
+
+#include <vector>
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/common/password_form.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace password_manager {
+
+namespace {
+
+constexpr char kUsername1[] = "alice";
+constexpr char kUsername2[] = "bob";
+
+constexpr char kWeakShortPassword[] = "123456";
+constexpr char kWeakLongPassword[] =
+    "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcda";
+constexpr char kStrongShortPassword[] = "fnlsr4@cm^mdls@fkspnsg3d";
+constexpr char kStrongLongPassword[] =
+    "pmsFlsnoab4nsl#losb@skpfnsbkjb^klsnbs!cns";
+
+using autofill::PasswordForm;
+using ::testing::ElementsAre;
+
+PasswordForm MakeSavedPassword(base::StringPiece username,
+                               base::StringPiece password) {
+  PasswordForm form;
+  form.signon_realm = "https://example.com";
+  form.username_value = base::ASCIIToUTF16(username);
+  form.password_value = base::ASCIIToUTF16(password);
+  return form;
+}
+
+}  // namespace
+
+TEST(WeakCheckUtilityTest, WeakPasswordsNotFound) {
+  std::vector<PasswordForm> passwords = {
+      MakeSavedPassword(kUsername1, kStrongShortPassword),
+      MakeSavedPassword(kUsername2, kStrongLongPassword)};
+
+  EXPECT_THAT(BulkWeakCheck(passwords), testing::IsEmpty());
+}
+
+TEST(WeakCheckUtilityTest, DetectedShortAndLongWeakPasswords) {
+  std::vector<PasswordForm> passwords = {
+      MakeSavedPassword(kUsername1, kStrongLongPassword),
+      MakeSavedPassword(kUsername1, kWeakShortPassword),
+      MakeSavedPassword(kUsername1, kStrongShortPassword),
+      MakeSavedPassword(kUsername2, kWeakLongPassword)};
+
+  base::flat_set<base::string16> weak_passwords = BulkWeakCheck(passwords);
+
+  EXPECT_THAT(weak_passwords,
+              ElementsAre(base::ASCIIToUTF16(kWeakShortPassword),
+                          base::ASCIIToUTF16(kWeakLongPassword)));
+}
+
+TEST(WeakCheckUtilityTest, WeakPasswordsSetContainsNoCopies) {
+  std::vector<PasswordForm> passwords = {
+      MakeSavedPassword(kUsername1, kWeakShortPassword),
+      MakeSavedPassword(kUsername2, kWeakShortPassword)};
+
+  base::flat_set<base::string16> weak_passwords = BulkWeakCheck(passwords);
+
+  EXPECT_THAT(weak_passwords,
+              ElementsAre(base::ASCIIToUTF16(kWeakShortPassword)));
+}
+
+}  // namespace password_manager
diff --git a/components/payments/content/android/java/src/org/chromium/components/payments/ComponentPaymentRequestImpl.java b/components/payments/content/android/java/src/org/chromium/components/payments/ComponentPaymentRequestImpl.java
index 499abe1..7946ef4 100644
--- a/components/payments/content/android/java/src/org/chromium/components/payments/ComponentPaymentRequestImpl.java
+++ b/components/payments/content/android/java/src/org/chromium/components/payments/ComponentPaymentRequestImpl.java
@@ -188,9 +188,9 @@
         assert onClosedListener != null;
 
         WebContents webContents = WebContentsStatics.fromRenderFrameHost(renderFrameHost);
-        if (webContents == null) {
-            abortBeforeInstantiation(client, /*journeyLogger=*/null, ErrorStrings.NO_WEB_CONTENTS,
-                    AbortReason.INVALID_DATA_FROM_RENDERER);
+        if (webContents == null || webContents.isDestroyed()) {
+            abortBeforeInstantiation(/*client=*/null, /*journeyLogger=*/null,
+                    ErrorStrings.NO_WEB_CONTENTS, AbortReason.INVALID_DATA_FROM_RENDERER);
             return null;
         }
 
diff --git a/components/payments/content/android/java/src/org/chromium/components/payments/JourneyLogger.java b/components/payments/content/android/java/src/org/chromium/components/payments/JourneyLogger.java
index 09ef3b5..d1e5c355 100644
--- a/components/payments/content/android/java/src/org/chromium/components/payments/JourneyLogger.java
+++ b/components/payments/content/android/java/src/org/chromium/components/payments/JourneyLogger.java
@@ -20,7 +20,14 @@
 
     private boolean mHasRecorded;
 
+    /**
+     * Creates the journey logger.
+     * @param isIncognito Whether the user profile is incognito.
+     * @param webContents The web contents where PaymentRequest API is invoked. Should not be null.
+     */
     public JourneyLogger(boolean isIncognito, WebContents webContents) {
+        assert webContents != null;
+        assert !webContents.isDestroyed();
         // Note that this pointer could leak the native object. The called must call destroy() to
         // ensure that the native object is destroyed.
         mJourneyLoggerAndroid = JourneyLoggerJni.get().initJourneyLoggerAndroid(
diff --git a/components/policy/core/browser/browser_policy_connector.cc b/components/policy/core/browser/browser_policy_connector.cc
index adddd65..909751a 100644
--- a/components/policy/core/browser/browser_policy_connector.cc
+++ b/components/policy/core/browser/browser_policy_connector.cc
@@ -135,6 +135,24 @@
   return false;
 }
 
+std::string BrowserPolicyConnector::GetDeviceManagementUrl() const {
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kDeviceManagementUrl) &&
+      IsCommandLineSwitchSupported())
+    return command_line->GetSwitchValueASCII(switches::kDeviceManagementUrl);
+  else
+    return kDefaultDeviceManagementServerUrl;
+}
+
+std::string BrowserPolicyConnector::GetRealtimeReportingUrl() const {
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kRealtimeReportingUrl) &&
+      IsCommandLineSwitchSupported())
+    return command_line->GetSwitchValueASCII(switches::kRealtimeReportingUrl);
+  else
+    return kDefaultRealtimeReportingServerUrl;
+}
+
 // static
 bool BrowserPolicyConnector::IsNonEnterpriseUser(const std::string& username) {
   TRACE_EVENT0("browser", "BrowserPolicyConnector::IsNonEnterpriseUser");
@@ -166,24 +184,6 @@
 }
 
 // static
-std::string BrowserPolicyConnector::GetDeviceManagementUrl() {
-  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  if (command_line->HasSwitch(switches::kDeviceManagementUrl))
-    return command_line->GetSwitchValueASCII(switches::kDeviceManagementUrl);
-  else
-    return kDefaultDeviceManagementServerUrl;
-}
-
-// static
-std::string BrowserPolicyConnector::GetRealtimeReportingUrl() {
-  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  if (command_line->HasSwitch(switches::kRealtimeReportingUrl))
-    return command_line->GetSwitchValueASCII(switches::kRealtimeReportingUrl);
-  else
-    return kDefaultRealtimeReportingServerUrl;
-}
-
-// static
 void BrowserPolicyConnector::RegisterPrefs(PrefRegistrySimple* registry) {
   registry->RegisterIntegerPref(
       policy_prefs::kUserPolicyRefreshRate,
diff --git a/components/policy/core/browser/browser_policy_connector.h b/components/policy/core/browser/browser_policy_connector.h
index ccf1fdd..b635722e 100644
--- a/components/policy/core/browser/browser_policy_connector.h
+++ b/components/policy/core/browser/browser_policy_connector.h
@@ -57,6 +57,12 @@
     return device_management_service_.get();
   }
 
+  // Returns the URL for the device management service endpoint.
+  std::string GetDeviceManagementUrl() const;
+
+  // Returns the URL for the realtime reporting service endpoint.
+  std::string GetRealtimeReportingUrl() const;
+
   // Check whether a user is known to be non-enterprise. Domains such as
   // gmail.com and googlemail.com are known to not be managed. Also returns
   // false if the username is empty.
@@ -67,15 +73,12 @@
   // with a nullptr.
   static void SetNonEnterpriseDomainForTesting(const char* domain);
 
-  // Returns the URL for the device management service endpoint.
-  static std::string GetDeviceManagementUrl();
-
-  // Returns the URL for the realtime reporting service endpoint.
-  static std::string GetRealtimeReportingUrl();
-
   // Registers refresh rate prefs.
   static void RegisterPrefs(PrefRegistrySimple* registry);
 
+  // Returns true if the command line switch of policy can be used.
+  virtual bool IsCommandLineSwitchSupported() const = 0;
+
  protected:
   // Builds an uninitialized BrowserPolicyConnector.
   // Init() should be called to create and start the policy components.
diff --git a/components/policy/proto/device_management_backend.proto b/components/policy/proto/device_management_backend.proto
index 1b8e86b..4b6dfaa49 100644
--- a/components/policy/proto/device_management_backend.proto
+++ b/components/policy/proto/device_management_backend.proto
@@ -2926,6 +2926,8 @@
     CRX_FETCH_URL_EMPTY = 25;
 
     CRX_FETCH_URL_INVALID = 26;
+
+    OVERRIDDEN_BY_SETTINGS = 27;
   }
 
   //  Stage of extension installing process. See InstallStageTracker::Stage for
diff --git a/components/prerender/browser/prerender_contents.h b/components/prerender/browser/prerender_contents.h
index 49e92219..cb07ec2 100644
--- a/components/prerender/browser/prerender_contents.h
+++ b/components/prerender/browser/prerender_contents.h
@@ -120,10 +120,8 @@
 
   static Factory* CreateFactory();
 
-  // Start rendering the contents in the prerendered state. If
-  // |is_control_group| is true, this will go through some of the mechanics of
-  // starting a prerender, without actually creating the RenderView. |bounds|
-  // indicates the rectangle that the prerendered page should be in.
+  // Starts rendering the contents in the prerendered state.
+  // |bounds| indicates the rectangle that the prerendered page should be in.
   // |session_storage_namespace| indicates the namespace that the prerendered
   // page should be part of.
   virtual void StartPrerendering(
diff --git a/components/signin/ios/browser/account_consistency_service_unittest.mm b/components/signin/ios/browser/account_consistency_service_unittest.mm
index 4b97071..ba57fbd 100644
--- a/components/signin/ios/browser/account_consistency_service_unittest.mm
+++ b/components/signin/ios/browser/account_consistency_service_unittest.mm
@@ -10,6 +10,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/ios/ios_util.h"
 #include "base/test/bind_test_util.h"
 #import "base/test/ios/wait_util.h"
 #include "base/values.h"
@@ -472,6 +473,13 @@
 // signon realm returns with a X-Chrome-Manage-Accounts header with ADDSESSION
 // action.
 TEST_F(AccountConsistencyServiceTest, ChromeManageAccountsShowAddAccount) {
+#if !TARGET_IPHONE_SIMULATOR
+  // TODO(crbug.com/1126746): Test is failing on iOS 12 device.
+  if (!base::ios::IsRunningOnOrLater(13, 0, 0)) {
+    return;
+  }
+#endif
+
   id delegate =
       [OCMockObject mockForProtocol:@protocol(ManageAccountsDelegate)];
   [[delegate expect] onAddAccount];
diff --git a/components/signin/public/android/java/src/org/chromium/components/signin/identitymanager/IdentityManager.java b/components/signin/public/android/java/src/org/chromium/components/signin/identitymanager/IdentityManager.java
index a25e4d5f..5f6552c 100644
--- a/components/signin/public/android/java/src/org/chromium/components/signin/identitymanager/IdentityManager.java
+++ b/components/signin/public/android/java/src/org/chromium/components/signin/identitymanager/IdentityManager.java
@@ -146,7 +146,7 @@
     }
 
     /**
-     * Looks up and returns information for account with given |email_address|. If the account
+     * Looks up and returns information for account with given |email|. If the account
      * cannot be found, return a null value.
      */
     public @Nullable CoreAccountInfo
diff --git a/components/signin/public/android/java/src/org/chromium/components/signin/identitymanager/IdentityMutator.java b/components/signin/public/android/java/src/org/chromium/components/signin/identitymanager/IdentityMutator.java
index b310b73..609b1af5 100644
--- a/components/signin/public/android/java/src/org/chromium/components/signin/identitymanager/IdentityMutator.java
+++ b/components/signin/public/android/java/src/org/chromium/components/signin/identitymanager/IdentityMutator.java
@@ -37,7 +37,7 @@
     }
 
     /**
-     * Marks the account with |account_id| as the primary account, and returns whether the operation
+     * Marks the account with |accountId| as the primary account, and returns whether the operation
      * succeeded or not. To succeed, this requires that:
      *   - the account is known by the IdentityManager.
      *   - setting the primary account is allowed,
diff --git a/components/strings/components_strings_or.xtb b/components/strings/components_strings_or.xtb
index 7d87cef3..8662bd37 100644
--- a/components/strings/components_strings_or.xtb
+++ b/components/strings/components_strings_or.xtb
@@ -114,6 +114,7 @@
 <translation id="1380591466760231819">ଲେଟର୍ ଫୋଲ୍ଡ</translation>
 <translation id="138218114945450791">ହାଲୁକା ନୀଳ</translation>
 <translation id="1382194467192730611">ଆପଣଙ୍କର ଆଡିମିନିଷ୍ଟ୍ରେଟର୍ ଦ୍ୱାରା ଅନୁମତି ଦିଆଯାଇଥିବା USB ଡିଭାଇସ୍</translation>
+<translation id="1386623374109090026">ଏନୋଟେସନଗୁଡ଼ିକ</translation>
 <translation id="139305205187523129"><ph name="HOST_NAME" /> କୌଣସି ଡାଟା ପଠାଇନାହିଁ।</translation>
 <translation id="1405567553485452995">ହାଲୁକା ସବୁଜ</translation>
 <translation id="1407135791313364759">ସବୁ ଖୋଲନ୍ତୁ</translation>
diff --git a/components/sync/base/pref_names.cc b/components/sync/base/pref_names.cc
index bde36ba..4976db3 100644
--- a/components/sync/base/pref_names.cc
+++ b/components/sync/base/pref_names.cc
@@ -45,7 +45,7 @@
 // OS user selectable types.
 const char kSyncOsApps[] = "sync.os_apps";
 const char kSyncOsPreferences[] = "sync.os_preferences";
-#endif
+#endif  // defined(OS_CHROMEOS)
 
 // Booleans specifying whether the user has selected to sync the following
 // user selectable types.
@@ -134,6 +134,13 @@
 const char kSyncDemographicsBirthYearOffset[] =
     "sync.demographics_birth_year_offset";
 
+#if defined(OS_ANDROID)
+// Stores whether sync should no longer respect the state of master toggle for
+// this user.
+const char kSyncDecoupledFromAndroidMasterSync[] =
+    "sync.decoupled_from_master_sync";
+#endif  // defined(OS_ANDROID)
+
 }  // namespace prefs
 
 }  // namespace syncer
diff --git a/components/sync/base/pref_names.h b/components/sync/base/pref_names.h
index 8e77052e..2884201 100644
--- a/components/sync/base/pref_names.h
+++ b/components/sync/base/pref_names.h
@@ -23,7 +23,7 @@
 extern const char kSyncAllOsTypes[];
 extern const char kSyncOsApps[];
 extern const char kSyncOsPreferences[];
-#endif
+#endif  // defined(OS_CHROMEOS)
 
 extern const char kSyncApps[];
 extern const char kSyncAutofill[];
@@ -60,6 +60,10 @@
 extern const char kSyncDemographics[];
 extern const char kSyncDemographicsBirthYearOffset[];
 
+#if defined(OS_ANDROID)
+extern const char kSyncDecoupledFromAndroidMasterSync[];
+#endif  // defined(OS_ANDROID)
+
 // These are not prefs, they are paths inside of kSyncDemographics.
 extern const char kSyncDemographics_BirthYearPath[];
 extern const char kSyncDemographics_GenderPath[];
diff --git a/components/sync/base/sync_prefs.cc b/components/sync/base/sync_prefs.cc
index ef07132e..6d0d1f3b 100644
--- a/components/sync/base/sync_prefs.cc
+++ b/components/sync/base/sync_prefs.cc
@@ -288,6 +288,10 @@
   registry->RegisterStringPref(prefs::kSyncLastRunVersion, std::string());
   registry->RegisterBooleanPref(prefs::kEnableLocalSyncBackend, false);
   registry->RegisterFilePathPref(prefs::kLocalSyncBackendDir, base::FilePath());
+#if defined(OS_ANDROID)
+  registry->RegisterBooleanPref(prefs::kSyncDecoupledFromAndroidMasterSync,
+                                false);
+#endif  // defined(OS_ANDROID)
 
   // Demographic prefs.
   registry->RegisterDictionaryPref(
@@ -341,6 +345,9 @@
   pref_service_->ClearPref(prefs::kSyncCacheGuid);
   pref_service_->ClearPref(prefs::kSyncBirthday);
   pref_service_->ClearPref(prefs::kSyncBagOfChips);
+#if defined(OS_ANDROID)
+  pref_service_->ClearPref(prefs::kSyncDecoupledFromAndroidMasterSync);
+#endif  // defined(OS_ANDROID)
 
   // No need to clear kManaged, kEnableLocalSyncBackend or kLocalSyncBackendDir,
   // since they're never actually set as user preferences.
@@ -666,6 +673,18 @@
   pref_service_->SetBoolean(prefs::kSyncPassphrasePrompted, value);
 }
 
+#if defined(OS_ANDROID)
+void SyncPrefs::SetDecoupledFromAndroidMasterSync() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  pref_service_->SetBoolean(prefs::kSyncDecoupledFromAndroidMasterSync, true);
+}
+
+bool SyncPrefs::GetDecoupledFromAndroidMasterSync() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  return pref_service_->GetBoolean(prefs::kSyncDecoupledFromAndroidMasterSync);
+}
+#endif  // defined(OS_ANDROID)
+
 void SyncPrefs::GetInvalidationVersions(
     std::map<ModelType, int64_t>* invalidation_versions) const {
   const base::DictionaryValue* invalidation_dictionary =
diff --git a/components/sync/base/sync_prefs.h b/components/sync/base/sync_prefs.h
index 0e6ac1c7..3b1ed71 100644
--- a/components/sync/base/sync_prefs.h
+++ b/components/sync/base/sync_prefs.h
@@ -169,6 +169,17 @@
   bool IsPassphrasePrompted() const;
   void SetPassphrasePrompted(bool value);
 
+#if defined(OS_ANDROID)
+  // Sets a boolean pref representing that Sync should no longer respect whether
+  // Android master sync is enabled/disabled.
+  void SetDecoupledFromAndroidMasterSync();
+
+  // Gets the value for the boolean pref representing whether Sync should no
+  // longer respect if Android master sync is enabled/disabled. Returns false
+  // until |SetDecoupledFromAndroidMasterSync()| is called.
+  bool GetDecoupledFromAndroidMasterSync();
+#endif  // defined(OS_ANDROID)
+
   // For testing.
   void SetManagedForTest(bool is_managed);
 
diff --git a/components/sync/driver/profile_sync_service.cc b/components/sync/driver/profile_sync_service.cc
index ef2a45d..df884907 100644
--- a/components/sync/driver/profile_sync_service.cc
+++ b/components/sync/driver/profile_sync_service.cc
@@ -328,6 +328,12 @@
       invalidations_identity_provider_->SetActiveAccountId(
           GetAuthenticatedAccountInfo().account_id);
     }
+
+    SyncInvalidationsService* sync_invalidations_service =
+        sync_client_->GetSyncInvalidationsService();
+    if (sync_invalidations_service) {
+      sync_invalidations_service->SetActive(IsSignedIn());
+    }
   }
 
   // If sync is disabled permanently, clean up old data that may be around (e.g.
@@ -414,6 +420,12 @@
     invalidations_identity_provider_->SetActiveAccountId(
         GetAuthenticatedAccountInfo().account_id);
   }
+
+  SyncInvalidationsService* sync_invalidations_service =
+      sync_client_->GetSyncInvalidationsService();
+  if (sync_invalidations_service) {
+    sync_invalidations_service->SetActive(IsSignedIn());
+  }
 }
 
 void ProfileSyncService::CredentialsChanged() {
@@ -1966,6 +1978,18 @@
   sync_prefs_.SetPassphrasePrompted(prompted);
 }
 
+#if defined(OS_ANDROID)
+void ProfileSyncService::SetDecoupledFromAndroidMasterSync() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  sync_prefs_.SetDecoupledFromAndroidMasterSync();
+}
+
+bool ProfileSyncService::GetDecoupledFromAndroidMasterSync() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  return sync_prefs_.GetDecoupledFromAndroidMasterSync();
+}
+#endif  // defined(OS_ANDROID)
+
 SyncEncryptionHandler::Observer*
 ProfileSyncService::GetEncryptionObserverForTest() {
   return &crypto_;
diff --git a/components/sync/driver/profile_sync_service.h b/components/sync/driver/profile_sync_service.h
index dc38a88..475bd2f 100644
--- a/components/sync/driver/profile_sync_service.h
+++ b/components/sync/driver/profile_sync_service.h
@@ -19,6 +19,7 @@
 #include "base/sequenced_task_runner.h"
 #include "base/threading/thread.h"
 #include "base/time/time.h"
+#include "build/build_config.h"
 #include "components/invalidation/public/identity_provider.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
 #include "components/sync/base/model_type.h"
@@ -216,6 +217,16 @@
   bool IsPassphrasePrompted() const;
   void SetPassphrasePrompted(bool prompted);
 
+#if defined(OS_ANDROID)
+  // Persists the fact that sync should no longer respect whether Android master
+  // sync is enabled. Only called on Android.
+  void SetDecoupledFromAndroidMasterSync();
+
+  // Gets the persisted information of whether sync should no longer respect
+  // if Android master sync is enabled. Only called on Android.
+  bool GetDecoupledFromAndroidMasterSync();
+#endif  // defined(OS_ANDROID)
+
   // Returns whether or not the underlying sync engine has made any
   // local changes to items that have not yet been synced with the
   // server.
diff --git a/components/sync/driver/profile_sync_service_unittest.cc b/components/sync/driver/profile_sync_service_unittest.cc
index a17bd7b..8eeb6bd 100644
--- a/components/sync/driver/profile_sync_service_unittest.cc
+++ b/components/sync/driver/profile_sync_service_unittest.cc
@@ -1648,5 +1648,45 @@
   service()->SetInvalidationsForSessionsEnabled(false);
 }
 
+TEST_F(ProfileSyncServiceTestWithSubscribeForSyncInvalidations,
+       ShouldActivateSyncInvalidationsServiceWhenSyncIsInitialized) {
+  CreateService(ProfileSyncService::AUTO_START);
+  EXPECT_CALL(*sync_invalidations_service(), SetActive(true)).Times(0);
+  SignIn();
+  EXPECT_CALL(*sync_invalidations_service(), SetActive(true));
+  InitializeForFirstSync();
+}
+
+TEST_F(ProfileSyncServiceTestWithSubscribeForSyncInvalidations,
+       ShouldActivateSyncInvalidationsServiceOnSignIn) {
+  CreateService(ProfileSyncService::AUTO_START);
+  EXPECT_CALL(*sync_invalidations_service(), SetActive(false));
+  InitializeForFirstSync();
+  EXPECT_CALL(*sync_invalidations_service(), SetActive(true));
+  SignIn();
+}
+
+// CrOS does not support signout.
+#if !defined(OS_CHROMEOS)
+TEST_F(ProfileSyncServiceTestWithSubscribeForSyncInvalidations,
+       ShouldDectivateSyncInvalidationsServiceOnSignOut) {
+  CreateService(ProfileSyncService::AUTO_START);
+  SignIn();
+  EXPECT_CALL(*sync_invalidations_service(), SetActive(true));
+  InitializeForFirstSync();
+
+  auto* account_mutator = identity_manager()->GetPrimaryAccountMutator();
+  // GetPrimaryAccountMutator() returns nullptr on ChromeOS only.
+  DCHECK(account_mutator);
+
+  // Sign out.
+  EXPECT_CALL(*sync_invalidations_service(), SetActive(false));
+  account_mutator->ClearPrimaryAccount(
+      signin::PrimaryAccountMutator::ClearAccountsAction::kDefault,
+      signin_metrics::SIGNOUT_TEST,
+      signin_metrics::SignoutDelete::IGNORE_METRIC);
+}
+#endif
+
 }  // namespace
 }  // namespace syncer
diff --git a/components/sync/invalidations/fcm_handler.cc b/components/sync/invalidations/fcm_handler.cc
index aee1352..0acc583 100644
--- a/components/sync/invalidations/fcm_handler.cc
+++ b/components/sync/invalidations/fcm_handler.cc
@@ -7,6 +7,7 @@
 #include <map>
 #include <utility>
 
+#include "base/bind_helpers.h"
 #include "base/logging.h"
 #include "base/time/time.h"
 #include "components/gcm_driver/gcm_driver.h"
@@ -51,6 +52,15 @@
   }
 }
 
+void FCMHandler::StopListeningPermanently() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (instance_id_driver_->ExistsInstanceID(app_id_)) {
+    instance_id_driver_->GetInstanceID(app_id_)->DeleteID(
+        /*callback=*/base::DoNothing());
+  }
+  StopListening();
+}
+
 const std::string& FCMHandler::GetFCMRegistrationToken() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   return fcm_registration_token_;
diff --git a/components/sync/invalidations/fcm_handler.h b/components/sync/invalidations/fcm_handler.h
index aa40529..e670e5e 100644
--- a/components/sync/invalidations/fcm_handler.h
+++ b/components/sync/invalidations/fcm_handler.h
@@ -40,15 +40,24 @@
   FCMHandler& operator=(const FCMHandler&) = delete;
 
   // Used to start handling incoming invalidations from the server and to obtain
-  // an FCM token. Before StartListening() is called for the first time, the
-  // FCM registration token will be empty.
+  // an FCM token. This method gets called after sign-in, or during browser
+  // startup if the user is already signed in. Before StartListening() is called
+  // for the first time, the FCM registration token will be empty.
   void StartListening();
 
   // Stop handling incoming invalidations. It doesn't cleanup the FCM
   // registration token and doesn't unsubscribe from FCM. All incoming
-  // invalidations will be dropped.
+  // invalidations will be dropped. This method gets called during browser
+  // shutdown.
   void StopListening();
 
+  // Stop handling incoming invalidations and delete Instance ID. This method
+  // gets called during sign-out.
+  void StopListeningPermanently();
+
+  // Returns if the handler is listening for incoming invalidations.
+  bool IsListening() const;
+
   // Add or remove a new listener which will be notified on each new incoming
   // invalidation. |listener| must not be nullptr.
   void AddListener(InvalidationsListener* listener);
@@ -74,8 +83,6 @@
                           const std::string& message_id) override;
 
  private:
-  bool IsListening() const;
-
   // Called when a subscription token is obtained from the GCM server.
   void DidRetrieveToken(const std::string& subscription_token,
                         instance_id::InstanceID::Result result);
diff --git a/components/sync/invalidations/mock_sync_invalidations_service.h b/components/sync/invalidations/mock_sync_invalidations_service.h
index 626a576..c1a8187 100644
--- a/components/sync/invalidations/mock_sync_invalidations_service.h
+++ b/components/sync/invalidations/mock_sync_invalidations_service.h
@@ -17,6 +17,7 @@
   MockSyncInvalidationsService();
   ~MockSyncInvalidationsService() override;
 
+  MOCK_METHOD(void, SetActive, (bool active));
   MOCK_METHOD(void, AddListener, (InvalidationsListener * listener));
   MOCK_METHOD(void, RemoveListener, (InvalidationsListener * listener));
   MOCK_METHOD(void,
diff --git a/components/sync/invalidations/sync_invalidations_service.h b/components/sync/invalidations/sync_invalidations_service.h
index 434fa20e..475f86f 100644
--- a/components/sync/invalidations/sync_invalidations_service.h
+++ b/components/sync/invalidations/sync_invalidations_service.h
@@ -22,6 +22,9 @@
 // should be added.
 class SyncInvalidationsService : public KeyedService {
  public:
+  // Start or stop listening to invalidations.
+  virtual void SetActive(bool active) = 0;
+
   // Add or remove a new listener which will be notified on each new incoming
   // invalidation. |listener| must not be nullptr. If there is no such
   // |listener| then RemoveListener will do nothing.
diff --git a/components/sync/invalidations/sync_invalidations_service_impl.cc b/components/sync/invalidations/sync_invalidations_service_impl.cc
index 26b1036f..be5f1ee1 100644
--- a/components/sync/invalidations/sync_invalidations_service_impl.cc
+++ b/components/sync/invalidations/sync_invalidations_service_impl.cc
@@ -21,11 +21,22 @@
     instance_id::InstanceIDDriver* instance_id_driver) {
   fcm_handler_ = std::make_unique<FCMHandler>(gcm_driver, instance_id_driver,
                                               kSenderId, kApplicationId);
-  fcm_handler_->StartListening();
 }
 
 SyncInvalidationsServiceImpl::~SyncInvalidationsServiceImpl() = default;
 
+void SyncInvalidationsServiceImpl::SetActive(bool active) {
+  if (fcm_handler_->IsListening() == active) {
+    return;
+  }
+
+  if (active) {
+    fcm_handler_->StartListening();
+  } else {
+    fcm_handler_->StopListeningPermanently();
+  }
+}
+
 void SyncInvalidationsServiceImpl::AddListener(
     InvalidationsListener* listener) {
   fcm_handler_->AddListener(listener);
diff --git a/components/sync/invalidations/sync_invalidations_service_impl.h b/components/sync/invalidations/sync_invalidations_service_impl.h
index 6eb00207..666d945 100644
--- a/components/sync/invalidations/sync_invalidations_service_impl.h
+++ b/components/sync/invalidations/sync_invalidations_service_impl.h
@@ -32,6 +32,7 @@
   ~SyncInvalidationsServiceImpl() override;
 
   // SyncInvalidationsService implementation.
+  void SetActive(bool active) override;
   void AddListener(InvalidationsListener* listener) override;
   void RemoveListener(InvalidationsListener* listener) override;
   void AddTokenObserver(FCMRegistrationTokenObserver* observer) override;
diff --git a/components/test/data/payments/create_many_requests.html b/components/test/data/payments/create_many_requests.html
new file mode 100644
index 0000000..e565b95
--- /dev/null
+++ b/components/test/data/payments/create_many_requests.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<!--
+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.
+-->
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1">
+<title>Create Many Requests</title>
+</head>
+<body>
+<script src="create_many_requests.js"></script>
+</body>
+</html>
diff --git a/components/test/data/payments/create_many_requests.js b/components/test/data/payments/create_many_requests.js
new file mode 100644
index 0000000..90f2240
--- /dev/null
+++ b/components/test/data/payments/create_many_requests.js
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+const supportedInstruments = [{
+  supportedMethods: 'secure-payment-confirmation',
+  data: {
+    'credentialIds': [new ArrayBuffer(4)],
+    'fallbackUrl': 'localhost:8000',
+    'networkData': new ArrayBuffer(4),
+  },
+}];
+
+const details = {
+  total: {label: 'Total', amount: {currency: 'USD', value: '55.00'}},
+};
+
+for (let i = 0; i < 0x1000; i++) {
+  new PaymentRequest(supportedInstruments, details);
+}
diff --git a/components/test/data/payments/load_and_remove_iframe.html b/components/test/data/payments/load_and_remove_iframe.html
new file mode 100644
index 0000000..102d37d
--- /dev/null
+++ b/components/test/data/payments/load_and_remove_iframe.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<!--
+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.
+-->
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1">
+<title>Remove Iframe</title>
+</head>
+<body>
+<iframe id="ifrm" allow="payment"></iframe>
+<script src="load_and_remove_iframe.js"></script>
+</body>
+</html>
diff --git a/components/test/data/payments/load_and_remove_iframe.js b/components/test/data/payments/load_and_remove_iframe.js
new file mode 100644
index 0000000..43f10830
--- /dev/null
+++ b/components/test/data/payments/load_and_remove_iframe.js
@@ -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.
+ */
+
+/**
+ * Loads the given `url` into an iframe and then removes it after the `timeout`.
+ * @param {string} url - The URL to load into the iframe.
+ * @param {int} timeout - The number of milliseconds to wait before removing the
+ * iframe.
+ * @return {Promise<string>} - The string "success".
+ */
+async function loadAndRemoveIframe(url, timeout) { // eslint-disable-line no-unused-vars, max-len
+  const frame = document.getElementById('ifrm');
+  frame.src = url;
+  return new Promise((resolve) => {
+    frame.onload = () => {
+      window.setTimeout(() => {
+        frame.parentNode.removeChild(frame);
+        resolve('success');
+      }, timeout);
+    };
+  });
+}
diff --git a/components/viz/service/surfaces/surface.cc b/components/viz/service/surfaces/surface.cc
index 49407cf..0b89979 100644
--- a/components/viz/service/surfaces/surface.cc
+++ b/components/viz/service/surfaces/surface.cc
@@ -8,6 +8,8 @@
 #include <stdint.h>
 
 #include <algorithm>
+#include <limits>
+#include <utility>
 
 #include "base/metrics/histogram_functions.h"
 #include "base/stl_util.h"
diff --git a/content/browser/DEPS b/content/browser/DEPS
index bbd8af7..afeee5b4 100644
--- a/content/browser/DEPS
+++ b/content/browser/DEPS
@@ -160,8 +160,11 @@
   # SiteInstance and BrowsingInstance should not depend on the types of things
   # that rely on them, like RenderFrameHostImpl or WebContentsImpl.
   "(site_instance_impl|browsing_instance)\.(cc|h)": [
-    "-content/browser/frame_host",
+    "-content/browser/renderer_host",
     "-content/browser/web_contents",
+    # These files do not cycle back to SiteInstance or BrowsingInstance.
+    "+content/browser/renderer_host/render_process_host_impl.h",
+    "+content/browser/renderer_host/agent_scheduling_group_host.h",
   ],
   "storage_partition_impl_unittest\.cc": [
     "+services/network/cookie_manager.h",
diff --git a/content/browser/conversions/impression_declaration_browsertest.cc b/content/browser/conversions/impression_declaration_browsertest.cc
index f7a6008..512f757 100644
--- a/content/browser/conversions/impression_declaration_browsertest.cc
+++ b/content/browser/conversions/impression_declaration_browsertest.cc
@@ -203,17 +203,10 @@
   EXPECT_EQ(1UL, impression_observer.last_impression().impression_data);
 }
 
-// Flaky on Mac: crbug.com/1099410
-#if defined(OS_MAC)
-#define MAYBE_ImpressionTagNavigatesExistingRemoteFrame_ImpressionReceived \
-  DISABLED_ImpressionTagNavigatesExistingRemoteFrame_ImpressionReceived
-#else
-#define MAYBE_ImpressionTagNavigatesExistingRemoteFrame_ImpressionReceived \
-  ImpressionTagNavigatesExistingRemoteFrame_ImpressionReceived
-#endif
+// Flaky: crbug.com/1077216
 IN_PROC_BROWSER_TEST_F(
     ImpressionDeclarationBrowserTest,
-    MAYBE_ImpressionTagNavigatesExistingRemoteFrame_ImpressionReceived) {
+    DISABLED_ImpressionTagNavigatesExistingRemoteFrame_ImpressionReceived) {
   EXPECT_TRUE(NavigateToURL(
       web_contents(),
       https_server()->GetURL("b.test", "/page_with_impression_creator.html")));
diff --git a/content/browser/dom_storage/README.md b/content/browser/dom_storage/README.md
index 803f475..d16805d8 100644
--- a/content/browser/dom_storage/README.md
+++ b/content/browser/dom_storage/README.md
@@ -18,7 +18,7 @@
 
 
 This object is primarily held by both the [`NavigationControllerImpl`](
-https://cs.chromium.org/chromium/src/content/browser/frame_host/navigation_controller_impl.h?dr=CSs&l=426)
+https://cs.chromium.org/chromium/src/content/browser/renderer_host/navigation_controller_impl.h?dr=CSs&l=426)
 and in the [`ContentPlatformSpecificTabData`](
 https://cs.chromium.org/chromium/src/components/sessions/content/content_platform_specific_tab_data.h?dr=C&l=35)
 which is used to restore tabs. The services stores recent tab
@@ -80,7 +80,7 @@
 `CreateNewWindowParams` object in [frame.mojom](https://cs.chromium.org/chromium/src/content/common/frame.mojom).
 
 If the frame wasn't created from a previous frame, the SessionStorage namespace
-object is created [here](https://cs.chromium.org/chromium/src/content/browser/frame_host/navigation_controller_impl.cc?type=cs&l=1904)
+object is created [here](https://cs.chromium.org/chromium/src/content/browser/renderer_host/navigation_controller_impl.cc?type=cs&l=1904)
 and the id is accessed [here](https://cs.chromium.org/chromium/src/content/browser/renderer_host/render_view_host_impl.cc?type=cs&l=321).
 
 ## Renderer Connection to Session Storage
diff --git a/content/browser/renderer_host/render_frame_host_manager.cc b/content/browser/renderer_host/render_frame_host_manager.cc
index b0818261..ea884b7e 100644
--- a/content/browser/renderer_host/render_frame_host_manager.cc
+++ b/content/browser/renderer_host/render_frame_host_manager.cc
@@ -2586,9 +2586,9 @@
   int previous_routing_id =
       GetReplacementRoutingId(existing_proxy, render_frame_host);
 
-  return delegate_->CreateRenderFrameForRenderManager(
-      render_frame_host, previous_routing_id, opener_frame_token,
-      parent_routing_id, previous_sibling_routing_id);
+  return render_frame_host->CreateRenderFrame(
+      previous_routing_id, opener_frame_token, parent_routing_id,
+      previous_sibling_routing_id);
 }
 
 int RenderFrameHostManager::GetReplacementRoutingId(
diff --git a/content/browser/renderer_host/render_frame_host_manager.h b/content/browser/renderer_host/render_frame_host_manager.h
index a80954b..ea7832e0b 100644
--- a/content/browser/renderer_host/render_frame_host_manager.h
+++ b/content/browser/renderer_host/render_frame_host_manager.h
@@ -128,12 +128,6 @@
         int proxy_routing_id) = 0;
     virtual void CreateRenderWidgetHostViewForRenderManager(
         RenderViewHost* render_view_host) = 0;
-    virtual bool CreateRenderFrameForRenderManager(
-        RenderFrameHost* render_frame_host,
-        int proxy_routing_id,
-        const base::Optional<base::UnguessableToken>& opener_frame_token,
-        int parent_routing_id,
-        int previous_sibling_routing_id) = 0;
     virtual void BeforeUnloadFiredFromRenderManager(
         bool proceed,
         const base::TimeTicks& proceed_time,
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index d62d4f4d..88d4426 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -7970,35 +7970,6 @@
   return true;
 }
 
-bool WebContentsImpl::CreateRenderFrameForRenderManager(
-    RenderFrameHost* render_frame_host,
-    int previous_routing_id,
-    const base::Optional<base::UnguessableToken>& opener_frame_token,
-    int parent_routing_id,
-    int previous_sibling_routing_id) {
-  TRACE_EVENT2(
-      "browser,navigation",
-      "WebContentsImpl::CreateRenderFrameForRenderManager", "render_frame_host",
-      base::trace_event::ToTracedValue(render_frame_host), "params",
-      base::trace_event::TracedValue::Build(
-          {{"previous_routing_id", previous_routing_id},
-           {"parent_routing_id", parent_routing_id},
-           {"previous_sibling_routing_id", previous_sibling_routing_id}}));
-
-  RenderFrameHostImpl* rfh =
-      static_cast<RenderFrameHostImpl*>(render_frame_host);
-  if (!rfh->CreateRenderFrame(previous_routing_id, opener_frame_token,
-                              parent_routing_id, previous_sibling_routing_id)) {
-    return false;
-  }
-
-  // TODO(nasko): When RenderWidgetHost is owned by RenderFrameHost, the passed
-  // RenderFrameHost will have to be associated with the appropriate
-  // RenderWidgetHostView or a new one should be created here.
-
-  return true;
-}
-
 #if defined(OS_ANDROID)
 
 base::android::ScopedJavaLocalRef<jobject>
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index 0af5c4e..902cfe9 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -959,12 +959,6 @@
       int proxy_routing_id) override;
   void CreateRenderWidgetHostViewForRenderManager(
       RenderViewHost* render_view_host) override;
-  bool CreateRenderFrameForRenderManager(
-      RenderFrameHost* render_frame_host,
-      int previous_routing_id,
-      const base::Optional<base::UnguessableToken>& opener_frame_token,
-      int parent_routing_id,
-      int previous_sibling_routing_id) override;
   void BeforeUnloadFiredFromRenderManager(
       bool proceed,
       const base::TimeTicks& proceed_time,
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 63ec77b..209362d 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -1432,16 +1432,6 @@
                               this, &RenderViewImpl::SendFrameStateUpdates);
 }
 
-void RenderViewImpl::SetMouseOverURL(const WebURL& url) {
-  mouse_over_url_ = GURL(url);
-  GetWebView()->UpdateTargetURL(mouse_over_url_, focus_url_);
-}
-
-void RenderViewImpl::SetKeyboardFocusURL(const WebURL& url) {
-  focus_url_ = GURL(url);
-  GetWebView()->UpdateTargetURL(focus_url_, mouse_over_url_);
-}
-
 bool RenderViewImpl::AcceptsLoadDrops() {
   return renderer_preferences_.can_accept_load_drops;
 }
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h
index eb9dc07f..71dd97fd 100644
--- a/content/renderer/render_view_impl.h
+++ b/content/renderer/render_view_impl.h
@@ -218,8 +218,6 @@
                                      base::i18n::TextDirection main_text_hint,
                                      base::string16* sub_text,
                                      base::i18n::TextDirection sub_text_hint);
-  void SetMouseOverURL(const blink::WebURL& url) override;
-  void SetKeyboardFocusURL(const blink::WebURL& url) override;
   bool AcceptsLoadDrops() override;
   void FocusNext() override;
   void FocusPrevious() override;
@@ -381,7 +379,6 @@
   void OnSetRendererPrefs(
       const blink::mojom::RendererPreferences& renderer_prefs);
   void OnSuppressDialogsUntilSwapOut();
-  void OnUpdateTargetURLAck();
   void OnUpdateWebPreferences(const WebPreferences& prefs);
 
   // Page message handlers -----------------------------------------------------
@@ -409,10 +406,6 @@
   // update to inform the browser process.
   void SendFrameStateUpdates();
 
-  // Update the target url and tell the browser that the target URL has changed.
-  // If |url| is empty, show |fallback_url|.
-  void UpdateTargetURL(const GURL& url, const GURL& fallback_url);
-
   // RenderFrameImpl accessible state ------------------------------------------
   // The following section is the set of methods that RenderFrameImpl needs
   // to access RenderViewImpl state. The set of state variables are page-level
@@ -496,14 +489,6 @@
   // process.
   int history_list_length_ = 0;
 
-  // UI state ------------------------------------------------------------------
-
-  // The URL the user's mouse is hovering over.
-  GURL mouse_over_url_;
-
-  // The URL that has keyboard focus.
-  GURL focus_url_;
-
   // View ----------------------------------------------------------------------
 
   // This class owns this member, and is responsible for calling
diff --git a/docs/accessibility/overview.md b/docs/accessibility/overview.md
index ca77b707..de6e382 100644
--- a/docs/accessibility/overview.md
+++ b/docs/accessibility/overview.md
@@ -531,7 +531,7 @@
 [Node]: https://cs.chromium.org/chromium/src/third_party/blink/renderer/core/dom/node.h
 [RenderAccessibilityImpl]: https://cs.chromium.org/chromium/src/content/renderer/accessibility/render_accessibility_impl.h
 [RenderAccessibilityManager]: https://source.chromium.org/chromium/chromium/src/+/master:content/renderer/accessibility/render_accessibility_manager.h
-[RenderFrameHostImpl]: https://cs.chromium.org/chromium/src/content/browser/frame_host/render_frame_host_impl.h
+[RenderFrameHostImpl]: https://cs.chromium.org/chromium/src/content/browser/renderer_host/render_frame_host_impl.h
 [ui::AXNodeData]: https://cs.chromium.org/chromium/src/ui/accessibility/ax_node_data.h
 [WebAXObject]: https://cs.chromium.org/chromium/src/third_party/blink/public/web/web_ax_object.h
 [automation API]: https://cs.chromium.org/chromium/src/chrome/renderer/resources/extensions/automation
diff --git a/docs/navigation-request-navigation-state.gv b/docs/navigation-request-navigation-state.gv
index 30f40975..2affcd00 100644
--- a/docs/navigation-request-navigation-state.gv
+++ b/docs/navigation-request-navigation-state.gv
@@ -1,5 +1,5 @@
 // Generated with https://crrev.com/c/2220116 and:
-//   python3 tools/state_transitions/state_graph.py content/browser/frame_host/navigation_request.cc NavigationState
+//   python3 tools/state_transitions/state_graph.py content/browser/renderer_host/navigation_request.cc NavigationState
 //
 // See tools/state_transitions/README.md
 digraph createflow {
diff --git a/docs/render-frame-host-lifecycle-state.gv b/docs/render-frame-host-lifecycle-state.gv
index fffc7b5b..37d8a951 100644
--- a/docs/render-frame-host-lifecycle-state.gv
+++ b/docs/render-frame-host-lifecycle-state.gv
@@ -1,5 +1,5 @@
 // Generated with https://crrev.com/c/2220116 and:
-//   python3 tools/state_transitions/state_graph.py content/browser/frame_host/render_frame_host_impl.cc LifecycleState
+//   python3 tools/state_transitions/state_graph.py content/browser/renderer_host/render_frame_host_impl.cc LifecycleState
 //
 // See tools/state_transitions/README.md
 digraph createflow {
diff --git a/gpu/command_buffer/service/shared_context_state.cc b/gpu/command_buffer/service/shared_context_state.cc
index bc48671..eaf0b3a 100644
--- a/gpu/command_buffer/service/shared_context_state.cc
+++ b/gpu/command_buffer/service/shared_context_state.cc
@@ -734,45 +734,40 @@
   return nullptr;
 }
 
-bool SharedContextState::CheckResetStatus(bool needs_gl) {
+base::Optional<error::ContextLostReason> SharedContextState::GetResetStatus(
+    bool needs_gl) {
   DCHECK(!context_lost());
 
-  if (device_needs_reset_)
-    return true;
-
   if (gr_context_) {
     // Maybe Skia detected VK_ERROR_DEVICE_LOST.
     if (gr_context_->abandoned()) {
       LOG(ERROR) << "SharedContextState context lost via Skia.";
-      device_needs_reset_ = true;
-      MarkContextLost(error::kUnknown);
-      return true;
+      return error::kUnknown;
     }
 
     if (gr_context_->oomed()) {
       LOG(ERROR) << "SharedContextState context lost via Skia OOM.";
-      device_needs_reset_ = true;
-      MarkContextLost(error::kOutOfMemory);
-      return true;
+      return error::kOutOfMemory;
     }
   }
 
   // Not using GL.
   if (!GrContextIsGL() && !needs_gl)
-    return false;
+    return base::nullopt;
 
   // GL is not initialized.
   if (!context_state_)
-    return false;
+    return base::nullopt;
 
-  GLenum error = context_state_->api()->glGetErrorFn();
-  if (error == GL_OUT_OF_MEMORY) {
-    LOG(ERROR) << "SharedContextState lost due to GL_OUT_OF_MEMORY";
-    MarkContextLost(error::kOutOfMemory);
-    device_needs_reset_ = true;
-    return true;
+  GLenum error;
+  while ((error = context_state_->api()->glGetErrorFn()) != GL_NO_ERROR) {
+    if (error == GL_OUT_OF_MEMORY) {
+      LOG(ERROR) << "SharedContextState lost due to GL_OUT_OF_MEMORY";
+      return error::kOutOfMemory;
+    }
+    if (error == GL_CONTEXT_LOST_KHR)
+      break;
   }
-
   // Checking the reset status is expensive on some OS/drivers
   // (https://crbug.com/1090232). Rate limit it.
   constexpr base::TimeDelta kMinCheckDelay =
@@ -780,33 +775,42 @@
   base::Time now = base::Time::Now();
   if (!disable_check_reset_status_throttling_for_test_ &&
       now < last_gl_check_graphics_reset_status_ + kMinCheckDelay) {
-    return false;
+    return base::nullopt;
   }
   last_gl_check_graphics_reset_status_ = now;
 
   GLenum driver_status = context()->CheckStickyGraphicsResetStatus();
   if (driver_status == GL_NO_ERROR)
-    return false;
+    return base::nullopt;
   LOG(ERROR) << "SharedContextState context lost via ARB/EXT_robustness. Reset "
                 "status = "
              << gles2::GLES2Util::GetStringEnum(driver_status);
 
-  device_needs_reset_ = true;
   switch (driver_status) {
     case GL_GUILTY_CONTEXT_RESET_ARB:
-      MarkContextLost(error::kGuilty);
-      break;
+      return error::kGuilty;
     case GL_INNOCENT_CONTEXT_RESET_ARB:
-      MarkContextLost(error::kInnocent);
-      break;
+      return error::kInnocent;
     case GL_UNKNOWN_CONTEXT_RESET_ARB:
-      MarkContextLost(error::kUnknown);
-      break;
+      return error::kUnknown;
     default:
       NOTREACHED();
       break;
   }
-  return true;
+  return base::nullopt;
+}
+
+bool SharedContextState::CheckResetStatus(bool need_gl) {
+  DCHECK(!context_lost());
+  DCHECK(!device_needs_reset_);
+
+  auto status = GetResetStatus(need_gl);
+  if (status.has_value()) {
+    device_needs_reset_ = true;
+    MarkContextLost(status.value());
+    return true;
+  }
+  return false;
 }
 
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/shared_context_state.h b/gpu/command_buffer/service/shared_context_state.h
index 0241632..bcba574 100644
--- a/gpu/command_buffer/service/shared_context_state.h
+++ b/gpu/command_buffer/service/shared_context_state.h
@@ -273,6 +273,8 @@
 
   ~SharedContextState() override;
 
+  base::Optional<error::ContextLostReason> GetResetStatus(bool needs_gl);
+
   // gpu::GLContextVirtualDelegate implementation.
   bool initialized() const override;
   const gles2::ContextState* GetContextState() override;
diff --git a/gpu/ipc/client/shared_image_interface_proxy.cc b/gpu/ipc/client/shared_image_interface_proxy.cc
index b7750812..061026e7 100644
--- a/gpu/ipc/client/shared_image_interface_proxy.cc
+++ b/gpu/ipc/client/shared_image_interface_proxy.cc
@@ -202,7 +202,7 @@
   }
 
   base::AutoLock lock(lock_);
-  AddMailbox(params.mailbox, usage);
+  AddMailbox(mailbox, usage);
   return mailbox;
 }
 
diff --git a/infra/config/generated/commit-queue.cfg b/infra/config/generated/commit-queue.cfg
index d663a1e6..a9e5791 100644
--- a/infra/config/generated/commit-queue.cfg
+++ b/infra/config/generated/commit-queue.cfg
@@ -78,6 +78,12 @@
         owner_whitelist_group: "project-chromium-robot-committers"
       }
       builders {
+        name: "chrome/try/linux-chrome"
+        includable_only: true
+        owner_whitelist_group: "googlers"
+        owner_whitelist_group: "project-chromium-robot-committers"
+      }
+      builders {
         name: "chrome/try/linux-chrome-beta"
         includable_only: true
         owner_whitelist_group: "googlers"
@@ -1253,7 +1259,7 @@
       }
       builders {
         name: "chromium/try/mac-coverage-rel"
-        experiment_percentage: 7
+        experiment_percentage: 10
         location_regexp: ".*"
         location_regexp_exclude: ".+/[+]/docs/.+"
         location_regexp_exclude: ".+/[+]/infra/config/.+"
diff --git a/infra/config/generated/cq-builders.md b/infra/config/generated/cq-builders.md
index 07b7f1d1..f9236d48 100644
--- a/infra/config/generated/cq-builders.md
+++ b/infra/config/generated/cq-builders.md
@@ -367,5 +367,5 @@
   * [`//services/tracing/.+`](https://cs.chromium.org/chromium/src/services/tracing/)
 
 * [mac-coverage-rel](https://ci.chromium.org/p/chromium/builders/try/mac-coverage-rel) ([definition](https://cs.chromium.org/search?q=package:%5Echromium$+file:/cq.star$+-file:/beta/+-file:/stable/+mac-coverage-rel)) ([matching builders](https://cs.chromium.org/search?q=+file:trybots.py+mac-coverage-rel))
-  * Experiment percentage: 7
+  * Experiment percentage: 10
 
diff --git a/infra/config/subprojects/chromium/try.star b/infra/config/subprojects/chromium/try.star
index f97aacd8..a79fda94 100644
--- a/infra/config/subprojects/chromium/try.star
+++ b/infra/config/subprojects/chromium/try.star
@@ -1092,7 +1092,7 @@
     builderless = False,
     use_clang_coverage = True,
     goma_jobs = goma.jobs.J150,
-    tryjob = try_.job(experiment_percentage = 7),
+    tryjob = try_.job(experiment_percentage = 10),
 )
 
 try_.chromium_mac_builder(
@@ -1577,6 +1577,10 @@
 )
 
 chrome_internal_verifier(
+    builder = "linux-chrome",
+)
+
+chrome_internal_verifier(
     builder = "linux-chrome-beta",
     branch_selector = branches.STANDARD_RELEASES,
 )
diff --git a/ios/build/bots/chromium.webrtc.fyi/WebRTC Chromium FYI ios-simulator.json b/ios/build/bots/chromium.webrtc.fyi/WebRTC Chromium FYI ios-simulator.json
index 874bc4592..987cc6e 100644
--- a/ios/build/bots/chromium.webrtc.fyi/WebRTC Chromium FYI ios-simulator.json
+++ b/ios/build/bots/chromium.webrtc.fyi/WebRTC Chromium FYI ios-simulator.json
@@ -24,21 +24,21 @@
       "include": "webrtc_tests.json",
       "device type": "iPhone 6s Plus",
       "os": "12.4",
-      "host os": "Mac-10.14.6",
+      "host os": "Mac-10.15",
       "pool": "chromium.tests"
     },
     {
       "include": "webrtc_tests.json",
       "device type": "iPhone 6s",
       "os": "12.4",
-      "host os": "Mac-10.14.6",
+      "host os": "Mac-10.15",
       "pool": "chromium.tests"
     },
     {
       "include": "webrtc_tests.json",
       "device type": "iPad Air 2",
       "os": "12.4",
-      "host os": "Mac-10.14.6",
+      "host os": "Mac-10.15",
       "pool": "chromium.tests"
     }
   ]
diff --git a/ios/chrome/app/application_delegate/app_state_unittest.mm b/ios/chrome/app/application_delegate/app_state_unittest.mm
index aa118b6..2558b6f 100644
--- a/ios/chrome/app/application_delegate/app_state_unittest.mm
+++ b/ios/chrome/app/application_delegate/app_state_unittest.mm
@@ -47,6 +47,7 @@
 #import "ios/chrome/browser/ui/util/multi_window_support.h"
 #include "ios/chrome/test/block_cleanup_test.h"
 #include "ios/chrome/test/ios_chrome_scoped_testing_chrome_browser_provider.h"
+#import "ios/chrome/test/scoped_key_window.h"
 #include "ios/public/provider/chrome/browser/distribution/app_distribution_provider.h"
 #include "ios/public/provider/chrome/browser/test_chrome_browser_provider.h"
 #include "ios/public/provider/chrome/browser/user_feedback/test_user_feedback_provider.h"
@@ -625,10 +626,11 @@
   // Swizzle Startup Parameters.
   swizzleHandleStartupParameters(tabOpener, getBrowserState());
 
-  UIWindow* window = [[UIWindow alloc] init];
-  AppState* appState = getAppStateWithOpenNTPAndIncognitoBlock(NO, window);
+  ScopedKeyWindow scopedKeyWindow;
+  AppState* appState =
+      getAppStateWithOpenNTPAndIncognitoBlock(NO, scopedKeyWindow.Get());
 
-  ASSERT_EQ(NSUInteger(1), [window subviews].count);
+  ASSERT_EQ(NSUInteger(1), [scopedKeyWindow.Get() subviews].count);
 
   // Action.
   [appState resumeSessionWithTabOpener:tabOpener
@@ -636,7 +638,7 @@
                  connectionInformation:getConnectionInformationMock()];
 
   // Test.
-  EXPECT_EQ(NSUInteger(0), [window subviews].count);
+  EXPECT_EQ(NSUInteger(0), [scopedKeyWindow.Get() subviews].count);
   EXPECT_EQ(1, getProfileSessionDurationsService()->session_started_count());
   EXPECT_EQ(0, getProfileSessionDurationsService()->session_ended_count());
 }
@@ -678,11 +680,11 @@
   id tabSwitcher = [OCMockObject mockForProtocol:@protocol(TabSwitching)];
   [[[tabSwitcher stub] andReturnValue:@YES] openNewTabFromTabSwitcher];
 
+  ScopedKeyWindow scopedKeyWindow;
+  AppState* appState =
+      getAppStateWithOpenNTPAndIncognitoBlock(YES, scopedKeyWindow.Get());
 
-  UIWindow* window = [[UIWindow alloc] init];
-  AppState* appState = getAppStateWithOpenNTPAndIncognitoBlock(YES, window);
-
-  ASSERT_EQ(NSUInteger(1), [window subviews].count);
+  ASSERT_EQ(NSUInteger(1), [scopedKeyWindow.Get() subviews].count);
 
   // Action.
   [appState resumeSessionWithTabOpener:tabOpener
@@ -690,7 +692,7 @@
                  connectionInformation:getConnectionInformationMock()];
 
   // Test.
-  EXPECT_EQ(NSUInteger(0), [window subviews].count);
+  EXPECT_EQ(NSUInteger(0), [scopedKeyWindow.Get() subviews].count);
 }
 
 // Test that -resumeSessionWithTabOpener removes incognito blocker,
@@ -743,11 +745,12 @@
   id tabSwitcher = [OCMockObject mockForProtocol:@protocol(TabSwitching)];
   [[[tabSwitcher stub] andReturnValue:@NO] openNewTabFromTabSwitcher];
 
-  UIWindow* window = [[UIWindow alloc] init];
-  AppState* appState = getAppStateWithOpenNTPAndIncognitoBlock(YES, window);
+  ScopedKeyWindow scopedKeyWindow;
+  AppState* appState =
+      getAppStateWithOpenNTPAndIncognitoBlock(YES, scopedKeyWindow.Get());
 
   // incognitoBlocker.
-  ASSERT_EQ(NSUInteger(1), [window subviews].count);
+  ASSERT_EQ(NSUInteger(1), [scopedKeyWindow.Get() subviews].count);
 
   // Action.
   [appState resumeSessionWithTabOpener:tabOpener
@@ -755,7 +758,7 @@
                  connectionInformation:getConnectionInformationMock()];
 
   // Test.
-  EXPECT_EQ(NSUInteger(0), [window subviews].count);
+  EXPECT_EQ(NSUInteger(0), [scopedKeyWindow.Get() subviews].count);
 }
 
 // Tests that -applicationWillEnterForeground resets components as needed.
@@ -887,7 +890,7 @@
 // Tests that -applicationDidEnterBackground creates an incognito blocker.
 TEST_F(AppStateTest, applicationDidEnterBackgroundIncognito) {
   // Setup.
-  UIWindow* window = [[UIWindow alloc] init];
+  ScopedKeyWindow scopedKeyWindow;
   id application = [OCMockObject niceMockForClass:[UIApplication class]];
   id memoryHelper = [OCMockObject mockForClass:[MemoryWarningHelper class]];
   StubBrowserInterfaceProvider* interfaceProvider = getInterfaceProvider();
@@ -897,7 +900,7 @@
   id browserLauncher = getBrowserLauncherMock();
   BrowserInitializationStageType stage = INITIALIZATION_STAGE_FOREGROUND;
 
-  AppState* appState = getAppStateWithRealWindow(window);
+  AppState* appState = getAppStateWithRealWindow(scopedKeyWindow.Get());
 
   [[startupInformation expect] expireFirstUserActionRecorder];
   [[[memoryHelper stub] andReturnValue:@0] foregroundMemoryWarningCount];
@@ -907,7 +910,7 @@
 
   swizzleMetricsMediatorDisableReporting();
 
-  ASSERT_EQ(NSUInteger(0), [window subviews].count);
+  ASSERT_EQ(NSUInteger(0), [scopedKeyWindow.Get() subviews].count);
 
   // Action.
   [appState applicationDidEnterBackground:application
@@ -917,14 +920,14 @@
   // Tests.
   EXPECT_OCMOCK_VERIFY(startupInformation);
   EXPECT_TRUE(metricsMediatorHasBeenCalled());
-  EXPECT_EQ(NSUInteger(1), [window subviews].count);
+  EXPECT_EQ(NSUInteger(1), [scopedKeyWindow.Get() subviews].count);
 }
 
 // Tests that -applicationDidEnterBackground do nothing if the application has
 // never been in a Foreground stage.
 TEST_F(AppStateTest, applicationDidEnterBackgroundStageBackground) {
   // Setup.
-  UIWindow* window = [[UIWindow alloc] init];
+  ScopedKeyWindow scopedKeyWindow;
   id application = [OCMockObject mockForClass:[UIApplication class]];
   id memoryHelper = [OCMockObject mockForClass:[MemoryWarningHelper class]];
   id browserLauncher = getBrowserLauncherMock();
@@ -933,22 +936,23 @@
   [[[browserLauncher stub] andReturnValue:@(stage)] browserInitializationStage];
   [[[browserLauncher stub] andReturn:nil] interfaceProvider];
 
-  ASSERT_EQ(NSUInteger(0), [window subviews].count);
+  ASSERT_EQ(NSUInteger(0), [scopedKeyWindow.Get() subviews].count);
 
   // Action.
-  [getAppStateWithRealWindow(window) applicationDidEnterBackground:application
-                                                      memoryHelper:memoryHelper
-                                           incognitoContentVisible:YES];
+  [getAppStateWithRealWindow(scopedKeyWindow.Get())
+      applicationDidEnterBackground:application
+                       memoryHelper:memoryHelper
+            incognitoContentVisible:YES];
 
   // Tests.
-  EXPECT_EQ(NSUInteger(0), [window subviews].count);
+  EXPECT_EQ(NSUInteger(0), [scopedKeyWindow.Get() subviews].count);
 }
 
 // Tests that -applicationDidEnterBackground does not create an incognito
 // blocker if there is no incognito tab.
 TEST_F(AppStateTest, applicationDidEnterBackgroundNoIncognitoBlocker) {
   // Setup.
-  UIWindow* window = [[UIWindow alloc] init];
+  ScopedKeyWindow scopedKeyWindow;
   id application = [OCMockObject niceMockForClass:[UIApplication class]];
   id memoryHelper = [OCMockObject mockForClass:[MemoryWarningHelper class]];
   StubBrowserInterfaceProvider* interfaceProvider = getInterfaceProvider();
@@ -958,7 +962,7 @@
   id browserLauncher = getBrowserLauncherMock();
   BrowserInitializationStageType stage = INITIALIZATION_STAGE_FOREGROUND;
 
-  AppState* appState = getAppStateWithRealWindow(window);
+  AppState* appState = getAppStateWithRealWindow(scopedKeyWindow.Get());
 
   [[startupInformation expect] expireFirstUserActionRecorder];
   [[[memoryHelper stub] andReturnValue:@0] foregroundMemoryWarningCount];
@@ -968,7 +972,7 @@
 
   swizzleMetricsMediatorDisableReporting();
 
-  ASSERT_EQ(NSUInteger(0), [window subviews].count);
+  ASSERT_EQ(NSUInteger(0), [scopedKeyWindow.Get() subviews].count);
 
   // Action.
   [appState applicationDidEnterBackground:application
@@ -978,5 +982,5 @@
   // Tests.
   EXPECT_OCMOCK_VERIFY(startupInformation);
   EXPECT_TRUE(metricsMediatorHasBeenCalled());
-  EXPECT_EQ(NSUInteger(0), [window subviews].count);
+  EXPECT_EQ(NSUInteger(0), [scopedKeyWindow.Get() subviews].count);
 }
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index 98f0502..f99fc03 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -982,7 +982,6 @@
 
 - (void)scheduleLowPriorityStartupTasks {
   [_startupTasks initializeOmaha];
-  [_startupTasks donateIntents];
 
   // Deferred tasks.
   [self schedulePrefObserverInitialization];
diff --git a/ios/chrome/app/resources/chrome_localize_strings_config.plist b/ios/chrome/app/resources/chrome_localize_strings_config.plist
index 7de946931..7dc24e50 100644
--- a/ios/chrome/app/resources/chrome_localize_strings_config.plist
+++ b/ios/chrome/app/resources/chrome_localize_strings_config.plist
@@ -21,6 +21,8 @@
 				<string>IDS_IOS_SAFE_MODE_CRASH_REPORT_SENT</string>
 				<string>IDS_IOS_SAFE_MODE_RELOAD_CHROME</string>
 				<string>IDS_IOS_SAFE_MODE_AW_SNAP</string>
+				<string>IDS_IOS_UI_BLOCKED_USE_OTHER_WINDOW_DESCRIPTION</string>
+				<string>IDS_IOS_UI_BLOCKED_USE_OTHER_WINDOW_SWITCH_WINDOW_ACTION</string>
 			</array>
 		</dict>
 		<dict>
@@ -64,12 +66,12 @@
 					<key>output</key>
 					<string>Z6KvRw</string>
 				</dict>
-                <dict>
-                    <key>input</key>
-                    <string>IDS_IOS_INTENTS_SEARCH_IN_CHROME_PARAMETER_COMBINATION_TITLE</string>
-                    <key>output</key>
-                    <string>TqBLdA</string>
-                </dict>
+				<dict>
+					<key>input</key>
+					<string>IDS_IOS_INTENTS_SEARCH_IN_CHROME_PARAMETER_COMBINATION_TITLE</string>
+					<key>output</key>
+					<string>TqBLdA</string>
+				</dict>
 				<dict>
 					<key>input</key>
 					<string>IDS_IOS_INTENTS_OPEN_IN_CHROME_PARAMETER_COMBINATION_TITLE</string>
diff --git a/ios/chrome/app/startup_tasks.h b/ios/chrome/app/startup_tasks.h
index a4c8307..2664398 100644
--- a/ios/chrome/app/startup_tasks.h
+++ b/ios/chrome/app/startup_tasks.h
@@ -18,8 +18,6 @@
     (ChromeBrowserState*)browserState;
 // Starts Omaha and, if first run, sets install time.  For official builds only.
 - (void)initializeOmaha;
-// Donate initial Intents.
-- (void)donateIntents;
 // Registers to receive UIApplicationWillResignActiveNotification.
 - (void)registerForApplicationWillResignActiveNotification;
 
diff --git a/ios/chrome/app/startup_tasks.mm b/ios/chrome/app/startup_tasks.mm
index 82ced71..7e030fe0 100644
--- a/ios/chrome/app/startup_tasks.mm
+++ b/ios/chrome/app/startup_tasks.mm
@@ -77,17 +77,6 @@
            object:nil];
 }
 
-- (void)donateIntents {
-  SearchInChromeIntent* searchInChromeIntent =
-      [[SearchInChromeIntent alloc] init];
-  searchInChromeIntent.suggestedInvocationPhrase = l10n_util::GetNSString(
-      IDS_IOS_INTENTS_SEARCH_IN_CHROME_INVOCATION_PHRASE);
-  INInteraction* interaction =
-      [[INInteraction alloc] initWithIntent:searchInChromeIntent response:nil];
-  [interaction donateInteractionWithCompletion:^(NSError* _Nullable error){
-  }];
-}
-
 #pragma mark - Private methods.
 
 + (void)performDeferredInitializationForBrowserState:
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index d743994..b7f1e6e 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -2615,7 +2615,7 @@
           Finish what you were doing in your other open Chrome window.
       </message>
       <message name="IDS_IOS_UI_BLOCKED_USE_OTHER_WINDOW_SWITCH_WINDOW_ACTION" desc="Button label that appears on a button to switch to some other window, when the user has multiple windows open, and one window is showing a dialog that has to be interacted with before any other window can be used.">
-          Switch to Open Window.
+          Switch to Open Window
       </message>
     </messages>
   </release>
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_UI_BLOCKED_USE_OTHER_WINDOW_SWITCH_WINDOW_ACTION.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_UI_BLOCKED_USE_OTHER_WINDOW_SWITCH_WINDOW_ACTION.png.sha1
index a0d8dad..a4195a29 100644
--- a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_UI_BLOCKED_USE_OTHER_WINDOW_SWITCH_WINDOW_ACTION.png.sha1
+++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_UI_BLOCKED_USE_OTHER_WINDOW_SWITCH_WINDOW_ACTION.png.sha1
@@ -1 +1 @@
-e448023f24ac158305420ed7805ebb815672c2f3
\ No newline at end of file
+c95d540e199725667b9c55a84e699a267bcdc70b
\ No newline at end of file
diff --git a/ios/chrome/browser/crash_report/breadcrumbs/application_breadcrumbs_logger.h b/ios/chrome/browser/crash_report/breadcrumbs/application_breadcrumbs_logger.h
index 83d05ba..b157b0c 100644
--- a/ios/chrome/browser/crash_report/breadcrumbs/application_breadcrumbs_logger.h
+++ b/ios/chrome/browser/crash_report/breadcrumbs/application_breadcrumbs_logger.h
@@ -52,10 +52,8 @@
   // Observes device orientation.
   id<NSObject> orientation_observer_;
 
-  // Used to avoid logging the same orientation twice as well as logging
-  // UIDeviceOrientationUnknown on startup (the only place where "unknown"
-  // shows up). Fewer logs leave more room for more useful logs.
-  UIDeviceOrientation last_orientation_ = UIDeviceOrientationUnknown;
+  // Used to avoid logging the same orientation twice.
+  base::Optional<UIDeviceOrientation> last_orientation_;
 };
 
 #endif  // IOS_CHROME_BROWSER_CRASH_REPORT_BREADCRUMBS_APPLICATION_BREADCRUMBS_LOGGER_H_
diff --git a/ios/chrome/browser/policy/browser_policy_connector_ios.h b/ios/chrome/browser/policy/browser_policy_connector_ios.h
index 7627d864..9879b0f0 100644
--- a/ios/chrome/browser/policy/browser_policy_connector_ios.h
+++ b/ios/chrome/browser/policy/browser_policy_connector_ios.h
@@ -58,6 +58,11 @@
   bool HasMachineLevelPolicies() override;
   void Shutdown() override;
 
+  // BrowserPolicyConnector.
+  // Always returns true because there is no way for normal users to use command
+  // line switch anyway.
+  bool IsCommandLineSwitchSupported() const override;
+
  protected:
   // BrowserPolicyConnectorBase.
   std::vector<std::unique_ptr<policy::ConfigurationPolicyProvider>>
diff --git a/ios/chrome/browser/policy/browser_policy_connector_ios.mm b/ios/chrome/browser/policy/browser_policy_connector_ios.mm
index f096557..ba1e7bd9 100644
--- a/ios/chrome/browser/policy/browser_policy_connector_ios.mm
+++ b/ios/chrome/browser/policy/browser_policy_connector_ios.mm
@@ -58,8 +58,7 @@
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
   std::unique_ptr<policy::DeviceManagementService::Configuration> configuration(
       new policy::DeviceManagementServiceConfigurationIOS(
-          BrowserPolicyConnector::GetDeviceManagementUrl(),
-          BrowserPolicyConnector::GetRealtimeReportingUrl()));
+          GetDeviceManagementUrl(), GetRealtimeReportingUrl()));
   std::unique_ptr<policy::DeviceManagementService> device_management_service(
       new policy::DeviceManagementService(std::move(configuration)));
   device_management_service->ScheduleInitialization(
@@ -86,6 +85,10 @@
   BrowserPolicyConnector::Shutdown();
 }
 
+bool BrowserPolicyConnectorIOS::IsCommandLineSwitchSupported() const {
+  return true;
+}
+
 std::vector<std::unique_ptr<policy::ConfigurationPolicyProvider>>
 BrowserPolicyConnectorIOS::CreatePolicyProviders() {
   auto providers = BrowserPolicyConnector::CreatePolicyProviders();
diff --git a/ios/chrome/browser/ui/blocking_overlay/BUILD.gn b/ios/chrome/browser/ui/blocking_overlay/BUILD.gn
index 55f71f19..ae69f97 100644
--- a/ios/chrome/browser/ui/blocking_overlay/BUILD.gn
+++ b/ios/chrome/browser/ui/blocking_overlay/BUILD.gn
@@ -15,6 +15,5 @@
     "//ios/chrome/app/strings:ios_strings",
     "//ios/chrome/common/ui/colors",
     "//ios/chrome/common/ui/util",
-    "//ui/base",
   ]
 }
diff --git a/ios/chrome/browser/ui/blocking_overlay/blocking_overlay_view_controller.mm b/ios/chrome/browser/ui/blocking_overlay/blocking_overlay_view_controller.mm
index 5f62455..f461679 100644
--- a/ios/chrome/browser/ui/blocking_overlay/blocking_overlay_view_controller.mm
+++ b/ios/chrome/browser/ui/blocking_overlay/blocking_overlay_view_controller.mm
@@ -8,7 +8,6 @@
 #import "ios/chrome/common/ui/colors/semantic_color_names.h"
 #import "ios/chrome/common/ui/util/constraints_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
-#include "ui/base/l10n/l10n_util_mac.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -22,6 +21,9 @@
 
 }  // namespace
 
+// This view controller is used in Safe Mode. This means everything used here
+// must not require any advanced initialization that only happens after safe
+// mode.
 @implementation BlockingOverlayViewController
 
 - (void)viewWillAppear:(BOOL)animated {
@@ -41,8 +43,11 @@
   AddSameConstraints(self.view, backgroundBlurEffect);
 
   UILabel* label = [[UILabel alloc] init];
-  label.text =
-      l10n_util::GetNSString(IDS_IOS_UI_BLOCKED_USE_OTHER_WINDOW_DESCRIPTION);
+  // Here and everywhere, use NSLocalizedString because the usual localization
+  // method with l10n_util::GetNSString() requires initialization that happens
+  // after safe mode completes.
+  label.text = NSLocalizedString(
+      @"IDS_IOS_UI_BLOCKED_USE_OTHER_WINDOW_DESCRIPTION", @"");
   label.textColor = [UIColor colorNamed:kGrey800Color];
   label.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
   label.textAlignment = NSTextAlignmentCenter;
@@ -56,9 +61,11 @@
 
   UIButton* button = [[UIButton alloc] init];
   button.translatesAutoresizingMaskIntoConstraints = NO;
-  [button setTitle:l10n_util::GetNSString(
-                       IDS_IOS_UI_BLOCKED_USE_OTHER_WINDOW_SWITCH_WINDOW_ACTION)
-          forState:UIControlStateNormal];
+  [button
+      setTitle:NSLocalizedString(
+                   @"IDS_IOS_UI_BLOCKED_USE_OTHER_WINDOW_SWITCH_WINDOW_ACTION",
+                   @"")
+      forState:UIControlStateNormal];
   [button setTitleColor:[UIColor colorNamed:kBlueColor]
                forState:UIControlStateNormal];
   button.titleLabel.font =
diff --git a/ios/chrome/browser/ui/elements/selector_coordinator_unittest.mm b/ios/chrome/browser/ui/elements/selector_coordinator_unittest.mm
index 429c53f3c..529d9fc 100644
--- a/ios/chrome/browser/ui/elements/selector_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/elements/selector_coordinator_unittest.mm
@@ -9,6 +9,7 @@
 #import "ios/chrome/browser/main/test_browser.h"
 #import "ios/chrome/browser/ui/elements/selector_picker_view_controller.h"
 #import "ios/chrome/browser/ui/elements/selector_view_controller_delegate.h"
+#import "ios/chrome/test/scoped_key_window.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
 #include "testing/platform_test.h"
@@ -31,8 +32,8 @@
 // that invoking stop dismisses the view and invokes the delegate.
 TEST_F(SelectorCoordinatorTest, StartAndStop) {
   base::test::TaskEnvironment task_environment_;
-
-  UIWindow* keyWindow = [[UIApplication sharedApplication] keyWindow];
+  ScopedKeyWindow scopedKeyWindow;
+  UIWindow* keyWindow = scopedKeyWindow.Get();
   UIViewController* rootViewController = keyWindow.rootViewController;
   std::unique_ptr<Browser> browser_ = std::make_unique<TestBrowser>();
   SelectorCoordinator* coordinator =
@@ -45,9 +46,10 @@
                 rootViewController.presentedViewController);
 
     [coordinator stop];
-    base::test::ios::WaitUntilCondition(^{
+    bool success = base::test::ios::WaitUntilConditionOrTimeout(1.0, ^{
       return !rootViewController.presentedViewController;
     });
+    EXPECT_TRUE(success);
   };
   // Ensure any other presented controllers are dismissed before starting the
   // coordinator.
@@ -59,7 +61,8 @@
 TEST_F(SelectorCoordinatorTest, Delegate) {
   base::test::TaskEnvironment task_environment_;
 
-  UIWindow* keyWindow = [[UIApplication sharedApplication] keyWindow];
+  ScopedKeyWindow scopedKeyWindow;
+  UIWindow* keyWindow = scopedKeyWindow.Get();
   UIViewController* rootViewController = keyWindow.rootViewController;
   std::unique_ptr<Browser> browser_ = std::make_unique<TestBrowser>();
   SelectorCoordinator* coordinator =
@@ -76,9 +79,10 @@
                   didCompleteWithSelection:testOption];
     [coordinator selectorViewController:coordinator.selectorPickerViewController
                         didSelectOption:testOption];
-    base::test::ios::WaitUntilCondition(^{
+    bool success = base::test::ios::WaitUntilConditionOrTimeout(1.0, ^{
       return !rootViewController.presentedViewController;
     });
+    EXPECT_TRUE(success);
   };
   // Ensure any other presented controllers are dismissed before starting the
   // coordinator.
diff --git a/ios/third_party/material_components_ios/BUILD.gn b/ios/third_party/material_components_ios/BUILD.gn
index b891057b..f0b6c10 100644
--- a/ios/third_party/material_components_ios/BUILD.gn
+++ b/ios/third_party/material_components_ios/BUILD.gn
@@ -372,11 +372,11 @@
   "src/components/Tabs/src/private/MDCItemBarCell+Private.h",
   "src/components/Tabs/src/private/MDCItemBarCell.h",
   "src/components/Tabs/src/private/MDCItemBarDelegate.h",
-  "src/components/Tabs/src/private/MDCItemBarStringConstants.h",
   "src/components/Tabs/src/private/MDCItemBarStyle.h",
   "src/components/Tabs/src/private/MDCTabBarIndicatorView.h",
   "src/components/Tabs/src/private/MDCTabBarPrivateIndicatorContext.h",
   "src/components/TextControls/src/BaseTextAreas/MDCBaseTextArea.h",
+  "src/components/TextControls/src/BaseTextAreas/MDCBaseTextAreaDelegate.h",
   "src/components/TextControls/src/BaseTextAreas/MaterialTextControls+BaseTextAreas.h",
   "src/components/TextControls/src/BaseTextAreas/private/MDCBaseTextAreaLayout.h",
   "src/components/TextControls/src/BaseTextAreas/private/MDCBaseTextAreaTextView.h",
@@ -1247,7 +1247,6 @@
   "src/components/Tabs/src/private/MDCItemBarCell.h",
   "src/components/Tabs/src/private/MDCItemBarCell.m",
   "src/components/Tabs/src/private/MDCItemBarDelegate.h",
-  "src/components/Tabs/src/private/MDCItemBarStringConstants.h",
   "src/components/Tabs/src/private/MDCItemBarStyle.h",
   "src/components/Tabs/src/private/MDCItemBarStyle.m",
   "src/components/Tabs/src/private/MDCTabBarIndicatorView.h",
@@ -1256,6 +1255,7 @@
   "src/components/Tabs/src/private/MDCTabBarPrivateIndicatorContext.m",
   "src/components/TextControls/src/BaseTextAreas/MDCBaseTextArea.h",
   "src/components/TextControls/src/BaseTextAreas/MDCBaseTextArea.m",
+  "src/components/TextControls/src/BaseTextAreas/MDCBaseTextAreaDelegate.h",
   "src/components/TextControls/src/BaseTextAreas/MaterialTextControls+BaseTextAreas.h",
   "src/components/TextControls/src/BaseTextAreas/private/MDCBaseTextAreaLayout.h",
   "src/components/TextControls/src/BaseTextAreas/private/MDCBaseTextAreaLayout.m",
@@ -1634,7 +1634,6 @@
   "Dialogs",
   "PageControl",
   "Snackbar",
-  "Tabs",
 ]
 
 foreach(_component, _components) {
diff --git a/ios/web_view/internal/cwv_preferences.mm b/ios/web_view/internal/cwv_preferences.mm
index 4d5117ea..bf23e96 100644
--- a/ios/web_view/internal/cwv_preferences.mm
+++ b/ios/web_view/internal/cwv_preferences.mm
@@ -72,4 +72,14 @@
       password_manager::prefs::kCredentialsEnableService);
 }
 
+- (void)setPasswordLeakCheckEnabled:(BOOL)enabled {
+  _prefService->SetBoolean(
+      password_manager::prefs::kPasswordLeakDetectionEnabled, enabled);
+}
+
+- (BOOL)isPasswordLeakCheckEnabled {
+  return _prefService->GetBoolean(
+      password_manager::prefs::kPasswordLeakDetectionEnabled);
+}
+
 @end
diff --git a/ios/web_view/internal/cwv_preferences_unittest.mm b/ios/web_view/internal/cwv_preferences_unittest.mm
index 973d4ca..efa87cf 100644
--- a/ios/web_view/internal/cwv_preferences_unittest.mm
+++ b/ios/web_view/internal/cwv_preferences_unittest.mm
@@ -37,6 +37,8 @@
     pref_registry->RegisterBooleanPref(
         password_manager::prefs::kCredentialsEnableService, true);
     pref_registry->RegisterBooleanPref(prefs::kOfferTranslateEnabled, true);
+    pref_registry->RegisterBooleanPref(
+        password_manager::prefs::kPasswordLeakDetectionEnabled, true);
 
     scoped_refptr<PersistentPrefStore> pref_store = new InMemoryPrefStore();
     PrefServiceFactory factory;
@@ -72,4 +74,18 @@
   EXPECT_FALSE(preferences_.translationEnabled);
 }
 
+// Tests CWVPreferences |passwordAutofillEnabled|.
+TEST_F(CWVPreferencesTest, PasswordAutofillEnabled) {
+  EXPECT_TRUE(preferences_.passwordAutofillEnabled);
+  preferences_.passwordAutofillEnabled = NO;
+  EXPECT_FALSE(preferences_.passwordAutofillEnabled);
+}
+
+// Tests CWVPreferences |passwordLeakCheckEnabled|.
+TEST_F(CWVPreferencesTest, PasswordLeakCheckEnabled) {
+  EXPECT_TRUE(preferences_.passwordLeakCheckEnabled);
+  preferences_.passwordLeakCheckEnabled = NO;
+  EXPECT_FALSE(preferences_.passwordLeakCheckEnabled);
+}
+
 }  // namespace ios_web_view
diff --git a/ios/web_view/public/cwv_preferences.h b/ios/web_view/public/cwv_preferences.h
index 7e4529d..90bd23d 100644
--- a/ios/web_view/public/cwv_preferences.h
+++ b/ios/web_view/public/cwv_preferences.h
@@ -43,6 +43,11 @@
 @property(nonatomic, assign, getter=isPasswordAutofillEnabled)
     BOOL passwordAutofillEnabled;
 
+// Whether or not password leak checks will be performed after successful form
+// submission. Defaults to |YES|.
+@property(nonatomic, assign, getter=isPasswordLeakCheckEnabled)
+    BOOL passwordLeakCheckEnabled;
+
 - (instancetype)init NS_UNAVAILABLE;
 
 // Resets all translation settings back to default. In particular, this will
diff --git a/media/gpu/v4l2/v4l2_video_decoder.cc b/media/gpu/v4l2/v4l2_video_decoder.cc
index cc8d25e..9b8847a 100644
--- a/media/gpu/v4l2/v4l2_video_decoder.cc
+++ b/media/gpu/v4l2/v4l2_video_decoder.cc
@@ -569,6 +569,8 @@
             << ", Number of queued output buffers: "
             << output_queue_->QueuedBuffersCount();
 
+  backend_->OnServiceDeviceTask(event);
+
   // Dequeue V4L2 output buffer first to reduce output latency.
   bool success;
   while (output_queue_->QueuedBuffersCount() > 0) {
@@ -597,8 +599,6 @@
     if (!dequeued_buffer)
       break;
   }
-
-  backend_->OnServiceDeviceTask(event);
 }
 
 void V4L2VideoDecoder::OutputFrame(scoped_refptr<VideoFrame> frame,
diff --git a/media/gpu/v4l2/v4l2_video_decoder_backend_stateful.cc b/media/gpu/v4l2/v4l2_video_decoder_backend_stateful.cc
index 417598f8..e25779ff 100644
--- a/media/gpu/v4l2/v4l2_video_decoder_backend_stateful.cc
+++ b/media/gpu/v4l2/v4l2_video_decoder_backend_stateful.cc
@@ -230,18 +230,21 @@
                                 weak_this_));
 }
 
+void V4L2StatefulVideoDecoderBackend::ProcessEventQueue() {
+  while (base::Optional<struct v4l2_event> ev = device_->DequeueEvent()) {
+    if (ev->type == V4L2_EVENT_SOURCE_CHANGE &&
+        (ev->u.src_change.changes & V4L2_EVENT_SRC_CH_RESOLUTION)) {
+      ChangeResolution();
+    }
+  }
+}
+
 void V4L2StatefulVideoDecoderBackend::OnServiceDeviceTask(bool event) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DVLOGF(3);
 
-  if (event) {
-    while (base::Optional<struct v4l2_event> ev = device_->DequeueEvent()) {
-      if (ev->type == V4L2_EVENT_SOURCE_CHANGE &&
-          (ev->u.src_change.changes & V4L2_EVENT_SRC_CH_RESOLUTION)) {
-        ChangeResolution();
-      }
-    }
-  }
+  if (event)
+    ProcessEventQueue();
 
   // We can enqueue dequeued output buffers immediately.
   EnqueueOutputBuffers();
@@ -384,11 +387,16 @@
   // The order here is important! A flush event may come after a resolution
   // change event (but not the opposite), so we must make sure both events
   // are processed in the correct order.
-  if (buffer->IsLast() && resolution_change_cb_) {
-    std::move(resolution_change_cb_).Run();
-  } else if (buffer->IsLast() && flush_cb_) {
-    // We were waiting for a flush to complete, and received the last buffer.
-    CompleteFlush();
+  if (buffer->IsLast()){
+    if (!resolution_change_cb_ && !flush_cb_)
+      ProcessEventQueue();
+
+    if (resolution_change_cb_) {
+      std::move(resolution_change_cb_).Run();
+    } else if (flush_cb_) {
+      // We were waiting for a flush to complete, and received the last buffer.
+      CompleteFlush();
+    }
   }
 
   EnqueueOutputBuffers();
diff --git a/media/gpu/v4l2/v4l2_video_decoder_backend_stateful.h b/media/gpu/v4l2/v4l2_video_decoder_backend_stateful.h
index 62d6d71..3b41c34 100644
--- a/media/gpu/v4l2/v4l2_video_decoder_backend_stateful.h
+++ b/media/gpu/v4l2/v4l2_video_decoder_backend_stateful.h
@@ -112,6 +112,9 @@
 
   void ScheduleDecodeWork();
 
+  // Process all the event in the event queue
+  void ProcessEventQueue();
+
   // Video profile we are decoding.
   VideoCodecProfile profile_;
 
diff --git a/media/gpu/vaapi/vp9_vaapi_video_decoder_delegate.cc b/media/gpu/vaapi/vp9_vaapi_video_decoder_delegate.cc
index edb382eb..0c5837cb 100644
--- a/media/gpu/vaapi/vp9_vaapi_video_decoder_delegate.cc
+++ b/media/gpu/vaapi/vp9_vaapi_video_decoder_delegate.cc
@@ -139,10 +139,8 @@
   }
 
   if (!vaapi_wrapper_->SubmitBuffers(
-          {{VAPictureParameterBufferType,
-            sizeof(VADecPictureParameterBufferVP9), &pic_param},
-           {VASliceParameterBufferType, sizeof(VASliceParameterBufferVP9),
-            &slice_param},
+          {{VAPictureParameterBufferType, sizeof(pic_param), &pic_param},
+           {VASliceParameterBufferType, sizeof(slice_param), &slice_param},
            {VASliceDataBufferType, frame_hdr->frame_size, frame_hdr->data}})) {
     return false;
   }
diff --git a/pdf/out_of_process_instance.cc b/pdf/out_of_process_instance.cc
index f37df981..bd0a5e0 100644
--- a/pdf/out_of_process_instance.cc
+++ b/pdf/out_of_process_instance.cc
@@ -18,7 +18,6 @@
 #include "base/callback.h"
 #include "base/feature_list.h"
 #include "base/logging.h"
-#include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/notreached.h"
@@ -1078,9 +1077,10 @@
   }
 }
 
-void OutOfProcessInstance::DidOpen(int32_t result) {
+void OutOfProcessInstance::DidOpen(std::unique_ptr<UrlLoader> loader,
+                                   int32_t result) {
   if (result == PP_OK) {
-    if (!engine()->HandleDocumentLoad(embed_loader_)) {
+    if (!engine()->HandleDocumentLoad(std::move(loader))) {
       document_load_state_ = LOAD_STATE_LOADING;
       DocumentLoadFailed();
     }
@@ -1089,13 +1089,14 @@
   }
 }
 
-void OutOfProcessInstance::DidOpenPreview(int32_t result) {
+void OutOfProcessInstance::DidOpenPreview(std::unique_ptr<UrlLoader> loader,
+                                          int32_t result) {
   if (result == PP_OK) {
     preview_client_ = std::make_unique<PreviewModeClient>(this);
     preview_engine_ =
         std::make_unique<PDFiumEngine>(preview_client_.get(),
                                        /*enable_javascript=*/false);
-    preview_engine_->HandleDocumentLoad(embed_preview_loader_);
+    preview_engine_->HandleDocumentLoad(std::move(loader));
   } else {
     NOTREACHED();
   }
@@ -1472,13 +1473,11 @@
 }
 
 void OutOfProcessInstance::FormDidOpen(int32_t result) {
-  // TODO: inform the user of success/failure.
-  if (result != PP_OK) {
-    LOG(ERROR) << "FormDidOpen failed: " << result;
-  }
+  // TODO(crbug.com/719344): Process response.
+  LOG_IF(ERROR, result != PP_OK) << "FormDidOpen failed: " << result;
 }
 
-scoped_refptr<UrlLoader> OutOfProcessInstance::CreateUrlLoader() {
+std::unique_ptr<UrlLoader> OutOfProcessInstance::CreateUrlLoader() {
   if (full_) {
     if (!did_call_start_loading_) {
       did_call_start_loading_ = true;
@@ -2092,18 +2091,17 @@
   request.method = "GET";
   request.ignore_redirects = true;
 
-  scoped_refptr<UrlLoader>& loader =
-      is_print_preview ? embed_preview_loader_ : embed_loader_;
-  loader = CreateUrlLoaderInternal();
-  loader->Open(
+  std::unique_ptr<UrlLoader> loader = CreateUrlLoaderInternal();
+  UrlLoader* raw_loader = loader.get();
+  raw_loader->Open(
       request,
       base::BindOnce(is_print_preview ? &OutOfProcessInstance::DidOpenPreview
                                       : &OutOfProcessInstance::DidOpen,
-                     weak_factory_.GetWeakPtr()));
+                     weak_factory_.GetWeakPtr(), std::move(loader)));
 }
 
-scoped_refptr<UrlLoader> OutOfProcessInstance::CreateUrlLoaderInternal() {
-  auto loader = base::MakeRefCounted<PepperUrlLoader>(this);
+std::unique_ptr<UrlLoader> OutOfProcessInstance::CreateUrlLoaderInternal() {
+  auto loader = std::make_unique<PepperUrlLoader>(this);
   loader->GrantUniversalAccess();
   return loader;
 }
diff --git a/pdf/out_of_process_instance.h b/pdf/out_of_process_instance.h
index ccf5892..48db493f 100644
--- a/pdf/out_of_process_instance.h
+++ b/pdf/out_of_process_instance.h
@@ -16,7 +16,6 @@
 
 #include "base/callback.h"
 #include "base/containers/queue.h"
-#include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
 #include "pdf/paint_manager.h"
 #include "pdf/pdf_view_plugin_base.h"
@@ -106,8 +105,8 @@
                         const PP_PdfPrintSettings_Dev* pdf_print_settings);
 
   void FlushCallback(int32_t result);
-  void DidOpen(int32_t result);
-  void DidOpenPreview(int32_t result);
+  void DidOpen(std::unique_ptr<UrlLoader> loader, int32_t result);
+  void DidOpenPreview(std::unique_ptr<UrlLoader> loader, int32_t result);
 
   // PdfViewPluginBase implementation.
   void ProposeDocumentLayout(const DocumentLayout& layout) override;
@@ -145,7 +144,7 @@
   void SubmitForm(const std::string& url,
                   const void* data,
                   int length) override;
-  scoped_refptr<UrlLoader> CreateUrlLoader() override;
+  std::unique_ptr<UrlLoader> CreateUrlLoader() override;
   std::vector<SearchStringResult> SearchString(const base::char16* string,
                                                const base::char16* term,
                                                bool case_sensitive) override;
@@ -224,7 +223,7 @@
 
   // Creates a URL loader and allows it to access all urls, i.e. not just the
   // frame's origin.
-  scoped_refptr<UrlLoader> CreateUrlLoaderInternal();
+  std::unique_ptr<UrlLoader> CreateUrlLoaderInternal();
 
   bool CanSaveEdits() const;
   void SaveToFile(const std::string& token);
@@ -338,11 +337,6 @@
   pp::ImageData image_data_;
   SkBitmap skia_image_data_;  // Must be kept in sync with |image_data_|.
 
-  // Used when the plugin is embedded in a page and we have to create the loader
-  // ourself.
-  scoped_refptr<UrlLoader> embed_loader_;
-  scoped_refptr<UrlLoader> embed_preview_loader_;
-
   // The current cursor.
   PP_CursorType_Dev cursor_ = PP_CURSORTYPE_POINTER;
 
@@ -435,7 +429,7 @@
   std::string url_;
 
   // Used for submitting forms.
-  scoped_refptr<UrlLoader> form_loader_;
+  std::unique_ptr<UrlLoader> form_loader_;
 
   // The callback for receiving the password from the page.
   base::OnceCallback<void(const std::string&)> password_callback_;
diff --git a/pdf/pdf_engine.h b/pdf/pdf_engine.h
index 9d10140..187892f 100644
--- a/pdf/pdf_engine.h
+++ b/pdf/pdf_engine.h
@@ -7,12 +7,12 @@
 
 #include <stdint.h>
 
+#include <memory>
 #include <string>
 #include <vector>
 
 #include "base/callback.h"
 #include "base/containers/span.h"
-#include "base/memory/scoped_refptr.h"
 #include "base/optional.h"
 #include "base/strings/string16.h"
 #include "base/time/time.h"
@@ -221,7 +221,7 @@
                             int length) {}
 
     // Creates and returns new URL loader for partial document requests.
-    virtual scoped_refptr<UrlLoader> CreateUrlLoader() = 0;
+    virtual std::unique_ptr<UrlLoader> CreateUrlLoader() = 0;
 
     // Searches the given string for "term" and returns the results.  Unicode-
     // aware.
@@ -337,7 +337,7 @@
                      std::vector<gfx::Rect>& ready,
                      std::vector<gfx::Rect>& pending) = 0;
   virtual void PostPaint() = 0;
-  virtual bool HandleDocumentLoad(scoped_refptr<UrlLoader> loader) = 0;
+  virtual bool HandleDocumentLoad(std::unique_ptr<UrlLoader> loader) = 0;
   virtual bool HandleEvent(const InputEvent& event) = 0;
   virtual uint32_t QuerySupportedPrintOutputFormats() = 0;
   virtual void PrintBegin() = 0;
diff --git a/pdf/pdf_view_web_plugin.cc b/pdf/pdf_view_web_plugin.cc
index 1882a05..bbefe9b 100644
--- a/pdf/pdf_view_web_plugin.cc
+++ b/pdf/pdf_view_web_plugin.cc
@@ -10,7 +10,6 @@
 #include <vector>
 
 #include "base/check_op.h"
-#include "base/memory/scoped_refptr.h"
 #include "base/thread_annotations.h"
 #include "base/threading/thread_checker.h"
 #include "cc/paint/paint_canvas.h"
@@ -207,7 +206,7 @@
                                   const void* data,
                                   int length) {}
 
-scoped_refptr<UrlLoader> PdfViewWebPlugin::CreateUrlLoader() {
+std::unique_ptr<UrlLoader> PdfViewWebPlugin::CreateUrlLoader() {
   return nullptr;
 }
 
diff --git a/pdf/pdf_view_web_plugin.h b/pdf/pdf_view_web_plugin.h
index c0e913a..a6c10d2 100644
--- a/pdf/pdf_view_web_plugin.h
+++ b/pdf/pdf_view_web_plugin.h
@@ -79,7 +79,7 @@
   void SubmitForm(const std::string& url,
                   const void* data,
                   int length) override;
-  scoped_refptr<UrlLoader> CreateUrlLoader() override;
+  std::unique_ptr<UrlLoader> CreateUrlLoader() override;
   std::vector<SearchStringResult> SearchString(const base::char16* string,
                                                const base::char16* term,
                                                bool case_sensitive) override;
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc
index 8f865b07..51897a5 100644
--- a/pdf/pdfium/pdfium_engine.cc
+++ b/pdf/pdfium/pdfium_engine.cc
@@ -20,7 +20,6 @@
 #include "base/check_op.h"
 #include "base/debug/alias.h"
 #include "base/feature_list.h"
-#include "base/memory/scoped_refptr.h"
 #include "base/notreached.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
@@ -632,7 +631,7 @@
   }
 }
 
-bool PDFiumEngine::HandleDocumentLoad(scoped_refptr<UrlLoader> loader) {
+bool PDFiumEngine::HandleDocumentLoad(std::unique_ptr<UrlLoader> loader) {
   password_tries_remaining_ = kMaxPasswordTries;
   process_when_pending_request_complete_ =
       base::FeatureList::IsEnabled(features::kPdfIncrementalLoading);
diff --git a/pdf/pdfium/pdfium_engine.h b/pdf/pdfium/pdfium_engine.h
index 6e1be60..fbed9e0 100644
--- a/pdf/pdfium/pdfium_engine.h
+++ b/pdf/pdfium/pdfium_engine.h
@@ -93,7 +93,7 @@
              std::vector<gfx::Rect>& ready,
              std::vector<gfx::Rect>& pending) override;
   void PostPaint() override;
-  bool HandleDocumentLoad(scoped_refptr<UrlLoader> loader) override;
+  bool HandleDocumentLoad(std::unique_ptr<UrlLoader> loader) override;
   bool HandleEvent(const InputEvent& event) override;
   uint32_t QuerySupportedPrintOutputFormats() override;
   void PrintBegin() override;
diff --git a/pdf/ppapi_migration/url_loader.h b/pdf/ppapi_migration/url_loader.h
index 4c314dc..60db83f 100644
--- a/pdf/ppapi_migration/url_loader.h
+++ b/pdf/ppapi_migration/url_loader.h
@@ -11,7 +11,6 @@
 #include <string>
 
 #include "base/containers/span.h"
-#include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
 #include "pdf/ppapi_migration/callback.h"
@@ -72,10 +71,11 @@
 };
 
 // Abstraction for a Blink or Pepper URL loader.
-class UrlLoader : public base::RefCounted<UrlLoader> {
+class UrlLoader {
  public:
   UrlLoader(const UrlLoader&) = delete;
   UrlLoader& operator=(const UrlLoader&) = delete;
+  virtual ~UrlLoader();
 
   // Tries to grant the loader the capability to make unrestricted cross-origin
   // requests ("universal access," in `blink::SecurityOrigin` terms). Must be
@@ -97,13 +97,10 @@
 
  protected:
   UrlLoader();
-  virtual ~UrlLoader();
 
   UrlResponse& mutable_response() { return response_; }
 
  private:
-  friend class base::RefCounted<UrlLoader>;
-
   UrlResponse response_;
 };
 
@@ -130,6 +127,7 @@
   explicit BlinkUrlLoader(base::WeakPtr<Client> client);
   BlinkUrlLoader(const BlinkUrlLoader&) = delete;
   BlinkUrlLoader& operator=(const BlinkUrlLoader&) = delete;
+  ~BlinkUrlLoader() override;
 
   // UrlLoader:
   void GrantUniversalAccess() override;
@@ -154,9 +152,6 @@
   void DidFail(const blink::WebURLError& error) override;
 
  private:
-  // Private because the class is RefCounted.
-  ~BlinkUrlLoader() override;
-
   base::WeakPtr<Client> client_;
   bool grant_universal_access_ = false;
 
@@ -169,6 +164,7 @@
   explicit PepperUrlLoader(pp::InstanceHandle plugin_instance);
   PepperUrlLoader(const PepperUrlLoader&) = delete;
   PepperUrlLoader& operator=(const PepperUrlLoader&) = delete;
+  ~PepperUrlLoader() override;
 
   // UrlLoader:
   void GrantUniversalAccess() override;
@@ -180,9 +176,6 @@
   void Close() override;
 
  private:
-  // Private because the class is RefCounted.
-  ~PepperUrlLoader() override;
-
   void DidOpen(ResultCallback callback, int32_t result);
 
   pp::InstanceHandle plugin_instance_;
diff --git a/pdf/ppapi_migration/url_loader_unittest.cc b/pdf/ppapi_migration/url_loader_unittest.cc
index 5916dbe5..e55deea 100644
--- a/pdf/ppapi_migration/url_loader_unittest.cc
+++ b/pdf/ppapi_migration/url_loader_unittest.cc
@@ -9,7 +9,6 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
-#include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/single_thread_task_runner.h"
 #include "base/test/mock_callback.h"
@@ -70,7 +69,7 @@
     ON_CALL(mock_client_, CreateAssociatedURLLoader(_))
         .WillByDefault(
             Invoke(this, &BlinkUrlLoaderTest::FakeCreateAssociatedURLLoader));
-    loader_ = base::MakeRefCounted<BlinkUrlLoader>(mock_client_.GetWeakPtr());
+    loader_ = std::make_unique<BlinkUrlLoader>(mock_client_.GetWeakPtr());
   }
 
   std::unique_ptr<blink::WebAssociatedURLLoader> FakeCreateAssociatedURLLoader(
@@ -82,7 +81,7 @@
 
   NiceMock<MockBlinkUrlLoaderClient> mock_client_;
   base::MockCallback<ResultCallback> mock_callback_;
-  scoped_refptr<BlinkUrlLoader> loader_;
+  std::unique_ptr<BlinkUrlLoader> loader_;
 
   std::unique_ptr<MockWebAssociatedURLLoader> mock_url_loader_ =
       std::make_unique<MockWebAssociatedURLLoader>();
diff --git a/pdf/preview_mode_client.cc b/pdf/preview_mode_client.cc
index 756a620..b4511fe8 100644
--- a/pdf/preview_mode_client.cc
+++ b/pdf/preview_mode_client.cc
@@ -6,11 +6,11 @@
 
 #include <stdint.h>
 
+#include <memory>
 #include <string>
 #include <utility>
 
 #include "base/callback.h"
-#include "base/memory/scoped_refptr.h"
 #include "base/notreached.h"
 #include "pdf/document_layout.h"
 #include "pdf/ppapi_migration/url_loader.h"
@@ -116,7 +116,7 @@
   NOTREACHED();
 }
 
-scoped_refptr<UrlLoader> PreviewModeClient::CreateUrlLoader() {
+std::unique_ptr<UrlLoader> PreviewModeClient::CreateUrlLoader() {
   NOTREACHED();
   return nullptr;
 }
diff --git a/pdf/preview_mode_client.h b/pdf/preview_mode_client.h
index f818a42..4b9c2e6 100644
--- a/pdf/preview_mode_client.h
+++ b/pdf/preview_mode_client.h
@@ -62,7 +62,7 @@
   void SubmitForm(const std::string& url,
                   const void* data,
                   int length) override;
-  scoped_refptr<UrlLoader> CreateUrlLoader() override;
+  std::unique_ptr<UrlLoader> CreateUrlLoader() override;
   std::vector<SearchStringResult> SearchString(const base::char16* string,
                                                const base::char16* term,
                                                bool case_sensitive) override;
diff --git a/pdf/test/test_client.cc b/pdf/test/test_client.cc
index bdc0ab89..70aa727ef8 100644
--- a/pdf/test/test_client.cc
+++ b/pdf/test/test_client.cc
@@ -4,7 +4,8 @@
 
 #include "pdf/test/test_client.h"
 
-#include "base/memory/scoped_refptr.h"
+#include <memory>
+
 #include "pdf/document_layout.h"
 #include "pdf/ppapi_migration/url_loader.h"
 
@@ -35,7 +36,7 @@
   return std::string();
 }
 
-scoped_refptr<UrlLoader> TestClient::CreateUrlLoader() {
+std::unique_ptr<UrlLoader> TestClient::CreateUrlLoader() {
   return nullptr;
 }
 
diff --git a/pdf/test/test_client.h b/pdf/test/test_client.h
index 48429bc..521bb04 100644
--- a/pdf/test/test_client.h
+++ b/pdf/test/test_client.h
@@ -30,7 +30,7 @@
   std::string Prompt(const std::string& question,
                      const std::string& default_answer) override;
   std::string GetURL() override;
-  scoped_refptr<UrlLoader> CreateUrlLoader() override;
+  std::unique_ptr<UrlLoader> CreateUrlLoader() override;
   std::vector<SearchStringResult> SearchString(const base::char16* string,
                                                const base::char16* term,
                                                bool case_sensitive) override;
diff --git a/pdf/url_loader_wrapper_impl.cc b/pdf/url_loader_wrapper_impl.cc
index afc6920..7266ef72 100644
--- a/pdf/url_loader_wrapper_impl.cc
+++ b/pdf/url_loader_wrapper_impl.cc
@@ -9,6 +9,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <memory>
 #include <string>
 #include <utility>
 
@@ -100,7 +101,8 @@
 
 }  // namespace
 
-URLLoaderWrapperImpl::URLLoaderWrapperImpl(scoped_refptr<UrlLoader> url_loader)
+URLLoaderWrapperImpl::URLLoaderWrapperImpl(
+    std::unique_ptr<UrlLoader> url_loader)
     : url_loader_(std::move(url_loader)) {
   SetHeadersFromLoader();
 }
diff --git a/pdf/url_loader_wrapper_impl.h b/pdf/url_loader_wrapper_impl.h
index c6a1ac5f..deb4b13 100644
--- a/pdf/url_loader_wrapper_impl.h
+++ b/pdf/url_loader_wrapper_impl.h
@@ -10,7 +10,6 @@
 #include <memory>
 #include <string>
 
-#include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/timer/timer.h"
 #include "pdf/ppapi_migration/callback.h"
@@ -23,7 +22,7 @@
 
 class URLLoaderWrapperImpl : public URLLoaderWrapper {
  public:
-  explicit URLLoaderWrapperImpl(scoped_refptr<UrlLoader> url_loader);
+  explicit URLLoaderWrapperImpl(std::unique_ptr<UrlLoader> url_loader);
   URLLoaderWrapperImpl(const URLLoaderWrapperImpl&) = delete;
   URLLoaderWrapperImpl& operator=(const URLLoaderWrapperImpl&) = delete;
   ~URLLoaderWrapperImpl() override;
@@ -59,7 +58,7 @@
 
   void ReadResponseBodyImpl(ResultCallback callback);
 
-  scoped_refptr<UrlLoader> url_loader_;
+  std::unique_ptr<UrlLoader> url_loader_;
   std::string response_headers_;
 
   int content_length_ = -1;
diff --git a/services/device/BUILD.gn b/services/device/BUILD.gn
index dc1fe3e..7cf18e9 100644
--- a/services/device/BUILD.gn
+++ b/services/device/BUILD.gn
@@ -234,16 +234,19 @@
       "//services/device/vibration",
     ]
 
-    if (!is_linux_without_udev && !is_android) {
+    if (!is_linux_without_udev) {
       sources += [
         "hid/hid_connection_impl_unittest.cc",
-        "hid/hid_service_unittest.cc",
         "hid/input_service_linux_unittest.cc",
         "hid/test_report_descriptors.cc",
         "hid/test_report_descriptors.h",
         "public/cpp/hid/hid_device_filter_unittest.cc",
         "public/cpp/hid/hid_report_descriptor_unittest.cc",
       ]
+      if (!is_fuchsia) {
+        # Fuchsia does not currently implement HidService.
+        sources += [ "hid/hid_service_unittest.cc" ]
+      }
       if (!is_ios) {
         sources += [ "hid/hid_connection_unittest.cc" ]
         deps += [
diff --git a/services/device/nfc/android/java/src/org/chromium/device/nfc/NfcImpl.java b/services/device/nfc/android/java/src/org/chromium/device/nfc/NfcImpl.java
index 1fc5cd3..8e3fe97 100644
--- a/services/device/nfc/android/java/src/org/chromium/device/nfc/NfcImpl.java
+++ b/services/device/nfc/android/java/src/org/chromium/device/nfc/NfcImpl.java
@@ -533,11 +533,6 @@
     private void processPendingWatchOperations() {
         if (mTagHandler == null || mClient == null || mWatchers.size() == 0) return;
 
-        // Skip reading if there is a pending push operation and ignoreRead flag is set.
-        if (mPendingPushOperation != null && mPendingPushOperation.ndefWriteOptions.ignoreRead) {
-            return;
-        }
-
         if (mTagHandler.isTagOutOfRange()) {
             mTagHandler = null;
             return;
diff --git a/services/device/nfc/android/junit/src/org/chromium/device/nfc/NFCTest.java b/services/device/nfc/android/junit/src/org/chromium/device/nfc/NFCTest.java
index b2f4a4b..2e8b0f3 100644
--- a/services/device/nfc/android/junit/src/org/chromium/device/nfc/NFCTest.java
+++ b/services/device/nfc/android/junit/src/org/chromium/device/nfc/NFCTest.java
@@ -1736,7 +1736,6 @@
      */
     private NdefWriteOptions createNdefWriteOptions() {
         NdefWriteOptions pushOptions = new NdefWriteOptions();
-        pushOptions.ignoreRead = false;
         pushOptions.overwrite = true;
         return pushOptions;
     }
diff --git a/services/device/public/mojom/nfc.mojom b/services/device/public/mojom/nfc.mojom
index f45e07c7..c45dc3ef 100644
--- a/services/device/public/mojom/nfc.mojom
+++ b/services/device/public/mojom/nfc.mojom
@@ -97,14 +97,9 @@
 };
 
 struct NDEFWriteOptions {
-  // Only the case of |ignore_read| being |true| matters: while this push
-  // operation is pending, even a NFC tag comes in proximity range, do not read
-  // it for all active watchers.
-  bool ignore_read;
-
   // Only the case of |overwrite| being |false| matters: the push operation will
-  // read the NFC tag regardless of |ignore_read| to determine if it has NDEF
-  // records on it, and if yes, do not execute write.
+  // read the NFC tag to determine if it has NDEF records on it, and if yes, do
+  // not execute write.
   bool overwrite;
 };
 
diff --git a/services/network/public/cpp/content_security_policy/csp_context.h b/services/network/public/cpp/content_security_policy/csp_context.h
index 971752c..968b39da 100644
--- a/services/network/public/cpp/content_security_policy/csp_context.h
+++ b/services/network/public/cpp/content_security_policy/csp_context.h
@@ -18,7 +18,7 @@
 // A CSPContext represents the Document where the Content-Security-Policy are
 // checked. One must define via its virtual methods how to report violations
 // and what is the set of scheme that bypass the CSP. Its main implementation
-// is in content/browser/frame_host/render_frame_host_impl.h
+// is in content/browser/renderer_host/render_frame_host_impl.h
 class COMPONENT_EXPORT(NETWORK_CPP) CSPContext {
  public:
   // This enum represents what set of policies should be checked by
diff --git a/services/network/public/cpp/features.cc b/services/network/public/cpp/features.cc
index d09afe0..f5cab38 100644
--- a/services/network/public/cpp/features.cc
+++ b/services/network/public/cpp/features.cc
@@ -251,5 +251,9 @@
 constexpr base::FeatureParam<double> kSCTAuditingSamplingRate{
     &kSCTAuditing, "sampling_rate", 0.0};
 
+// Enables usage of First Party Sets to determine cookie availability.
+constexpr base::Feature kFirstPartySets{"FirstPartySets",
+                                        base::FEATURE_DISABLED_BY_DEFAULT};
+
 }  // namespace features
 }  // namespace network
diff --git a/services/network/public/cpp/features.h b/services/network/public/cpp/features.h
index 0cc0959..bf27faf 100644
--- a/services/network/public/cpp/features.h
+++ b/services/network/public/cpp/features.h
@@ -102,6 +102,9 @@
 COMPONENT_EXPORT(NETWORK_CPP)
 extern const base::FeatureParam<double> kSCTAuditingSamplingRate;
 
+COMPONENT_EXPORT(NETWORK_CPP)
+extern const base::Feature kFirstPartySets;
+
 }  // namespace features
 }  // namespace network
 
diff --git a/services/network/public/mojom/web_sandbox_flags.mojom b/services/network/public/mojom/web_sandbox_flags.mojom
index 04d3d5b..f4927ca7 100644
--- a/services/network/public/mojom/web_sandbox_flags.mojom
+++ b/services/network/public/mojom/web_sandbox_flags.mojom
@@ -6,7 +6,7 @@
 // Enum types for the sandbox attributes of the main resource.
 // TODO(https://crbug.com/1041376): Parse the flags in the network service.
 //
-// See content/browser/frame_host/sandbox_flags.md for more details about how
+// See content/browser/renderer_host/sandbox_flags.md for more details about how
 // the web-layer components (i.e. //content and Blink) consume and apply these
 // flags.
 
diff --git a/testing/buildbot/chromium.perf.fyi.json b/testing/buildbot/chromium.perf.fyi.json
index 6d321246..e8e49a2 100644
--- a/testing/buildbot/chromium.perf.fyi.json
+++ b/testing/buildbot/chromium.perf.fyi.json
@@ -110,10 +110,6 @@
         ],
         "isolate_name": "performance_test_suite",
         "merge": {
-          "args": [
-            "--lightweight",
-            "--skip-perf"
-          ],
           "script": "//tools/perf/process_perf_results.py"
         },
         "name": "performance_test_suite",
@@ -149,14 +145,6 @@
       }
     ]
   },
-  "android-pixel2-processor-perf-fyi": {
-    "merge": {
-      "args": [
-        "--lightweight"
-      ],
-      "script": "//tools/perf/process_perf_results.py"
-    }
-  },
   "chromeos-kevin-perf-fyi": {
     "isolated_scripts": [
       {
@@ -216,10 +204,6 @@
         ],
         "isolate_name": "performance_test_suite",
         "merge": {
-          "args": [
-            "--lightweight",
-            "--skip-perf"
-          ],
           "script": "//tools/perf/process_perf_results.py"
         },
         "name": "performance_test_suite",
@@ -254,14 +238,6 @@
       }
     ]
   },
-  "linux-processor-perf-fyi": {
-    "merge": {
-      "args": [
-        "--lightweight"
-      ],
-      "script": "//tools/perf/process_perf_results.py"
-    }
-  },
   "win-10_laptop_low_end-perf_HP-Candidate": {
     "isolated_scripts": [
       {
@@ -275,10 +251,6 @@
         ],
         "isolate_name": "performance_test_suite",
         "merge": {
-          "args": [
-            "--lightweight",
-            "--skip-perf"
-          ],
           "script": "//tools/perf/process_perf_results.py"
         },
         "name": "performance_test_suite",
@@ -312,13 +284,5 @@
         }
       }
     ]
-  },
-  "win-10_laptop_low_end-perf_HP-Candidate-processor": {
-    "merge": {
-      "args": [
-        "--lightweight"
-      ],
-      "script": "//tools/perf/process_perf_results.py"
-    }
   }
 }
diff --git a/testing/buildbot/filters/fuchsia.services_unittests.filter b/testing/buildbot/filters/fuchsia.services_unittests.filter
index 0163191d..ea9f8e9 100644
--- a/testing/buildbot/filters/fuchsia.services_unittests.filter
+++ b/testing/buildbot/filters/fuchsia.services_unittests.filter
@@ -1,28 +1,5 @@
-# https://crbug.com/925652 - There are no |services_|.
--HidServiceTest.GetDevices
-
-# https://crbug.com/925652 - |num_sockets| expectations mismatch.
--NetworkContextTest.PreconnectFour
--NetworkContextTest.PreconnectTwo
-
-# https://crbug.com/925653 - IsTracingEnabled() expectations not met.
+# https://crbug.com/1125854 - IsTracingEnabled() expectations not met.
 -TracingConsumerTest.NotifiesOnTracingEnabledWaitsFor*
 
-# https://crbug.com/925653 - Flaky OOM and virtual method crashes.
--TracingConsumerTest.FlushProducers
--TracingConsumerTest.LargeDataSize
--TracingConsumerTest.PrivacyFilterConfig
--TracingConsumerTest.PrivacyFilterConfigInJson
--TracingConsumerTest.TestConsumerPriority
-
-# https://crbug.com/925653 - Second socket receives too many packets.
+# https://crbug.com/1125855 - Second socket receives too many packets.
 -UDPSocketTest.JoinMulticastGroup
-
-# https://crbug.com/925653 - Unexpected address-in-use.
--TCPBoundSocketTest.ListenError
-
-# https://crbug.com/976319 - Flakily times-out due to virtualization overhead.
--SimpleURLLoaderTest.OnUploadProgressCallback/*
-
-# https://crbug.com/986544 - Flakes with mismatched state expectations.
--URLLoaderTest.ResourceSchedulerIntegration
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index 705846a8..3bb477a 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -519,6 +519,7 @@
       "../../chrome/test/chromedriver/test/run_webdriver_tests.py",
       "-v",
       "--chromedriver=chromedriver",
+      "--log-path=${ISOLATED_OUTDIR}/chromedriver.log",
       "--output-dir=${ISOLATED_OUTDIR}",
       "--test-path=../../third_party/blink/web_tests/external/wpt/webdriver/tests/",
     ],
diff --git a/testing/scripts/representative_perf_test_data/representatives_frame_times_upper_limit.json b/testing/scripts/representative_perf_test_data/representatives_frame_times_upper_limit.json
index 91466a0..81e6cdf7 100644
--- a/testing/scripts/representative_perf_test_data/representatives_frame_times_upper_limit.json
+++ b/testing/scripts/representative_perf_test_data/representatives_frame_times_upper_limit.json
@@ -86,7 +86,9 @@
     "balls_javascript_canvas": {
       "ci_095": 1.324,
       "avg": 39.475,
-      "cpu_wall_time_ratio": 0.556
+      "cpu_wall_time_ratio": 0.556,
+      "experimental": true,
+      "_comment": "crbug.com/1122037"
     },
     "transform_transitions_js_block": {
       "ci_095": 0.366,
@@ -101,7 +103,9 @@
     "fill_shapes": {
       "ci_095": 0.949,
       "avg": 32.306,
-      "cpu_wall_time_ratio": 0.539
+      "cpu_wall_time_ratio": 0.539,
+      "experimental": true,
+      "_comment": "crbug.com/1122037"
     },
     "css_value_type_shadow": {
       "ci_095": 18.3,
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index b811187..172a3188 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -661,21 +661,6 @@
             ]
         }
     ],
-    "BackgroundPurgeOnMac": [
-        {
-            "platforms": [
-                "mac"
-            ],
-            "experiments": [
-                {
-                    "name": "BackgrounPurgeOnMac",
-                    "enable_features": [
-                        "PurgeRendererMemoryWhenBackgrounded"
-                    ]
-                }
-            ]
-        }
-    ],
     "BackgroundSync": [
         {
             "platforms": [
@@ -930,26 +915,6 @@
             ]
         }
     ],
-    "CacheStorageEagerReading": [
-        {
-            "platforms": [
-                "windows",
-                "mac",
-                "chromeos",
-                "linux",
-                "android",
-                "android_weblayer"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled2",
-                    "enable_features": [
-                        "CacheStorageEagerReading"
-                    ]
-                }
-            ]
-        }
-    ],
     "CacheStorageSequenceChromeOS": [
         {
             "platforms": [
@@ -1304,6 +1269,35 @@
             ]
         }
     ],
+    "ClientSideDetectionModel": [
+        {
+            "platforms": [
+                "chromeos",
+                "linux",
+                "mac"
+            ],
+            "experiments": [
+                {
+                    "name": "EnabledWithVisualModel",
+                    "params": {
+                        "ModelNum": "5"
+                    },
+                    "enable_features": [
+                        "ClientSideDetectionModel"
+                    ]
+                },
+                {
+                    "name": "EnabledDomOnly",
+                    "params": {
+                        "ModelNum": "4"
+                    },
+                    "enable_features": [
+                        "ClientSideDetectionModel"
+                    ]
+                }
+            ]
+        }
+    ],
     "CodeCacheDeletionWithoutFilter": [
         {
             "platforms": [
@@ -2154,12 +2148,12 @@
                 {
                     "name": "Enabled",
                     "params": {
-                        "BlockExtensionList": "mix_dl_blocked_for_testing",
-                        "SilentBlockExtensionList": "mix_dl_silently_blocked_for_testing",
+                        "BlockExtensionList": "",
+                        "SilentBlockExtensionList": "exe,scr,msi,vb,dmg,pkg,crx",
                         "TreatBlockListAsAllowlist": "false",
                         "TreatSilentBlockListAsAllowlist": "false",
                         "TreatWarnListAsAllowlist": "false",
-                        "WarnExtensionList": "exe,scr,msi,vb,dmg,pkg,crx"
+                        "WarnExtensionList": "zip,iso,rar,7z,tar,gz,bz2"
                     },
                     "enable_features": [
                         "TreatUnsafeDownloadsAsActive"
@@ -4923,6 +4917,41 @@
             ]
         }
     ],
+    "PdfPartialLoading": [
+        {
+            "platforms": [
+                "chromeos",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Disabled",
+                    "disable_features": [
+                        "PdfIncrementalLoading",
+                        "PdfPartialLoading"
+                    ]
+                },
+                {
+                    "name": "IncrementalOnly",
+                    "enable_features": [
+                        "PdfIncrementalLoading"
+                    ],
+                    "disable_features": [
+                        "PdfPartialLoading"
+                    ]
+                },
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "PdfIncrementalLoading",
+                        "PdfPartialLoading"
+                    ]
+                }
+            ]
+        }
+    ],
     "PerProcessReclaim": [
         {
             "platforms": [
@@ -7155,27 +7184,6 @@
             ]
         }
     ],
-    "VisualClientSideDetectionModel": [
-        {
-            "platforms": [
-                "chromeos",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "params": {
-                        "ModelNum": "5"
-                    },
-                    "enable_features": [
-                        "ClientSideDetectionModel"
-                    ]
-                }
-            ]
-        }
-    ],
     "VizForWebView": [
         {
             "platforms": [
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 29c41e9..bb172b6 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -143,12 +143,11 @@
 // Perform a memory purge after a renderer is backgrounded. Formerly labelled as
 // the "PurgeAndSuspend" experiment.
 //
-// TODO(adityakeerthi): Disabled by default on Mac and Android for historical
+// TODO(https://crbug.com/926186): Disabled by default on Android for historical
 // reasons. Consider enabling by default if experiment results are positive.
-// https://crbug.com/926186
 const base::Feature kPurgeRendererMemoryWhenBackgrounded {
   "PurgeRendererMemoryWhenBackgrounded",
-#if defined(OS_MAC) || defined(OS_ANDROID)
+#if defined(OS_ANDROID)
       base::FEATURE_DISABLED_BY_DEFAULT
 #else
       base::FEATURE_ENABLED_BY_DEFAULT
diff --git a/third_party/blink/public/web/web_view.h b/third_party/blink/public/web/web_view.h
index 1c61630..965eb09 100644
--- a/third_party/blink/public/web/web_view.h
+++ b/third_party/blink/public/web/web_view.h
@@ -282,11 +282,6 @@
   // Asks the browser process to activate this web view.
   virtual void Focus() = 0;
 
-  // Update the target url and tell the browser that the target URL has changed.
-  // If |url| is empty, show |fallback_url|.
-  virtual void UpdateTargetURL(const WebURL& url,
-                               const WebURL& fallback_url) = 0;
-
   // Sets the ratio as computed by computePageScaleConstraints.
   // TODO(oshima): Remove this once the device scale factor implementation is
   // fully migrated to use zooming mechanism.
diff --git a/third_party/blink/public/web/web_view_client.h b/third_party/blink/public/web/web_view_client.h
index dbf2e36..2e0745c 100644
--- a/third_party/blink/public/web/web_view_client.h
+++ b/third_party/blink/public/web/web_view_client.h
@@ -44,7 +44,6 @@
 namespace blink {
 
 class WebPagePopup;
-class WebURL;
 class WebURLRequest;
 class WebView;
 struct WebRect;
@@ -103,12 +102,6 @@
 
   // UI ------------------------------------------------------------------
 
-  // Called when hovering over an anchor with the given URL.
-  virtual void SetMouseOverURL(const WebURL&) {}
-
-  // Called when keyboard focus switches to an anchor with the given URL.
-  virtual void SetKeyboardFocusURL(const WebURL&) {}
-
   // Called to determine if drag-n-drop operations may initiate a page
   // navigation.
   virtual bool AcceptsLoadDrops() { return true; }
diff --git a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
index 472fbbf..6a2faf6 100644
--- a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
@@ -1110,8 +1110,7 @@
     result =
         primitive_value.ComputeLength<float>(state.CssToLengthConversionData());
   }
-  double zoomed_result = state.StyleRef().EffectiveZoom() * result;
-  if (zoomed_result > 0.0 && zoomed_result < 1.0)
+  if (result > 0.0 && result < 1.0)
     return 1.0;
   return clampTo<float>(result, defaultMinimumForClamp<float>(),
                         defaultMaximumForClamp<float>());
diff --git a/third_party/blink/renderer/core/css/resolver/style_cascade.cc b/third_party/blink/renderer/core/css/resolver/style_cascade.cc
index ef3bb8c..dd12921 100644
--- a/third_party/blink/renderer/core/css/resolver/style_cascade.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_cascade.cc
@@ -550,6 +550,8 @@
 
   int bg_color_alpha =
       style->VisitedDependentColor(GetCSSPropertyBackgroundColor()).Alpha();
+  int visited_bg_color_alpha =
+      style->ResolvedColor(style->InternalVisitedBackgroundColor()).Alpha();
   const SVGComputedStyle& svg_style = style->SvgStyle();
 
   MaybeForceColor(GetCSSPropertyColor(), style->GetColor());
@@ -604,6 +606,10 @@
   style->SetBackgroundColor(
       StyleColor(style->BackgroundColor().ResolveWithAlpha(
           style->GetCurrentColor(), WebColorScheme::kLight, bg_color_alpha)));
+  style->SetInternalVisitedBackgroundColor(
+      StyleColor(style->InternalVisitedBackgroundColor().ResolveWithAlpha(
+          style->GetCurrentColor(), WebColorScheme::kLight,
+          visited_bg_color_alpha)));
 }
 
 void StyleCascade::MaybeForceColor(const CSSProperty& property,
@@ -626,8 +632,10 @@
   CascadePriority* p = map_.Find(name, CascadeOrigin::kUserAgent);
   if (p)
     return ValueAt(match_result_, p->GetPosition());
-  if (name.Id() == CSSPropertyID::kBackgroundColor)
+  if (name.Id() == CSSPropertyID::kBackgroundColor ||
+      name.Id() == CSSPropertyID::kInternalVisitedBackgroundColor) {
     return CSSIdentifierValue::Create(CSSValueID::kCanvas);
+  }
   return cssvalue::CSSUnsetValue::Create();
 }
 
diff --git a/third_party/blink/renderer/core/css/resolver/style_cascade_test.cc b/third_party/blink/renderer/core/css/resolver/style_cascade_test.cc
index db3d8dc..8937b095 100644
--- a/third_party/blink/renderer/core/css/resolver/style_cascade_test.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_cascade_test.cc
@@ -3530,4 +3530,29 @@
   EXPECT_EQ("-5s", CssTextAt(map, "animation-delay"));
 }
 
+TEST_F(StyleCascadeTest, ForcedVisitedBackgroundColor) {
+  ScopedForcedColorsForTest scoped_feature(true);
+  ColorSchemeHelper color_scheme_helper(GetDocument());
+  color_scheme_helper.SetForcedColors(GetDocument(), ForcedColors::kActive);
+  UpdateAllLifecyclePhasesForTest();
+
+  TestCascade cascade(GetDocument());
+  cascade.State().Style()->SetInsideLink(EInsideLink::kInsideVisitedLink);
+  cascade.Add(ParseDeclarationBlock("background-color:#aabbccdd"),
+              CascadeOrigin::kAuthor, CSSSelector::kMatchVisited);
+  cascade.Apply();
+
+  Color forced_bg_color =
+      StyleColor(CSSValueID::kCanvas).Resolve(Color(), WebColorScheme::kLight);
+  Color expected_bg_color =
+      Color(forced_bg_color.Red(), forced_bg_color.Green(),
+            forced_bg_color.Blue(), 0xdd);
+
+  // Verify that the visited background color alpha channel is preserved in
+  // Forced Colors Mode.
+  EXPECT_EQ(
+      expected_bg_color,
+      cascade.State().Style()->InternalVisitedBackgroundColor().GetColor());
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc
index 53e01585d..57a29ee2 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -372,7 +372,7 @@
 
 void WebViewImpl::HandleMouseLeave(LocalFrame& main_frame,
                                    const WebMouseEvent& event) {
-  web_view_client_->SetMouseOverURL(WebURL());
+  SetMouseOverURL(WebURL());
   PageWidgetEventHandler::HandleMouseLeave(main_frame, event);
 }
 
@@ -1521,6 +1521,16 @@
   web_widget_ = widget;
 }
 
+void WebViewImpl::SetMouseOverURL(const KURL& url) {
+  mouse_over_url_ = url;
+  UpdateTargetURL(mouse_over_url_, focus_url_);
+}
+
+void WebViewImpl::SetKeyboardFocusURL(const KURL& url) {
+  focus_url_ = url;
+  UpdateTargetURL(focus_url_, mouse_over_url_);
+}
+
 WebFrameWidgetBase* WebViewImpl::MainFrameWidgetBase() {
   return web_widget_;
 }
@@ -2958,30 +2968,30 @@
     // see |ParamTraits<GURL>|.
     if (latest_url.GetString().length() > url::kMaxURLChars)
       latest_url = KURL();
-    UpdateTargetURLInBrowser(latest_url);
+    SendUpdatedTargetURLToBrowser(latest_url);
     target_url_ = latest_url;
     target_url_status_ = TARGET_INFLIGHT;
   }
 }
 
-void WebViewImpl::UpdateTargetURLInBrowser(const KURL& target_url) {
+void WebViewImpl::SendUpdatedTargetURLToBrowser(const KURL& target_url) {
   if (GetPage()->MainFrame()->IsLocalFrame()) {
     DCHECK(local_main_frame_host_remote_);
     local_main_frame_host_remote_->UpdateTargetURL(
-        target_url, WTF::Bind(&WebViewImpl::TargetURLUpdated,
+        target_url, WTF::Bind(&WebViewImpl::TargetURLUpdatedInBrowser,
                               weak_ptr_factory_.GetWeakPtr()));
   } else {
     DCHECK(remote_main_frame_host_remote_);
     remote_main_frame_host_remote_->UpdateTargetURL(
-        target_url, WTF::Bind(&WebViewImpl::TargetURLUpdated,
+        target_url, WTF::Bind(&WebViewImpl::TargetURLUpdatedInBrowser,
                               weak_ptr_factory_.GetWeakPtr()));
   }
 }
 
-void WebViewImpl::TargetURLUpdated() {
+void WebViewImpl::TargetURLUpdatedInBrowser() {
   // Check if there is a targeturl waiting to be sent.
   if (target_url_status_ == TARGET_PENDING)
-    UpdateTargetURLInBrowser(pending_target_url_);
+    SendUpdatedTargetURLToBrowser(pending_target_url_);
 
   target_url_status_ = TARGET_NONE;
 }
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.h b/third_party/blink/renderer/core/exported/web_view_impl.h
index b838f6e870..94277a4 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.h
+++ b/third_party/blink/renderer/core/exported/web_view_impl.h
@@ -189,7 +189,6 @@
   void UpdatePreferredSize() override;
   void EnablePreferredSizeChangedMode() override;
   void Focus() override;
-  void UpdateTargetURL(const WebURL& url, const WebURL& fallback_url) override;
   void SetDeviceScaleFactor(float) override;
   void SetZoomFactorForDeviceScaleFactor(float) override;
   float ZoomFactorForDeviceScaleFactor() override {
@@ -453,6 +452,12 @@
   void SetMainFrameWidgetBase(WebViewFrameWidget* widget);
   WebFrameWidgetBase* MainFrameWidgetBase();
 
+  // Called when hovering over an anchor with the given URL.
+  void SetMouseOverURL(const KURL&);
+
+  // Called when keyboard focus switches to an anchor with the given URL.
+  void SetKeyboardFocusURL(const KURL&);
+
  private:
   FRIEND_TEST_ALL_PREFIXES(WebFrameTest, DivScrollIntoEditableTest);
   FRIEND_TEST_ALL_PREFIXES(WebFrameTest,
@@ -498,8 +503,14 @@
   bool SelectionBounds(WebRect& anchor, WebRect& focus) const;
   WebURL GetURLForDebugTrace();
 
-  void UpdateTargetURLInBrowser(const KURL& target_url);
-  void TargetURLUpdated();
+  // Update the target url locally and tell the browser that the target URL has
+  // changed. If |url| is empty, show |fallback_url|.
+  void UpdateTargetURL(const WebURL& url, const WebURL& fallback_url);
+
+  // Helper functions to send the updated target URL to the right render frame
+  // in the browser process, and to handle its associated reply message.
+  void SendUpdatedTargetURLToBrowser(const KURL& target_url);
+  void TargetURLUpdatedInBrowser();
 
   void SetPageScaleFactorAndLocation(float scale,
                                      bool is_pinch_gesture_active,
@@ -645,6 +656,12 @@
   // The next target URL we want to send to the browser.
   KURL pending_target_url_;
 
+  // The URL the user's mouse is hovering over.
+  KURL mouse_over_url_;
+
+  // The URL that has keyboard focus.
+  KURL focus_url_;
+
   // Keeps track of the current zoom level. 0 means no zoom, positive numbers
   // mean zoom in, negative numbers mean zoom out.
   double zoom_level_ = 0.;
diff --git a/third_party/blink/renderer/core/feature_policy/document_policy_parser.cc b/third_party/blink/renderer/core/feature_policy/document_policy_parser.cc
index fd4e78d..a1bd473f 100644
--- a/third_party/blink/renderer/core/feature_policy/document_policy_parser.cc
+++ b/third_party/blink/renderer/core/feature_policy/document_policy_parser.cc
@@ -224,7 +224,8 @@
 
     if (parsed_feature.feature ==
         mojom::blink::DocumentPolicyFeature::kDefault) {
-      default_endpoint = *parsed_feature.endpoint_group;
+      if (parsed_feature.endpoint_group)
+        default_endpoint = *parsed_feature.endpoint_group;
       continue;
     }
 
diff --git a/third_party/blink/renderer/core/feature_policy/document_policy_parser_test.cc b/third_party/blink/renderer/core/feature_policy/document_policy_parser_test.cc
index f1bcd7e..f8041001 100644
--- a/third_party/blink/renderer/core/feature_policy/document_policy_parser_test.cc
+++ b/third_party/blink/renderer/core/feature_policy/document_policy_parser_test.cc
@@ -274,7 +274,26 @@
          /* endpoint_map */ {}},
         /* messages */ {},
     },
-
+    {
+        "MissingEndpointGroupForDefaultFeature1",
+        "*",
+        /* parsed_policy */
+        {
+            /* feature_state */ {},
+            /* endpoint_map */ {},
+        },
+        /* messages */ {},
+    },
+    {
+        "MissingEndpointGroupForDefaultFeature2",
+        "*,f-bool=?0,f-double=1;report-to=default",
+        /* parsed_policy */
+        {/* feature_state */ {
+             {kBoolFeature, PolicyValue::CreateBool(false)},
+             {kDoubleFeature, PolicyValue::CreateDecDouble(1.0)}},
+         /* endpoint_map */ {{kDoubleFeature, "default"}}},
+        /* messages */ {},
+    },
     //
     // Parse invalid policies.
     //
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
index c9e1ef8d..b4aaa68 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
+++ b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
@@ -128,7 +128,7 @@
       DCHECK(LowLatencyEnabled());
       provider = CanvasResourceProvider::CreatePassThroughProvider(
           Size(), FilterQuality(), ColorParams(),
-          SharedGpuContext::ContextProviderWrapper(), std::move(dispatcher),
+          SharedGpuContext::ContextProviderWrapper(), dispatcher,
           RenderingContext()->IsOriginTopLeft());
     }
     if (!provider) {
@@ -168,8 +168,7 @@
   if (!provider) {
     provider = CanvasResourceProvider::CreateSharedBitmapProvider(
         Size(), FilterQuality(), ColorParams(),
-        CanvasResourceProvider::ShouldInitialize::kCallClear,
-        std::move(dispatcher));
+        CanvasResourceProvider::ShouldInitialize::kCallClear, dispatcher);
   }
   if (!provider) {
     provider = CanvasResourceProvider::CreateBitmapProvider(
@@ -209,7 +208,7 @@
       provider = CanvasResourceProvider::CreateSwapChainProvider(
           Size(), FilterQuality(), ColorParams(),
           CanvasResourceProvider::ShouldInitialize::kCallClear,
-          SharedGpuContext::ContextProviderWrapper(), std::move(dispatcher),
+          SharedGpuContext::ContextProviderWrapper(), dispatcher,
           is_origin_top_left);
     }
     // If SwapChain failed or it was not possible, we will try a SharedImage
@@ -258,8 +257,7 @@
   if (!provider) {
     provider = CanvasResourceProvider::CreateSharedBitmapProvider(
         Size(), FilterQuality(), ColorParams(),
-        CanvasResourceProvider::ShouldInitialize::kCallClear,
-        std::move(dispatcher));
+        CanvasResourceProvider::ShouldInitialize::kCallClear, dispatcher);
   }
   if (!provider) {
     provider = CanvasResourceProvider::CreateBitmapProvider(
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index c04e9b9..c747213 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -1668,6 +1668,18 @@
   return MinMaxSizes();
 }
 
+MinMaxSizes LayoutBox::IntrinsicLogicalWidths(MinMaxSizesType type) const {
+  if (type == MinMaxSizesType::kContent && StyleRef().AspectRatio()) {
+    MinMaxSizes sizes;
+    if (ComputeLogicalWidthFromAspectRatio(&sizes.min_size)) {
+      sizes.max_size = sizes.min_size;
+      return sizes;
+    }
+  }
+  const_cast<LayoutBox*>(this)->UpdateCachedIntrinsicLogicalWidthsIfNeeded();
+  return intrinsic_logical_widths_;
+}
+
 void LayoutBox::UpdateCachedIntrinsicLogicalWidthsIfNeeded() {
   if (!IntrinsicLogicalWidthsDirty())
     return;
@@ -3538,7 +3550,7 @@
 bool LayoutBox::ComputeLogicalWidthFromAspectRatio(
     LayoutUnit* out_logical_width) const {
   LayoutUnit logical_height_for_ar = kIndefiniteSize;
-  if (StyleRef().AspectRatio() && StyleRef().LogicalWidth().IsAuto() &&
+  if (StyleRef().AspectRatio() &&
       (StyleRef().LogicalHeight().IsFixed() ||
        StyleRef().LogicalHeight().IsPercentOrCalc())) {
     logical_height_for_ar = ComputeLogicalHeightUsing(
@@ -3618,7 +3630,8 @@
       ContainerWidthInInlineDirection();
   LayoutBlock* cb = ContainingBlock();
 
-  if (ComputeLogicalWidthFromAspectRatio(&computed_values.extent_)) {
+  if (StyleRef().LogicalWidth().IsAuto() &&
+      ComputeLogicalWidthFromAspectRatio(&computed_values.extent_)) {
     /* we're good */
   } else if (treat_as_replaced) {
     computed_values.extent_ =
@@ -3722,7 +3735,10 @@
                     FillAvailableMeasure(available_logical_width));
   }
 
-  MinMaxSizes sizes = IntrinsicLogicalWidths();
+  MinMaxSizesType type = MinMaxSizesType::kContent;
+  if (logical_width_length.IsMinIntrinsic())
+    type = MinMaxSizesType::kIntrinsic;
+  MinMaxSizes sizes = IntrinsicLogicalWidths(type);
 
   if (logical_width_length.IsMinContent() ||
       logical_width_length.IsMinIntrinsic())
diff --git a/third_party/blink/renderer/core/layout/layout_box.h b/third_party/blink/renderer/core/layout/layout_box.h
index 7aa3b2e5..ee69d70 100644
--- a/third_party/blink/renderer/core/layout/layout_box.h
+++ b/third_party/blink/renderer/core/layout/layout_box.h
@@ -1713,10 +1713,8 @@
   virtual MinMaxSizes ComputeIntrinsicLogicalWidths() const = 0;
 
   // Returns the (maybe cached) intrinsic logical widths for this layout box.
-  MinMaxSizes IntrinsicLogicalWidths() const {
-    const_cast<LayoutBox*>(this)->UpdateCachedIntrinsicLogicalWidthsIfNeeded();
-    return intrinsic_logical_widths_;
-  }
+  MinMaxSizes IntrinsicLogicalWidths(
+      MinMaxSizesType type = MinMaxSizesType::kContent) const;
 
   // If |IntrinsicLogicalWidthsDirty()| is true, recalculates the intrinsic
   // logical widths.
diff --git a/third_party/blink/renderer/core/layout/layout_object_child_list.cc b/third_party/blink/renderer/core/layout/layout_object_child_list.cc
index 63b241f3..279d65e 100644
--- a/third_party/blink/renderer/core/layout/layout_object_child_list.cc
+++ b/third_party/blink/renderer/core/layout/layout_object_child_list.cc
@@ -242,12 +242,8 @@
   if (new_child->WasNotifiedOfSubtreeChange())
     owner->NotifyAncestorsOfSubtreeChange();
 
-  if (owner->ForceLegacyLayout()) {
+  if (owner->ForceLegacyLayout() && !new_child->IsLayoutNGObject())
     new_child->SetForceLegacyLayout();
-    // TODO(crbug.com/943574): This would be a great place to DCHECK that the
-    // child isn't an NG object, but there are unfortunately cases where this
-    // actually happens.
-  }
 
   new_child->SetNeedsLayoutAndIntrinsicWidthsRecalc(
       layout_invalidation_reason::kAddedToLayout);
diff --git a/third_party/blink/renderer/core/layout/min_max_sizes.h b/third_party/blink/renderer/core/layout/min_max_sizes.h
index 721ecec..129ddc3 100644
--- a/third_party/blink/renderer/core/layout/min_max_sizes.h
+++ b/third_party/blink/renderer/core/layout/min_max_sizes.h
@@ -12,6 +12,11 @@
 
 namespace blink {
 
+// min/max-content take the CSS aspect-ratio property into account.
+// In some cases that's undesirable; this enum lets you choose not
+// to do that using |kIntrinsic|.
+enum class MinMaxSizesType { kContent, kIntrinsic };
+
 // A struct that holds a pair of two sizes, a "min" size and a "max" size.
 // Useful for holding a {min,max}-content size pair or a
 // {min,max}-{width,height}.
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.cc
index 78127ba..8fd4ffd 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.cc
@@ -159,6 +159,7 @@
       continue;
     }
 
+    const unsigned children_count = child.children_count;
     // Children of inline boxes are flattened and added to |items_|, with the
     // count of descendant items to preserve the tree structure.
     //
@@ -167,14 +168,14 @@
     items_.emplace_back(child.rect.offset, std::move(child), writing_mode);
 
     // Add all children, including their desendants, skipping this item.
-    CHECK_GE(child.children_count, 1u);  // 0 will loop infinitely.
-    NGLogicalLineItem* end_child_iter = child_iter + child.children_count;
+    CHECK_GE(children_count, 1u);  // 0 will loop infinitely.
+    NGLogicalLineItem* end_child_iter = child_iter + children_count;
     CHECK_LE(end_child_iter - child_begin, child_end - child_begin);
     AddItems(child_iter + 1, end_child_iter);
     child_iter = end_child_iter;
 
     // All children are added. Compute how many items are actually added. The
-    // number of items added maybe different from |child.children_count|.
+    // number of items added may be different from |children_count|.
     const wtf_size_t item_count = items_.size() - box_start_index;
     NGFragmentItem& box_item = items_[box_start_index].item;
     DCHECK_EQ(box_item.DescendantsCount(), 1u);
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
index 0a3d370..b2d27a8 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
@@ -806,8 +806,9 @@
       (input.percentage_resolution_block_size ==
            box_->IntrinsicLogicalWidthsPercentageResolutionBlockSize() ||
        !box_->IntrinsicLogicalWidthsChildDependsOnPercentageBlockSize())) {
-    MinMaxSizes sizes = box_->IsTable() ? box_->PreferredLogicalWidths()
-                                        : box_->IntrinsicLogicalWidths();
+    MinMaxSizes sizes = box_->IsTable()
+                            ? box_->PreferredLogicalWidths()
+                            : box_->IntrinsicLogicalWidths(input.type);
     bool depends_on_percentage_block_size =
         box_->IntrinsicLogicalWidthsDependsOnPercentageBlockSize();
     return {sizes, depends_on_percentage_block_size};
@@ -835,8 +836,9 @@
   // depend on the *input* %-block-size.
   if (can_use_cached_intrinsic_inline_sizes &&
       !cache_depends_on_percentage_block_size) {
-    MinMaxSizes sizes = box_->IsTable() ? box_->PreferredLogicalWidths()
-                                        : box_->IntrinsicLogicalWidths();
+    MinMaxSizes sizes = box_->IsTable()
+                            ? box_->PreferredLogicalWidths()
+                            : box_->IntrinsicLogicalWidths(input.type);
     return {sizes, cache_depends_on_percentage_block_size};
   }
 
@@ -919,8 +921,9 @@
   // meaning for tables.
   //
   // Due to this the min/max content contribution is their min/max content size.
-  MinMaxSizes sizes = box_->IsTable() ? box_->PreferredLogicalWidths()
-                                      : box_->IntrinsicLogicalWidths();
+  MinMaxSizes sizes = box_->IsTable()
+                          ? box_->PreferredLogicalWidths()
+                          : box_->IntrinsicLogicalWidths(input.type);
 
   if (needs_size_reset)
     box_->ClearOverrideContainingBlockContentSize();
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h b/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
index 585c623..ab52557 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
@@ -27,11 +27,6 @@
 struct MinMaxSizes;
 struct PhysicalSize;
 
-// min/max-content take the CSS aspect-ratio property into account.
-// In some cases that's undesirable; this enum lets you choose not
-// to do that using |kIntrinsic|.
-enum class MinMaxSizesType { kContent, kIntrinsic };
-
 // The input to the min/max inline size calculation algorithm for child nodes.
 // Child nodes within the same formatting context need to know which floats are
 // beside them.
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 10e7f3c..c9d3cfa3 100644
--- a/third_party/blink/renderer/core/page/chrome_client_impl.cc
+++ b/third_party/blink/renderer/core/page/chrome_client_impl.cc
@@ -106,6 +106,7 @@
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/text/text_direction.h"
 #include "third_party/blink/renderer/platform/web_test_support.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
 #include "third_party/blink/renderer/platform/widget/frame_widget.h"
 #include "third_party/blink/renderer/platform/wtf/text/character_names.h"
@@ -224,11 +225,11 @@
 }
 
 void ChromeClientImpl::SetKeyboardFocusURL(Element* new_focus_element) {
-  WebURL focus_url;
+  KURL focus_url;
   if (new_focus_element && new_focus_element->IsLiveLink() &&
       new_focus_element->ShouldHaveFocusAppearance())
     focus_url = new_focus_element->HrefURL();
-  web_view_->Client()->SetKeyboardFocusURL(focus_url);
+  web_view_->SetKeyboardFocusURL(focus_url);
 }
 
 void ChromeClientImpl::StartDragging(LocalFrame* frame,
@@ -544,7 +545,7 @@
   if (!web_view_->Client())
     return;
 
-  WebURL url;
+  KURL url;
 
   // Ignore URL if hitTest include scrollbar since we might have both a
   // scrollbar and an element in the case of overlay scrollbars.
@@ -568,7 +569,7 @@
     }
   }
 
-  web_view_->Client()->SetMouseOverURL(url);
+  web_view_->SetMouseOverURL(url);
 }
 
 void ChromeClientImpl::SetToolTip(LocalFrame& frame,
diff --git a/third_party/blink/renderer/core/style/computed_style.h b/third_party/blink/renderer/core/style/computed_style.h
index 529d56ff..007775b2 100644
--- a/third_party/blink/renderer/core/style/computed_style.h
+++ b/third_party/blink/renderer/core/style/computed_style.h
@@ -2937,6 +2937,7 @@
   FRIEND_TEST_ALL_PREFIXES(ComputedStyleTest, InitialVariableNames);
   FRIEND_TEST_ALL_PREFIXES(ComputedStyleTest,
                            InitialAndInheritedAndNonInheritedVariableNames);
+  FRIEND_TEST_ALL_PREFIXES(StyleCascadeTest, ForcedVisitedBackgroundColor);
 };
 
 inline bool ComputedStyle::HasAnyPseudoElementStyles() const {
diff --git a/third_party/blink/renderer/core/svg/animation/smil_animation_sandwich.cc b/third_party/blink/renderer/core/svg/animation/smil_animation_sandwich.cc
index 2e8ef9a..126ac9b1 100644
--- a/third_party/blink/renderer/core/svg/animation/smil_animation_sandwich.cc
+++ b/third_party/blink/renderer/core/svg/animation/smil_animation_sandwich.cc
@@ -93,23 +93,26 @@
   if (!result_element)
     return false;
 
-  // Only reset the animated type to the base value once for
-  // the lowest priority animation that animates and
-  // contributes to a particular element/attribute pair.
-  result_element->ResetAnimatedType();
-
   // Animations have to be applied lowest to highest prio.
   //
   // Only calculate the relevant animations. If we actually set the
   // animation value, we don't need to calculate what is beneath it
   // in the sandwich.
+  bool needs_underlying_value = true;
   auto* sandwich_start = active_.end();
   while (sandwich_start != active_.begin()) {
     --sandwich_start;
-    if ((*sandwich_start)->OverwritesUnderlyingAnimationValue())
+    if ((*sandwich_start)->OverwritesUnderlyingAnimationValue()) {
+      needs_underlying_value = false;
       break;
+    }
   }
 
+  // Only reset the animated type to the base value once for
+  // the lowest priority animation that animates and
+  // contributes to a particular element/attribute pair.
+  result_element->ResetAnimatedType(needs_underlying_value);
+
   for (auto* sandwich_it = sandwich_start; sandwich_it != active_.end();
        sandwich_it++) {
     (*sandwich_it)->ApplyAnimation(result_element);
diff --git a/third_party/blink/renderer/core/svg/svg_animate_element.cc b/third_party/blink/renderer/core/svg/svg_animate_element.cc
index e1b9bea..b403ad0 100644
--- a/third_party/blink/renderer/core/svg/svg_animate_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_animate_element.cc
@@ -432,7 +432,7 @@
   return true;
 }
 
-void SVGAnimateElement::ResetAnimatedType() {
+void SVGAnimateElement::ResetAnimatedType(bool needs_underlying_value) {
   DCHECK(targetElement());
   if (IsAnimatingSVGDom()) {
     // SVG DOM animVal animation code-path.
@@ -447,7 +447,9 @@
 
   // CSS properties animation code-path.
   String base_value =
-      ComputeCSSPropertyValue(targetElement(), css_property_id_);
+      needs_underlying_value
+          ? ComputeCSSPropertyValue(targetElement(), css_property_id_)
+          : g_empty_string;
   animated_value_ = CreatePropertyForAnimation(base_value);
 }
 
diff --git a/third_party/blink/renderer/core/svg/svg_animate_element.h b/third_party/blink/renderer/core/svg/svg_animate_element.h
index 7608aef..2576de8 100644
--- a/third_party/blink/renderer/core/svg/svg_animate_element.h
+++ b/third_party/blink/renderer/core/svg/svg_animate_element.h
@@ -59,7 +59,7 @@
 
   bool HasValidAnimation() const override;
 
-  void ResetAnimatedType() final;
+  void ResetAnimatedType(bool needs_underlying_value) final;
   void ClearAnimatedType() final;
 
   bool CalculateToAtEndOfDurationValue(
diff --git a/third_party/blink/renderer/core/svg/svg_animate_motion_element.cc b/third_party/blink/renderer/core/svg/svg_animate_motion_element.cc
index ba3ac201..4b3b3d2 100644
--- a/third_party/blink/renderer/core/svg/svg_animate_motion_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_animate_motion_element.cc
@@ -153,7 +153,7 @@
   });
 }
 
-void SVGAnimateMotionElement::ResetAnimatedType() {
+void SVGAnimateMotionElement::ResetAnimatedType(bool needs_underlying_value) {
   SVGElement* target_element = targetElement();
   DCHECK(target_element);
   DCHECK(TargetCanHaveMotionTransform(*target_element));
diff --git a/third_party/blink/renderer/core/svg/svg_animate_motion_element.h b/third_party/blink/renderer/core/svg/svg_animate_motion_element.h
index 511821e..cef0e9c 100644
--- a/third_party/blink/renderer/core/svg/svg_animate_motion_element.h
+++ b/third_party/blink/renderer/core/svg/svg_animate_motion_element.h
@@ -42,7 +42,7 @@
 
   void ParseAttribute(const AttributeModificationParams&) override;
 
-  void ResetAnimatedType() override;
+  void ResetAnimatedType(bool needs_underlying_value) override;
   void ClearAnimatedType() override;
   bool CalculateToAtEndOfDurationValue(
       const String& to_at_end_of_duration_string) override;
diff --git a/third_party/blink/renderer/core/svg/svg_animation_element.h b/third_party/blink/renderer/core/svg/svg_animation_element.h
index fba834e..11164d7 100644
--- a/third_party/blink/renderer/core/svg/svg_animation_element.h
+++ b/third_party/blink/renderer/core/svg/svg_animation_element.h
@@ -71,7 +71,7 @@
   DEFINE_ATTRIBUTE_EVENT_LISTENER(end, kEndEvent)
   DEFINE_ATTRIBUTE_EVENT_LISTENER(repeat, kRepeatEvent)
 
-  virtual void ResetAnimatedType() = 0;
+  virtual void ResetAnimatedType(bool needs_underlying_value) = 0;
   virtual void ClearAnimatedType() = 0;
   virtual void ApplyResultsToTarget() = 0;
   // Returns true if this animation "sets" the value of the animation. Thus all
diff --git a/third_party/blink/renderer/modules/nfc/ndef_write_options.idl b/third_party/blink/renderer/modules/nfc/ndef_write_options.idl
index 81fe17b1..4d7116a 100644
--- a/third_party/blink/renderer/modules/nfc/ndef_write_options.idl
+++ b/third_party/blink/renderer/modules/nfc/ndef_write_options.idl
@@ -5,7 +5,6 @@
 // https://w3c.github.io/web-nfc/#the-ndefwriteoptions-dictionary
 
 dictionary NDEFWriteOptions {
-    boolean ignoreRead = true;
     boolean overwrite = true;
     AbortSignal? signal;
 };
diff --git a/third_party/blink/renderer/modules/nfc/nfc_type_converters.cc b/third_party/blink/renderer/modules/nfc/nfc_type_converters.cc
index 7587b5a4..d05ec7b8 100644
--- a/third_party/blink/renderer/modules/nfc/nfc_type_converters.cc
+++ b/third_party/blink/renderer/modules/nfc/nfc_type_converters.cc
@@ -57,9 +57,8 @@
     const blink::NDEFWriteOptions* write_options) {
   // https://w3c.github.io/web-nfc/#the-ndefwriteoptions-dictionary
   // Default values for NDEFWriteOptions dictionary are:
-  // ignoreRead = true, overwrite = true
+  // overwrite = true
   NDEFWriteOptionsPtr write_options_ptr = NDEFWriteOptions::New();
-  write_options_ptr->ignore_read = write_options->ignoreRead();
   write_options_ptr->overwrite = write_options->overwrite();
 
   return write_options_ptr;
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_container.cc b/third_party/blink/renderer/modules/service_worker/service_worker_container.cc
index 1846f25..a4a827a 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_container.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_container.cc
@@ -579,9 +579,10 @@
     return registration;
   }
 
+  const int64_t registration_id = info.registration_id;
   registration = MakeGarbageCollected<ServiceWorkerRegistration>(
       GetSupplementable()->GetExecutionContext(), std::move(info));
-  service_worker_registration_objects_.Set(info.registration_id, registration);
+  service_worker_registration_objects_.Set(registration_id, registration);
   return registration;
 }
 
@@ -591,9 +592,10 @@
     return nullptr;
   ServiceWorker* worker = service_worker_objects_.at(info.version_id);
   if (!worker) {
+    const int64_t version_id = info.version_id;
     worker = ServiceWorker::Create(GetSupplementable()->GetExecutionContext(),
                                    std::move(info));
-    service_worker_objects_.Set(info.version_id, worker);
+    service_worker_objects_.Set(version_id, worker);
   }
   return worker;
 }
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
index ae95a8a..ebfc413c 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
@@ -710,8 +710,9 @@
     return nullptr;
   ::blink::ServiceWorker* worker = service_worker_objects_.at(info.version_id);
   if (!worker) {
+    const int64_t version_id = info.version_id;
     worker = ::blink::ServiceWorker::Create(this, std::move(info));
-    service_worker_objects_.Set(info.version_id, worker);
+    service_worker_objects_.Set(version_id, worker);
   }
   return worker;
 }
diff --git a/third_party/blink/renderer/modules/websockets/dom_websocket.cc b/third_party/blink/renderer/modules/websockets/dom_websocket.cc
index 006263c..e4aa818 100644
--- a/third_party/blink/renderer/modules/websockets/dom_websocket.cc
+++ b/third_party/blink/renderer/modules/websockets/dom_websocket.cc
@@ -73,9 +73,6 @@
 #include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
 #include "third_party/blink/renderer/platform/wtf/wtf_size_t.h"
 
-static const size_t kMaxByteSizeForHistogram = 100 * 1000 * 1000;
-static const int32_t kBucketCountForMessageSizeHistogram = 50;
-
 namespace blink {
 
 DOMWebSocket::EventQueue::EventQueue(EventTarget* target)
@@ -357,8 +354,6 @@
     return;
   }
   RecordSendTypeHistogram(WebSocketSendType::kArrayBuffer);
-  RecordSendMessageSizeHistogram(WebSocketSendType::kArrayBuffer,
-                                 binary_data->ByteLengthAsSizeT());
   DCHECK(channel_);
   buffered_amount_ += binary_data->ByteLengthAsSizeT();
   channel_->Send(*binary_data, 0, binary_data->ByteLengthAsSizeT(),
@@ -380,8 +375,6 @@
     return;
   }
   RecordSendTypeHistogram(WebSocketSendType::kArrayBufferView);
-  RecordSendMessageSizeHistogram(WebSocketSendType::kArrayBufferView,
-                                 array_buffer_view.View()->byteLengthAsSizeT());
   DCHECK(channel_);
   buffered_amount_ += array_buffer_view.View()->byteLengthAsSizeT();
   channel_->Send(*array_buffer_view.View()->buffer(),
@@ -404,9 +397,6 @@
   }
   uint64_t size = binary_data->size();
   RecordSendTypeHistogram(WebSocketSendType::kBlob);
-  RecordSendMessageSizeHistogram(
-      WebSocketSendType::kBlob,
-      clampTo<size_t>(size, 0, kMaxByteSizeForHistogram));
   buffered_amount_ += size;
   DCHECK(channel_);
 
@@ -569,15 +559,12 @@
       }
       auto* blob = MakeGarbageCollected<Blob>(
           BlobDataHandle::Create(std::move(blob_data), size));
-      RecordReceiveMessageSizeHistogram(WebSocketReceiveType::kBlob, size);
       event_queue_->Dispatch(MessageEvent::Create(blob, origin_string_));
       break;
     }
 
     case kBinaryTypeArrayBuffer:
       DOMArrayBuffer* array_buffer = DOMArrayBuffer::Create(data);
-      RecordReceiveMessageSizeHistogram(WebSocketReceiveType::kArrayBuffer,
-                                        size);
       event_queue_->Dispatch(
           MessageEvent::Create(array_buffer, origin_string_));
       break;
@@ -633,60 +620,6 @@
   base::UmaHistogramEnumeration("WebCore.WebSocket.SendType", type);
 }
 
-void DOMWebSocket::RecordSendMessageSizeHistogram(WebSocketSendType type,
-                                                  size_t size) {
-  // Truncate |size| to avoid overflowing int32_t.
-  int32_t size_to_count = clampTo<int32_t>(size, 0, kMaxByteSizeForHistogram);
-  switch (type) {
-    case WebSocketSendType::kArrayBuffer:
-      base::UmaHistogramCustomCounts(
-          "WebCore.WebSocket.MessageSize.Send.ArrayBuffer", size_to_count, 1,
-          kMaxByteSizeForHistogram, kBucketCountForMessageSizeHistogram);
-      return;
-
-    case WebSocketSendType::kArrayBufferView:
-      base::UmaHistogramCustomCounts(
-          "WebCore.WebSocket.MessageSize.Send.ArrayBufferView", size_to_count,
-          1, kMaxByteSizeForHistogram, kBucketCountForMessageSizeHistogram);
-      return;
-
-    case WebSocketSendType::kBlob:
-      base::UmaHistogramCustomCounts("WebCore.WebSocket.MessageSize.Send.Blob",
-                                     size_to_count, 1, kMaxByteSizeForHistogram,
-                                     kBucketCountForMessageSizeHistogram);
-      return;
-
-    case WebSocketSendType::kString:
-      NOTREACHED();
-      return;
-  }
-  NOTREACHED();
-}
-
-void DOMWebSocket::RecordReceiveMessageSizeHistogram(WebSocketReceiveType type,
-                                                     size_t size) {
-  // Truncate |size| to avoid overflowing int32_t.
-  int32_t size_to_count = clampTo<int32_t>(size, 0, kMaxByteSizeForHistogram);
-  switch (type) {
-    case WebSocketReceiveType::kArrayBuffer:
-      base::UmaHistogramCustomCounts(
-          "WebCore.WebSocket.MessageSize.Receive.ArrayBuffer", size_to_count, 1,
-          kMaxByteSizeForHistogram, kBucketCountForMessageSizeHistogram);
-      return;
-
-    case WebSocketReceiveType::kBlob:
-      base::UmaHistogramCustomCounts(
-          "WebCore.WebSocket.MessageSize.Receive.Blob", size_to_count, 1,
-          kMaxByteSizeForHistogram, kBucketCountForMessageSizeHistogram);
-      return;
-
-    case WebSocketReceiveType::kString:
-      NOTREACHED();
-      return;
-  }
-  NOTREACHED();
-}
-
 void DOMWebSocket::Trace(Visitor* visitor) const {
   visitor->Trace(channel_);
   visitor->Trace(event_queue_);
diff --git a/third_party/blink/renderer/modules/websockets/dom_websocket.h b/third_party/blink/renderer/modules/websockets/dom_websocket.h
index fb8a9375..883b63d 100644
--- a/third_party/blink/renderer/modules/websockets/dom_websocket.h
+++ b/third_party/blink/renderer/modules/websockets/dom_websocket.h
@@ -202,13 +202,6 @@
     kMaxValue = kBlob,
   };
 
-  enum class WebSocketReceiveType {
-    kString,
-    kArrayBuffer,
-    kBlob,
-    kMaxValue = kBlob,
-  };
-
   enum BinaryType { kBinaryTypeBlob, kBinaryTypeArrayBuffer };
 
   // This function is virtual for unittests.
@@ -244,8 +237,6 @@
 
   void ReleaseChannel();
   void RecordSendTypeHistogram(WebSocketSendType);
-  void RecordSendMessageSizeHistogram(WebSocketSendType, size_t);
-  void RecordReceiveMessageSizeHistogram(WebSocketReceiveType, size_t);
 
   Member<WebSocketChannel> channel_;
 
diff --git a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
index f652d28..4ca87ce1 100644
--- a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
+++ b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
@@ -119,7 +119,6 @@
 
 ### external/wpt/css/css-sizing/
 crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/abspos-001.tentative.html [ Failure ]
-crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/abspos-002.tentative.html [ Failure ]
 crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/abspos-003.tentative.html [ Failure ]
 crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/abspos-004.tentative.html [ Failure ]
 crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/abspos-005.tentative.html [ Failure ]
@@ -143,11 +142,6 @@
 crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/block-aspect-ratio-028.tentative.html [ Failure ]
 crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/flex-aspect-ratio-008.tentative.html [ Failure ]
 crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/flex-aspect-ratio-009.tentative.html [ Failure ]
-crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/intrinsic-size-001.tentative.html [ Failure ]
-crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/intrinsic-size-002.tentative.html [ Failure ]
-crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/intrinsic-size-004.tentative.html [ Failure ]
-crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/intrinsic-size-006.tentative.html [ Failure ]
-crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/intrinsic-size-008.tentative.html [ Failure ]
 crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/percentage-resolution-001.tentative.html [ Failure ]
 crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/percentage-resolution-002.tentative.html [ Failure ]
 crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/percentage-resolution-004.tentative.html [ Failure ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 83ee34d..7b0a852d 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -2537,6 +2537,10 @@
 crbug.com/1105958 external/wpt/payment-request/payment-is-showing.https.html [ Timeout ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 [ Linux ] external/wpt/css/css-text/white-space/eol-spaces-bidi-002.html [ Failure ]
+crbug.com/626703 [ Mac ] external/wpt/css/css-text/white-space/eol-spaces-bidi-002.html [ Failure ]
+crbug.com/626703 [ Mac11.0 ] external/wpt/css/css-text/white-space/eol-spaces-bidi-002.html [ Failure ]
+crbug.com/626703 [ Win ] external/wpt/css/css-text/white-space/eol-spaces-bidi-002.html [ Failure ]
 crbug.com/626703 [ Linux ] external/wpt/css/css-text/white-space/trailing-ogham-002.html [ Failure ]
 crbug.com/626703 [ Mac ] external/wpt/css/css-text/white-space/trailing-ogham-002.html [ Failure ]
 crbug.com/626703 [ Mac11.0 ] external/wpt/css/css-text/white-space/trailing-ogham-002.html [ Failure ]
@@ -6600,6 +6604,7 @@
 
 # Flaky timeout
 crbug.com/1092048 external/wpt/FileAPI/blob/Blob-stream.any.html [ Pass Timeout ]
+crbug.com/1092048 external/wpt/FileAPI/blob/Blob-stream.any.worker.html [ Pass Timeout ]
 
 # Sheriff 2020-08-04: New wpt tests are failing
 crbug.com/1112771 external/wpt/webhid/idlharness.https.window.html [ Failure ]
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 dce9bc7..d78b75b 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
@@ -43527,6 +43527,71 @@
        {}
       ]
      ],
+     "border-width-small-values-001-a.html": [
+      "d5354a3585469bbec045a8d14193fc3332e83d0f",
+      [
+       null,
+       [
+        [
+         "/css/css-backgrounds/reference/border-width-small-values-001-ref.html",
+         "!="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "border-width-small-values-001-b.html": [
+      "ccb5004a64f584a5d26ed636519f945dd3c7580f",
+      [
+       null,
+       [
+        [
+         "/css/css-backgrounds/reference/border-width-small-values-001-ref.html",
+         "!="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "border-width-small-values-001-c.html": [
+      "43651fe2312bbdb1f4a5bd2914ee8e94c6c4076f",
+      [
+       null,
+       [
+        [
+         "/css/css-backgrounds/reference/border-width-small-values-001-ref.html",
+         "!="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "border-width-small-values-001-d.html": [
+      "11ff8b5c5553d5bff1ceff5da36a4342a650610c",
+      [
+       null,
+       [
+        [
+         "/css/css-backgrounds/reference/border-width-small-values-001-ref.html",
+         "!="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "border-width-small-values-001-e.html": [
+      "5fc44349834938dc6b3d6ba60334bcd7737d1a40",
+      [
+       null,
+       [
+        [
+         "/css/css-backgrounds/reference/border-width-small-values-001-ref.html",
+         "!="
+        ]
+       ],
+       {}
+      ]
+     ],
      "box-shadow-005.html": [
       "705ced279d30e6113eed68b819b287f7e48219cd",
       [
@@ -100025,7 +100090,7 @@
        ]
       ],
       "eol-spaces-bidi-001.html": [
-       "976ce7c639f10d2137da1492f50ea74c769c1091",
+       "b8bcbe17b738d40e4facffc0285282fe20002d30",
        [
         null,
         [
@@ -100037,6 +100102,19 @@
         {}
        ]
       ],
+      "eol-spaces-bidi-002.html": [
+       "0efba0a363fc8353775263928223773a9d10e3b4",
+       [
+        null,
+        [
+         [
+          "/css/css-text/white-space/reference/eol-spaces-bidi-002-ref.html",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
       "line-edge-white-space-collapse-001.html": [
        "4e144e6c330191435f183936c2ab2437ec4f7609",
        [
@@ -168965,6 +169043,10 @@
        "99dd2f0beb2a6a9b5bcf79408d1fbf089b8e15ec",
        []
       ],
+      "border-width-small-values-001-ref.html": [
+       "26177acb379017189f4deceb5519217fd97d2c51",
+       []
+      ],
       "box-shadow-005-ref.html": [
        "81a5cbf6b8e06f6435bc133287f128ed6af8ed62",
        []
@@ -188887,7 +188969,11 @@
         []
        ],
        "eol-spaces-bidi-001-ref.html": [
-        "37da6649f9b776cb046a2bacdeb24968d27a2af8",
+        "430706c55697597681c71202dd4cb18da8b5de37",
+        []
+       ],
+       "eol-spaces-bidi-002-ref.html": [
+        "30a4ffd303d55f6228b886aa658822975601967a",
         []
        ],
        "line-edge-white-space-collapse-001-ref.html": [
@@ -205412,7 +205498,7 @@
      []
     ],
     "generic-sensor-tests.js": [
-     "129ccd48543d6dfbc3f1e339443d44a3d864ce7b",
+     "26ff691959917b7b4921900f0603dcc23867c0ca",
      []
     ],
     "resources": {
@@ -229803,7 +229889,7 @@
     ],
     "resources": {
      "shapedetection-helpers.js": [
-      "bdb0e857d788ab0b2778cc9946386ead3d224b2c",
+      "05424de893dc9ac59d7f40c436bb73c9523da52f",
       []
      ]
     }
@@ -338664,7 +338750,7 @@
       ]
      ],
      "none.https.html": [
-      "0fbd4165a5f19f19a4e6cca3ee43bba88f0336b5",
+      "24b1fce1764d74a01c4eeb21c3d9e05de1bb12ba",
       [
        null,
        {
@@ -339217,6 +339303,24 @@
      ],
      "reporting": {
       "access-reporting": {
+       "access-from-coop-page-to-openee_coop-ro.https.html": [
+        "fc7c192b6b69303067c01ee407a67e9eed9201d2",
+        [
+         null,
+         {
+          "timeout": "long"
+         }
+        ]
+       ],
+       "access-from-coop-page-to-opener_coop-ro.https.html": [
+        "d7384e21195c16e558fe85fadfaca45e56c149cb",
+        [
+         null,
+         {
+          "timeout": "long"
+         }
+        ]
+       ],
        "access-from-coop-page-to-other_coop-ro.https.html": [
         "e5cc726c5e0b38c8d25cd3ee8fb80f227e1c3e19",
         [
@@ -339226,8 +339330,8 @@
          }
         ]
        ],
-       "access-to-coop-page-from-other_coop-ro.https.html": [
-        "c349b9a708e7cb579db921cc1d574869dc0b081c",
+       "access-to-coop-page-from-openee_coop-ro.https.html": [
+        "e54d5e3fe1c34113bd79849df4e3bfc16739d467",
         [
          null,
          {
@@ -339235,7 +339339,7 @@
          }
         ]
        ],
-       "openee-accessed_openee-coop-ro.https.html": [
+       "access-to-coop-page-from-opener_coop-ro.https.html": [
         "ef969738c33f8cacc8a269f5159e60900f98a7c7",
         [
          null,
@@ -339244,26 +339348,8 @@
          }
         ]
        ],
-       "openee-accessed_opener-coop-ro.https.html": [
-        "fc7c192b6b69303067c01ee407a67e9eed9201d2",
-        [
-         null,
-         {
-          "timeout": "long"
-         }
-        ]
-       ],
-       "opener-accessed_openee-coop-ro.https.html": [
-        "d7384e21195c16e558fe85fadfaca45e56c149cb",
-        [
-         null,
-         {
-          "timeout": "long"
-         }
-        ]
-       ],
-       "opener-accessed_opener-coop-ro.https.html": [
-        "e54d5e3fe1c34113bd79849df4e3bfc16739d467",
+       "access-to-coop-page-from-other_coop-ro.https.html": [
+        "c349b9a708e7cb579db921cc1d574869dc0b081c",
         [
          null,
          {
@@ -346749,6 +346835,13 @@
         ]
        ],
        "sizes": {
+        "implicit-sizes-ignores-width.html": [
+         "db61db351eacb5f38ce6767a55a61e588f5580e5",
+         [
+          null,
+          {}
+         ]
+        ],
         "parse-a-sizes-attribute-display-none.html": [
          "6aa77ebf85b9de2757e80abb32c32fd2c8021958",
          [
@@ -386322,7 +386415,7 @@
      ]
     ],
     "detection-on-worker.https.worker.js": [
-     "94b8e37d7272ea8f882d856d49fb9be334f1ffe5",
+     "3981c6fdc8e12839d3aa30206fa16d8af1faf513",
      [
       "shape-detection/detection-on-worker.https.worker.html",
       {}
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/border-width-small-values-001-a.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/border-width-small-values-001-a.html
new file mode 100644
index 0000000..d5354a3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/border-width-small-values-001-a.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Backgrounds and Borders Test: border-width small values</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds/#border-width">
+<link rel="mismatch" href="reference/border-width-small-values-001-ref.html">
+<meta name="assert" content="Tese tests check that small values for border-width (greater than 0px and lower than 1px) are visible.">
+<div style="border: 0.1px solid black;">The test passes if this text has a border</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/border-width-small-values-001-b.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/border-width-small-values-001-b.html
new file mode 100644
index 0000000..ccb5004
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/border-width-small-values-001-b.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Backgrounds and Borders Test: border-width small values</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds/#border-width">
+<link rel="mismatch" href="reference/border-width-small-values-001-ref.html">
+<meta name="assert" content="Tese tests check that small values for border-width (greater than 0px and lower than 1px) are visible.">
+<div style="border: 0.25px solid black;">The test passes if this text has a border</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/border-width-small-values-001-c.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/border-width-small-values-001-c.html
new file mode 100644
index 0000000..43651fe
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/border-width-small-values-001-c.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Backgrounds and Borders Test: border-width small values</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds/#border-width">
+<link rel="mismatch" href="reference/border-width-small-values-001-ref.html">
+<meta name="assert" content="Tese tests check that small values for border-width (greater than 0px and lower than 1px) are visible.">
+<div style="border: 0.5px solid black;">The test passes if this text has a border</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/border-width-small-values-001-d.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/border-width-small-values-001-d.html
new file mode 100644
index 0000000..11ff8b5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/border-width-small-values-001-d.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Backgrounds and Borders Test: border-width small values</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds/#border-width">
+<link rel="mismatch" href="reference/border-width-small-values-001-ref.html">
+<meta name="assert" content="Tese tests check that small values for border-width (greater than 0px and lower than 1px) are visible.">
+<div style="border: 0.7px solid black;">The test passes if this text has a border</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/border-width-small-values-001-e.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/border-width-small-values-001-e.html
new file mode 100644
index 0000000..5fc44349
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/border-width-small-values-001-e.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Backgrounds and Borders Test: border-width small values</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds/#border-width">
+<link rel="mismatch" href="reference/border-width-small-values-001-ref.html">
+<meta name="assert" content="Tese tests check that small values for border-width (greater than 0px and lower than 1px) are visible.">
+<div style="border: 0.9px solid black;">The test passes if this text has a border</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/reference/border-width-small-values-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/reference/border-width-small-values-001-ref.html
new file mode 100644
index 0000000..26177ac
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/reference/border-width-small-values-001-ref.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Backgrounds and Borders Reference Test: border-width small values</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<div>The test passes if this text has a border</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/eol-spaces-bidi-001.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/eol-spaces-bidi-001.html
index 976ce7c..b8bcbe1 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/eol-spaces-bidi-001.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/eol-spaces-bidi-001.html
@@ -1,44 +1,46 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>CSS Text level 3 Test: collapsible white space at end-of-line and bidi</title>
-<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
+<title>CSS Text 3 test: trailing collapsible spaces and bidi</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
 <link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2">
 <link rel="match" href="reference/eol-spaces-bidi-001-ref.html">
-<meta name="assert" content="Collapsible space at the end of the line prior to bidi reordering are removed.">
+<meta name="assert" content="Space before a line break is removed even if reordered to the middle of line by bidi reordering">
+
 <style>
 div {
-  font-family: monospace;
-  border: solid blue;
-  font-size: 1.5em;
-  margin-bottom:1em;
-  display: inline-block;
+    font-family: monospace;
+    border: solid blue;
+    font-size: 1.5em;
 }
 .ref {
-  white-space: pre;
-  border-color: orange;
+    border-color: orange;
+    white-space: pre;
 }
 .w5 { width: 5ch; }
 .w6 { width: 6ch; }
 .w7 { width: 7ch; }
-.w8 { width: 8ch; }
 
-.blue {	background: #aaaaff; }
-.red {	background: #ffaaaa; }
-.green {	background: #aaffaa; }
-.pink {	background: #ffaaff; }
-.yellow {	background: #ffffaa; }
-
+.blue { background: #aaaaff; }
+.red { background: #ffaaaa; }
+.green { background: #aaffaa; }
+.pink { background: #ffaaff; }
+.yellow { background: #ffffaa; }
 </style>
-<p>Test passes if the content of each blue box (on the left) is laid out identically to the content of the orange box to its right.
+
+<p>Test passes if each pair of blue / orange boxes are identical (except for the color of their border).
 
 <div class=w5><span class=pink> </span>A<span class=blue> </span>B<span class=red> </span>ا<span class=green> </span>ب<span class=yellow> </span></div>
-<div class="ref w5">A<span class=blue> </span>B<span class=red> </span>ا<br>ب</div>
-<br>
+
+<div class="w5 ref">A<span class=blue> </span>B<span class=red> </span>ا<br>ب</div>
+
+<hr>
+
 <div class=w6><span class=pink> </span>A<span class=blue> </span>B<span class=red> </span>ا<span class=green> </span>ب<span class=yellow> </span></div>
-<div class="ref w6">A<span class=blue> </span>B<span class=red> </span>ا<br>ب</div>
-<br>
+
+<div class="w6 ref">A<span class=blue> </span>B<span class=red> </span>ا<br>ب</div>
+
+<hr>
+
 <div class=w7><span class=pink> </span>A<span class=blue> </span>B<span class=red> </span>ا<span class=green> </span>ب<span class=yellow> </span></div>
-<div class="ref w7">A<span class=blue> </span>B<span class=red> </span>ا<span class=green> </span>ب</div>
-<br>
-<div class=w8><span class=pink> </span>A<span class=blue> </span>B<span class=red> </span>ا<span class=green> </span>ب<span class=yellow> </span></div>
-<div class="ref w8">A<span class=blue> </span>B<span class=red> </span>ا<span class=green> </span>ب</div>
+
+<div class="w7 ref">A<span class=blue> </span>B<span class=red> </span>ا<span class=green> </span>ب</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/eol-spaces-bidi-002.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/eol-spaces-bidi-002.html
new file mode 100644
index 0000000..0efba0a3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/eol-spaces-bidi-002.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Text 3 test: trailing pre-wrap spaces and bidi</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2">
+<link rel="help" href="https://www.w3.org/TR/css-writing-modes/#text-direction">
+<link rel="help" href="http://www.unicode.org/reports/tr9/#L1">
+<link rel="match" href="reference/eol-spaces-bidi-002-ref.html">
+<meta name="assert" content="Use UAX9L1 to determine which space is at the end of the line, taking into account that such spaces, when pre-wrap, must hang.">
+
+<style>
+div {
+    font-family: monospace;
+    border: solid blue;
+    font-size: 1.5em;
+    white-space: pre-wrap;
+}
+.ref {
+    border-color: orange;
+    white-space: pre;
+}
+.w6 { width: 6ch; }
+.w7 { width: 7ch; }
+.w8 { width: 8ch; }
+.w9 { width: 9ch; }
+
+.blue { background: #aaaaff; }
+.red { background: #ffaaaa; }
+.green { background: #aaffaa; }
+.pink { background: #ffaaff; }
+.yellow { background: #ffffaa; }
+</style>
+
+<p>Test passes if each pair of blue / orange boxes are identical (except for the color of their border).
+
+
+<!-- not coloring the space between ا and ب in this particular case,
+   because per UAX9 L1 and css-text-3 4.1.2 point 4 bullet 2:
+   this space MUST be at the end of the line and hang,
+   but also the UA MAY collapse it's advance width.
+   Not giving it a color lets the test pass either way.
+-->
+
+<div class="w6"><span class=pink> </span>A<span class=blue> </span>B<span class=red> </span>ا<span> </span>ب<span class=yellow> </span></div>
+<div class="w6 ref"><span class=pink> </span>A<span class=blue> </span>B<span class=red> </span>ا<br>ب<span class=yellow> </span></div>
+
+<hr>
+
+<div class="w7"><span class=pink> </span>A<span class=blue> </span>B<span class=red> </span>ا<span class=green> </span>ب<span class=yellow> </span></div>
+<div class="w7 ref"><span class=pink> </span>A<span class=blue> </span>B<span class=red> </span>ا<span class=green> </span><br>ب<span class=yellow> </span></div>
+
+<hr>
+
+<!-- not coloring the last space in this particular case,
+   because per 4.1.2 point 4 bullet 2:
+   this space MUST hang,
+   but also the UA MAY collapse it's advance width.
+   So we know for sure it won't cause a line break,
+   but it may or may not be visible at the end of the line.
+   Not giving it a color lets the test pass either way.
+-->
+
+<div class="w8"><span class=pink> </span>A<span class=blue> </span>B<span class=red> </span>ا<span class=green> </span>ب<span> </span></div>
+<div class="w8 ref"><span class=pink> </span>A<span class=blue> </span>B<span class=red> </span>ا<span class=green> </span>ب</div>
+
+<hr>
+
+<div class="w9"><span class=pink> </span>A<span class=blue> </span>B<span class=red> </span>ا<span class=green> </span>ب<span class=yellow> </span></div>
+<div class="w9 ref"><span class=pink> </span>A<span class=blue> </span>B<span class=red> </span>ا<span class=green> </span>ب<span class=yellow> </span></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/eol-spaces-bidi-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/eol-spaces-bidi-001-ref.html
index 37da664..430706c 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/eol-spaces-bidi-001-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/eol-spaces-bidi-001-ref.html
@@ -1,39 +1,38 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>CSS test reference</title>
-<link rel="author" title="Florian Rivoal" href="http://florian.rivoal.net/">
+<title>CSS Text 3 test reference</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
+
 <style>
 div {
-  font-family: monospace;
-  border: solid blue;
-  font-size: 1.5em;
-  margin-bottom:1em;
-  display: inline-block;
-  white-space: pre;
+    font-family: monospace;
+    border: solid blue;
+    font-size: 1.5em;
+    white-space: pre;
 }
 .ref {
-  border-color: orange;
+    border-color: orange;
 }
 .w5 { width: 5ch; }
 .w6 { width: 6ch; }
 .w7 { width: 7ch; }
-.w8 { width: 8ch; }
 
-.blue {	background: #aaaaff; }
-.red {	background: #ffaaaa; }
-.green {	background: #aaffaa; }
-
+.blue { background: #aaaaff; }
+.red { background: #ffaaaa; }
+.green { background: #aaffaa; }
 </style>
-<p>Test passes if the content of each blue box (on the left) is laid out identically to the content of the orange box to its right.
+
+<p>Test passes if each pair of blue / orange boxes are identical (except for the color of their border).
 
 <div class="w5">A<span class=blue> </span>B<span class=red> </span>ا<br>ب</div>
-<div class="ref w5">A<span class=blue> </span>B<span class=red> </span>ا<br>ب</div>
-<br>
+<div class="w5 ref">A<span class=blue> </span>B<span class=red> </span>ا<br>ب</div>
+
+<hr>
+
 <div class="w6">A<span class=blue> </span>B<span class=red> </span>ا<br>ب</div>
-<div class="ref w6">A<span class=blue> </span>B<span class=red> </span>ا<br>ب</div>
-<br>
+<div class="w6 ref">A<span class=blue> </span>B<span class=red> </span>ا<br>ب</div>
+
+<hr>
+
 <div class="w7">A<span class=blue> </span>B<span class=red> </span>ا<span class=green> </span>ب</div>
-<div class="ref w7">A<span class=blue> </span>B<span class=red> </span>ا<span class=green> </span>ب</div>
-<br>
-<div class="w8">A<span class=blue> </span>B<span class=red> </span>ا<span class=green> </span>ب</div>
-<div class="ref w8">A<span class=blue> </span>B<span class=red> </span>ا<span class=green> </span>ب</div>
+<div class="w7 ref">A<span class=blue> </span>B<span class=red> </span>ا<span class=green> </span>ب</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/eol-spaces-bidi-002-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/eol-spaces-bidi-002-ref.html
new file mode 100644
index 0000000..30a4ffd
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/white-space/reference/eol-spaces-bidi-002-ref.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Text 3 test reference</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
+
+<style>
+div {
+    font-family: monospace;
+    border: solid blue;
+    font-size: 1.5em;
+    white-space: pre;
+}
+.ref {
+    border-color: orange;
+}
+.w6 { width: 6ch; }
+.w7 { width: 7ch; }
+.w8 { width: 8ch; }
+.w9 { width: 9ch; }
+
+.blue { background: #aaaaff; }
+.red { background: #ffaaaa; }
+.green { background: #aaffaa; }
+.pink { background: #ffaaff; }
+.yellow { background: #ffffaa; }
+</style>
+
+<p>Test passes if each pair of blue / orange boxes are identical (except for the color of their border).
+
+
+<div class="w6"><span class=pink> </span>A<span class=blue> </span>B<span class=red> </span>ا<br>ب<span class=yellow> </span></div>
+<div class="w6 ref"><span class=pink> </span>A<span class=blue> </span>B<span class=red> </span>ا<br>ب<span class=yellow> </span></div>
+
+<hr>
+
+<div class="w7"><span class=pink> </span>A<span class=blue> </span>B<span class=red> </span>ا<span class=green> </span><br>ب<span class=yellow> </span></div>
+<div class="w7 ref"><span class=pink> </span>A<span class=blue> </span>B<span class=red> </span>ا<span class=green> </span><br>ب<span class=yellow> </span></div>
+
+<hr>
+
+<div class="w8"><span class=pink> </span>A<span class=blue> </span>B<span class=red> </span>ا<span class=green> </span>ب</div>
+<div class="w8 ref"><span class=pink> </span>A<span class=blue> </span>B<span class=red> </span>ا<span class=green> </span>ب</div>
+
+<hr>
+
+<div class="w9"><span class=pink> </span>A<span class=blue> </span>B<span class=red> </span>ا<span class=green> </span>ب<span class=yellow> </span></div>
+<div class="w9 ref"><span class=pink> </span>A<span class=blue> </span>B<span class=red> </span>ا<span class=green> </span>ب<span class=yellow> </span></div>
+
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-40-ref.html b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-39-ref.html
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-40-ref.html
rename to third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-39-ref.html
diff --git a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-40.html b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-39.html
similarity index 87%
rename from third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-40.html
rename to third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-39.html
index 7b02b41..7b69fc9 100644
--- a/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-40.html
+++ b/third_party/blink/web_tests/external/wpt/forced-colors-mode/forced-colors-mode-39.html
@@ -2,7 +2,7 @@
 <meta charset="utf-8">
 <title>Forced colors mode - pseudo elements.</title>
 <link rel="help" href="https://www.w3.org/TR/css-color-adjust-1/#forced-colors-properties">
-<link rel=match href="forced-colors-mode-40-ref.html">
+<link rel=match href="forced-colors-mode-39-ref.html">
 <style>
   p::before {
     background: blue;
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/sizes/implicit-sizes-ignores-width.html b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/sizes/implicit-sizes-ignores-width.html
new file mode 100644
index 0000000..db61db35
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/sizes/implicit-sizes-ignores-width.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<title>Implicit sizes ignores width</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+img {width: auto;}
+</style>
+<img srcset="../srcset/resources/image.png 100w" sizes="400px" id="sizes">
+<img srcset="../srcset/resources/image.png 100w" width="400" id="width">
+<script>
+setup({explicit_done:true});
+onload = () => {
+  test(() => {
+    assert_equals(document.getElementById("sizes").width, 400);
+    assert_equals(document.getElementById("width").width, window.innerWidth);
+    done();
+  });
+};
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/resources/chromium/nfc-mock.js b/third_party/blink/web_tests/external/wpt/resources/chromium/nfc-mock.js
index 1a7e158..4c5f68b 100644
--- a/third_party/blink/web_tests/external/wpt/resources/chromium/nfc-mock.js
+++ b/third_party/blink/web_tests/external/wpt/resources/chromium/nfc-mock.js
@@ -94,10 +94,10 @@
 // Compares NDEFWriteOptions structures that were provided to API and
 // received by the mock mojo service.
 function assertNDEFWriteOptionsEqual(provided, received) {
-  if (provided.ignoreRead !== undefined)
-    assert_equals(provided.ignoreRead, !!received.ignoreRead);
+  if (provided.overwrite !== undefined)
+    assert_equals(provided.overwrite, !!received.overwrite);
   else
-    assert_equals(!!received.ignore_read, true);
+    assert_equals(!!received.overwrite, true);
 }
 
 // Compares NDEFReaderOptions structures that were provided to API and
@@ -319,8 +319,9 @@
       this.reading_messages_.push(message);
       // Ignores reading if NFC operation is suspended.
       if(this.operations_suspended_) return;
-      // Ignores reading if NDEFWriteOptions.ignoreRead is true.
-      if (this.pending_write_options_ && this.pending_write_options_.ignoreRead)
+      // when overwrite is false, the write algorithm will read the NFC tag
+      // to determine if it has NDEF records on it.
+      if (this.pending_write_options_ && this.pending_write_options_.overwrite)
         return;
       // Triggers onWatch if the new message matches existing watchers.
       for (let watcher of this.watchers_) {
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/NDEFWriter_write.https.html b/third_party/blink/web_tests/external/wpt/web-nfc/NDEFWriter_write.https.html
index e2bbd57b..57fd300 100644
--- a/third_party/blink/web_tests/external/wpt/web-nfc/NDEFWriter_write.https.html
+++ b/third_party/blink/web_tests/external/wpt/web-nfc/NDEFWriter_write.https.html
@@ -382,57 +382,21 @@
 nfc_test(async (t, mockNFC) => {
   const writer = new NDEFWriter();
   await writer.write(test_text_data);
-  assertNDEFWriteOptionsEqual(createNDEFWriteOptions(true),
-                            mockNFC.writeOptions());
+  assertNDEFWriteOptionsEqual({overwrite: true}, mockNFC.writeOptions());
 }, "Check that default NDEFWriteOptions values are correctly set.");
 
 nfc_test(async (t, mockNFC) => {
   const writer = new NDEFWriter();
-  let ndefWriteOptions = createNDEFWriteOptions(false);
-  await writer.write(test_text_data, ndefWriteOptions);
-  assertNDEFWriteOptionsEqual(ndefWriteOptions, mockNFC.writeOptions());
+  await writer.write(test_text_data, {overwrite: false});
+  assertNDEFWriteOptionsEqual({overwrite: false}, mockNFC.writeOptions());
 }, "Check that provided NDEFWriteOptions values are correctly converted.");
 
 nfc_test(async (t, mockNFC) => {
-  const reader = new NDEFReader();
-  const message = createMessage([createTextRecord(test_text_data)]);
-  const controller = new AbortController();
-  const readerWatcher = new EventWatcher(t, reader, ["reading", "error"]);
-  await reader.scan({ signal: controller.signal });
-
-  const writer = new NDEFWriter();
-  await writer.write(test_text_data, { ignoreRead: false });
-  assertNDEFMessagesEqual(test_text_data, mockNFC.pushedMessage());
-
-  mockNFC.setReadingMessage(message);
-  await readerWatcher.wait_for("reading").then(event => {
-    controller.abort();
-    assertWebNDEFMessagesEqual(event.message, new NDEFMessage(message));
-  });
-
-}, "NDEFWriter.write should read data when ignoreRead is false.");
-
-nfc_test(async (t, mockNFC) => {
-  const reader = new NDEFReader();
-  const message = createMessage([createTextRecord(test_text_data)]);
-  // Ignore reading if NDEFWriteOptions.ignoreRead is true
-  reader.onreading = t.unreached_func("reading event should not be fired.");
-  await reader.scan();
-
-  const writer = new NDEFWriter();
-  await writer.write(test_text_data, { ignoreRead: true });
-  mockNFC.setReadingMessage(message);
-  assertNDEFMessagesEqual(test_text_data, mockNFC.pushedMessage());
-}, "NDEFWriter.write should ignore reading data when ignoreRead is true.");
-
-nfc_test(async (t, mockNFC) => {
   const writer1 = new NDEFWriter();
   const writer2 = new NDEFWriter();
 
-  const ndefWriteOptions1 = createNDEFWriteOptions( false);
-  const ndefWriteOptions2 = createNDEFWriteOptions(true);
-  const p1 = writer1.write(test_text_data, ndefWriteOptions1);
-  const p2 = writer2.write(test_url_data, ndefWriteOptions2);
+  const p1 = writer1.write(test_text_data, {overwrite: false});
+  const p2 = writer2.write(test_url_data, {overwrite: true});
 
   await new Promise((resolve, reject) => {
     // Make first push pending
@@ -445,7 +409,7 @@
     });
     p2.then(() => {
       assertNDEFMessagesEqual(test_url_data, mockNFC.pushedMessage());
-      assertNDEFWriteOptionsEqual(ndefWriteOptions2, mockNFC.writeOptions());
+      assertNDEFWriteOptionsEqual( {overwrite: true}, mockNFC.writeOptions());
       assert_equals(err, "AbortError", "the pending push should be aborted");
       resolve();
     });
@@ -478,7 +442,7 @@
 
 nfc_test(async (t, mockNFC) => {
   const writer = new NDEFWriter();
-  await writer.write(test_text_data, { overwrite: false });
+  await writer.write(test_text_data, {overwrite: false});
   assertNDEFMessagesEqual(test_text_data, mockNFC.pushedMessage());
 }, "NDEFWriter.write should succeed to write data to an unformatted NFC device \
 when the NDEFWriteOptions.overwrite is false.");
@@ -487,14 +451,14 @@
   const writer = new NDEFWriter();
   await writer.write(test_buffer_data);
   assertNDEFMessagesEqual(test_buffer_data, mockNFC.pushedMessage());
-  await writer.write(test_text_data, { overwrite: true });
+  await writer.write(test_text_data, {overwrite: true});
   assertNDEFMessagesEqual(test_text_data, mockNFC.pushedMessage());
 }, "NDEFWriter.write should succeed to overwrite the existing data \
 when the NDEFWriteOptions.overwrite is true.");
 
 nfc_test(async (t, mockNFC) => {
   const writer = new NDEFWriter();
-  const p = writer.write(test_text_data, { overwrite: false });
+  const p = writer.write(test_text_data, {overwrite: false});
   mockNFC.setIsFormattedTag(true);
   await promise_rejects_dom(t, 'NotAllowedError', p);
 }, "NDEFWriter.write should fail when there are NDEF records on the NFC device \
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/resources/nfc-helpers.js b/third_party/blink/web_tests/external/wpt/web-nfc/resources/nfc-helpers.js
index aa698e15..13cbe49 100644
--- a/third_party/blink/web_tests/external/wpt/web-nfc/resources/nfc-helpers.js
+++ b/third_party/blink/web_tests/external/wpt/web-nfc/resources/nfc-helpers.js
@@ -149,10 +149,6 @@
   return createRecord('url', url, test_record_id);
 }
 
-function createNDEFWriteOptions(ignoreRead) {
-  return {ignoreRead};
-}
-
 // Compares NDEFMessageSource that was provided to the API
 // (e.g. NDEFWriter.write), and NDEFMessage that was received by the
 // mock NFC service.
diff --git a/third_party/blink/web_tests/platform/linux/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png b/third_party/blink/web_tests/platform/linux/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png
index b8f8dc68..78dee36 100644
--- a/third_party/blink/web_tests/platform/linux/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png
+++ b/third_party/blink/web_tests/platform/linux/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png
index 74c7653..b33fc2e 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.14/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/svg/zoom/page/zoom-background-images-expected.png b/third_party/blink/web_tests/platform/mac/svg/zoom/page/zoom-background-images-expected.png
index 6f31c28c..e42d5ea 100644
--- a/third_party/blink/web_tests/platform/mac/svg/zoom/page/zoom-background-images-expected.png
+++ b/third_party/blink/web_tests/platform/mac/svg/zoom/page/zoom-background-images-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png b/third_party/blink/web_tests/platform/mac/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png
index 31a8223f..40178f0 100644
--- a/third_party/blink/web_tests/platform/mac/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png
+++ b/third_party/blink/web_tests/platform/mac/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-auto-size-expected.png b/third_party/blink/web_tests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-auto-size-expected.png
index ab2a007..3e4a3034 100644
--- a/third_party/blink/web_tests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-auto-size-expected.png
+++ b/third_party/blink/web_tests/platform/mac/svg/zoom/page/zoom-svg-through-object-with-auto-size-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/svg/zoom/page/zoom-background-images-expected.png b/third_party/blink/web_tests/platform/win/svg/zoom/page/zoom-background-images-expected.png
index 942f4668..6498018 100644
--- a/third_party/blink/web_tests/platform/win/svg/zoom/page/zoom-background-images-expected.png
+++ b/third_party/blink/web_tests/platform/win/svg/zoom/page/zoom-background-images-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png b/third_party/blink/web_tests/platform/win/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png
index 16663ac7..15db67c 100644
--- a/third_party/blink/web_tests/platform/win/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png
+++ b/third_party/blink/web_tests/platform/win/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/svg/zoom/page/zoom-svg-through-object-with-auto-size-expected.png b/third_party/blink/web_tests/platform/win/svg/zoom/page/zoom-svg-through-object-with-auto-size-expected.png
index aa1d3ca0..9e835b4b 100644
--- a/third_party/blink/web_tests/platform/win/svg/zoom/page/zoom-svg-through-object-with-auto-size-expected.png
+++ b/third_party/blink/web_tests/platform/win/svg/zoom/page/zoom-svg-through-object-with-auto-size-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/regress/regress-1117258.html b/third_party/blink/web_tests/regress/regress-1117258.html
new file mode 100644
index 0000000..8f801fd7
--- /dev/null
+++ b/third_party/blink/web_tests/regress/regress-1117258.html
@@ -0,0 +1,35 @@
+<title>Regression tests for crbug.com/1117258</title>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+
+<script>
+async_test((test) => {
+  function worker_code() {
+      self.addEventListener('message', () => {
+      let code = [
+          0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00
+      ];
+      let wasm_blob = URL.createObjectURL(
+          new Blob([new Uint8Array(code)], { type: "application/wasm" })
+      );
+      let controller = new AbortController();
+      let signal = controller.signal;
+      Object.defineProperty(WebAssembly.Module.prototype, 'then', {
+          get: function () {
+              controller.abort();
+          }
+      });
+      WebAssembly.compileStreaming(fetch(wasm_blob, { signal })).finally(
+       () => self.postMessage('success')
+      );
+    });
+  }
+  let blob = new Blob(['(', worker_code.toString(), ')()']);
+  let worker = new Worker(window.URL.createObjectURL(blob));
+  worker.addEventListener('message', (message) => {
+    assert_equals(message.data, 'success');
+    test.done();
+  });
+  worker.postMessage('start');
+}, 'Regression test for crbug.com/1117258');
+</script>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-backgrounds/border-width-zoom-001-ref.html b/third_party/blink/web_tests/wpt_internal/css/css-backgrounds/border-width-zoom-001-ref.html
new file mode 100644
index 0000000..dd26ea3
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/css/css-backgrounds/border-width-zoom-001-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Backgrounds and Borders Reference Test: border-width zoom</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<style>
+  div { width: 75px; height: 75px; }
+</style>
+<p>The test passses if you see 4 boxes with green border, the last 2 ones with a thicker border.</p>
+<div style="border: solid 0.75px green;"></div>
+<br>
+<div style="border: solid 0.75px green; border-radius: 15px;"></div>
+</br>
+<div style="border: solid 5px green;"></div>
+<br>
+<div style="border: solid 5px green; border-radius: 10px;"></div>
diff --git a/third_party/blink/web_tests/wpt_internal/css/css-backgrounds/border-width-zoom-001.html b/third_party/blink/web_tests/wpt_internal/css/css-backgrounds/border-width-zoom-001.html
new file mode 100644
index 0000000..d45e77a
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/css/css-backgrounds/border-width-zoom-001.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<!-- This test has to be internal because "zoom" property is not standard and is not supported by all browsers. -->
+<meta charset="utf-8">
+<title>CSS Backgrounds and Borders Test: border-width zoom</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds/#border-width">
+<link rel="match" href="border-width-zoom-001-ref.html">
+<meta name="assert" content="Tese tests check that border-width with different zoom values are properly rendered and always visible.">
+<p>The test passses if you see 4 boxes with green border, the last 2 ones with a thicker border.</p>
+<div style="zoom: 1.5; border: solid 0.5px green; width: 50px; height: 50px;"></div>
+<br>
+<div style="zoom: 1.5; border: solid 0.5px green; width: 50px; height: 50px; border-radius: 10px;"></div>
+</br>
+<div style="zoom: 0.1; border: solid 50px green; width: 750px; height: 750px;"></div>
+<br>
+<div style="zoom: 0.1; border: solid 50px green; width: 750px; height: 750px; border-radius: 100px;"></div>
diff --git a/third_party/crashpad/README.chromium b/third_party/crashpad/README.chromium
index 25886a79..de8fc93 100644
--- a/third_party/crashpad/README.chromium
+++ b/third_party/crashpad/README.chromium
@@ -2,7 +2,7 @@
 Short Name: crashpad
 URL: https://crashpad.chromium.org/
 Version: unknown
-Revision: 0cccdc0b7ec32bd31e789b3945a08c04ef775834
+Revision: 9a5a789123d7528d1c1cb71e66134fe0d7a9d37a
 License: Apache 2.0
 License File: crashpad/LICENSE
 Security Critical: yes
diff --git a/third_party/crashpad/crashpad/DEPS b/third_party/crashpad/crashpad/DEPS
index 3640572..3ecc47d 100644
--- a/third_party/crashpad/crashpad/DEPS
+++ b/third_party/crashpad/crashpad/DEPS
@@ -42,7 +42,7 @@
       '7bde79cc274d06451bf65ae82c012a5d3e476b5a',
   'crashpad/third_party/mini_chromium/mini_chromium':
       Var('chromium_git') + '/chromium/mini_chromium@' +
-      '891e31d0b649ec9fa98ca5745f9dcd14a34de34c',
+      'e0008f2714a76c7f2a3854fa75774427a886d6b9',
   'crashpad/third_party/libfuzzer/src':
       Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' +
       'fda403cf93ecb8792cb1d061564d89a6553ca020',
@@ -81,26 +81,6 @@
     'condition': 'checkout_fuchsia and host_os == "linux"',
     'dep_type': 'cipd'
   },
-  'crashpad/third_party/fuchsia/qemu/mac-amd64': {
-    'packages': [
-      {
-        'package': 'fuchsia/qemu/mac-amd64',
-        'version': 'latest'
-      },
-    ],
-    'condition': 'checkout_fuchsia and host_os == "mac"',
-    'dep_type': 'cipd'
-  },
-  'crashpad/third_party/fuchsia/qemu/linux-amd64': {
-    'packages': [
-      {
-        'package': 'fuchsia/qemu/linux-amd64',
-        'version': 'latest'
-      },
-    ],
-    'condition': 'checkout_fuchsia and host_os == "linux"',
-    'dep_type': 'cipd'
-  },
   'crashpad/third_party/fuchsia/sdk/mac-amd64': {
     'packages': [
       {
diff --git a/third_party/crashpad/crashpad/build/ios/convert_gn_xcodeproj.py b/third_party/crashpad/crashpad/build/ios/convert_gn_xcodeproj.py
index 3bbbb4e..d546279 100755
--- a/third_party/crashpad/crashpad/build/ios/convert_gn_xcodeproj.py
+++ b/third_party/crashpad/crashpad/build/ios/convert_gn_xcodeproj.py
@@ -29,6 +29,7 @@
 import json
 import hashlib
 import os
+import re
 import shutil
 import subprocess
 import sys
@@ -37,239 +38,244 @@
 
 class XcodeProject(object):
 
-    def __init__(self, objects, counter=0):
-        self.objects = objects
-        self.counter = 0
+  def __init__(self, objects, counter = 0):
+    self.objects = objects
+    self.counter = 0
 
-    def AddObject(self, parent_name, obj):
-        while True:
-            self.counter += 1
-            str_id = "%s %s %d" % (parent_name, obj['isa'], self.counter)
-            new_id = hashlib.sha1(
-                str_id.encode("utf-8")).hexdigest()[:24].upper()
+  def AddObject(self, parent_name, obj):
+    while True:
+      self.counter += 1
+      str_id = "%s %s %d" % (parent_name, obj['isa'], self.counter)
+      new_id = hashlib.sha1(str_id.encode("utf-8")).hexdigest()[:24].upper()
 
-            # Make sure ID is unique. It's possible there could be an id
-            # conflict since this is run after GN runs.
-            if new_id not in self.objects:
-                self.objects[new_id] = obj
-                return new_id
+      # Make sure ID is unique. It's possible there could be an id conflict
+      # since this is run after GN runs.
+      if new_id not in self.objects:
+        self.objects[new_id] = obj
+        return new_id
 
 
 def check_output(command):
-    """Wrapper around subprocess.check_output that decode output as utf-8."""
-    return subprocess.check_output(command).decode('utf-8')
+  """Wrapper around subprocess.check_output that decode output as utf-8."""
+  return subprocess.check_output(command).decode('utf-8')
 
 
 def CopyFileIfChanged(source_path, target_path):
-    """Copy |source_path| to |target_path| if different."""
-    target_dir = os.path.dirname(target_path)
-    if not os.path.isdir(target_dir):
-        os.makedirs(target_dir)
-    if not os.path.exists(target_path) or \
-        not filecmp.cmp(source_path, target_path):
-        shutil.copyfile(source_path, target_path)
+  """Copy |source_path| to |target_path| if different."""
+  target_dir = os.path.dirname(target_path)
+  if not os.path.isdir(target_dir):
+    os.makedirs(target_dir)
+  if not os.path.exists(target_path) or \
+      not filecmp.cmp(source_path, target_path):
+    shutil.copyfile(source_path, target_path)
 
 
 def CopyTreeIfChanged(source, target):
-    """Copy |source| to |target| recursively; files are copied iff changed."""
-    if os.path.isfile(source):
-        return CopyFileIfChanged(source, target)
-    if not os.path.isdir(target):
-        os.makedirs(target)
-    for name in os.listdir(source):
-        CopyTreeIfChanged(os.path.join(source, name),
-                          os.path.join(target, name))
+  """Copy |source| to |target| recursively; files are copied iff changed."""
+  if os.path.isfile(source):
+    return CopyFileIfChanged(source, target)
+  if not os.path.isdir(target):
+    os.makedirs(target)
+  for name in os.listdir(source):
+    CopyTreeIfChanged(
+        os.path.join(source, name),
+        os.path.join(target, name))
 
 
 def LoadXcodeProjectAsJSON(project_dir):
-    """Return Xcode project at |path| as a JSON string."""
-    return check_output([
-        'plutil', '-convert', 'json', '-o', '-',
-        os.path.join(project_dir, 'project.pbxproj')
-    ])
+  """Return Xcode project at |path| as a JSON string."""
+  return check_output([
+      'plutil', '-convert', 'json', '-o', '-',
+      os.path.join(project_dir, 'project.pbxproj')])
 
 
 def WriteXcodeProject(output_path, json_string):
-    """Save Xcode project to |output_path| as XML."""
-    with tempfile.NamedTemporaryFile() as temp_file:
-        temp_file.write(json_string.encode("utf-8"))
-        temp_file.flush()
-        subprocess.check_call(['plutil', '-convert', 'xml1', temp_file.name])
-        CopyFileIfChanged(temp_file.name,
-                          os.path.join(output_path, 'project.pbxproj'))
+  """Save Xcode project to |output_path| as XML."""
+  with tempfile.NamedTemporaryFile() as temp_file:
+    temp_file.write(json_string.encode("utf-8"))
+    temp_file.flush()
+    subprocess.check_call(['plutil', '-convert', 'xml1', temp_file.name])
+    CopyFileIfChanged(
+        temp_file.name,
+        os.path.join(output_path, 'project.pbxproj'))
 
 
 def UpdateXcodeProject(project_dir, configurations, root_dir):
-    """Update inplace Xcode project to support multiple configurations.
+  """Update inplace Xcode project to support multiple configurations.
 
-    Args:
-      project_dir: path to the input Xcode project
-      configurations: list of string corresponding to the configurations that
-        need to be supported by the tweaked Xcode projects, must contains at
-        least one value.
-      root_dir: path to the root directory used to find markdown files
-    """
-    json_data = json.loads(LoadXcodeProjectAsJSON(project_dir))
-    project = XcodeProject(json_data['objects'])
+  Args:
+    project_dir: path to the input Xcode project
+    configurations: list of string corresponding to the configurations that
+      need to be supported by the tweaked Xcode projects, must contains at
+      least one value.
+    root_dir: path to the root directory used to find markdown files
+  """
+  json_data = json.loads(LoadXcodeProjectAsJSON(project_dir))
+  project = XcodeProject(json_data['objects'])
 
-    objects_to_remove = []
-    for value in list(project.objects.values()):
-        isa = value['isa']
+  objects_to_remove = []
+  for value in list(project.objects.values()):
+    isa = value['isa']
 
-        # Teach build shell script to look for the configuration and platform.
-        if isa == 'PBXShellScriptBuildPhase':
-            value['shellScript'] = value['shellScript'].replace(
-                'ninja -C .',
-                'ninja -C "../${CONFIGURATION}${EFFECTIVE_PLATFORM_NAME}"')
+    # Teach build shell script to look for the configuration and platform.
+    if isa == 'PBXShellScriptBuildPhase':
+      shell_path = value['shellPath']
+      if shell_path.endswith('/sh'):
+        value['shellScript'] = value['shellScript'].replace(
+            'ninja -C .',
+            'ninja -C "../${CONFIGURATION}${EFFECTIVE_PLATFORM_NAME}"')
+      elif re.search('[ /]python[23]?$', shell_path):
+        value['shellScript'] = value['shellScript'].replace(
+            'ninja_params = [ \'-C\', \'.\' ]',
+            'ninja_params = [ \'-C\', \'../\' + os.environ[\'CONFIGURATION\']'
+            ' + os.environ[\'EFFECTIVE_PLATFORM_NAME\'] ]')
 
-        # Add new configuration, using the first one as default.
-        if isa == 'XCConfigurationList':
-            value['defaultConfigurationName'] = configurations[0]
-            objects_to_remove.extend(value['buildConfigurations'])
+    # Add new configuration, using the first one as default.
+    if isa == 'XCConfigurationList':
+      value['defaultConfigurationName'] = configurations[0]
+      objects_to_remove.extend(value['buildConfigurations'])
 
-            build_config_template = project.objects[value['buildConfigurations']
-                                                    [0]]
-            build_config_template['buildSettings']['CONFIGURATION_BUILD_DIR'] =\
-                '$(PROJECT_DIR)/../$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)'
+      build_config_template = project.objects[value['buildConfigurations'][0]]
+      build_config_template['buildSettings']['CONFIGURATION_BUILD_DIR'] = \
+          '$(PROJECT_DIR)/../$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)'
 
-            value['buildConfigurations'] = []
-            for configuration in configurations:
-                new_build_config = copy.copy(build_config_template)
-                new_build_config['name'] = configuration
-                value['buildConfigurations'].append(
-                    project.AddObject('products', new_build_config))
+      value['buildConfigurations'] = []
+      for configuration in configurations:
+        new_build_config = copy.copy(build_config_template)
+        new_build_config['name'] = configuration
+        value['buildConfigurations'].append(
+            project.AddObject('products', new_build_config))
 
-    for object_id in objects_to_remove:
-        del project.objects[object_id]
+  for object_id in objects_to_remove:
+    del project.objects[object_id]
 
-    source = GetOrCreateRootGroup(project, json_data['rootObject'], 'Source')
-    AddMarkdownToProject(project, root_dir, source)
-    SortFileReferencesByName(project, source)
+  source = GetOrCreateRootGroup(project, json_data['rootObject'], 'Source')
+  AddMarkdownToProject(project, root_dir, source)
+  SortFileReferencesByName(project, source)
 
-    objects = collections.OrderedDict(sorted(project.objects.items()))
-    WriteXcodeProject(project_dir, json.dumps(json_data))
+  objects = collections.OrderedDict(sorted(project.objects.items()))
+  WriteXcodeProject(project_dir, json.dumps(json_data))
 
 
 def CreateGroup(project, parent_group, group_name, path=None):
-    group_object = {
-        'children': [],
-        'isa': 'PBXGroup',
-        'name': group_name,
-        'sourceTree': '<group>',
-    }
-    if path is not None:
-        group_object['path'] = path
-    parent_group_name = parent_group.get('name', '')
-    group_object_key = project.AddObject(parent_group_name, group_object)
-    parent_group['children'].append(group_object_key)
-    return group_object
+  group_object = {
+    'children': [],
+    'isa': 'PBXGroup',
+    'name': group_name,
+    'sourceTree': '<group>',
+  }
+  if path is not None:
+    group_object['path'] = path
+  parent_group_name = parent_group.get('name', '')
+  group_object_key = project.AddObject(parent_group_name, group_object)
+  parent_group['children'].append(group_object_key)
+  return group_object
 
 
 def GetOrCreateRootGroup(project, root_object, group_name):
-    main_group = project.objects[project.objects[root_object]['mainGroup']]
-    for child_key in main_group['children']:
-        child = project.objects[child_key]
-        if child['name'] == group_name:
-            return child
-    return CreateGroup(project, main_group, group_name, path='../..')
+  main_group = project.objects[project.objects[root_object]['mainGroup']]
+  for child_key in main_group['children']:
+    child = project.objects[child_key]
+    if child['name'] == group_name:
+      return child
+  return CreateGroup(project, main_group, group_name, path='../..')
 
 
 class ObjectKey(object):
-    """Wrapper around PBXFileReference and PBXGroup for sorting.
 
-    A PBXGroup represents a "directory" containing a list of files in an
-    Xcode project; it can contain references to a list of directories or
-    files.
+  """Wrapper around PBXFileReference and PBXGroup for sorting.
 
-    A PBXFileReference represents a "file".
+  A PBXGroup represents a "directory" containing a list of files in an
+  Xcode project; it can contain references to a list of directories or
+  files.
 
-    The type is stored in the object "isa" property as a string. Since we
-    want to sort all directories before all files, the < and > operators
-    are defined so that if "isa" is different, they are sorted in the
-    reverse of alphabetic ordering, otherwise the name (or path) property
-    is checked and compared in alphabetic order.
-    """
+  A PBXFileReference represents a "file".
 
-    def __init__(self, obj):
-        self.isa = obj['isa']
-        if 'name' in obj:
-            self.name = obj['name']
-        else:
-            self.name = obj['path']
+  The type is stored in the object "isa" property as a string. Since we
+  want to sort all directories before all files, the < and > operators
+  are defined so that if "isa" is different, they are sorted in the
+  reverse of alphabetic ordering, otherwise the name (or path) property
+  is checked and compared in alphabetic order.
+  """
 
-    def __lt__(self, other):
-        if self.isa != other.isa:
-            return self.isa > other.isa
-        return self.name < other.name
+  def __init__(self, obj):
+    self.isa = obj['isa']
+    if 'name' in obj:
+      self.name = obj['name']
+    else:
+      self.name = obj['path']
 
-    def __gt__(self, other):
-        if self.isa != other.isa:
-            return self.isa < other.isa
-        return self.name > other.name
+  def __lt__(self, other):
+    if self.isa != other.isa:
+      return self.isa > other.isa
+    return self.name < other.name
 
-    def __eq__(self, other):
-        return self.isa == other.isa and self.name == other.name
+  def __gt__(self, other):
+    if self.isa != other.isa:
+      return self.isa < other.isa
+    return self.name > other.name
+
+  def __eq__(self, other):
+    return self.isa == other.isa and self.name == other.name
 
 
 def SortFileReferencesByName(project, group_object):
-    SortFileReferencesByNameWithSortKey(
-        project, group_object, lambda ref: ObjectKey(project.objects[ref]))
+  SortFileReferencesByNameWithSortKey(
+      project, group_object, lambda ref: ObjectKey(project.objects[ref]))
 
 
 def SortFileReferencesByNameWithSortKey(project, group_object, sort_key):
-    group_object['children'].sort(key=sort_key)
-    for key in group_object['children']:
-        child = project.objects[key]
-        if child['isa'] == 'PBXGroup':
-            SortFileReferencesByNameWithSortKey(project, child, sort_key)
+  group_object['children'].sort(key=sort_key)
+  for key in group_object['children']:
+    child = project.objects[key]
+    if child['isa'] == 'PBXGroup':
+      SortFileReferencesByNameWithSortKey(project, child, sort_key)
 
 
 def AddMarkdownToProject(project, root_dir, group_object):
-    list_files_cmd = ['git', '-C', root_dir, 'ls-files', '*.md']
-    paths = check_output(list_files_cmd).splitlines()
-    ios_internal_dir = os.path.join(root_dir, 'ios_internal')
-    if os.path.exists(ios_internal_dir):
-        list_files_cmd = ['git', '-C', ios_internal_dir, 'ls-files', '*.md']
-        ios_paths = check_output(list_files_cmd).splitlines()
-        paths.extend([os.path.join("ios_internal", path) for path in ios_paths])
-    for path in paths:
-        new_markdown_entry = {
-            "fileEncoding": "4",
-            "isa": "PBXFileReference",
-            "lastKnownFileType": "net.daringfireball.markdown",
-            "name": os.path.basename(path),
-            "path": path,
-            "sourceTree": "<group>"
-        }
-        new_markdown_entry_id = project.AddObject('sources', new_markdown_entry)
-        folder = GetFolderForPath(project, group_object, os.path.dirname(path))
-        folder['children'].append(new_markdown_entry_id)
+  list_files_cmd = ['git', '-C', root_dir, 'ls-files', '*.md']
+  paths = check_output(list_files_cmd).splitlines()
+  ios_internal_dir = os.path.join(root_dir, 'ios_internal')
+  if os.path.exists(ios_internal_dir):
+    list_files_cmd = ['git', '-C', ios_internal_dir, 'ls-files', '*.md']
+    ios_paths = check_output(list_files_cmd).splitlines()
+    paths.extend([os.path.join("ios_internal", path) for path in ios_paths])
+  for path in paths:
+    new_markdown_entry = {
+      "fileEncoding": "4",
+      "isa": "PBXFileReference",
+      "lastKnownFileType": "net.daringfireball.markdown",
+      "name": os.path.basename(path),
+      "path": path,
+      "sourceTree": "<group>"
+    }
+    new_markdown_entry_id = project.AddObject('sources', new_markdown_entry)
+    folder = GetFolderForPath(project, group_object, os.path.dirname(path))
+    folder['children'].append(new_markdown_entry_id)
 
 
 def GetFolderForPath(project, group_object, path):
-    objects = project.objects
-    if not path:
-        return group_object
-    for folder in path.split('/'):
-        children = group_object['children']
-        new_root = None
-        for child in children:
-            if objects[child]['isa'] == 'PBXGroup' and \
-               objects[child]['name'] == folder:
-                new_root = objects[child]
-                break
-        if not new_root:
-            # If the folder isn't found we could just cram it into the leaf
-            # existing folder, but that leads to folders with tons of README.md
-            # inside.
-            new_root = CreateGroup(project, group_object, folder)
-        group_object = new_root
+  objects = project.objects
+  if not path:
     return group_object
+  for folder in path.split('/'):
+    children = group_object['children']
+    new_root = None
+    for child in children:
+      if objects[child]['isa'] == 'PBXGroup' and \
+         objects[child]['name'] == folder:
+        new_root = objects[child]
+        break
+    if not new_root:
+      # If the folder isn't found we could just cram it into the leaf existing
+      # folder, but that leads to folders with tons of README.md inside.
+      new_root = CreateGroup(project, group_object, folder)
+    group_object = new_root
+  return group_object
 
 
 def ConvertGnXcodeProject(root_dir, input_dir, output_dir, configurations):
-    '''Tweak the Xcode project generated by gn to support multiple
-    configurations.
+  '''Tweak the Xcode project generated by gn to support multiple configurations.
 
   The Xcode projects generated by "gn gen --ide" only supports a single
   platform and configuration (as the platform and configuration are set
@@ -285,76 +291,71 @@
       least one value.
   '''
 
-    # Update the project (supports legacy name "products.xcodeproj" or the new
-    # project name "all.xcodeproj").
-    for project_name in ('all.xcodeproj', 'products.xcodeproj'):
-        if os.path.exists(os.path.join(input_dir, project_name)):
-            UpdateXcodeProject(os.path.join(input_dir, project_name),
-                               configurations, root_dir)
+  # Update the project (supports legacy name "products.xcodeproj" or the new
+  # project name "all.xcodeproj").
+  for project_name in ('all.xcodeproj', 'products.xcodeproj'):
+    if os.path.exists(os.path.join(input_dir, project_name)):
+      UpdateXcodeProject(
+          os.path.join(input_dir, project_name),
+          configurations, root_dir)
 
-            CopyTreeIfChanged(os.path.join(input_dir, project_name),
-                              os.path.join(output_dir, project_name))
+      CopyTreeIfChanged(os.path.join(input_dir, project_name),
+                        os.path.join(output_dir, project_name))
 
-        else:
-            shutil.rmtree(os.path.join(output_dir, project_name),
-                          ignore_errors=True)
-
-    # Copy all.xcworkspace if it exists (will be removed in a future gn version).
-    workspace_name = 'all.xcworkspace'
-    if os.path.exists(os.path.join(input_dir, workspace_name)):
-        CopyTreeIfChanged(os.path.join(input_dir, workspace_name),
-                          os.path.join(output_dir, workspace_name))
     else:
-        shutil.rmtree(os.path.join(output_dir, workspace_name),
-                      ignore_errors=True)
+      shutil.rmtree(os.path.join(output_dir, project_name), ignore_errors=True)
+
+  # Copy all.xcworkspace if it exists (will be removed in a future gn version).
+  workspace_name = 'all.xcworkspace'
+  if os.path.exists(os.path.join(input_dir, workspace_name)):
+    CopyTreeIfChanged(os.path.join(input_dir, workspace_name),
+                      os.path.join(output_dir, workspace_name))
+  else:
+    shutil.rmtree(os.path.join(output_dir, workspace_name), ignore_errors=True)
 
 
 def Main(args):
-    parser = argparse.ArgumentParser(
-        description='Convert GN Xcode projects for iOS.')
-    parser.add_argument(
-        'input', help='directory containing [product|all] Xcode projects.')
-    parser.add_argument(
-        'output', help='directory where to generate the iOS configuration.')
-    parser.add_argument('--add-config',
-                        dest='configurations',
-                        default=[],
-                        action='append',
-                        help='configuration to add to the Xcode project')
-    parser.add_argument('--root',
-                        type=os.path.abspath,
-                        required=True,
-                        help='root directory of the project')
-    args = parser.parse_args(args)
+  parser = argparse.ArgumentParser(
+      description='Convert GN Xcode projects for iOS.')
+  parser.add_argument(
+      'input',
+      help='directory containing [product|all] Xcode projects.')
+  parser.add_argument(
+      'output',
+      help='directory where to generate the iOS configuration.')
+  parser.add_argument(
+      '--add-config', dest='configurations', default=[], action='append',
+      help='configuration to add to the Xcode project')
+  parser.add_argument(
+      '--root', type=os.path.abspath, required=True,
+      help='root directory of the project')
+  args = parser.parse_args(args)
 
-    if not os.path.isdir(args.input):
-        sys.stderr.write('Input directory does not exists.\n')
-        return 1
+  if not os.path.isdir(args.input):
+    sys.stderr.write('Input directory does not exists.\n')
+    return 1
 
-    # Depending on the version of "gn", there should be either one project file
-    # named "all.xcodeproj" or a project file named "products.xcodeproj" and a
-    # workspace named "all.xcworkspace".
-    required_files_sets = [
-        set(("all.xcodeproj",)),
-        set(("products.xcodeproj", "all.xcworkspace")),
-    ]
+  # Depending on the version of "gn", there should be either one project file
+  # named "all.xcodeproj" or a project file named "products.xcodeproj" and a
+  # workspace named "all.xcworkspace".
+  required_files_sets = [
+      set(("all.xcodeproj",)),
+      set(("products.xcodeproj", "all.xcworkspace")),
+  ]
 
-    for required_files in required_files_sets:
-        if required_files.issubset(os.listdir(args.input)):
-            break
-    else:
-        sys.stderr.write(
-            'Input directory does not contain all necessary Xcode projects.\n')
-        return 1
+  for required_files in required_files_sets:
+    if required_files.issubset(os.listdir(args.input)):
+      break
+  else:
+    sys.stderr.write(
+        'Input directory does not contain all necessary Xcode projects.\n')
+    return 1
 
-    if not args.configurations:
-        sys.stderr.write(
-            'At least one configuration required, see --add-config.\n')
-        return 1
+  if not args.configurations:
+    sys.stderr.write('At least one configuration required, see --add-config.\n')
+    return 1
 
-    ConvertGnXcodeProject(args.root, args.input, args.output,
-                          args.configurations)
-
+  ConvertGnXcodeProject(args.root, args.input, args.output, args.configurations)
 
 if __name__ == '__main__':
-    sys.exit(Main(sys.argv[1:]))
+  sys.exit(Main(sys.argv[1:]))
diff --git a/third_party/crashpad/crashpad/build/run_fuchsia_qemu.py b/third_party/crashpad/crashpad/build/run_fuchsia_qemu.py
deleted file mode 100755
index 67463e63..0000000
--- a/third_party/crashpad/crashpad/build/run_fuchsia_qemu.py
+++ /dev/null
@@ -1,145 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright 2017 The Crashpad Authors. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Helper script to [re]start or stop a helper Fuchsia QEMU instance to be used
-for running tests without a device.
-"""
-
-from __future__ import print_function
-
-import getpass
-import os
-import random
-import signal
-import subprocess
-import sys
-import tempfile
-import time
-
-try:
-    from subprocess import DEVNULL
-except ImportError:
-    DEVNULL = open(os.devnull, 'r+b')
-
-CRASHPAD_ROOT = os.path.join(os.path.dirname(os.path.abspath(__file__)),
-                             os.pardir)
-
-
-def _Stop(pid_file):
-    if os.path.isfile(pid_file):
-        with open(pid_file, 'rb') as f:
-            pid = int(f.read().strip())
-        try:
-            os.kill(pid, signal.SIGTERM)
-        except:
-            print('Unable to kill pid %d, continuing' % pid, file=sys.stderr)
-        os.unlink(pid_file)
-
-
-def _CheckForTun():
-    """Check for networking. TODO(scottmg): Currently, this is Linux-specific.
-    """
-    returncode = subprocess.call(
-        ['tunctl', '-b', '-u',
-         getpass.getuser(), '-t', 'qemu'],
-        stdout=DEVNULL,
-        stderr=DEVNULL)
-    if returncode != 0:
-        print('To use QEMU with networking on Linux, configure TUN/TAP. See:',
-              file=sys.stderr)
-        print(
-            '  https://fuchsia.googlesource.com/zircon/+/HEAD/docs/qemu.md#enabling-networking-under-qemu-x86_64-only',
-            file=sys.stderr)
-        return 2
-    return 0
-
-
-def _Start(pid_file):
-    tun_result = _CheckForTun()
-    if tun_result != 0:
-        return tun_result
-
-    arch = 'mac-amd64' if sys.platform == 'darwin' else 'linux-amd64'
-    fuchsia_dir = os.path.join(CRASHPAD_ROOT, 'third_party', 'fuchsia')
-    qemu_path = os.path.join(fuchsia_dir, 'qemu', arch, 'bin',
-                             'qemu-system-x86_64')
-    kernel_data_dir = os.path.join(fuchsia_dir, 'sdk', arch, 'target', 'x86_64')
-    kernel_path = os.path.join(kernel_data_dir, 'zircon.bin')
-    initrd_path = os.path.join(kernel_data_dir, 'bootdata.bin')
-
-    mac_tail = ':'.join('%02x' % random.randint(0, 255) for x in range(3))
-    instance_name = (
-        'crashpad_qemu_' +
-        ''.join(chr(random.randint(ord('A'), ord('Z'))) for x in range(8)))
-
-    # These arguments are from the Fuchsia repo in zircon/scripts/run-zircon.
-
-    # yapf: disable
-    popen = subprocess.Popen([
-        qemu_path,
-        '-m', '2048',
-        '-nographic',
-        '-kernel', kernel_path,
-        '-initrd', initrd_path,
-        '-smp', '4',
-        '-serial', 'stdio',
-        '-monitor', 'none',
-        '-machine', 'q35',
-        '-cpu', 'host,migratable=no,+invtsc',
-        '-enable-kvm',
-        '-netdev', 'type=tap,ifname=qemu,script=no,downscript=no,id=net0',
-        '-device', 'e1000,netdev=net0,mac=52:54:00:' + mac_tail,
-        '-append', 'TERM=dumb zircon.nodename=' + instance_name,
-    ],
-                             stdin=DEVNULL,
-                             stdout=DEVNULL,
-                             stderr=DEVNULL)
-    # yapf: enable
-
-    with open(pid_file, 'wb') as f:
-        f.write('%d\n' % popen.pid)
-
-    for i in range(10):
-        netaddr_path = os.path.join(fuchsia_dir, 'sdk', arch, 'tools',
-                                    'netaddr')
-        if subprocess.call([netaddr_path, '--nowait', instance_name],
-                           stdout=open(os.devnull),
-                           stderr=open(os.devnull)) == 0:
-            break
-        time.sleep(.5)
-    else:
-        print('instance did not respond after start', file=sys.stderr)
-        return 1
-
-    return 0
-
-
-def main(args):
-    if len(args) != 1 or args[0] not in ('start', 'stop'):
-        print('usage: run_fuchsia_qemu.py start|stop', file=sys.stderr)
-        return 1
-
-    command = args[0]
-
-    pid_file = os.path.join(tempfile.gettempdir(), 'crashpad_fuchsia_qemu_pid')
-    _Stop(pid_file)
-    if command == 'start':
-        return _Start(pid_file)
-
-    return 0
-
-
-if __name__ == '__main__':
-    sys.exit(main(sys.argv[1:]))
diff --git a/third_party/crashpad/crashpad/build/run_tests.py b/third_party/crashpad/crashpad/build/run_tests.py
index 5e70d7b..f48652ff 100755
--- a/third_party/crashpad/crashpad/build/run_tests.py
+++ b/third_party/crashpad/crashpad/build/run_tests.py
@@ -313,144 +313,6 @@
         _adb_shell(['rm', '-rf', device_temp_dir])
 
 
-def _GetFuchsiaSDKRoot():
-    arch = 'mac-amd64' if sys.platform == 'darwin' else 'linux-amd64'
-    return os.path.join(CRASHPAD_DIR, 'third_party', 'fuchsia', 'sdk', arch)
-
-
-def _GenerateFuchsiaRuntimeDepsFiles(binary_dir, tests):
-    """Ensures a <binary_dir>/<test>.runtime_deps file exists for each test."""
-    targets_file = os.path.join(binary_dir, 'targets.txt')
-    with open(targets_file, 'wb') as f:
-        f.write('//:' + '\n//:'.join(tests) + '\n')
-    gn_path = _FindGNFromBinaryDir(binary_dir)
-    subprocess.check_call([
-        gn_path, '--root=' + CRASHPAD_DIR, 'gen', binary_dir,
-        '--runtime-deps-list-file=' + targets_file
-    ])
-
-    # Run again so that --runtime-deps-list-file isn't in the regen rule. See
-    # https://crbug.com/814816.
-    subprocess.check_call(
-        [gn_path, '--root=' + CRASHPAD_DIR, 'gen', binary_dir])
-
-
-def _HandleOutputFromFuchsiaLogListener(process, done_message):
-    """Pass through the output from |process| (which should be an instance of
-    Fuchsia's loglistener) until a special termination |done_message| is
-    encountered.
-
-    Also attempts to determine if any tests failed by inspecting the log output,
-    and returns False if there were failures.
-    """
-    success = True
-    while True:
-        line = process.stdout.readline().rstrip()
-        if 'FAILED TEST' in line:
-            success = False
-        elif done_message in line and 'echo ' not in line:
-            break
-        print(line)
-    return success
-
-
-def _RunOnFuchsiaTarget(binary_dir, test, device_name, extra_command_line):
-    """Runs the given Fuchsia |test| executable on the given |device_name|. The
-    device must already be booted.
-
-    Copies the executable and its runtime dependencies as specified by GN to the
-    target in /tmp using `netcp`, runs the binary on the target, and logs output
-    back to stdout on this machine via `loglistener`.
-    """
-    sdk_root = _GetFuchsiaSDKRoot()
-
-    # Run loglistener and filter the output to know when the test is done.
-    loglistener_process = subprocess.Popen(
-        [os.path.join(sdk_root, 'tools', 'loglistener'), device_name],
-        stdout=subprocess.PIPE,
-        stdin=open(os.devnull),
-        stderr=open(os.devnull))
-
-    runtime_deps_file = os.path.join(binary_dir, test + '.runtime_deps')
-    with open(runtime_deps_file, 'rb') as f:
-        runtime_deps = f.read().splitlines()
-
-    def netruncmd(*args):
-        """Runs a list of commands on the target device. Each command is escaped
-        by using pipes.quote(), and then each command is chained by shell ';'.
-        """
-        netruncmd_path = os.path.join(sdk_root, 'tools', 'netruncmd')
-        final_args = ' ; '.join(
-            ' '.join(pipes.quote(x) for x in command) for command in args)
-        subprocess.check_call([netruncmd_path, device_name, final_args])
-
-    try:
-        unique_id = uuid.uuid4().hex
-        test_root = '/tmp/%s_%s' % (test, unique_id)
-        tmp_root = test_root + '/tmp'
-        staging_root = test_root + '/pkg'
-
-        # Make a staging directory tree on the target.
-        directories_to_create = [
-            tmp_root,
-            '%s/bin' % staging_root,
-            '%s/assets' % staging_root
-        ]
-        netruncmd(['mkdir', '-p'] + directories_to_create)
-
-        def netcp(local_path):
-            """Uses `netcp` to copy a file or directory to the device. Files
-            located inside the build dir are stored to /pkg/bin, otherwise to
-            /pkg/assets. .so files are stored somewhere completely different,
-            into /boot/lib (!). This is because the loader service does not yet
-            correctly handle the namespace in which the caller is being run, and
-            so can only load .so files from a couple hardcoded locations, the
-            only writable one of which is /boot/lib, so we copy all .so files
-            there. This bug is filed upstream as ZX-1619.
-            """
-            in_binary_dir = local_path.startswith(binary_dir + '/')
-            if in_binary_dir:
-                if local_path.endswith('.so'):
-                    target_path = os.path.join('/boot/lib',
-                                               local_path[len(binary_dir) + 1:])
-                else:
-                    target_path = os.path.join(staging_root, 'bin',
-                                               local_path[len(binary_dir) + 1:])
-            else:
-                relative_path = os.path.relpath(local_path, CRASHPAD_DIR)
-                target_path = os.path.join(staging_root, 'assets',
-                                           relative_path)
-            netcp_path = os.path.join(sdk_root, 'tools', 'netcp')
-            subprocess.check_call(
-                [netcp_path, local_path, device_name + ':' + target_path],
-                stderr=open(os.devnull))
-
-        # Copy runtime deps into the staging tree.
-        for dep in runtime_deps:
-            local_path = os.path.normpath(os.path.join(binary_dir, dep))
-            if os.path.isdir(local_path):
-                for root, dirs, files in os.walk(local_path):
-                    for f in files:
-                        netcp(os.path.join(root, f))
-            else:
-                netcp(local_path)
-
-        done_message = 'TERMINATED: ' + unique_id
-        namespace_command = [
-            'namespace', '/pkg=' + staging_root, '/tmp=' + tmp_root,
-            '/svc=/svc', '--replace-child-argv0=/pkg/bin/' + test, '--',
-            staging_root + '/bin/' + test
-        ] + extra_command_line
-        netruncmd(namespace_command, ['echo', done_message])
-
-        success = _HandleOutputFromFuchsiaLogListener(loglistener_process,
-                                                      done_message)
-        if not success:
-            raise subprocess.CalledProcessError(1, test)
-    finally:
-        netruncmd(['rm', '-rf', test_root])
-
-
 def _RunOnIOSTarget(binary_dir, test, is_xcuitest=False):
     """Runs the given iOS |test| app on iPhone 8 with the default OS version."""
 
@@ -544,7 +406,6 @@
 
     target_os = _BinaryDirTargetOS(args.binary_dir)
     is_android = target_os == 'android'
-    is_fuchsia = target_os == 'fuchsia'
     is_ios = target_os == 'ios'
 
     tests = [
@@ -575,21 +436,6 @@
                 return 2
             android_device = devices[0]
             print('Using autodetected Android device:', android_device)
-    elif is_fuchsia:
-        zircon_nodename = os.environ.get('ZIRCON_NODENAME')
-        if not zircon_nodename:
-            netls = os.path.join(_GetFuchsiaSDKRoot(), 'tools', 'netls')
-            popen = subprocess.Popen([netls, '--nowait'],
-                                     stdout=subprocess.PIPE)
-            devices = popen.communicate()[0].splitlines()
-            if popen.returncode != 0 or len(devices) != 1:
-                print("Please set ZIRCON_NODENAME to your device's hostname",
-                      file=sys.stderr)
-                return 2
-            zircon_nodename = devices[0].strip().split()[1]
-            print('Using autodetected Fuchsia device:', zircon_nodename)
-        _GenerateFuchsiaRuntimeDepsFiles(
-            args.binary_dir, [t for t in tests if not t.endswith('.py')])
     elif is_ios:
         tests.append('ios_crash_xcuitests')
     elif IS_WINDOWS_HOST:
@@ -618,9 +464,6 @@
             if is_android:
                 _RunOnAndroidTarget(args.binary_dir, test, android_device,
                                     extra_command_line)
-            elif is_fuchsia:
-                _RunOnFuchsiaTarget(args.binary_dir, test, zircon_nodename,
-                                    extra_command_line)
             elif is_ios:
                 _RunOnIOSTarget(args.binary_dir,
                                 test,
diff --git a/third_party/crashpad/crashpad/client/BUILD.gn b/third_party/crashpad/crashpad/client/BUILD.gn
index f448d35..10b994f 100644
--- a/third_party/crashpad/crashpad/client/BUILD.gn
+++ b/third_party/crashpad/crashpad/client/BUILD.gn
@@ -116,6 +116,7 @@
     deps += [ "../third_party/fuchsia" ]
     if (crashpad_is_in_fuchsia) {
       deps += [ "//sdk/lib/fdio" ]
+      configs += [ "//build/config:Wno-conversion" ]
     }
   }
 }
diff --git a/third_party/crashpad/crashpad/client/crashpad_client.h b/third_party/crashpad/crashpad/client/crashpad_client.h
index 36589727..5d42139 100644
--- a/third_party/crashpad/crashpad/client/crashpad_client.h
+++ b/third_party/crashpad/crashpad/client/crashpad_client.h
@@ -33,7 +33,7 @@
 #elif defined(OS_WIN)
 #include <windows.h>
 #include "util/win/scoped_handle.h"
-#elif defined(OS_LINUX) || defined(OS_ANDROID)
+#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
 #include <signal.h>
 #include <ucontext.h>
 #endif
@@ -121,7 +121,7 @@
                     bool asynchronous_start,
                     const std::vector<base::FilePath>& attachments = {});
 
-#if defined(OS_ANDROID) || defined(OS_LINUX) || DOXYGEN
+#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) || DOXYGEN
   //! \brief Retrieve the socket and process ID for the handler.
   //!
   //! `StartHandler()` must have successfully been called before calling this
@@ -166,7 +166,7 @@
   //!
   //! \return `true` on success. Otherwise `false` with a message logged.
   static bool InitializeSignalStackForThread();
-#endif  // OS_ANDROID || OS_LINUX || DOXYGEN
+#endif  // OS_ANDROID || OS_LINUX || OS_CHROMEOS || DOXYGEN
 
 #if defined(OS_ANDROID) || DOXYGEN
   //! \brief Installs a signal handler to execute `/system/bin/app_process` and
@@ -337,7 +337,7 @@
       int socket);
 #endif  // OS_ANDROID || DOXYGEN
 
-#if defined(OS_LINUX) || defined(OS_ANDROID) || DOXYGEN
+#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_CHROMEOS) || DOXYGEN
   //! \brief Installs a signal handler to launch a handler process in reponse to
   //!     a crash.
   //!
@@ -450,7 +450,7 @@
   //!
   //! \param[in] unhandled_signals The set of unhandled signals
   void SetUnhandledSignals(const std::set<int>& unhandled_signals);
-#endif  // OS_LINUX || OS_ANDROID || DOXYGEN
+#endif  // OS_LINUX || OS_ANDROID || OS_CHROMEOS || DOXYGEN
 
 #if defined(OS_IOS) || DOXYGEN
   //! \brief Configures the process to direct its crashes to the iOS in-process
@@ -662,7 +662,7 @@
 #elif defined(OS_WIN)
   std::wstring ipc_pipe_;
   ScopedKernelHANDLE handler_start_thread_;
-#elif defined(OS_LINUX) || defined(OS_ANDROID)
+#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
   std::set<int> unhandled_signals_;
 #endif  // OS_APPLE
 
diff --git a/third_party/crashpad/crashpad/client/crashpad_client_linux.cc b/third_party/crashpad/crashpad/client/crashpad_client_linux.cc
index 117ed19..8425d77 100644
--- a/third_party/crashpad/crashpad/client/crashpad_client_linux.cc
+++ b/third_party/crashpad/crashpad/client/crashpad_client_linux.cc
@@ -411,7 +411,7 @@
       std::move(client_sock), handler_pid, &unhandled_signals_);
 }
 
-#if defined(OS_ANDROID) || defined(OS_LINUX)
+#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
 // static
 bool CrashpadClient::GetHandlerSocket(int* sock, pid_t* pid) {
   auto signal_handler = RequestCrashDumpHandler::Get();
@@ -515,7 +515,7 @@
   }
   return true;
 }
-#endif  // OS_ANDROID || OS_LINUX
+#endif  // OS_ANDROID || OS_LINUX || OS_CHROMEOS
 
 #if defined(OS_ANDROID)
 
diff --git a/third_party/crashpad/crashpad/client/crashpad_client_mac.cc b/third_party/crashpad/crashpad/client/crashpad_client_mac.cc
index 3c6d13a..ddcd485f 100644
--- a/third_party/crashpad/crashpad/client/crashpad_client_mac.cc
+++ b/third_party/crashpad/crashpad/client/crashpad_client_mac.cc
@@ -14,6 +14,7 @@
 
 #include "client/crashpad_client.h"
 
+#include <Availability.h>
 #include <errno.h>
 #include <mach/mach.h>
 #include <pthread.h>
@@ -454,14 +455,15 @@
   // The “restartable” behavior can only be selected on OS X 10.10 and later. In
   // previous OS versions, if the initial client were to crash while attempting
   // to restart the handler, it would become an unkillable process.
-  base::mac::ScopedMachSendRight exception_port(
-      HandlerStarter::InitialStart(handler,
-                                   database,
-                                   metrics_dir,
-                                   url,
-                                   annotations,
-                                   arguments,
-                                   restartable && MacOSXMinorVersion() >= 10));
+  base::mac::ScopedMachSendRight exception_port(HandlerStarter::InitialStart(
+      handler,
+      database,
+      metrics_dir,
+      url,
+      annotations,
+      arguments,
+      restartable && (__MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_10 ||
+                      MacOSVersionNumber() >= 10'10'00)));
   if (!exception_port.is_valid()) {
     return false;
   }
diff --git a/third_party/crashpad/crashpad/client/crashpad_info.cc b/third_party/crashpad/crashpad/client/crashpad_info.cc
index 12307be5..929c0df 100644
--- a/third_party/crashpad/crashpad/client/crashpad_info.cc
+++ b/third_party/crashpad/crashpad/client/crashpad_info.cc
@@ -94,7 +94,8 @@
 
 // static
 CrashpadInfo* CrashpadInfo::GetCrashpadInfo() {
-#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_FUCHSIA)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) || \
+    defined(OS_FUCHSIA)
   // This otherwise-unused reference is used so that any module that
   // references GetCrashpadInfo() will also include the note in the
   // .note.crashpad.info section. That note in turn contains the address of
diff --git a/third_party/crashpad/crashpad/client/simulate_crash.h b/third_party/crashpad/crashpad/client/simulate_crash.h
index 68c84e5..18af98f3 100644
--- a/third_party/crashpad/crashpad/client/simulate_crash.h
+++ b/third_party/crashpad/crashpad/client/simulate_crash.h
@@ -21,7 +21,7 @@
 #include "client/simulate_crash_mac.h"
 #elif defined(OS_WIN)
 #include "client/simulate_crash_win.h"
-#elif defined(OS_LINUX) || defined(OS_ANDROID)
+#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
 #include "client/simulate_crash_linux.h"
 #endif
 
diff --git a/third_party/crashpad/crashpad/compat/BUILD.gn b/third_party/crashpad/crashpad/compat/BUILD.gn
index f2ffcf5..d98a6a6e 100644
--- a/third_party/crashpad/crashpad/compat/BUILD.gn
+++ b/third_party/crashpad/crashpad/compat/BUILD.gn
@@ -57,10 +57,17 @@
     # static_library.
     group(target_name) {
       forward_variables_from(invoker, "*")
+      not_needed([ "configs" ])
     }
   } else {
     static_library(target_name) {
-      forward_variables_from(invoker, "*")
+      forward_variables_from(invoker, "*", [ "configs" ])
+      if (!(defined(configs))) {
+        configs = []
+      }
+      if (defined(invoker.configs)) {
+        configs += invoker.configs
+      }
     }
   }
 }
@@ -70,7 +77,8 @@
 
   if (crashpad_is_mac || crashpad_is_ios) {
     sources += [
-      "mac/AvailabilityMacros.h",
+      "mac/Availability.h",
+      "mac/AvailabilityVersions.h",
       "mac/kern/exc_resource.h",
       "mac/mach-o/loader.h",
       "mac/mach/i386/thread_state.h",
@@ -171,4 +179,8 @@
   if (!crashpad_is_linux && !crashpad_is_android && !crashpad_is_fuchsia) {
     deps += [ "../third_party/glibc" ]
   }
+
+  if (crashpad_is_in_fuchsia) {
+    configs = [ "//build/config:Wno-conversion" ]
+  }
 }
diff --git a/third_party/crashpad/crashpad/compat/compat.gyp b/third_party/crashpad/crashpad/compat/compat.gyp
index b99d690..1c2eeaf4 100644
--- a/third_party/crashpad/crashpad/compat/compat.gyp
+++ b/third_party/crashpad/crashpad/compat/compat.gyp
@@ -38,7 +38,8 @@
         'linux/signal.h',
         'linux/sys/ptrace.h',
         'linux/sys/user.h',
-        'mac/AvailabilityMacros.h',
+        'mac/Availability.h',
+        'mac/AvailabilityVersions.h',
         'mac/kern/exc_resource.h',
         'mac/mach/i386/thread_state.h',
         'mac/mach/mach.h',
diff --git a/third_party/crashpad/crashpad/compat/mac/Availability.h b/third_party/crashpad/crashpad/compat/mac/Availability.h
new file mode 100644
index 0000000..b8f8f2d
--- /dev/null
+++ b/third_party/crashpad/crashpad/compat/mac/Availability.h
@@ -0,0 +1,28 @@
+// Copyright 2020 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef CRASHPAD_COMPAT_MAC_AVAILABILITY_H_
+#define CRASHPAD_COMPAT_MAC_AVAILABILITY_H_
+
+// Until the 10.15 SDK, the contents of <AvailabilityVersions.h> was in-line in
+// <Availability.h>, but since then, it was broken out into its own header.
+// This compat version of <Availability.h> allows these macros to always appear
+// to be provided by the new header, <AvailabilityVersions.h>, even when an
+// older SDK is in use.
+
+#include_next <Availability.h>
+
+#include <AvailabilityVersions.h>
+
+#endif  // CRASHPAD_COMPAT_MAC_AVAILABILITY_H_
diff --git a/third_party/crashpad/crashpad/compat/mac/AvailabilityMacros.h b/third_party/crashpad/crashpad/compat/mac/AvailabilityMacros.h
deleted file mode 100644
index a83d2a4..0000000
--- a/third_party/crashpad/crashpad/compat/mac/AvailabilityMacros.h
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2014 The Crashpad Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef CRASHPAD_COMPAT_MAC_AVAILABILITYMACROS_H_
-#define CRASHPAD_COMPAT_MAC_AVAILABILITYMACROS_H_
-
-#include_next <AvailabilityMacros.h>
-
-// 10.7 SDK
-
-#ifndef MAC_OS_X_VERSION_10_7
-#define MAC_OS_X_VERSION_10_7 1070
-#endif
-
-// 10.8 SDK
-
-#ifndef MAC_OS_X_VERSION_10_8
-#define MAC_OS_X_VERSION_10_8 1080
-#endif
-
-// 10.9 SDK
-
-#ifndef MAC_OS_X_VERSION_10_9
-#define MAC_OS_X_VERSION_10_9 1090
-#endif
-
-// 10.10 SDK
-
-#ifndef MAC_OS_X_VERSION_10_10
-#define MAC_OS_X_VERSION_10_10 101000
-#endif
-
-// 10.11 SDK
-
-#ifndef MAC_OS_X_VERSION_10_11
-#define MAC_OS_X_VERSION_10_11 101100
-#endif
-
-// 10.12 SDK
-
-#ifndef MAC_OS_X_VERSION_10_12
-#define MAC_OS_X_VERSION_10_12 101200
-#endif
-
-// 10.13 SDK
-
-#ifndef MAC_OS_X_VERSION_10_13
-#define MAC_OS_X_VERSION_10_13 101300
-#endif
-
-// 10.14 SDK
-
-#ifndef MAC_OS_X_VERSION_10_14
-#define MAC_OS_X_VERSION_10_14 101400
-#endif
-
-// 10.15 SDK
-
-#ifndef MAC_OS_X_VERSION_10_15
-#define MAC_OS_X_VERSION_10_15 101500
-#endif
-
-#endif  // CRASHPAD_COMPAT_MAC_AVAILABILITYMACROS_H_
diff --git a/third_party/crashpad/crashpad/compat/mac/AvailabilityVersions.h b/third_party/crashpad/crashpad/compat/mac/AvailabilityVersions.h
new file mode 100644
index 0000000..0bedb3d
--- /dev/null
+++ b/third_party/crashpad/crashpad/compat/mac/AvailabilityVersions.h
@@ -0,0 +1,90 @@
+// Copyright 2020 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef CRASHPAD_COMPAT_MAC_AVAILABILITYVERSIONS_H_
+#define CRASHPAD_COMPAT_MAC_AVAILABILITYVERSIONS_H_
+
+#if __has_include_next(<AvailabilityVersions.h>)
+#include_next <AvailabilityVersions.h>
+#endif
+
+// 10.7 SDK
+
+#ifndef __MAC_10_7
+#define __MAC_10_7 1070
+#endif
+
+// 10.8 SDK
+
+#ifndef __MAC_10_8
+#define __MAC_10_8 1080
+#endif
+
+// 10.9 SDK
+
+#ifndef __MAC_10_9
+#define __MAC_10_9 1090
+#endif
+
+// 10.10 SDK
+
+#ifndef __MAC_10_10
+#define __MAC_10_10 101000
+#endif
+
+// 10.11 SDK
+
+#ifndef __MAC_10_11
+#define __MAC_10_11 101100
+#endif
+
+// 10.12 SDK
+
+#ifndef __MAC_10_12
+#define __MAC_10_12 101200
+#endif
+
+// 10.13 SDK
+
+#ifndef __MAC_10_13
+#define __MAC_10_13 101300
+#endif
+
+#ifndef __MAC_10_13_4
+#define __MAC_10_13_4 101304
+#endif
+
+// 10.14 SDK
+
+#ifndef __MAC_10_14
+#define __MAC_10_14 101400
+#endif
+
+// 10.15 SDK
+
+#ifndef __MAC_10_15
+#define __MAC_10_15 101500
+#endif
+
+// 11.0 SDK
+
+#ifndef __MAC_10_16
+#define __MAC_10_16 101600
+#endif
+
+#ifndef __MAC_11_0
+#define __MAC_11_0 110000
+#endif
+
+#endif  // CRASHPAD_COMPAT_MAC_AVAILABILITYVERSIONS_H_
diff --git a/third_party/crashpad/crashpad/handler/BUILD.gn b/third_party/crashpad/crashpad/handler/BUILD.gn
index 54af697..dc481784 100644
--- a/third_party/crashpad/crashpad/handler/BUILD.gn
+++ b/third_party/crashpad/crashpad/handler/BUILD.gn
@@ -185,9 +185,9 @@
 
     if (crashpad_is_in_chromium) {
       no_default_deps = true
+      remove_configs =
+          [ "//build/config/android:default_orderfile_instrumentation" ]
     }
-    remove_configs =
-        [ "//build/config/android:default_orderfile_instrumentation" ]
   }
 }
 
diff --git a/third_party/crashpad/crashpad/handler/handler_main.cc b/third_party/crashpad/crashpad/handler/handler_main.cc
index c8001f45..f3730e8 100644
--- a/third_party/crashpad/crashpad/handler/handler_main.cc
+++ b/third_party/crashpad/crashpad/handler/handler_main.cc
@@ -60,7 +60,7 @@
 #include "handler/linux/cros_crash_report_exception_handler.h"
 #endif
 
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
 #include <unistd.h>
 
 #include "handler/linux/crash_report_exception_handler.h"
@@ -86,9 +86,6 @@
 #include "util/win/handle.h"
 #include "util/win/initial_client_data.h"
 #include "util/win/session_end_watcher.h"
-#elif defined(OS_LINUX)
-#include "handler/linux/crash_report_exception_handler.h"
-#include "handler/linux/exception_handler_server.h"
 #endif  // OS_APPLE
 
 namespace crashpad {
@@ -125,9 +122,9 @@
 "                            Address_debug_critical_section\n"
 "                              use precreated data to register initial client\n"
 #endif  // OS_WIN
-#if defined(OS_ANDROID) || defined(OS_LINUX)
+#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
 "      --initial-client-fd=FD  a socket connected to a client.\n"
-#endif  // OS_ANDROID || OS_LINUX
+#endif  // OS_ANDROID || OS_LINUX || OS_CHROMEOS
 #if defined(OS_APPLE)
 "      --mach-service=SERVICE  register SERVICE with the bootstrap server\n"
 #endif  // OS_APPLE
@@ -154,7 +151,7 @@
 "      --reset-own-crash-exception-port-to-system-default\n"
 "                              reset the server's exception handler to default\n"
 #endif  // OS_APPLE
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
 "      --sanitization-information=SANITIZATION_INFORMATION_ADDRESS\n"
 "                              the address of a SanitizationInformation struct.\n"
 "      --shared-client-connection the file descriptor provided by\n"
@@ -162,7 +159,7 @@
 "                              clients\n"
 "      --trace-parent-with-exception=EXCEPTION_INFORMATION_ADDRESS\n"
 "                              request a dump for the handler's parent process\n"
-#endif  // OS_LINUX || OS_ANDROID
+#endif  // OS_LINUX || OS_CHROMEOS || OS_ANDROID
 "      --url=URL               send crash reports to this Breakpad server URL,\n"
 "                              only if uploads are enabled for the database\n"
 #if defined(OS_CHROMEOS)
@@ -197,7 +194,7 @@
   std::string mach_service;
   int handshake_fd;
   bool reset_own_crash_exception_port_to_system_default;
-#elif defined(OS_LINUX) || defined(OS_ANDROID)
+#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
   VMAddress exception_information_address;
   VMAddress sanitization_information_address;
   int initial_client_fd;
@@ -280,7 +277,8 @@
   DISALLOW_COPY_AND_ASSIGN(CallMetricsRecordNormalExit);
 };
 
-#if defined(OS_APPLE) || defined(OS_LINUX) || defined(OS_ANDROID)
+#if defined(OS_APPLE) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
+  defined(OS_ANDROID)
 
 void HandleCrashSignal(int sig, siginfo_t* siginfo, void* context) {
   MetricsRecordExit(Metrics::LifetimeMilestone::kCrashed);
@@ -539,9 +537,9 @@
 #if defined(OS_WIN)
     kOptionInitialClientData,
 #endif  // OS_WIN
-#if defined(OS_ANDROID) || defined(OS_LINUX)
+#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
     kOptionInitialClientFD,
-#endif  // OS_ANDROID || OS_LINUX
+#endif  // OS_ANDROID || OS_LINUX || OS_CHROMEOS
 #if defined(OS_APPLE)
     kOptionMachService,
 #endif  // OS_APPLE
@@ -562,7 +560,7 @@
 #if defined(OS_APPLE)
     kOptionResetOwnCrashExceptionPortToSystemDefault,
 #endif  // OS_APPLE
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
     kOptionSanitizationInformation,
     kOptionSharedClientConnection,
     kOptionTraceParentWithException,
@@ -597,9 +595,9 @@
      nullptr,
      kOptionInitialClientData},
 #endif  // OS_APPLE
-#if defined(OS_ANDROID) || defined(OS_LINUX)
+#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
     {"initial-client-fd", required_argument, nullptr, kOptionInitialClientFD},
-#endif  // OS_ANDROID || OS_LINUX
+#endif  // OS_ANDROID || OS_LINUX || OS_CHROMEOS
 #if defined(OS_APPLE)
     {"mach-service", required_argument, nullptr, kOptionMachService},
 #endif  // OS_APPLE
@@ -635,7 +633,7 @@
      nullptr,
      kOptionResetOwnCrashExceptionPortToSystemDefault},
 #endif  // OS_APPLE
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
     {"sanitization-information",
      required_argument,
      nullptr,
@@ -648,7 +646,7 @@
      required_argument,
      nullptr,
      kOptionTraceParentWithException},
-#endif  // OS_LINUX || OS_ANDROID
+#endif  // OS_LINUX || OS_CHROMEOS || OS_ANDROID
     {"url", required_argument, nullptr, kOptionURL},
 #if defined(OS_CHROMEOS)
     {"use-cros-crash-reporter",
@@ -677,7 +675,7 @@
   options.handshake_fd = -1;
 #endif
   options.identify_client_via_url = true;
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
   options.initial_client_fd = kInvalidFileHandle;
 #endif
   options.periodic_tasks = true;
@@ -733,7 +731,7 @@
         break;
       }
 #endif  // OS_WIN
-#if defined(OS_ANDROID) || defined(OS_LINUX)
+#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
       case kOptionInitialClientFD: {
         if (!base::StringToInt(optarg, &options.initial_client_fd)) {
           ToolSupport::UsageHint(me, "failed to parse --initial-client-fd");
@@ -741,7 +739,7 @@
         }
         break;
       }
-#endif  // OS_ANDROID || OS_LINUX
+#endif  // OS_ANDROID || OS_LINUX || OS_CHROMEOS
       case kOptionMetrics: {
         options.metrics_dir = base::FilePath(
             ToolSupport::CommandLineArgumentToFilePathStringType(optarg));
@@ -797,7 +795,7 @@
         break;
       }
 #endif  // OS_APPLE
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
       case kOptionSanitizationInformation: {
         if (!StringToNumber(optarg,
                             &options.sanitization_information_address)) {
@@ -819,7 +817,7 @@
         }
         break;
       }
-#endif  // OS_LINUX || OS_ANDROID
+#endif  // OS_LINUX || OS_CHROMEOS || OS_ANDROID
       case kOptionURL: {
         options.url = optarg;
         break;
@@ -885,7 +883,7 @@
         me, "--initial-client-data and --pipe-name are incompatible");
     return ExitFailure();
   }
-#elif defined(OS_LINUX) || defined(OS_ANDROID)
+#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
   if (!options.exception_information_address &&
       options.initial_client_fd == kInvalidFileHandle) {
     ToolSupport::UsageHint(
@@ -978,7 +976,7 @@
     upload_thread.Get()->Start();
   }
 
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
   std::unique_ptr<ExceptionHandlerServer::Delegate> exception_handler;
 #else
   std::unique_ptr<CrashReportExceptionHandler> exception_handler;
@@ -1029,7 +1027,7 @@
       user_stream_sources);
 #endif  // OS_CHROMEOS
 
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
   if (options.exception_information_address) {
     ExceptionHandlerProtocol::ClientInformation info;
     info.exception_information_address = options.exception_information_address;
@@ -1039,7 +1037,7 @@
                ? EXIT_SUCCESS
                : ExitFailure();
   }
-#endif  // OS_LINUX || OS_ANDROID
+#endif  // OS_LINUX || OS_CHROMEOS || OS_ANDROID
 
   ScopedStoppable prune_thread;
   if (options.periodic_tasks) {
@@ -1101,7 +1099,7 @@
   if (!options.pipe_name.empty()) {
     exception_handler_server.SetPipeName(base::UTF8ToUTF16(options.pipe_name));
   }
-#elif defined(OS_LINUX) || defined(OS_ANDROID)
+#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
   ExceptionHandlerServer exception_handler_server;
 #endif  // OS_APPLE
 
@@ -1123,7 +1121,7 @@
     exception_handler_server.InitializeWithInheritedDataForInitialClient(
         options.initial_client_data, exception_handler.get());
   }
-#elif defined(OS_LINUX) || defined(OS_ANDROID)
+#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
   if (options.initial_client_fd == kInvalidFileHandle ||
       !exception_handler_server.InitializeWithClient(
           ScopedFileHandle(options.initial_client_fd),
diff --git a/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.cc b/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.cc
index d2d85115..e17962cd 100644
--- a/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.cc
+++ b/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.cc
@@ -16,6 +16,7 @@
 
 #include <limits>
 
+#include "base/check_op.h"
 #include "base/logging.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/stl_util.h"
@@ -30,8 +31,8 @@
 #include "util/numeric/in_range_cast.h"
 #include "util/numeric/safe_assignment.h"
 
-#if defined(OS_APPLE)
-#include <AvailabilityMacros.h>
+#if defined(OS_MAC)
+#include <Availability.h>
 #elif defined(OS_ANDROID)
 #include <android/api-level.h>
 #endif
@@ -66,28 +67,34 @@
   return machine_description;
 }
 
-#if defined(OS_APPLE)
-// Converts the value of the MAC_OS_VERSION_MIN_REQUIRED or
-// MAC_OS_X_VERSION_MAX_ALLOWED macro from <AvailabilityMacros.h> to a number
-// identifying the minor macOS version that it represents. For example, with an
-// argument of MAC_OS_X_VERSION_10_6, this function will return 6.
-int AvailabilityVersionToMacOSXMinorVersion(int availability) {
-  // Through MAC_OS_X_VERSION_10_9, the minor version is the tens digit.
-  if (availability >= 1000 && availability <= 1099) {
-    return (availability / 10) % 10;
-  }
+#if defined(OS_MAC)
+// Converts the value of the __MAC_OS_X_VERSION_MIN_REQUIRED or
+// __MAC_OS_X_VERSION_MAX_ALLOWED macro from <Availability.h> to a number
+// identifying the macOS version that it represents, in the same format used by
+// MacOSVersionNumber(). For example, with an argument of __MAC_10_15, this
+// function will return 10'15'00, which is incidentally the same as __MAC_10_15.
+// With an argument of __MAC_10_9, this function will return 10'09'00, different
+// from __MAC_10_9, which is 10'9'0.
+int AvailabilityVersionToMacOSVersionNumber(int availability) {
+#if __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_10
+  DCHECK_GE(availability, 10'0'0);
 
-  // After MAC_OS_X_VERSION_10_9, the older format was insufficient to represent
-  // versions. Since then, the minor version is the thousands and hundreds
-  // digits.
-  if (availability >= 100000 && availability <= 109999) {
-    return (availability / 100) % 100;
+  // Until __MAC_10_10, the format is major * 1'0'0 + minor * 1'0 + bugfix.
+  if (availability >= 10'0'0 && availability <= 10'9'9) {
+    int minor = (availability / 1'0) % 1'0;
+    int bugfix = availability % 1'0;
+    return 10'00'00 + minor * 1'00 + bugfix;
   }
-
-  return 0;
-}
 #endif
 
+  // Since __MAC_10_10, the format is major * 1'00'00 + minor * 1'00 + bugfix.
+  DCHECK_GE(availability, 10'10'00);
+  DCHECK_LE(availability, 99'99'99);
+
+  return availability;
+}
+#endif  // OS_MAC
+
 }  // namespace
 
 namespace internal {
@@ -100,11 +107,13 @@
   // Caution: the minidump file format only has room for 39 UTF-16 code units
   // plus a UTF-16 NUL terminator. Don’t let strings get longer than this, or
   // they will be truncated and a message will be logged.
-#if defined(OS_APPLE)
+#if defined(OS_MAC)
   static constexpr char kOS[] = "mac";
+#elif defined(OS_IOS)
+  static constexpr char kOS[] = "ios";
 #elif defined(OS_ANDROID)
   static constexpr char kOS[] = "android";
-#elif defined(OS_LINUX)
+#elif defined(OS_LINUX) || defined(OS_CHROMEOS)
   static constexpr char kOS[] = "linux";
 #elif defined(OS_WIN)
   static constexpr char kOS[] = "win";
@@ -136,11 +145,11 @@
                                                       PACKAGE_VERSION,
                                                       kOS);
 
-#if defined(OS_APPLE)
+#if defined(OS_MAC)
   debug_build_string += base::StringPrintf(
       ",%d,%d",
-      AvailabilityVersionToMacOSXMinorVersion(MAC_OS_X_VERSION_MIN_REQUIRED),
-      AvailabilityVersionToMacOSXMinorVersion(MAC_OS_X_VERSION_MAX_ALLOWED));
+      AvailabilityVersionToMacOSVersionNumber(__MAC_OS_X_VERSION_MIN_REQUIRED),
+      AvailabilityVersionToMacOSVersionNumber(__MAC_OS_X_VERSION_MAX_ALLOWED));
 #elif defined(OS_ANDROID)
   debug_build_string += base::StringPrintf(",%d", __ANDROID_API__);
 #endif
diff --git a/third_party/crashpad/crashpad/snapshot/BUILD.gn b/third_party/crashpad/crashpad/snapshot/BUILD.gn
index 8615c99..0b452ca 100644
--- a/third_party/crashpad/crashpad/snapshot/BUILD.gn
+++ b/third_party/crashpad/crashpad/snapshot/BUILD.gn
@@ -232,7 +232,8 @@
     ]
   }
 
-  if (current_cpu == "x86" || current_cpu == "x64") {
+  if (current_cpu == "x86" || current_cpu == "x64" ||
+      (crashpad_is_mac && current_cpu == "mac_universal")) {
     sources += [
       "x86/cpuid_reader.cc",
       "x86/cpuid_reader.h",
@@ -261,6 +262,10 @@
   }
 
   configs += [ "..:disable_ubsan" ]
+
+  if (crashpad_is_in_fuchsia) {
+    configs += [ "//build/config:Wno-conversion" ]
+  }
 }
 
 # :context is the only part of snapshot that minidump may depend on.
@@ -281,6 +286,10 @@
   if (crashpad_is_win) {
     cflags = [ "/wd4201" ]  # nonstandard extension used : nameless struct/union
   }
+
+  if (crashpad_is_in_fuchsia) {
+    configs += [ "//build/config:Wno-conversion" ]
+  }
 }
 
 if (crashpad_is_linux) {
diff --git a/third_party/crashpad/crashpad/snapshot/crashpad_types/crashpad_info_reader.cc b/third_party/crashpad/crashpad/snapshot/crashpad_types/crashpad_info_reader.cc
index 9d0c781..cedab59a 100644
--- a/third_party/crashpad/crashpad/snapshot/crashpad_types/crashpad_info_reader.cc
+++ b/third_party/crashpad/crashpad/snapshot/crashpad_types/crashpad_info_reader.cc
@@ -22,7 +22,7 @@
 
 #if defined(OS_WIN)
 #include "util/win/traits.h"
-#elif defined(OS_LINUX) || defined(OS_ANDROID)
+#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
 #include "util/linux/traits.h"
 #elif defined(OS_FUCHSIA)
 #include "util/fuchsia/traits.h"
diff --git a/third_party/crashpad/crashpad/snapshot/elf/elf_image_reader_test.cc b/third_party/crashpad/crashpad/snapshot/elf/elf_image_reader_test.cc
index 34235a7d..63da92a 100644
--- a/third_party/crashpad/crashpad/snapshot/elf/elf_image_reader_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/elf/elf_image_reader_test.cc
@@ -35,7 +35,7 @@
 
 #include "base/fuchsia/fuchsia_logging.h"
 
-#elif defined(OS_LINUX) || defined(OS_ANDROID)
+#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
 
 #include "test/linux/fake_ptrace_connection.h"
 #include "util/linux/auxiliary_vector.h"
@@ -84,7 +84,7 @@
   *elf_address = base;
 }
 
-#elif defined(OS_LINUX) || defined(OS_ANDROID)
+#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
 
 void LocateExecutable(PtraceConnection* connection,
                       ProcessMemory* memory,
@@ -133,7 +133,7 @@
   ASSERT_TRUE(range.Initialize(&memory, am_64_bit));
 
   VMAddress elf_address;
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
   FakePtraceConnection connection;
   ASSERT_TRUE(connection.Initialize(process));
   LocateExecutable(&connection, &memory, &elf_address);
diff --git a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_annotations_reader_test.cc b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_annotations_reader_test.cc
index 8659a14..aea885a 100644
--- a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_annotations_reader_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_annotations_reader_test.cc
@@ -112,9 +112,7 @@
         break;
 
       case kCrashModuleInitialization:
-        // This crash is triggered by __builtin_trap(), which shows up as
-        // SIGILL.
-        SetExpectedChildTermination(kTerminationSignal, SIGILL);
+        SetExpectedChildTerminationBuiltinTrap();
         break;
 
       case kCrashDyld:
@@ -124,7 +122,8 @@
         // _dyld_fatal_error. This changed in 10.12 to use
         // abort_with_payload(), which appears as SIGABRT to a waiting parent.
         SetExpectedChildTermination(
-            kTerminationSignal, MacOSXMinorVersion() < 12 ? SIGTRAP : SIGABRT);
+            kTerminationSignal,
+            MacOSVersionNumber() < 10'12'00 ? SIGTRAP : SIGABRT);
         break;
     }
   }
@@ -186,8 +185,8 @@
       // Mac OS X 10.6 doesn’t have support for CrashReporter annotations
       // (CrashReporterClient.h), so don’t look for any special annotations in
       // that version.
-      int mac_os_x_minor_version = MacOSXMinorVersion();
-      if (mac_os_x_minor_version > 7) {
+      const int macos_version_number = MacOSVersionNumber();
+      if (macos_version_number > 10'07'00) {
         EXPECT_GE(all_annotations_vector.size(), 1u);
 
         std::string expected_annotation;
@@ -204,7 +203,7 @@
             // exec() occurred. See 10.9.5 Libc-997.90.3/sys/_libc_fork_child.c
             // _libc_fork_child().
             expected_annotation =
-                mac_os_x_minor_version <= 8
+                macos_version_number <= 10'08'00
                     ? "abort() called"
                     : "crashed on child side of fork pre-exec";
             break;
diff --git a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_reader_test.cc b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_reader_test.cc
index 53826bf..f1f3b1de 100644
--- a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_reader_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_reader_test.cc
@@ -14,7 +14,7 @@
 
 #include "snapshot/mac/mach_o_image_reader.h"
 
-#include <AvailabilityMacros.h>
+#include <Availability.h>
 #include <dlfcn.h>
 #include <mach-o/dyld.h>
 #include <mach-o/dyld_images.h>
@@ -606,7 +606,7 @@
     ASSERT_NO_FATAL_FAILURE(ExpectSymbolTable(mach_header, &image_reader));
   }
 
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_7
   // If dyld is new enough to record UUIDs, check the UUID of any module that
   // it says has one. Note that dyld doesn’t record UUIDs of anything that
   // loaded out of the shared cache, but it should at least have a UUID for the
diff --git a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_segment_reader.cc b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_segment_reader.cc
index 478b37d..1d7d429f4 100644
--- a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_segment_reader.cc
+++ b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_segment_reader.cc
@@ -14,6 +14,7 @@
 
 #include "snapshot/mac/mach_o_image_segment_reader.h"
 
+#include <Availability.h>
 #include <mach-o/loader.h>
 #include <string.h>
 
@@ -21,6 +22,7 @@
 
 #include "base/logging.h"
 #include "base/strings/stringprintf.h"
+#include "build/build_config.h"
 #include "snapshot/mac/process_reader_mac.h"
 #include "util/mac/checked_mach_address_range.h"
 #include "util/mac/mac_util.h"
@@ -39,12 +41,14 @@
 bool IsMalformedCLKernelsModule(uint32_t mach_o_file_type,
                                 const std::string& module_name,
                                 bool* has_timestamp) {
+#if defined(ARCH_CPU_X86_FAMILY)
   if (mach_o_file_type != MH_BUNDLE) {
     return false;
   }
 
   if (module_name == "cl_kernels") {
-    if (MacOSXMinorVersion() >= 10) {
+    if (__MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_10 ||
+        MacOSVersionNumber() >= 10'10'00) {
       if (has_timestamp) {
         *has_timestamp = false;
       }
@@ -57,12 +61,14 @@
       "/private/var/db/CVMS/cvmsCodeSignObj";
   if (module_name.compare(
           0, strlen(kCvmsObjectPathPrefix), kCvmsObjectPathPrefix) == 0 &&
-      MacOSXMinorVersion() >= 14) {
+      (__MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_14 ||
+       MacOSVersionNumber() >= 10'14'00)) {
     if (has_timestamp) {
       *has_timestamp = true;
     }
     return true;
   }
+#endif  // ARCH_CPU_X86_FAMILY
 
   return false;
 }
diff --git a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_segment_reader.h b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_segment_reader.h
index 1e72785..708cc37d5 100644
--- a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_segment_reader.h
+++ b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_segment_reader.h
@@ -46,6 +46,9 @@
 //! information stored in `MH_OBJECT` images, although `cl_kernels` images claim
 //! to be `MH_BUNDLE`.
 //!
+//! These `cl_kernels` modules have only been observed on x86, not on arm64.
+//! This function always returns `false` on arm64.
+//!
 //! This function is exposed for testing purposes only.
 //!
 //! \param[in] mach_o_file_type The Mach-O type of the module being examined.
diff --git a/third_party/crashpad/crashpad/snapshot/mac/process_reader_mac.cc b/third_party/crashpad/crashpad/snapshot/mac/process_reader_mac.cc
index ca2c1f7..821fe3c 100644
--- a/third_party/crashpad/crashpad/snapshot/mac/process_reader_mac.cc
+++ b/third_party/crashpad/crashpad/snapshot/mac/process_reader_mac.cc
@@ -14,7 +14,7 @@
 
 #include "snapshot/mac/process_reader_mac.h"
 
-#include <AvailabilityMacros.h>
+#include <Availability.h>
 #include <mach-o/loader.h>
 #include <mach/mach_vm.h>
 
@@ -95,9 +95,12 @@
       process_memory_(),
       task_(TASK_NULL),
       initialized_(),
+#if defined(CRASHPAD_MAC_32_BIT_SUPPORT)
       is_64_bit_(false),
+#endif  // CRASHPAD_MAC_32_BIT_SUPPORT
       initialized_threads_(false),
-      initialized_modules_(false) {}
+      initialized_modules_(false) {
+}
 
 ProcessReaderMac::~ProcessReaderMac() {
   for (const Thread& thread : threads_) {
@@ -117,7 +120,12 @@
     return false;
   }
 
+#if defined(CRASHPAD_MAC_32_BIT_SUPPORT)
   is_64_bit_ = process_info_.Is64Bit();
+#else  // CRASHPAD_MAC_32_BIT_SUPPORT
+  DCHECK(process_info_.Is64Bit());
+#endif  // CRASHPAD_MAC_32_BIT_SUPPORT
+
   task_ = task;
 
   INITIALIZATION_STATE_SET_VALID(initialized_);
@@ -213,7 +221,7 @@
 // This may look for the module that matches the executable path in the same
 // data set that vmmap uses.
 
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_7
   // The task_dyld_info_data_t struct grew in 10.7, adding the format field.
   // Don’t check this field if it’s not present, which can happen when either
   // the SDK used at compile time or the kernel at run time are too old and
diff --git a/third_party/crashpad/crashpad/snapshot/mac/process_reader_mac.h b/third_party/crashpad/crashpad/snapshot/mac/process_reader_mac.h
index ac57a061..2f8ea9dc 100644
--- a/third_party/crashpad/crashpad/snapshot/mac/process_reader_mac.h
+++ b/third_party/crashpad/crashpad/snapshot/mac/process_reader_mac.h
@@ -15,6 +15,7 @@
 #ifndef CRASHPAD_SNAPSHOT_MAC_PROCESS_READER_MAC_H_
 #define CRASHPAD_SNAPSHOT_MAC_PROCESS_READER_MAC_H_
 
+#include <Availability.h>
 #include <mach/mach.h>
 #include <stdint.h>
 #include <sys/time.h>
@@ -31,6 +32,14 @@
 #include "util/posix/process_info.h"
 #include "util/process/process_memory_mac.h"
 
+#if defined(ARCH_CPU_32_BIT) ||  \
+    (!defined(ARCH_CPU_ARM64) && \
+     __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_15)
+// There’s no 32-bit x86 environment on macOS 10.15 or later, and there’s no
+// 32-bit ARM environment for macOS at all.
+#define CRASHPAD_MAC_32_BIT_SUPPORT 1
+#endif  // ARCH_CPU_32_BIT || (!ARCH_CPU_ARM64 && DT < 10.15)
+
 namespace crashpad {
 
 class MachOImageReader;
@@ -116,7 +125,11 @@
   bool Initialize(task_t task);
 
   //! \return `true` if the target task is a 64-bit process.
+#if defined(CRASHPAD_MAC_32_BIT_SUPPORT) || DOXYGEN
   bool Is64Bit() const { return is_64_bit_; }
+#else  // CRASHPAD_MAC_32_BIT_SUPPORT
+  bool Is64Bit() const { return true; }
+#endif  // CRASHPAD_MAC_32_BIT_SUPPORT
 
   //! \return The target task’s process ID.
   pid_t ProcessID() const { return process_info_.ProcessID(); }
@@ -240,10 +253,12 @@
   task_t task_;  // weak
   InitializationStateDcheck initialized_;
 
+#if defined(CRASHPAD_MAC_32_BIT_SUPPORT)
   // This shadows a method of process_info_, but it’s accessed so frequently
   // that it’s given a first-class field to save a call and a few bit operations
   // on each access.
   bool is_64_bit_;
+#endif  // CRASHPAD_MAC_32_BIT_SUPPORT
 
   bool initialized_threads_;
   bool initialized_modules_;
diff --git a/third_party/crashpad/crashpad/snapshot/mac/process_reader_mac_test.cc b/third_party/crashpad/crashpad/snapshot/mac/process_reader_mac_test.cc
index 2d64ff1..a85eeb2 100644
--- a/third_party/crashpad/crashpad/snapshot/mac/process_reader_mac_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/mac/process_reader_mac_test.cc
@@ -14,19 +14,22 @@
 
 #include "snapshot/mac/process_reader_mac.h"
 
-#include <AvailabilityMacros.h>
-#include <errno.h>
+#include <Availability.h>
 #include <OpenCL/opencl.h>
+#include <dlfcn.h>
+#include <errno.h>
 #include <mach-o/dyld.h>
 #include <mach-o/dyld_images.h>
 #include <mach/mach.h>
 #include <string.h>
 #include <sys/stat.h>
+#include <sys/types.h>
 
 #include <map>
 #include <utility>
 
 #include "base/check_op.h"
+#include "base/logging.h"
 #include "base/mac/mach_logging.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/stl_util.h"
@@ -530,6 +533,75 @@
   process_reader_threaded_child.Run();
 }
 
+template <typename T>
+T GetDyldFunction(const char* symbol) {
+  static void* dl_handle = []() -> void* {
+    Dl_info dl_info;
+    if (!dladdr(reinterpret_cast<void*>(dlopen), &dl_info)) {
+      LOG(ERROR) << "dladdr: failed";
+      return nullptr;
+    }
+
+    void* dl_handle =
+        dlopen(dl_info.dli_fname, RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
+    DCHECK(dl_handle) << "dlopen: " << dlerror();
+
+    return dl_handle;
+  }();
+
+  if (!dl_handle) {
+    return nullptr;
+  }
+
+  return reinterpret_cast<T>(dlsym(dl_handle, symbol));
+}
+
+void VerifyImageExistenceAndTimestamp(const char* path, time_t timestamp) {
+  const char* stat_path;
+  bool timestamp_may_be_0;
+
+#if __MAC_OS_X_VERSION_MAX_ALLOWED < __MAC_10_16
+  static auto _dyld_shared_cache_contains_path =
+      GetDyldFunction<bool (*)(const char*)>(
+          "_dyld_shared_cache_contains_path");
+#endif
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunguarded-availability"
+  if (_dyld_shared_cache_contains_path &&
+      _dyld_shared_cache_contains_path(path)) {
+#pragma clang diagnostic pop
+    // The timestamp will either match the timestamp of the dyld_shared_cache
+    // file in use, or be 0.
+    static const char* dyld_shared_cache_file_path = []() -> const char* {
+      auto dyld_shared_cache_file_path_f =
+          GetDyldFunction<const char* (*)()>("dyld_shared_cache_file_path");
+
+      // dyld_shared_cache_file_path should always be present if
+      // _dyld_shared_cache_contains_path is.
+      DCHECK(dyld_shared_cache_file_path_f);
+
+      const char* dyld_shared_cache_file_path = dyld_shared_cache_file_path_f();
+      DCHECK(dyld_shared_cache_file_path);
+
+      return dyld_shared_cache_file_path;
+    }();
+
+    stat_path = dyld_shared_cache_file_path;
+    timestamp_may_be_0 = true;
+  } else {
+    stat_path = path;
+    timestamp_may_be_0 = false;
+  }
+
+  struct stat stat_buf;
+  int rv = stat(stat_path, &stat_buf);
+  EXPECT_EQ(rv, 0) << ErrnoMessage("stat");
+  if (rv == 0 && (!timestamp_may_be_0 || timestamp != 0)) {
+    EXPECT_EQ(timestamp, stat_buf.st_mtime);
+  }
+}
+
 // cl_kernels images (OpenCL kernels) are weird. They’re not ld output and don’t
 // exist as files on disk. On OS X 10.10 and 10.11, their Mach-O structure isn’t
 // perfect. They show up loaded into many executables, so these quirks should be
@@ -545,7 +617,10 @@
 class ScopedOpenCLNoOpKernel {
  public:
   ScopedOpenCLNoOpKernel()
-      : context_(nullptr), program_(nullptr), kernel_(nullptr) {}
+      : context_(nullptr),
+        program_(nullptr),
+        kernel_(nullptr),
+        success_(false) {}
 
   ~ScopedOpenCLNoOpKernel() {
     if (kernel_) {
@@ -569,12 +644,12 @@
     cl_int rv = clGetPlatformIDs(1, &platform_id, nullptr);
     ASSERT_EQ(rv, CL_SUCCESS) << "clGetPlatformIDs";
 
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10 && \
-    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10
-// cl_device_id is really available in OpenCL.framework back to 10.5, but in
-// the 10.10 SDK and later, OpenCL.framework includes <OpenGL/CGLDevice.h>,
-// which has its own cl_device_id that was introduced in 10.10. That
-// triggers erroneous availability warnings.
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_10 && \
+    __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_10
+    // cl_device_id is really available in OpenCL.framework back to 10.5, but in
+    // the 10.10 SDK and later, OpenCL.framework includes <OpenGL/CGLDevice.h>,
+    // which has its own cl_device_id that was introduced in 10.10. That
+    // triggers erroneous availability warnings.
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wunguarded-availability"
 #define DISABLED_WUNGUARDED_AVAILABILITY
@@ -589,6 +664,14 @@
 #endif  // DISABLED_WUNGUARDED_AVAILABILITY
     rv =
         clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_CPU, 1, &device_id, nullptr);
+#if defined(ARCH_CPU_ARM64)
+    // CL_DEVICE_TYPE_CPU doesn’t seem to work at all on arm64, meaning that
+    // these weird OpenCL modules probably don’t show up there at all. Keep this
+    // test even on arm64 in case this ever does start working.
+    if (rv == CL_INVALID_VALUE) {
+      return;
+    }
+#endif  // ARCH_CPU_ARM64
     ASSERT_EQ(rv, CL_SUCCESS) << "clGetDeviceIDs";
 
     context_ = clCreateContext(nullptr, 1, &device_id, nullptr, nullptr, &rv);
@@ -626,12 +709,17 @@
 
     kernel_ = clCreateKernel(program_, "NoOp", &rv);
     ASSERT_EQ(rv, CL_SUCCESS) << "clCreateKernel";
+
+    success_ = true;
   }
 
+  bool success() const { return success_; }
+
  private:
   cl_context context_;
   cl_program program_;
   cl_kernel kernel_;
+  bool success_;
 
   DISALLOW_COPY_AND_ASSIGN(ScopedOpenCLNoOpKernel);
 };
@@ -640,11 +728,8 @@
 // OpenCL kernels that run on the CPU do not result in cl_kernels images
 // appearing on that OS version.
 bool ExpectCLKernels() {
-#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7
-  return true;
-#else
-  return MacOSXMinorVersion() >= 7;
-#endif
+  return __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_7 ||
+         MacOSVersionNumber() >= 10'07'00;
 }
 
 TEST(ProcessReaderMac, SelfModules) {
@@ -695,16 +780,12 @@
       found_cl_kernels = true;
     } else {
       // Hope that the module didn’t change on disk.
-      struct stat stat_buf;
-      int rv = stat(dyld_image_name, &stat_buf);
-      EXPECT_EQ(rv, 0) << ErrnoMessage("stat");
-      if (rv == 0) {
-        EXPECT_EQ(modules[index].timestamp, stat_buf.st_mtime);
-      }
+      VerifyImageExistenceAndTimestamp(dyld_image_name,
+                                       modules[index].timestamp);
     }
   }
 
-  EXPECT_EQ(found_cl_kernels, ExpectCLKernels());
+  EXPECT_EQ(found_cl_kernels, ExpectCLKernels() && ensure_cl_kernels.success());
 
   size_t index = modules.size() - 1;
   EXPECT_EQ(modules[index].name, kDyldPath);
@@ -724,7 +805,9 @@
 
 class ProcessReaderModulesChild final : public MachMultiprocess {
  public:
-  ProcessReaderModulesChild() : MachMultiprocess() {}
+  explicit ProcessReaderModulesChild(bool ensure_cl_kernels_success)
+      : MachMultiprocess(),
+        ensure_cl_kernels_success_(ensure_cl_kernels_success) {}
 
   ~ProcessReaderModulesChild() {}
 
@@ -785,16 +868,13 @@
         found_cl_kernels = true;
       } else {
         // Hope that the module didn’t change on disk.
-        struct stat stat_buf;
-        int rv = stat(expect_name.c_str(), &stat_buf);
-        EXPECT_EQ(rv, 0) << ErrnoMessage("stat");
-        if (rv == 0) {
-          EXPECT_EQ(modules[index].timestamp, stat_buf.st_mtime);
-        }
+        VerifyImageExistenceAndTimestamp(expect_name.c_str(),
+                                         modules[index].timestamp);
       }
     }
 
-    EXPECT_EQ(found_cl_kernels, ExpectCLKernels());
+    EXPECT_EQ(found_cl_kernels,
+              ExpectCLKernels() && ensure_cl_kernels_success_);
   }
 
   void MachMultiprocessChild() override {
@@ -844,6 +924,8 @@
     CheckedReadFileAtEOF(ReadPipeHandle());
   }
 
+  bool ensure_cl_kernels_success_;
+
   DISALLOW_COPY_AND_ASSIGN(ProcessReaderModulesChild);
 };
 
@@ -851,7 +933,8 @@
   ScopedOpenCLNoOpKernel ensure_cl_kernels;
   ASSERT_NO_FATAL_FAILURE(ensure_cl_kernels.SetUp());
 
-  ProcessReaderModulesChild process_reader_modules_child;
+  ProcessReaderModulesChild process_reader_modules_child(
+      ensure_cl_kernels.success());
   process_reader_modules_child.Run();
 }
 
diff --git a/third_party/crashpad/crashpad/snapshot/mac/process_types.cc b/third_party/crashpad/crashpad/snapshot/mac/process_types.cc
index 0a1b7f9..92bc722 100644
--- a/third_party/crashpad/crashpad/snapshot/mac/process_types.cc
+++ b/third_party/crashpad/crashpad/snapshot/mac/process_types.cc
@@ -219,7 +219,7 @@
                                           size_t count,                        \
                                           struct_name<Traits>* specific) {     \
     return process_reader->Memory()->Read(                                     \
-        address, sizeof(struct_name<Traits>[count]), specific);                \
+        address, count * sizeof(struct_name<Traits>), specific);               \
   }                                                                            \
                                                                                \
   } /* namespace internal */                                                   \
diff --git a/third_party/crashpad/crashpad/snapshot/mac/process_types/custom.cc b/third_party/crashpad/crashpad/snapshot/mac/process_types/custom.cc
index a76c3eb..0b8d969e 100644
--- a/third_party/crashpad/crashpad/snapshot/mac/process_types/custom.cc
+++ b/third_party/crashpad/crashpad/snapshot/mac/process_types/custom.cc
@@ -22,6 +22,7 @@
 #include <limits>
 #include <type_traits>
 
+#include "base/check_op.h"
 #include "base/logging.h"
 #include "base/numerics/safe_math.h"
 #include "base/stl_util.h"
@@ -142,9 +143,10 @@
       offsetof(dyld_all_image_infos<Traits>, sharedCacheSlide),  // 11
       offsetof(dyld_all_image_infos<Traits>, sharedCacheUUID),  // 12
       offsetof(dyld_all_image_infos<Traits>, infoArrayChangeTimestamp),  // 13
-      offsetof(dyld_all_image_infos<Traits>, end_14),  // 14
+      offsetof(dyld_all_image_infos<Traits>, end_v14),  // 14
       std::numeric_limits<size_t>::max(),  // 15, see below
-      sizeof(dyld_all_image_infos<Traits>),  // 16
+      offsetof(dyld_all_image_infos<Traits>, end_v16),  // 16
+      sizeof(dyld_all_image_infos<Traits>),  // 17
   };
 
   if (version >= base::size(kSizeForVersion)) {
@@ -160,13 +162,13 @@
     // The revised one in macOS 10.13 grew. It’s safe to assume that the
     // dyld_all_image_infos structure came from the same system that’s now
     // interpreting it, so use an OS version check.
-    int mac_os_x_minor_version = MacOSXMinorVersion();
-    if (mac_os_x_minor_version == 12) {
-      return offsetof(dyld_all_image_infos<Traits>, end_14);
+    const int macos_version_number = MacOSVersionNumber();
+    if (macos_version_number / 1'00 == 10'12) {
+      return offsetof(dyld_all_image_infos<Traits>, end_v14);
     }
 
-    DCHECK_GE(mac_os_x_minor_version, 13);
-    DCHECK_LE(mac_os_x_minor_version, 14);
+    DCHECK_GE(macos_version_number, 10'13'00);
+    DCHECK_LT(macos_version_number, 10'15'00);
     return offsetof(dyld_all_image_infos<Traits>, platform);
   }
 
diff --git a/third_party/crashpad/crashpad/snapshot/mac/process_types/dyld_images.proctype b/third_party/crashpad/crashpad/snapshot/mac/process_types/dyld_images.proctype
index 3b040854..589ad09 100644
--- a/third_party/crashpad/crashpad/snapshot/mac/process_types/dyld_images.proctype
+++ b/third_party/crashpad/crashpad/snapshot/mac/process_types/dyld_images.proctype
@@ -121,29 +121,40 @@
   // the runtimes that use versions 14 and 15 were built with SDKs that did not
   // have this extra padding, it’s necessary to treat the element at index 4 on
   // 32-bit systems as outside of the version 14 and 15 structure. This is why
-  // |reserved| is only declared a 4-element array, with a special end_14 member
-  // (not present in the native definition) available to indicate the end of the
-  // native version 14 structure and the 10.12 version 15 structure, preceding
-  // the padding in the 32-bit structure that would natively be addressed at
-  // index 4 of |reserved|. Treat reserved_4_32 as only available in version 16
-  // of the structure.
+  // |reserved| is only declared a 4-element array, with a special end_v14
+  // member (not present in the native definition) available to indicate the end
+  // of the native version 14 structure and the 10.12 version 15 structure,
+  // preceding the padding in the 32-bit structure that would natively be
+  // addressed at index 4 of |reserved|. Treat reserved_4_32 as only available
+  // in version 16 of the structure.
   PROCESS_TYPE_STRUCT_MEMBER(UIntPtr, reserved, [4])
   PROCESS_TYPE_STRUCT_MEMBER(Reserved64_64Only, reserved_4_64)
   PROCESS_TYPE_STRUCT_MEMBER(Reserved64_64Only, reserved_5)
   PROCESS_TYPE_STRUCT_MEMBER(Reserved64_64Only, reserved_6)
   PROCESS_TYPE_STRUCT_MEMBER(Reserved64_64Only, reserved_7)
   PROCESS_TYPE_STRUCT_MEMBER(Reserved64_64Only, reserved_8)
-  PROCESS_TYPE_STRUCT_MEMBER(Nothing, end_14)
+  PROCESS_TYPE_STRUCT_MEMBER(Nothing, end_v14)
   PROCESS_TYPE_STRUCT_MEMBER(Reserved32_32Only, reserved_4_32)
 
-  // Version 15 (macOS 10.13). <mach-o/dyld_images.h> incorrectly claims that
-  // these were introduced at version 16. These fields are not present in macOS
-  // 10.12, which also identifies its structure as version 15.
+  // Version 15 (macOS 10.13)
+  // <mach-o/dyld_images.h> incorrectly claims that these were introduced at
+  // version 16. These fields are not present in macOS 10.12, which also
+  // identifies its structure as version 15.
   PROCESS_TYPE_STRUCT_MEMBER(UIntPtr, compact_dyld_image_info_addr)
   PROCESS_TYPE_STRUCT_MEMBER(ULong, compact_dyld_image_info_size)  // size_t
 
   // Version 16 (macOS 10.15)
+  // The native structure is followed by 4 bytes of padding, marked by the
+  // end_v16 member later, not present in the native version of the structure.
   PROCESS_TYPE_STRUCT_MEMBER(uint32_t, platform)  // dyld_platform_t
+
+  // Version 17 (macOS 10.16/11.0)
+  PROCESS_TYPE_STRUCT_MEMBER(uint32_t, aotInfoCount)
+  PROCESS_TYPE_STRUCT_MEMBER(Nothing, end_v16)
+  PROCESS_TYPE_STRUCT_MEMBER(Pointer, aotInfoArray)  // dyld_aot_image_info*
+  PROCESS_TYPE_STRUCT_MEMBER(uint64_t, aotInfoArrayChangeTimestamp)
+  PROCESS_TYPE_STRUCT_MEMBER(UIntPtr, aotSharedCacheBaseAddress)
+  PROCESS_TYPE_STRUCT_MEMBER(uint8_t, aotSharedCacheUUID, [16])
 PROCESS_TYPE_STRUCT_END(dyld_all_image_infos)
 
 #endif  // ! PROCESS_TYPE_STRUCT_IMPLEMENT_INTERNAL_READ_INTO &&
diff --git a/third_party/crashpad/crashpad/snapshot/mac/process_types_test.cc b/third_party/crashpad/crashpad/snapshot/mac/process_types_test.cc
index 0ad2869..b589821 100644
--- a/third_party/crashpad/crashpad/snapshot/mac/process_types_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/mac/process_types_test.cc
@@ -14,7 +14,7 @@
 
 #include "snapshot/mac/process_types.h"
 
-#include <AvailabilityMacros.h>
+#include <Availability.h>
 #include <mach/mach.h>
 #include <string.h>
 
@@ -48,17 +48,17 @@
 TEST(ProcessTypes, DyldImagesSelf) {
   // Get the in-process view of dyld_all_image_infos, and check it for sanity.
   const dyld_all_image_infos* self_image_infos = DyldGetAllImageInfos();
-  const int mac_os_x_minor_version = MacOSXMinorVersion();
+  const int macos_version_number = MacOSVersionNumber();
 
-  if (mac_os_x_minor_version >= 15) {
+  if (macos_version_number >= 10'15'00) {
     EXPECT_GE(self_image_infos->version, 16u);
-  } else if (mac_os_x_minor_version >= 12) {
+  } else if (macos_version_number >= 10'12'00) {
     EXPECT_GE(self_image_infos->version, 15u);
-  } else if (mac_os_x_minor_version >= 9) {
+  } else if (macos_version_number >= 10'09'00) {
     EXPECT_GE(self_image_infos->version, 13u);
-  } else if (mac_os_x_minor_version >= 7) {
+  } else if (macos_version_number >= 10'07'00) {
     EXPECT_GE(self_image_infos->version, 8u);
-  } else if (mac_os_x_minor_version >= 6) {
+  } else if (macos_version_number >= 10'06'00) {
     EXPECT_GE(self_image_infos->version, 2u);
   } else {
     EXPECT_GE(self_image_infos->version, 1u);
@@ -68,7 +68,7 @@
   if (self_image_infos->version >= 2) {
     EXPECT_TRUE(self_image_infos->libSystemInitialized);
   }
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_7
   if (self_image_infos->version >= 9) {
     EXPECT_EQ(self_image_infos->dyldAllImageInfosAddress, self_image_infos);
   }
@@ -90,8 +90,8 @@
 
   // This field is only present in the OS X 10.7 SDK (at build time) and kernel
   // (at run time).
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
-  if (MacOSXMinorVersion() >= 7) {
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_7
+  if (macos_version_number >= 10'07'00) {
 #if !defined(ARCH_CPU_64_BITS)
     EXPECT_EQ(dyld_info.all_image_info_format, TASK_DYLD_ALL_IMAGE_INFO_32);
 #else
@@ -103,15 +103,17 @@
   ProcessReaderMac process_reader;
   ASSERT_TRUE(process_reader.Initialize(mach_task_self()));
 
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_15
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_16
+  constexpr uint32_t kDyldAllImageInfosVersionInSDK = 17;
+#elif __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_15
   constexpr uint32_t kDyldAllImageInfosVersionInSDK = 16;
-#elif MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12
+#elif __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_12
   constexpr uint32_t kDyldAllImageInfosVersionInSDK = 15;
-#elif MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
+#elif __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_9
   constexpr uint32_t kDyldAllImageInfosVersionInSDK = 14;
-#elif MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
+#elif __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_7
   constexpr uint32_t kDyldAllImageInfosVersionInSDK = 12;
-#elif MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
+#elif __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_6
   constexpr uint32_t kDyldAllImageInfosVersionInSDK = 7;
 #else
   constexpr uint32_t kDyldAllImageInfosVersionInSDK = 1;
@@ -126,13 +128,13 @@
   // test can only be performed if the run-time OS natively uses the same format
   // structure as the SDK.
   bool test_expected_size_for_version_matches_sdk_sizeof;
-#if MAC_OS_X_VERSION_MAX_ALLOWED == MAC_OS_X_VERSION_10_12
+#if __MAC_OS_X_VERSION_MAX_ALLOWED == __MAC_10_12
   test_expected_size_for_version_matches_sdk_sizeof =
-      mac_os_x_minor_version == 12;
-#elif MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13 && \
-    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_15
+      macos_version_number / 1'00 == 10'12;
+#elif __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_13 && \
+    __MAC_OS_X_VERSION_MAX_ALLOWED < __MAC_10_15
   test_expected_size_for_version_matches_sdk_sizeof =
-      mac_os_x_minor_version >= 13 && mac_os_x_minor_version <= 14;
+      macos_version_number >= 10'13'00 && macos_version_number < 10'15'00;
 #else
   test_expected_size_for_version_matches_sdk_sizeof = true;
 #endif
@@ -144,8 +146,10 @@
   }
 
   // Make sure that the computed sizes of various versions of this structure are
-  // correct at different bitnessses.
+  // correct at different bitnessses. Version 16 and later are unsupported on
+  // 32-bit systems due to the OS deprecating 32-bit support in macOS 10.15.
   constexpr size_t kSpecialCase = std::numeric_limits<size_t>::max();
+  constexpr size_t kUnsupported = std::numeric_limits<size_t>::max() - 1;
   constexpr struct {
     uint32_t version;
     size_t size_32;
@@ -165,14 +169,15 @@
       {13, 104, 184},
       {14, 164, 304},
       {15, kSpecialCase, kSpecialCase},
-      {16, 184, 328},
+      {16, kUnsupported, 328},
+      {17, kUnsupported, 368},
   };
   for (size_t index = 0; index < base::size(kVersionsAndSizes); ++index) {
     uint32_t version = kVersionsAndSizes[index].version;
     SCOPED_TRACE(base::StringPrintf("index %zu, version %u", index, version));
 
     if (version == 15) {
-      if (mac_os_x_minor_version == 12) {
+      if (macos_version_number / 1'00 == 10'12) {
         EXPECT_EQ(process_types::internal::dyld_all_image_infos<
                       process_types::internal::Traits32>::
                       ExpectedSizeForVersion(version),
@@ -181,7 +186,8 @@
                       process_types::internal::Traits64>::
                       ExpectedSizeForVersion(version),
                   304u);
-      } else if (mac_os_x_minor_version >= 13 && mac_os_x_minor_version <= 14) {
+      } else if (macos_version_number >= 10'13'00 &&
+                 macos_version_number < 10'15'00) {
         EXPECT_EQ(process_types::internal::dyld_all_image_infos<
                       process_types::internal::Traits32>::
                       ExpectedSizeForVersion(version),
@@ -198,14 +204,18 @@
     ASSERT_NE(kVersionsAndSizes[index].size_32, kSpecialCase);
     ASSERT_NE(kVersionsAndSizes[index].size_64, kSpecialCase);
 
-    EXPECT_EQ(
-        process_types::internal::dyld_all_image_infos<
-            process_types::internal::Traits32>::ExpectedSizeForVersion(version),
-        kVersionsAndSizes[index].size_32);
-    EXPECT_EQ(
-        process_types::internal::dyld_all_image_infos<
-            process_types::internal::Traits64>::ExpectedSizeForVersion(version),
-        kVersionsAndSizes[index].size_64);
+    if (kVersionsAndSizes[index].size_32 != kUnsupported) {
+      EXPECT_EQ(process_types::internal::dyld_all_image_infos<
+                    process_types::internal::Traits32>::
+                    ExpectedSizeForVersion(version),
+                kVersionsAndSizes[index].size_32);
+    }
+    if (kVersionsAndSizes[index].size_64 != kUnsupported) {
+      EXPECT_EQ(process_types::internal::dyld_all_image_infos<
+                    process_types::internal::Traits64>::
+                    ExpectedSizeForVersion(version),
+                kVersionsAndSizes[index].size_64);
+    }
   }
 
   process_types::dyld_all_image_infos proctype_image_infos;
@@ -257,7 +267,7 @@
     EXPECT_EQ(proctype_image_infos.systemOrderFlag,
               implicit_cast<uint64_t>(self_image_infos->systemOrderFlag));
   }
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_7
   if (proctype_image_infos.version >= 8) {
     EXPECT_EQ(proctype_image_infos.uuidArrayCount,
               implicit_cast<uint64_t>(self_image_infos->uuidArrayCount));
@@ -299,7 +309,7 @@
               implicit_cast<uint64_t>(self_image_infos->sharedCacheSlide));
   }
 #endif
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_9
   if (proctype_image_infos.version >= 13) {
     EXPECT_EQ(memcmp(self_image_infos->sharedCacheUUID,
                      proctype_image_infos.sharedCacheUUID,
@@ -307,7 +317,7 @@
               0);
   }
 #endif
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_12
   if (proctype_image_infos.version >= 15) {
     EXPECT_EQ(proctype_image_infos.infoArrayChangeTimestamp,
               self_image_infos->infoArrayChangeTimestamp);
@@ -327,7 +337,7 @@
   }
 #endif
 
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_12
   // As dyld_all_image_infos has evolved over time, new fields were added to the
   // reserved region. process_types::dyld_all_image_infos declares a recent
   // version of the structure, but an older SDK may declare an older version
@@ -352,8 +362,8 @@
   }
 #endif
 
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13
-  if (proctype_image_infos.version >= 15 && mac_os_x_minor_version >= 13) {
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_13
+  if (proctype_image_infos.version >= 15 && macos_version_number >= 10'13'00) {
     EXPECT_EQ(proctype_image_infos.compact_dyld_image_info_addr,
               self_image_infos->compact_dyld_image_info_addr);
     EXPECT_EQ(proctype_image_infos.compact_dyld_image_info_size,
@@ -361,7 +371,7 @@
   }
 #endif
 
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_15
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_15
   if (proctype_image_infos.version >= 16) {
     EXPECT_EQ(proctype_image_infos.platform, self_image_infos->platform);
   }
@@ -399,7 +409,7 @@
     }
   }
 
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_7
   if (proctype_image_infos.version >= 8) {
     std::vector<process_types::dyld_uuid_info> proctype_uuid_info_vector(
         proctype_image_infos.uuidArrayCount);
diff --git a/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac.cc b/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac.cc
index 62eb814..7a12e74 100644
--- a/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac.cc
+++ b/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac.cc
@@ -14,7 +14,7 @@
 
 #include "snapshot/mac/system_snapshot_mac.h"
 
-#include <AvailabilityMacros.h>
+#include <Availability.h>
 #include <stddef.h>
 #include <sys/sysctl.h>
 #include <sys/types.h>
@@ -31,6 +31,7 @@
 #include "snapshot/mac/process_reader_mac.h"
 #include "snapshot/posix/timezone.h"
 #include "util/mac/mac_util.h"
+#include "util/mac/sysctl.h"
 #include "util/numeric/in_range_cast.h"
 
 namespace crashpad {
@@ -60,26 +61,6 @@
   return InRangeCast<T>(int_value, default_value);
 }
 
-std::string ReadStringSysctlByName(const char* name) {
-  size_t buf_len;
-  if (sysctlbyname(name, nullptr, &buf_len, nullptr, 0) != 0) {
-    PLOG(WARNING) << "sysctlbyname (size) " << name;
-    return std::string();
-  }
-
-  if (buf_len == 0) {
-    return std::string();
-  }
-
-  std::string value(buf_len - 1, '\0');
-  if (sysctlbyname(name, &value[0], &buf_len, nullptr, 0) != 0) {
-    PLOG(WARNING) << "sysctlbyname " << name;
-    return std::string();
-  }
-
-  return value;
-}
-
 #if defined(ARCH_CPU_X86_FAMILY)
 void CallCPUID(uint32_t leaf,
                uint32_t* eax,
@@ -119,15 +100,15 @@
   process_reader_ = process_reader;
   snapshot_time_ = snapshot_time;
 
-  // MacOSXVersion() logs its own warnings if it can’t figure anything out. It’s
-  // not fatal if this happens. The default values are reasonable.
+  // MacOSVersionComponents() logs its own warnings if it can’t figure anything
+  // out. It’s not fatal if this happens. The default values are reasonable.
   std::string os_version_string;
-  MacOSXVersion(&os_version_major_,
-                &os_version_minor_,
-                &os_version_bugfix_,
-                &os_version_build_,
-                &os_server_,
-                &os_version_string);
+  MacOSVersionComponents(&os_version_major_,
+                         &os_version_minor_,
+                         &os_version_bugfix_,
+                         &os_version_build_,
+                         &os_server_,
+                         &os_version_string);
 
   std::string uname_string;
   utsname uts;
@@ -194,9 +175,9 @@
   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
 
 #if defined(ARCH_CPU_X86_FAMILY)
-  return ReadStringSysctlByName("machdep.cpu.vendor");
+  return ReadStringSysctlByName("machdep.cpu.vendor", true);
 #elif defined(ARCH_CPU_ARM64)
-  return ReadStringSysctlByName("machdep.cpu.brand_string");
+  return ReadStringSysctlByName("machdep.cpu.brand_string", true);
 #else
 #error port to your architecture
 #endif
@@ -205,8 +186,18 @@
 void SystemSnapshotMac::CPUFrequency(
     uint64_t* current_hz, uint64_t* max_hz) const {
   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+#if defined(ARCH_CPU_X86_FAMILY)
   *current_hz = ReadIntSysctlByName<uint64_t>("hw.cpufrequency", 0);
   *max_hz = ReadIntSysctlByName<uint64_t>("hw.cpufrequency_max", 0);
+#elif defined(ARCH_CPU_ARM64)
+  // TODO(https://crashpad.chromium.org/bug/352): When production arm64
+  // hardware is available, determine whether CPU frequency is visible anywhere
+  // (likely via a sysctl or via IOKit) and use it if feasible.
+  *current_hz = 0;
+  *max_hz = 0;
+#else
+#error port to your architecture
+#endif
 }
 
 uint32_t SystemSnapshotMac::CPUX86Signature() const {
@@ -364,11 +355,11 @@
       // xnu-6153.11.26/bsd/kern/kern_sysctl.c (10.14.4 and 10.14.5 xnu source
       // are not yet available). In newer production kernels, NX is always
       // enabled. See 10.15.0 xnu-6153.11.26/osfmk/x86_64/pmap.c nx_enabled.
-#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_14
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_14
       const bool nx_always_enabled = true;
 #else  // DT >= 10.14
       base::ScopedClearLastError reset_errno;
-      const bool nx_always_enabled = MacOSXMinorVersion() >= 14;
+      const bool nx_always_enabled = MacOSVersionNumber() >= 10'14'00;
 #endif  // DT >= 10.14
       if (nx_always_enabled) {
         return true;
diff --git a/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac_test.cc b/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac_test.cc
index e13c9af..bdbc296 100644
--- a/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/mac/system_snapshot_mac_test.cc
@@ -117,8 +117,10 @@
   std::string build;
   system_snapshot().OSVersion(&major, &minor, &bugfix, &build);
 
-  EXPECT_EQ(major, 10);
-  EXPECT_EQ(minor, MacOSXMinorVersion());
+  const int macos_version_number = MacOSVersionNumber();
+  EXPECT_EQ(major * 1'00'00 + minor * 1'00 +
+                (macos_version_number >= 10'13'04 ? bugfix : 0),
+            macos_version_number);
   EXPECT_FALSE(build.empty());
 }
 
diff --git a/third_party/crashpad/crashpad/snapshot/sanitized/process_snapshot_sanitized_test.cc b/third_party/crashpad/crashpad/snapshot/sanitized/process_snapshot_sanitized_test.cc
index 0484778..931f5cb 100644
--- a/third_party/crashpad/crashpad/snapshot/sanitized/process_snapshot_sanitized_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/sanitized/process_snapshot_sanitized_test.cc
@@ -14,8 +14,11 @@
 
 #include "snapshot/sanitized/process_snapshot_sanitized.h"
 
+#include <string.h>
+
 #include "base/macros.h"
 #include "base/notreached.h"
+#include "base/stl_util.h"
 #include "build/build_config.h"
 #include "gtest/gtest.h"
 #include "test/multiprocess_exec.h"
@@ -23,7 +26,7 @@
 #include "util/misc/address_sanitizer.h"
 #include "util/numeric/safe_assignment.h"
 
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
 #include <sys/syscall.h>
 
 #include "snapshot/linux/process_snapshot_linux.h"
@@ -98,7 +101,7 @@
   static StringAnnotation<32> non_allowed_annotation(kNonAllowedAnnotationName);
   non_allowed_annotation.Set(kNonAllowedAnnotationValue);
 
-  char string_data[strlen(kSensitiveStackData) + 1];
+  char string_data[base::size(kSensitiveStackData)];
   strcpy(string_data, kSensitiveStackData);
 
   void (*code_pointer)(void) = ChildTestFunction;
diff --git a/third_party/crashpad/crashpad/snapshot/x86/cpuid_reader.cc b/third_party/crashpad/crashpad/snapshot/x86/cpuid_reader.cc
index e600141..5834058 100644
--- a/third_party/crashpad/crashpad/snapshot/x86/cpuid_reader.cc
+++ b/third_party/crashpad/crashpad/snapshot/x86/cpuid_reader.cc
@@ -16,7 +16,6 @@
 
 #include <stddef.h>
 
-#include "build/build_config.h"
 #include "snapshot/cpu_context.h"
 
 #if defined(OS_WIN)
@@ -24,6 +23,8 @@
 #include <intrin.h>
 #endif  // OS_WIN
 
+#if defined(ARCH_CPU_X86_FAMILY)
+
 namespace crashpad {
 namespace internal {
 
@@ -132,3 +133,5 @@
 
 }  // namespace internal
 }  // namespace crashpad
+
+#endif  // ARCH_CPU_X86_FAMILY
diff --git a/third_party/crashpad/crashpad/snapshot/x86/cpuid_reader.h b/third_party/crashpad/crashpad/snapshot/x86/cpuid_reader.h
index b6782af..39a1ca8 100644
--- a/third_party/crashpad/crashpad/snapshot/x86/cpuid_reader.h
+++ b/third_party/crashpad/crashpad/snapshot/x86/cpuid_reader.h
@@ -19,6 +19,10 @@
 
 #include <string>
 
+#include "build/build_config.h"
+
+#if defined(ARCH_CPU_X86_FAMILY)
+
 namespace crashpad {
 namespace internal {
 
@@ -65,4 +69,6 @@
 }  // namespace internal
 }  // namespace crashpad
 
+#endif  // ARCH_CPU_X86_FAMILY
+
 #endif  // CRASHPAD_SNAPSHOT_X86_CPUID_READER_H_
diff --git a/third_party/crashpad/crashpad/test/mac/dyld.cc b/third_party/crashpad/crashpad/test/mac/dyld.cc
index fb2156e..ba1cb56f 100644
--- a/third_party/crashpad/crashpad/test/mac/dyld.cc
+++ b/third_party/crashpad/crashpad/test/mac/dyld.cc
@@ -14,10 +14,10 @@
 
 #include "test/mac/dyld.h"
 
-#include <AvailabilityMacros.h>
+#include <Availability.h>
 #include <dlfcn.h>
-#include <mach/mach.h>
 #include <mach-o/dyld.h>
+#include <mach/mach.h>
 #include <stdint.h>
 
 #include "base/logging.h"
@@ -25,7 +25,7 @@
 #include "test/scoped_module_handle.h"
 #include "util/numeric/safe_assignment.h"
 
-#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_13
+#if __MAC_OS_X_VERSION_MAX_ALLOWED < __MAC_10_13
 extern "C" {
 
 // A non-public dyld API, declared in 10.12.4
@@ -41,14 +41,14 @@
 namespace test {
 
 const dyld_all_image_infos* DyldGetAllImageInfos() {
-#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_13
+#if __MAC_OS_X_VERSION_MAX_ALLOWED < __MAC_10_13
   // When building with the pre-10.13 SDK, the weak_import declaration above is
   // available and a symbol will be present in the SDK to link against. If the
   // old interface is also available at run time (running on pre-10.13), use it.
   if (_dyld_get_all_image_infos) {
     return _dyld_get_all_image_infos();
   }
-#elif MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_13
+#elif __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_13
   // When building with the 10.13 SDK or later, but able to run on pre-10.13,
   // look for _dyld_get_all_image_infos in the same module that provides
   // _dyld_image_count. There’s no symbol in the SDK to link against, so this is
diff --git a/third_party/crashpad/crashpad/test/mac/mach_multiprocess.cc b/third_party/crashpad/crashpad/test/mac/mach_multiprocess.cc
index eaa6a174..01b242a 100644
--- a/third_party/crashpad/crashpad/test/mac/mach_multiprocess.cc
+++ b/third_party/crashpad/crashpad/test/mac/mach_multiprocess.cc
@@ -14,7 +14,7 @@
 
 #include "test/mac/mach_multiprocess.h"
 
-#include <AvailabilityMacros.h>
+#include <Availability.h>
 #include <bsm/libbsm.h>
 
 #include <memory>
@@ -150,7 +150,7 @@
   // and other processes will be able to look it up and send messages to it,
   // these checks disambiguate genuine failures later on in the test from those
   // that would occur if an errant process sends a message to this service.
-#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8
+#if __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_8
   uid_t audit_auid;
   uid_t audit_euid;
   gid_t audit_egid;
diff --git a/third_party/crashpad/crashpad/test/multiprocess_exec_posix.cc b/third_party/crashpad/crashpad/test/multiprocess_exec_posix.cc
index 59aad829..e14a3b8 100644
--- a/third_party/crashpad/crashpad/test/multiprocess_exec_posix.cc
+++ b/third_party/crashpad/crashpad/test/multiprocess_exec_posix.cc
@@ -26,7 +26,7 @@
 #include "util/misc/scoped_forbid_return.h"
 #include "util/posix/close_multiple.h"
 
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
 #include <stdio_ext.h>
 #endif
 
@@ -90,7 +90,7 @@
 
   int rv;
 
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
   __fpurge(stdin);
 #else
   rv = fpurge(stdin);
diff --git a/third_party/crashpad/crashpad/test/multiprocess_posix.cc b/third_party/crashpad/crashpad/test/multiprocess_posix.cc
index 782d5ba9..c16aa08f 100644
--- a/third_party/crashpad/crashpad/test/multiprocess_posix.cc
+++ b/third_party/crashpad/crashpad/test/multiprocess_posix.cc
@@ -143,7 +143,7 @@
     if (exception_swallower.get()) {
       ExceptionSwallower::SwallowExceptions();
     }
-#elif defined(OS_LINUX) || defined(OS_ANDROID)
+#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
     if (reason_ == kTerminationSignal && Signals::IsCrashSignal(code_)) {
       Signals::InstallDefaultHandler(code_);
     }
diff --git a/third_party/crashpad/crashpad/test/process_type.cc b/third_party/crashpad/crashpad/test/process_type.cc
index ac0b865e..f6eec36 100644
--- a/third_party/crashpad/crashpad/test/process_type.cc
+++ b/third_party/crashpad/crashpad/test/process_type.cc
@@ -16,7 +16,7 @@
 
 #if defined(OS_FUCHSIA)
 #include <lib/zx/process.h>
-#elif defined(OS_LINUX) || defined(OS_ANDROID)
+#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
 #include <unistd.h>
 #endif
 
@@ -26,7 +26,7 @@
 ProcessType GetSelfProcess() {
 #if defined(OS_FUCHSIA)
   return zx::process::self();
-#elif defined(OS_LINUX) || defined(OS_ANDROID)
+#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
   return getpid();
 #elif defined(OS_WIN)
   return GetCurrentProcess();
diff --git a/third_party/crashpad/crashpad/test/process_type.h b/third_party/crashpad/crashpad/test/process_type.h
index d14514e5..cacac04f 100644
--- a/third_party/crashpad/crashpad/test/process_type.h
+++ b/third_party/crashpad/crashpad/test/process_type.h
@@ -19,7 +19,7 @@
 
 #if defined(OS_FUCHSIA)
 #include <lib/zx/process.h>
-#elif defined(OS_LINUX) || defined(OS_ANDROID)
+#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
 #include <sys/types.h>
 #elif defined(OS_WIN)
 #include <windows.h>
@@ -32,7 +32,8 @@
 
 #if defined(OS_FUCHSIA)
 using ProcessType = zx::unowned_process;
-#elif defined(OS_LINUX) || defined(OS_ANDROID) || DOXYGEN
+#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) || \
+    DOXYGEN
 //! \brief Alias for platform-specific type to represent a process.
 using ProcessType = pid_t;
 #elif defined(OS_WIN)
diff --git a/third_party/crashpad/crashpad/tools/generate_dump.cc b/third_party/crashpad/crashpad/tools/generate_dump.cc
index dd62cd7..e22f92a5 100644
--- a/third_party/crashpad/crashpad/tools/generate_dump.cc
+++ b/third_party/crashpad/crashpad/tools/generate_dump.cc
@@ -47,7 +47,7 @@
 #include "snapshot/win/process_snapshot_win.h"
 #include "util/win/scoped_process_suspend.h"
 #include "util/win/xp_compat.h"
-#elif defined(OS_LINUX) || defined(OS_ANDROID)
+#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
 #include "snapshot/linux/process_snapshot_linux.h"
 #endif  // OS_APPLE
 
@@ -196,7 +196,7 @@
                                      0)) {
       return EXIT_FAILURE;
     }
-#elif defined(OS_LINUX) || defined(OS_ANDROID)
+#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
     // TODO(jperaza): https://crashpad.chromium.org/bug/30.
     ProcessSnapshotLinux process_snapshot;
     if (!process_snapshot.Initialize(nullptr)) {
diff --git a/third_party/crashpad/crashpad/util/BUILD.gn b/third_party/crashpad/crashpad/util/BUILD.gn
index 2e1bbee..2585caa 100644
--- a/third_party/crashpad/crashpad/util/BUILD.gn
+++ b/third_party/crashpad/crashpad/util/BUILD.gn
@@ -131,6 +131,15 @@
         "--arch",
         "arm64",
       ]
+    } else if (crashpad_is_mac && current_cpu == "mac_universal") {
+      args += [
+        "--arch",
+        "x86_64",
+        "--arch",
+        "arm64",
+      ]
+    } else {
+      assert(false, "Unsupported architecture")
     }
   }
 
@@ -339,6 +348,8 @@
       "mac/mac_util.h",
       "mac/service_management.cc",
       "mac/service_management.h",
+      "mac/sysctl.cc",
+      "mac/sysctl.h",
       "mach/bootstrap.cc",
       "mach/bootstrap.h",
       "mach/child_port_handshake.cc",
@@ -612,6 +623,10 @@
   }
 
   configs += [ "..:disable_ubsan" ]
+
+  if (crashpad_is_in_fuchsia) {
+    configs += [ "//build/config:Wno-conversion" ]
+  }
 }
 
 if (!crashpad_is_android && !crashpad_is_ios) {
@@ -742,6 +757,7 @@
       "mac/launchd_test.mm",
       "mac/mac_util_test.mm",
       "mac/service_management_test.mm",
+      "mac/sysctl_test.cc",
       "mach/bootstrap_test.cc",
       "mach/child_port_handshake_test.cc",
       "mach/child_port_server_test.cc",
diff --git a/third_party/crashpad/crashpad/util/file/file_io.h b/third_party/crashpad/crashpad/util/file/file_io.h
index 6fa0f96d..1f502ad 100644
--- a/third_party/crashpad/crashpad/util/file/file_io.h
+++ b/third_party/crashpad/crashpad/util/file/file_io.h
@@ -398,7 +398,7 @@
                                    FileWriteMode mode,
                                    FilePermissions permissions);
 
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
 //! \brief Opens an in-memory file for input and output.
 //!
 //! This function first attempts to open the file with `memfd_create()`. If
@@ -420,7 +420,7 @@
 //! \sa LoggingOpenFileForWrite
 //! \sa LoggingOpenFileForReadAndWrite
 FileHandle LoggingOpenMemoryFileForReadAndWrite(const base::FilePath& name);
-#endif  // OS_LINUX
+#endif  // OS_LINUX || OS_CHROMEOS
 
 //! \brief Wraps OpenFileForReadAndWrite(), logging an error if the operation
 //!     fails.
diff --git a/third_party/crashpad/crashpad/util/file/file_io_posix.cc b/third_party/crashpad/crashpad/util/file/file_io_posix.cc
index 001b2d97..2baa811 100644
--- a/third_party/crashpad/crashpad/util/file/file_io_posix.cc
+++ b/third_party/crashpad/crashpad/util/file/file_io_posix.cc
@@ -153,7 +153,7 @@
   return fd;
 }
 
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
 FileHandle LoggingOpenMemoryFileForReadAndWrite(const base::FilePath& name) {
   DCHECK(name.value().find('/') == std::string::npos);
 
diff --git a/third_party/crashpad/crashpad/util/file/file_io_test.cc b/third_party/crashpad/crashpad/util/file/file_io_test.cc
index 0efded8..52bb6ee 100644
--- a/third_party/crashpad/crashpad/util/file/file_io_test.cc
+++ b/third_party/crashpad/crashpad/util/file/file_io_test.cc
@@ -473,7 +473,7 @@
   TestOpenFileForWrite(LoggingOpenFileForReadAndWrite);
 }
 
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
 TEST(FileIO, LoggingOpenMemoryFileForReadAndWrite) {
   ScopedFileHandle handle(
       LoggingOpenMemoryFileForReadAndWrite(base::FilePath("memfile")));
@@ -488,7 +488,7 @@
   ASSERT_TRUE(LoggingReadFileExactly(handle.get(), buffer, sizeof(buffer)));
   EXPECT_EQ(memcmp(buffer, kTestData, sizeof(buffer)), 0);
 }
-#endif  // OS_LINUX
+#endif  // OS_LINUX || OS_CHROMEOS
 
 enum class ReadOrWrite : bool {
   kRead,
diff --git a/third_party/crashpad/crashpad/util/file/file_writer.cc b/third_party/crashpad/crashpad/util/file/file_writer.cc
index 6dff975a..73fe708 100644
--- a/third_party/crashpad/crashpad/util/file/file_writer.cc
+++ b/third_party/crashpad/crashpad/util/file/file_writer.cc
@@ -171,7 +171,7 @@
   return true;
 }
 
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
 bool FileWriter::OpenMemfd(const base::FilePath& path) {
   CHECK(!file_.is_valid());
   file_.reset(LoggingOpenMemoryFileForReadAndWrite(path));
diff --git a/third_party/crashpad/crashpad/util/file/file_writer.h b/third_party/crashpad/crashpad/util/file/file_writer.h
index 4b99b37..987c0f5 100644
--- a/third_party/crashpad/crashpad/util/file/file_writer.h
+++ b/third_party/crashpad/crashpad/util/file/file_writer.h
@@ -131,7 +131,7 @@
             FileWriteMode write_mode,
             FilePermissions permissions);
 
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
   //! \brief Wraps LoggingOpenMemoryFileForWrite().
   //!
   //! \return `true` if the operation succeeded, `false` if it failed, with an
diff --git a/third_party/crashpad/crashpad/util/linux/exception_handler_protocol.cc b/third_party/crashpad/crashpad/util/linux/exception_handler_protocol.cc
index 45590c8..27f180c 100644
--- a/third_party/crashpad/crashpad/util/linux/exception_handler_protocol.cc
+++ b/third_party/crashpad/crashpad/util/linux/exception_handler_protocol.cc
@@ -19,9 +19,9 @@
 ExceptionHandlerProtocol::ClientInformation::ClientInformation()
     : exception_information_address(0),
       sanitization_information_address(0)
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
       , crash_loop_before_time(0)
-#endif  // OS_LINUX
+#endif  // OS_LINUX || OS_CHROMEOS
 {}
 
 ExceptionHandlerProtocol::ClientToServerMessage::ClientToServerMessage()
diff --git a/third_party/crashpad/crashpad/util/linux/exception_handler_protocol.h b/third_party/crashpad/crashpad/util/linux/exception_handler_protocol.h
index 7312b9d..60b0b1b7 100644
--- a/third_party/crashpad/crashpad/util/linux/exception_handler_protocol.h
+++ b/third_party/crashpad/crashpad/util/linux/exception_handler_protocol.h
@@ -52,7 +52,7 @@
     //!     SanitizationInformation struct, or 0 if there is no such struct.
     VMAddress sanitization_information_address;
 
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
     //! \brief Indicates that the client is likely in a crash loop if a crash
     //!     occurs before this timestamp. This value is only used by ChromeOS's
     //!     `/sbin/crash_reporter`.
diff --git a/third_party/crashpad/crashpad/util/mac/mac_util.cc b/third_party/crashpad/crashpad/util/mac/mac_util.cc
index 5f79701..10e7aad1 100644
--- a/third_party/crashpad/crashpad/util/mac/mac_util.cc
+++ b/third_party/crashpad/crashpad/util/mac/mac_util.cc
@@ -14,20 +14,25 @@
 
 #include "util/mac/mac_util.h"
 
+#include <Availability.h>
 #include <CoreFoundation/CoreFoundation.h>
 #include <IOKit/IOKitLib.h>
 #include <string.h>
 #include <sys/types.h>
 #include <sys/utsname.h>
 
+#include "base/check_op.h"
 #include "base/logging.h"
 #include "base/mac/foundation_util.h"
 #include "base/mac/scoped_cftyperef.h"
 #include "base/mac/scoped_ioobject.h"
+#include "base/notreached.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/sys_string_conversions.h"
+#include "build/build_config.h"
+#include "util/mac/sysctl.h"
 
 extern "C" {
 // Private CoreFoundation internals. See 10.9.2 CF-855.14/CFPriv.h and
@@ -56,9 +61,10 @@
 
 namespace {
 
+#if __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_13_4
 // Returns the running system’s Darwin major version. Don’t call this, it’s an
 // implementation detail and its result is meant to be cached by
-// MacOSXMinorVersion().
+// MacOSVersionNumber().
 //
 // This is very similar to Chromium’s base/mac/mac_util.mm
 // DarwinMajorVersionInternal().
@@ -92,6 +98,7 @@
 
   return darwin_major_version;
 }
+#endif  // DT < 10.13.4
 
 // Helpers for the weak-imported private CoreFoundation internals.
 
@@ -118,9 +125,10 @@
 }
 
 // Converts |version| to a triplet of version numbers on behalf of
-// MacOSXVersion(). Returns true on success. If |version| does not have the
-// expected format, returns false. |version| must be in the form "10.9.2" or
-// just "10.9". In the latter case, |bugfix| will be set to 0.
+// MacOSVersionNumber() and MacOSVersionComponents(). Returns true on success.
+// If |version| does not have the expected format, returns false. |version| must
+// be in the form "10.9.2" or just "10.9". In the latter case, |bugfix| will be
+// set to 0.
 bool StringToVersionNumbers(const std::string& version,
                             int* major,
                             int* minor,
@@ -180,20 +188,62 @@
 
 namespace crashpad {
 
-int MacOSXMinorVersion() {
-  // The Darwin major version is always 4 greater than the macOS minor version
-  // for Darwin versions beginning with 6, corresponding to Mac OS X 10.2.
-  static int mac_os_x_minor_version = DarwinMajorVersion() - 4;
-  DCHECK(mac_os_x_minor_version >= 2);
-  return mac_os_x_minor_version;
+int MacOSVersionNumber() {
+  static int macos_version_number = []() {
+    // kern.osproductversion is a lightweight way to get the operating system
+    // version from the kernel without having to open any files or spin up any
+    // threads, but it’s only available in macOS 10.13.4 and later.
+    std::string macos_version_number_string = ReadStringSysctlByName(
+        "kern.osproductversion",
+        __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_13_4);
+    if (!macos_version_number_string.empty()) {
+      int major;
+      int minor;
+      int bugfix;
+      if (StringToVersionNumbers(
+              macos_version_number_string, &major, &minor, &bugfix)) {
+        DCHECK_GE(major, 10);
+        DCHECK_LE(major, 99);
+        DCHECK_GE(minor, 0);
+        DCHECK_LE(minor, 99);
+        DCHECK_GE(bugfix, 0);
+        DCHECK_LE(bugfix, 99);
+        return major * 1'00'00 + minor * 1'00 + bugfix;
+      }
+    }
+
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_13_4
+    // On macOS 10.13.4 and later, the sysctlbyname above should have been
+    // successful.
+    NOTREACHED();
+    return -1;
+#else  // DT >= 10.13.4
+    // The Darwin major version is always 4 greater than the macOS minor version
+    // for Darwin versions beginning with 6, corresponding to Mac OS X 10.2,
+    // through Darwin 19, corresponding to macOS 10.15.
+    int darwin_major_version = DarwinMajorVersion();
+    DCHECK_GE(darwin_major_version, 6);
+    DCHECK_LE(darwin_major_version, 19);
+
+    int macos_version_number = 10'00'00 + (darwin_major_version - 4) * 1'00;
+
+    // On macOS 10.13.4 and later, the sysctlbyname above should have been
+    // successful.
+    DCHECK_LT(macos_version_number, 10'13'04);
+
+    return macos_version_number;
+#endif  // DT >= 10.13.4
+  }();
+
+  return macos_version_number;
 }
 
-bool MacOSXVersion(int* major,
-                   int* minor,
-                   int* bugfix,
-                   std::string* build,
-                   bool* server,
-                   std::string* version_string) {
+bool MacOSVersionComponents(int* major,
+                            int* minor,
+                            int* bugfix,
+                            std::string* build,
+                            bool* server,
+                            std::string* version_string) {
   base::ScopedCFTypeRef<CFDictionaryRef> dictionary(
       TryCFCopyServerVersionDictionary());
   if (dictionary) {
@@ -217,7 +267,16 @@
     success = false;
   } else {
     version = base::SysCFStringRefToUTF8(version_cf);
-    success &= StringToVersionNumbers(version, major, minor, bugfix);
+    if (!StringToVersionNumbers(version, major, minor, bugfix)) {
+      success = false;
+    } else {
+      DCHECK_GE(*major, 10);
+      DCHECK_LE(*major, 99);
+      DCHECK_GE(*minor, 0);
+      DCHECK_LE(*minor, 99);
+      DCHECK_GE(*bugfix, 0);
+      DCHECK_LE(*bugfix, 99);
+    }
   }
 
   CFStringRef build_cf = base::mac::CFCast<CFStringRef>(
@@ -270,8 +329,17 @@
   if (platform_expert) {
     model->assign(
         IORegistryEntryDataPropertyAsString(platform_expert, CFSTR("model")));
+#if defined(ARCH_CPU_X86_FAMILY)
+    CFStringRef kBoardProperty = CFSTR("board-id");
+#elif defined(ARCH_CPU_ARM64)
+    // TODO(https://crashpad.chromium.org/bug/352): When production arm64
+    // hardware is available, determine whether board-id works and switch to it
+    // if feasible, otherwise, determine whether target-type remains a viable
+    // alternative.
+    CFStringRef kBoardProperty = CFSTR("target-type");
+#endif
     board_id->assign(IORegistryEntryDataPropertyAsString(platform_expert,
-                                                         CFSTR("board-id")));
+                                                         kBoardProperty));
   } else {
     model->clear();
     board_id->clear();
diff --git a/third_party/crashpad/crashpad/util/mac/mac_util.h b/third_party/crashpad/crashpad/util/mac/mac_util.h
index d8b7159..c94e233 100644
--- a/third_party/crashpad/crashpad/util/mac/mac_util.h
+++ b/third_party/crashpad/crashpad/util/mac/mac_util.h
@@ -21,14 +21,24 @@
 
 //! \brief Returns the version of the running operating system.
 //!
-//! \return The minor version of the operating system, such as `12` for macOS
-//!     10.12.1.
+//! \return The version of the operating system, such as `10'15'06` for macOS
+//!     10.15.6.
+//!
+//! The format of the return value matches what is used by the <Availability.h>
+//! `__MAC_OS_X_VERSION_MIN_REQUIRED`, `__MAC_OS_X_VERSION_MAX_ALLOWED`, and
+//! per-version `__MAC_*` macros, for versions since OS X 10.10.
+//!
+//! On macOS 10.13.4 and later, this function will return the major, minor, and
+//! bugfix components combined into a single number. On older OS versions, only
+//! the major and minor components will be returned, and the bugfix component
+//! will always be reported as 0. By contrast, MacOSVersionComponents() always
+//! returns the bugfix component.
 //!
 //! \note This is similar to the base::mac::IsOS*() family of functions, but
 //!     is provided for situations where the caller needs to obtain version
 //!     information beyond what is provided by Chromium’s base, or for when the
 //!     caller needs the actual minor version value.
-int MacOSXMinorVersion();
+int MacOSVersionNumber();
 
 //! \brief Returns the version of the running operating system.
 //!
@@ -51,12 +61,12 @@
 //!     A failure is considered to have occurred if any element could not be
 //!     determined. When this happens, their values will be untouched, but other
 //!     values that could be determined will still be set properly.
-bool MacOSXVersion(int* major,
-                   int* minor,
-                   int* bugfix,
-                   std::string* build,
-                   bool* server,
-                   std::string* version_string);
+bool MacOSVersionComponents(int* major,
+                            int* minor,
+                            int* bugfix,
+                            std::string* build,
+                            bool* server,
+                            std::string* version_string);
 
 //! \brief Returns the model name and board ID of the running system.
 //!
diff --git a/third_party/crashpad/crashpad/util/mac/mac_util_test.mm b/third_party/crashpad/crashpad/util/mac/mac_util_test.mm
index 546c628..aa188e3 100644
--- a/third_party/crashpad/crashpad/util/mac/mac_util_test.mm
+++ b/third_party/crashpad/crashpad/util/mac/mac_util_test.mm
@@ -71,15 +71,22 @@
   }
 }
 
-TEST(MacUtil, MacOSXVersion) {
+TEST(MacUtil, MacOSVersionComponents) {
   int major;
   int minor;
   int bugfix;
   std::string build;
   bool server;
   std::string version_string;
-  ASSERT_TRUE(
-      MacOSXVersion(&major, &minor, &bugfix, &build, &server, &version_string));
+  ASSERT_TRUE(MacOSVersionComponents(
+      &major, &minor, &bugfix, &build, &server, &version_string));
+
+  EXPECT_GE(major, 10);
+  EXPECT_LE(major, 99);
+  EXPECT_GE(minor, 0);
+  EXPECT_LE(minor, 99);
+  EXPECT_GE(bugfix, 0);
+  EXPECT_LE(bugfix, 99);
 
   std::string version;
   if (bugfix) {
@@ -108,20 +115,26 @@
   EXPECT_EQ(version_string.find(expected_product_name), 0u);
 }
 
-TEST(MacUtil, MacOSXMinorVersion) {
-  // Make sure that MacOSXMinorVersion() and MacOSXVersion() agree. The two have
-  // their own distinct implementations, and the latter was checked against
-  // sw_vers above.
+TEST(MacUtil, MacOSVersionNumber) {
+  // Make sure that MacOSVersionNumber() and MacOSVersionComponents() agree. The
+  // two have their own distinct implementations, and the latter was checked
+  // against sw_vers above.
+  int macos_version_number = MacOSVersionNumber();
+  EXPECT_GE(macos_version_number, 10'00'00);
+  EXPECT_LE(macos_version_number, 99'99'99);
+
   int major;
   int minor;
   int bugfix;
   std::string build;
   bool server;
   std::string version_string;
-  ASSERT_TRUE(
-      MacOSXVersion(&major, &minor, &bugfix, &build, &server, &version_string));
+  ASSERT_TRUE(MacOSVersionComponents(
+      &major, &minor, &bugfix, &build, &server, &version_string));
 
-  EXPECT_EQ(MacOSXMinorVersion(), minor);
+  EXPECT_EQ(macos_version_number,
+            major * 1'00'00 + minor * 1'00 +
+                (macos_version_number >= 10'13'04 ? bugfix : 0));
 }
 
 TEST(MacUtil, MacModelAndBoard) {
diff --git a/third_party/crashpad/crashpad/util/mac/sysctl.cc b/third_party/crashpad/crashpad/util/mac/sysctl.cc
new file mode 100644
index 0000000..c364352
--- /dev/null
+++ b/third_party/crashpad/crashpad/util/mac/sysctl.cc
@@ -0,0 +1,47 @@
+// Copyright 2020 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "util/mac/sysctl.h"
+
+#include <errno.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+
+#include "base/check_op.h"
+#include "base/logging.h"
+
+namespace crashpad {
+
+std::string ReadStringSysctlByName(const char* name, bool may_log_enoent) {
+  size_t buf_len;
+  if (sysctlbyname(name, nullptr, &buf_len, nullptr, 0) != 0) {
+    PLOG_IF(WARNING, may_log_enoent || errno != ENOENT)
+        << "sysctlbyname (size) " << name;
+    return std::string();
+  }
+
+  DCHECK_GE(buf_len, 1u);
+
+  std::string value(buf_len - 1, '\0');
+  if (sysctlbyname(name, &value[0], &buf_len, nullptr, 0) != 0) {
+    PLOG(WARNING) << "sysctlbyname " << name;
+    return std::string();
+  }
+
+  DCHECK_EQ(value[buf_len - 1], '\0');
+
+  return value;
+}
+
+}  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/util/mac/sysctl.h b/third_party/crashpad/crashpad/util/mac/sysctl.h
new file mode 100644
index 0000000..cc74704
--- /dev/null
+++ b/third_party/crashpad/crashpad/util/mac/sysctl.h
@@ -0,0 +1,36 @@
+// Copyright 2020 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef CRASHPAD_UTIL_MAC_SYSCTL_H_
+#define CRASHPAD_UTIL_MAC_SYSCTL_H_
+
+#include <string>
+
+namespace crashpad {
+
+//! \brief Calls `sysctlbyname` to read a string.
+//!
+//! \param[in] name The string name of the sysctl to raed.
+//! \param[in] may_log_enoent If `true`, allows a warning to be logged if the
+//!     sysctl is not found, indicated by `sysctlbyname` setting `errno` to
+//!     `ENOENT`. If `false`, no warning will be logged if the sysctl is
+//!     missing, and an empty string will be returned silently.
+//!
+//! \return The value of the sysctl read on success. On failure, an empty string
+//!     with a warning logged, subject to \a may_log_enoent.
+std::string ReadStringSysctlByName(const char* name, bool may_log_enoent);
+
+}  // namespace crashpad
+
+#endif  // CRASHPAD_UTIL_MAC_SYSCTL_H_
diff --git a/third_party/crashpad/crashpad/util/mac/sysctl_test.cc b/third_party/crashpad/crashpad/util/mac/sysctl_test.cc
new file mode 100644
index 0000000..5aafef16
--- /dev/null
+++ b/third_party/crashpad/crashpad/util/mac/sysctl_test.cc
@@ -0,0 +1,35 @@
+// Copyright 2020 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "util/mac/sysctl.h"
+
+#include "gtest/gtest.h"
+
+namespace crashpad {
+namespace test {
+namespace {
+
+TEST(Sysctl, ReadStringSysctlByName) {
+  // kern.ostype is always provided by the kernel, and it’s a constant across
+  // all versions, so it makes for a good test.
+  EXPECT_EQ(ReadStringSysctlByName("kern.ostype", true), "Darwin");
+
+  // Names expected to not exist.
+  EXPECT_TRUE(ReadStringSysctlByName("kern.scheisskopf", true).empty());
+  EXPECT_TRUE(ReadStringSysctlByName("kern.sanders", false).empty());
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/util/mach/exc_server_variants.cc b/third_party/crashpad/crashpad/util/mach/exc_server_variants.cc
index e4c2d19..b4052ea 100644
--- a/third_party/crashpad/crashpad/util/mach/exc_server_variants.cc
+++ b/third_party/crashpad/crashpad/util/mach/exc_server_variants.cc
@@ -14,7 +14,7 @@
 
 #include "util/mach/exc_server_variants.h"
 
-#include <AvailabilityMacros.h>
+#include <Availability.h>
 #include <string.h>
 
 #include <algorithm>
@@ -682,8 +682,8 @@
                                              exception_behavior_t behavior,
                                              bool set_thread_state) {
   if (exception == EXC_CRASH
-#if !defined(OS_IOS) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_11
-      && MacOSXMinorVersion() >= 11
+#if defined(OS_MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_11
+      && MacOSVersionNumber() >= 10'11'00
 #endif
      ) {
     return KERN_SUCCESS;
diff --git a/third_party/crashpad/crashpad/util/mach/exc_server_variants_test.cc b/third_party/crashpad/crashpad/util/mach/exc_server_variants_test.cc
index 227ddfd..38d977f 100644
--- a/third_party/crashpad/crashpad/util/mach/exc_server_variants_test.cc
+++ b/third_party/crashpad/crashpad/util/mach/exc_server_variants_test.cc
@@ -31,9 +31,9 @@
 #include "util/mach/mach_message.h"
 #include "util/misc/implicit_cast.h"
 
-#if !defined(OS_IOS)
+#if defined(OS_MAC)
 #include "test/mac/mach_multiprocess.h"
-#endif  // !OS_IOS
+#endif  // OS_MAC
 
 namespace crashpad {
 namespace test {
@@ -961,7 +961,7 @@
             expect_request_ids);
 }
 
-#if !defined(OS_IOS)
+#if defined(OS_MAC)
 
 class TestExcServerVariants : public MachMultiprocess,
                               public UniversalMachExcServer::Interface {
@@ -975,8 +975,7 @@
         flavor_(flavor),
         state_count_(state_count),
         handled_(false) {
-    // This is how the __builtin_trap() in MachMultiprocessChild() appears.
-    SetExpectedChildTermination(kTerminationSignal, SIGILL);
+    SetExpectedChildTerminationBuiltinTrap();
   }
 
   // UniversalMachExcServer::Interface:
@@ -1202,7 +1201,7 @@
   }
 }
 
-#endif  // !OS_IOS
+#endif  // OS_MAC
 
 TEST(ExcServerVariants, ExcServerSuccessfulReturnValue) {
 #if defined(OS_IOS)
@@ -1210,7 +1209,7 @@
   const kern_return_t prefer_not_set_thread_state = KERN_SUCCESS;
 #else
   const kern_return_t prefer_not_set_thread_state =
-      MacOSXMinorVersion() < 11 ? MACH_RCV_PORT_DIED : KERN_SUCCESS;
+      MacOSVersionNumber() < 10'11'00 ? MACH_RCV_PORT_DIED : KERN_SUCCESS;
 #endif
 
   const struct {
diff --git a/third_party/crashpad/crashpad/util/mach/exception_ports_test.cc b/third_party/crashpad/crashpad/util/mach/exception_ports_test.cc
index 6dbc04e..ef79808 100644
--- a/third_party/crashpad/crashpad/util/mach/exception_ports_test.cc
+++ b/third_party/crashpad/crashpad/util/mach/exception_ports_test.cc
@@ -25,6 +25,7 @@
 #include "base/macros.h"
 #include "base/notreached.h"
 #include "base/strings/stringprintf.h"
+#include "build/build_config.h"
 #include "gtest/gtest.h"
 #include "test/mac/mach_errors.h"
 #include "test/mac/mach_multiprocess.h"
@@ -145,8 +146,7 @@
         who_crashes_(who_crashes),
         handled_(false) {
     if (who_crashes_ != kNobodyCrashes) {
-      // This is how the __builtin_trap() in Child::Crash() appears.
-      SetExpectedChildTermination(kTerminationSignal, SIGILL);
+      SetExpectedChildTerminationBuiltinTrap();
     }
   }
 
@@ -205,8 +205,14 @@
       int signal;
       ExcCrashRecoverOriginalException(code[0], nullptr, &signal);
 
-      // The child crashed with __builtin_trap(), which shows up as SIGILL.
-      EXPECT_EQ(signal, SIGILL);
+#if defined(ARCH_CPU_X86_FAMILY)
+      constexpr int kBuiltinTrapSignal = SIGILL;
+#elif defined(ARCH_CPU_ARM64)
+      constexpr int kBuiltinTrapSignal = SIGTRAP;
+#else
+#error Port
+#endif
+      EXPECT_EQ(signal, kBuiltinTrapSignal);
     }
 
     EXPECT_EQ(AuditPIDFromMachMessageTrailer(trailer), 0);
diff --git a/third_party/crashpad/crashpad/util/mach/exception_types.cc b/third_party/crashpad/crashpad/util/mach/exception_types.cc
index 2a1f3c0..7fc33f0 100644
--- a/third_party/crashpad/crashpad/util/mach/exception_types.cc
+++ b/third_party/crashpad/crashpad/util/mach/exception_types.cc
@@ -15,11 +15,10 @@
 #include "util/mach/exception_types.h"
 
 #include <Availability.h>
-#include <AvailabilityMacros.h>
 #include <dlfcn.h>
 #include <errno.h>
-#include <libproc.h>
 #include <kern/exc_resource.h>
+#include <libproc.h>
 #include <strings.h>
 
 #include "base/check_op.h"
@@ -29,7 +28,7 @@
 #include "util/mach/mach_extensions.h"
 #include "util/numeric/in_range_cast.h"
 
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_9
 
 extern "C" {
 
@@ -83,13 +82,13 @@
 // present on OS X 10.9 and later. If it’s not available, sets errno to ENOSYS
 // and returns -1.
 int ProcGetWakemonParams(pid_t pid, int* rate_hz, int* flags) {
-#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9
+#if __MAC_OS_X_VERSION_MAX_ALLOWED < __MAC_10_9
   // proc_get_wakemon_params() isn’t in the SDK. Look it up dynamically.
   static ProcGetWakemonParamsType proc_get_wakemon_params =
       GetProcGetWakemonParams();
 #endif
 
-#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9
+#if __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_9
   // proc_get_wakemon_params() is definitely available if the deployment target
   // is 10.9 or newer.
   if (!proc_get_wakemon_params) {
@@ -260,7 +259,8 @@
     // creation but can be made fatal by calling proc_rlimit_control() with
     // RLIMIT_CPU_USAGE_MONITOR as the second argument and CPUMON_MAKE_FATAL set
     // in the flags.
-    if (MacOSXMinorVersion() >= 10) {
+    if (__MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_10 ||
+        MacOSVersionNumber() >= 10'10'00) {
       // In OS X 10.10, the exception code indicates whether the exception is
       // fatal. See 10.10 xnu-2782.1.97/osfmk/kern/thread.c
       // THIS_THREAD_IS_CONSUMING_TOO_MUCH_CPU__SENDING_EXC_RESOURCE().
diff --git a/third_party/crashpad/crashpad/util/mach/exception_types_test.cc b/third_party/crashpad/crashpad/util/mach/exception_types_test.cc
index c36bdd0..9507c02 100644
--- a/third_party/crashpad/crashpad/util/mach/exception_types_test.cc
+++ b/third_party/crashpad/crashpad/util/mach/exception_types_test.cc
@@ -269,7 +269,7 @@
       EXC_RESOURCE_ENCODE_TYPE_FLAVOR(RESOURCE_TYPE_CPU, FLAVOR_CPU_MONITOR);
   EXPECT_TRUE(IsExceptionNonfatalResource(EXC_RESOURCE, code, pid));
 
-  if (MacOSXMinorVersion() >= 10) {
+  if (MacOSVersionNumber() >= 10'10'00) {
     // FLAVOR_CPU_MONITOR_FATAL was introduced in OS X 10.10.
     code = EXC_RESOURCE_ENCODE_TYPE_FLAVOR(RESOURCE_TYPE_CPU,
                                            FLAVOR_CPU_MONITOR_FATAL);
diff --git a/third_party/crashpad/crashpad/util/mach/mach_extensions.cc b/third_party/crashpad/crashpad/util/mach/mach_extensions.cc
index cefb9bf3..7f80693 100644
--- a/third_party/crashpad/crashpad/util/mach/mach_extensions.cc
+++ b/third_party/crashpad/crashpad/util/mach/mach_extensions.cc
@@ -15,7 +15,6 @@
 #include "util/mach/mach_extensions.h"
 
 #include <Availability.h>
-#include <AvailabilityMacros.h>
 #include <pthread.h>
 
 #include "base/mac/mach_logging.h"
@@ -50,8 +49,8 @@
 #error This code was not ported to iOS versions older than 7
 #endif
 
-#if !defined(OS_IOS) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9
-  const int mac_os_x_minor_version = MacOSXMinorVersion();
+#if defined(OS_MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_9
+  const int macos_version_number = MacOSVersionNumber();
 #endif
 
   // See 10.6.8 xnu-1504.15.3/osfmk/mach/exception_types.h. 10.7 uses the same
@@ -67,8 +66,8 @@
       EXC_MASK_MACH_SYSCALL |
       EXC_MASK_RPC_ALERT |
       EXC_MASK_MACHINE;
-#if !defined(OS_IOS) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8
-  if (mac_os_x_minor_version < 8) {
+#if defined(OS_MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_8
+  if (macos_version_number < 10'08'00) {
     return kExcMaskAll_10_6;
   }
 #endif
@@ -77,8 +76,8 @@
   // xnu-2050.48.11/osfmk/mach/exception_types.h.
   constexpr exception_mask_t kExcMaskAll_10_8 =
       kExcMaskAll_10_6 | EXC_MASK_RESOURCE;
-#if !defined(OS_IOS) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9
-  if (mac_os_x_minor_version < 9) {
+#if defined(OS_MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_9
+  if (macos_version_number < 10'09'00) {
     return kExcMaskAll_10_8;
   }
 #endif
@@ -97,8 +96,8 @@
 #error This code was not ported to iOS versions older than 9
 #endif
 
-#if !defined(OS_IOS) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_11
-  if (MacOSXMinorVersion() < 11) {
+#if defined(OS_MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_11
+  if (MacOSVersionNumber() < 10'11'00) {
     return kExcMaskValid_10_6;
   }
 #endif
diff --git a/third_party/crashpad/crashpad/util/mach/mach_extensions_test.cc b/third_party/crashpad/crashpad/util/mach/mach_extensions_test.cc
index 9fd49402..4ff53d94 100644
--- a/third_party/crashpad/crashpad/util/mach/mach_extensions_test.cc
+++ b/third_party/crashpad/crashpad/util/mach/mach_extensions_test.cc
@@ -85,14 +85,14 @@
   EXPECT_TRUE(exc_mask_all & EXC_MASK_RESOURCE);
   EXPECT_TRUE(exc_mask_all & EXC_MASK_GUARD);
 #else  // OS_IOS
-  const int mac_os_x_minor_version = MacOSXMinorVersion();
-  if (mac_os_x_minor_version >= 8) {
+  const int macos_version_number = MacOSVersionNumber();
+  if (macos_version_number >= 10'08'00) {
     EXPECT_TRUE(exc_mask_all & EXC_MASK_RESOURCE);
   } else {
     EXPECT_FALSE(exc_mask_all & EXC_MASK_RESOURCE);
   }
 
-  if (mac_os_x_minor_version >= 9) {
+  if (macos_version_number >= 10'09'00) {
     EXPECT_TRUE(exc_mask_all & EXC_MASK_GUARD);
   } else {
     EXPECT_FALSE(exc_mask_all & EXC_MASK_GUARD);
@@ -118,20 +118,20 @@
   EXPECT_TRUE(exc_mask_valid & EXC_MASK_GUARD);
   EXPECT_TRUE(exc_mask_valid & EXC_MASK_CORPSE_NOTIFY);
 #else  // OS_IOS
-  const int mac_os_x_minor_version = MacOSXMinorVersion();
-  if (mac_os_x_minor_version >= 8) {
+  const int macos_version_number = MacOSVersionNumber();
+  if (macos_version_number >= 10'08'00) {
     EXPECT_TRUE(exc_mask_valid & EXC_MASK_RESOURCE);
   } else {
     EXPECT_FALSE(exc_mask_valid & EXC_MASK_RESOURCE);
   }
 
-  if (mac_os_x_minor_version >= 9) {
+  if (macos_version_number >= 10'09'00) {
     EXPECT_TRUE(exc_mask_valid & EXC_MASK_GUARD);
   } else {
     EXPECT_FALSE(exc_mask_valid & EXC_MASK_GUARD);
   }
 
-  if (mac_os_x_minor_version >= 11) {
+  if (macos_version_number >= 10'11'00) {
     EXPECT_TRUE(exc_mask_valid & EXC_MASK_CORPSE_NOTIFY);
   } else {
     EXPECT_FALSE(exc_mask_valid & EXC_MASK_CORPSE_NOTIFY);
diff --git a/third_party/crashpad/crashpad/util/mach/mach_message.cc b/third_party/crashpad/crashpad/util/mach/mach_message.cc
index 72d71e3..00fe116f 100644
--- a/third_party/crashpad/crashpad/util/mach/mach_message.cc
+++ b/third_party/crashpad/crashpad/util/mach/mach_message.cc
@@ -14,7 +14,7 @@
 
 #include "util/mach/mach_message.h"
 
-#include <AvailabilityMacros.h>
+#include <Availability.h>
 
 #include <limits>
 
@@ -23,9 +23,9 @@
 #include "util/misc/clock.h"
 #include "util/misc/implicit_cast.h"
 
-#if !defined(OS_IOS)
+#if defined(OS_MAC)
 #include <bsm/libbsm.h>
-#endif  // !OS_IOS
+#endif  // OS_MAC
 
 namespace crashpad {
 
@@ -253,7 +253,7 @@
   }
 }
 
-#if !defined(OS_IOS)
+#if defined(OS_MAC)
 
 pid_t AuditPIDFromMachMessageTrailer(const mach_msg_trailer_t* trailer) {
   if (trailer->msgh_trailer_type != MACH_MSG_TRAILER_FORMAT_0) {
@@ -269,7 +269,7 @@
   const mach_msg_audit_trailer_t* audit_trailer =
       reinterpret_cast<const mach_msg_audit_trailer_t*>(trailer);
 
-#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8
+#if __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_8
   pid_t audit_pid;
   audit_token_to_au32(audit_trailer->msgh_audit,
                       nullptr,
@@ -287,6 +287,6 @@
   return audit_pid;
 }
 
-#endif  // !OS_IOS
+#endif  // OS_MAC
 
 }  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/util/mach/mach_message.h b/third_party/crashpad/crashpad/util/mach/mach_message.h
index fd8d3d5..c58b6d0 100644
--- a/third_party/crashpad/crashpad/util/mach/mach_message.h
+++ b/third_party/crashpad/crashpad/util/mach/mach_message.h
@@ -183,7 +183,7 @@
 bool MachMessageDestroyReceivedPort(mach_port_t port,
                                     mach_msg_type_name_t port_right_type);
 
-#if !defined(OS_IOS) || DOXYGEN
+#if defined(OS_MAC) || DOXYGEN
 
 //! \brief Returns the process ID of a Mach message’s sender from its audit
 //!     trailer.
@@ -201,7 +201,7 @@
 //!     audit information.
 pid_t AuditPIDFromMachMessageTrailer(const mach_msg_trailer_t* trailer);
 
-#endif  // !OS_IOS
+#endif  // OS_MAC
 
 }  // namespace crashpad
 
diff --git a/third_party/crashpad/crashpad/util/mach/mach_message_test.cc b/third_party/crashpad/crashpad/util/mach/mach_message_test.cc
index 729e3a3..5af954e 100644
--- a/third_party/crashpad/crashpad/util/mach/mach_message_test.cc
+++ b/third_party/crashpad/crashpad/util/mach/mach_message_test.cc
@@ -158,7 +158,7 @@
   EXPECT_TRUE(MachMessageDestroyReceivedPort(port, MACH_MSG_TYPE_PORT_SEND));
 }
 
-#if !defined(OS_IOS)
+#if defined(OS_MAC)
 
 TEST(MachMessage, AuditPIDFromMachMessageTrailer) {
   base::mac::ScopedMachReceiveRight port(NewMachPort(MACH_PORT_RIGHT_RECEIVE));
@@ -200,7 +200,7 @@
   EXPECT_EQ(AuditPIDFromMachMessageTrailer(&receive.trailer), getpid());
 }
 
-#endif  // !OS_IOS
+#endif  // OS_MAC
 
 }  // namespace
 }  // namespace test
diff --git a/third_party/crashpad/crashpad/util/mach/mig.py b/third_party/crashpad/crashpad/util/mach/mig.py
index fa35e006..53a7a5b 100755
--- a/third_party/crashpad/crashpad/util/mach/mig.py
+++ b/third_party/crashpad/crashpad/util/mach/mig.py
@@ -14,22 +14,88 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import os
+import shutil
 import sys
+import tempfile
 
 import mig_fix
 import mig_gen
 
 
-def main(args):
-    parsed = mig_gen.parse_args(args)
+def _try_remove(*paths):
+    for path in paths:
+        try:
+            os.remove(path)
+        except OSError:
+            pass
 
-    interface = mig_gen.MigInterface(parsed.user_c, parsed.server_c,
-                                     parsed.user_h, parsed.server_h)
-    mig_gen.generate_interface(parsed.defs, interface, parsed.include,
-                               parsed.sdk, parsed.clang_path, parsed.mig_path,
-                               parsed.migcom_path, parsed.arch)
+
+def _generate_and_fix(user_c, server_c, user_h, server_h, defs, include, sdk,
+                      clang_path, mig_path, migcom_path, arch):
+    interface = mig_gen.MigInterface(user_c, server_c, user_h, server_h)
+    mig_gen.generate_interface(defs, interface, include, sdk, clang_path,
+                               mig_path, migcom_path, arch)
     mig_fix.fix_interface(interface)
 
 
+def _wrap_arch_guards(file, arch):
+    contents = '#if defined(__%s__)\n' % arch
+    contents += open(file, 'r').read()
+    contents += '\n#endif  /* __%s__ */\n' % arch
+    return contents
+
+
+def _write_file(path, data):
+    with open(path, 'w') as file:
+        file.write(data)
+
+
+def main(args):
+    parsed = mig_gen.parse_args(args, multiple_arch=True)
+
+    _try_remove(parsed.user_c, parsed.server_c, parsed.user_h, parsed.server_h)
+
+    if len(parsed.arch) <= 1:
+        _generate_and_fix(parsed.user_c, parsed.server_c, parsed.user_h,
+                          parsed.server_h, parsed.defs, parsed.include,
+                          parsed.sdk, parsed.clang_path, parsed.mig_path,
+                          parsed.migcom_path,
+                          parsed.arch[0] if len(parsed.arch) >= 1 else None)
+        return 0
+
+    # Run mig once per architecture, and smush everything together, wrapped in
+    # in architecture-specific #if guards.
+
+    user_c_data = ''
+    server_c_data = ''
+    user_h_data = ''
+    server_h_data = ''
+
+    for arch in parsed.arch:
+        # Python 3: use tempfile.TempDirectory instead
+        temp_dir = tempfile.mkdtemp(prefix=os.path.basename(sys.argv[0]) + '_')
+        try:
+            user_c = os.path.join(temp_dir, os.path.basename(parsed.user_c))
+            server_c = os.path.join(temp_dir, os.path.basename(parsed.server_c))
+            user_h = os.path.join(temp_dir, os.path.basename(parsed.user_h))
+            server_h = os.path.join(temp_dir, os.path.basename(parsed.server_h))
+            _generate_and_fix(user_c, server_c, user_h, server_h, parsed.defs,
+                              parsed.include, parsed.sdk, parsed.clang_path,
+                              parsed.mig_path, parsed.migcom_path, arch)
+
+            user_c_data += _wrap_arch_guards(user_c, arch)
+            server_c_data += _wrap_arch_guards(server_c, arch)
+            user_h_data += _wrap_arch_guards(user_h, arch)
+            server_h_data += _wrap_arch_guards(server_h, arch)
+        finally:
+            shutil.rmtree(temp_dir)
+
+    _write_file(parsed.user_c, user_c_data)
+    _write_file(parsed.server_c, server_c_data)
+    _write_file(parsed.user_h, user_h_data)
+    _write_file(parsed.server_h, server_h_data)
+
+
 if __name__ == '__main__':
     sys.exit(main(sys.argv[1:]))
diff --git a/third_party/crashpad/crashpad/util/mach/mig_gen.py b/third_party/crashpad/crashpad/util/mach/mig_gen.py
index dcbf8296..99b4f7e 100755
--- a/third_party/crashpad/crashpad/util/mach/mig_gen.py
+++ b/third_party/crashpad/crashpad/util/mach/mig_gen.py
@@ -59,17 +59,25 @@
     subprocess.check_call(command)
 
 
-def parse_args(args):
+def parse_args(args, multiple_arch=False):
     parser = argparse.ArgumentParser()
-    parser.add_argument('--clang-path', help='Path to Clang')
+    parser.add_argument('--clang-path', help='Path to clang')
     parser.add_argument('--mig-path', help='Path to mig')
     parser.add_argument('--migcom-path', help='Path to migcom')
-    parser.add_argument('--arch', help='Target architecture')
+    if not multiple_arch:
+        parser.add_argument('--arch', help='Target architecture')
+    else:
+        parser.add_argument(
+            '--arch',
+            default=[],
+            action='append',
+            help='Target architecture (may appear multiple times)')
     parser.add_argument('--sdk', help='Path to SDK')
-    parser.add_argument('--include',
-                        default=[],
-                        action='append',
-                        help='Additional include directory')
+    parser.add_argument(
+        '--include',
+        default=[],
+        action='append',
+        help='Additional include directory (may appear multiple times)')
     parser.add_argument('defs')
     parser.add_argument('user_c')
     parser.add_argument('server_c')
diff --git a/third_party/crashpad/crashpad/util/misc/address_types.h b/third_party/crashpad/crashpad/util/misc/address_types.h
index b3c69c0..14942bd 100644
--- a/third_party/crashpad/crashpad/util/misc/address_types.h
+++ b/third_party/crashpad/crashpad/util/misc/address_types.h
@@ -25,7 +25,7 @@
 #include <mach/mach_types.h>
 #elif defined(OS_WIN)
 #include "util/win/address_types.h"
-#elif defined(OS_LINUX) || defined(OS_ANDROID)
+#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
 #include "util/linux/address_types.h"
 #elif defined(OS_FUCHSIA)
 #include <zircon/types.h>
@@ -55,7 +55,7 @@
 using VMAddress = WinVMAddress;
 using VMSize = WinVMSize;
 
-#elif defined(OS_LINUX) || defined(OS_ANDROID)
+#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
 
 using VMAddress = LinuxVMAddress;
 using VMSize = LinuxVMSize;
diff --git a/third_party/crashpad/crashpad/util/misc/capture_context.h b/third_party/crashpad/crashpad/util/misc/capture_context.h
index eda4efa..d21a24f 100644
--- a/third_party/crashpad/crashpad/util/misc/capture_context.h
+++ b/third_party/crashpad/crashpad/util/misc/capture_context.h
@@ -21,7 +21,7 @@
 #include <mach/mach.h>
 #elif defined(OS_WIN)
 #include <windows.h>
-#elif defined(OS_LINUX) || defined(OS_ANDROID)
+#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
 #include <ucontext.h>
 #elif defined(OS_FUCHSIA)
 #include <signal.h>
@@ -37,7 +37,8 @@
 #endif
 #elif defined(OS_WIN)
 using NativeCPUContext = CONTEXT;
-#elif defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_FUCHSIA)
+#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) || \
+    defined(OS_FUCHSIA)
 using NativeCPUContext = ucontext_t;
 #endif  // OS_APPLE
 
diff --git a/third_party/crashpad/crashpad/util/misc/metrics.cc b/third_party/crashpad/crashpad/util/misc/metrics.cc
index be75a720..4b87f107 100644
--- a/third_party/crashpad/crashpad/util/misc/metrics.cc
+++ b/third_party/crashpad/crashpad/util/misc/metrics.cc
@@ -25,7 +25,7 @@
 #define METRICS_OS_NAME "Win"
 #elif defined(OS_ANDROID)
 #define METRICS_OS_NAME "Android"
-#elif defined(OS_LINUX)
+#elif defined(OS_LINUX) || defined(OS_CHROMEOS)
 #define METRICS_OS_NAME "Linux"
 #elif defined(OS_FUCHSIA)
 #define METRICS_OS_NAME "Fuchsia"
diff --git a/third_party/crashpad/crashpad/util/misc/time.h b/third_party/crashpad/crashpad/util/misc/time.h
index dffe1a8a..dc992bdc 100644
--- a/third_party/crashpad/crashpad/util/misc/time.h
+++ b/third_party/crashpad/crashpad/util/misc/time.h
@@ -69,13 +69,13 @@
 
 #endif  // OS_WIN
 
-#if defined(OS_LINUX) || defined(OS_ANDROID) || DOXYGEN
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) || DOXYGEN
 //! \brief Get the kernel boot time. Subsequent calls to this function may
 //!     return different results due to the system clock being changed or
 //!     imprecision in measuring the boot time.
 //! \return `true` on success. Otherwise, `false` with a message logged.
 bool GetBootTime(timespec* ts);
-#endif  // OS_LINUX || OS_ANDROID || DOXYGEN
+#endif  // OS_LINUX || OS_CHROMEOS || OS_ANDROID || DOXYGEN
 
 }  // namespace crashpad
 
diff --git a/third_party/crashpad/crashpad/util/misc/uuid.cc b/third_party/crashpad/crashpad/util/misc/uuid.cc
index e444a07f..681a2353 100644
--- a/third_party/crashpad/crashpad/util/misc/uuid.cc
+++ b/third_party/crashpad/crashpad/util/misc/uuid.cc
@@ -93,8 +93,8 @@
   uuid_generate(uuid);
   InitializeFromBytes(uuid);
   return true;
-#elif defined(OS_WIN) || defined(OS_LINUX) || defined(OS_ANDROID) || \
-    defined(OS_FUCHSIA)
+#elif defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
+    defined(OS_ANDROID) || defined(OS_FUCHSIA)
   // Linux, Android, and Fuchsia do not provide a UUID generator in a
   // widely-available system library. On Linux and Android, uuid_generate()
   // from libuuid is not available everywhere.
diff --git a/third_party/crashpad/crashpad/util/net/http_transport_socket.cc b/third_party/crashpad/crashpad/util/net/http_transport_socket.cc
index b9c6c9c..0451d2c 100644
--- a/third_party/crashpad/crashpad/util/net/http_transport_socket.cc
+++ b/third_party/crashpad/crashpad/util/net/http_transport_socket.cc
@@ -123,7 +123,7 @@
         return false;
       }
     } else {
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
       if (SSL_CTX_load_verify_locations(
               ctx_.get(), nullptr, "/etc/ssl/certs") <= 0) {
         LOG(ERROR) << "SSL_CTX_load_verify_locations";
diff --git a/third_party/crashpad/crashpad/util/numeric/checked_address_range.cc b/third_party/crashpad/crashpad/util/numeric/checked_address_range.cc
index 18d75685..4ba7ff39 100644
--- a/third_party/crashpad/crashpad/util/numeric/checked_address_range.cc
+++ b/third_party/crashpad/crashpad/util/numeric/checked_address_range.cc
@@ -22,7 +22,7 @@
 #include <mach/mach.h>
 #elif defined(OS_WIN)
 #include "util/win/address_types.h"
-#elif defined(OS_LINUX) || defined(OS_ANDROID)
+#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
 #include "util/linux/address_types.h"
 #elif defined(OS_FUCHSIA)
 #include <zircon/types.h>
@@ -130,7 +130,7 @@
 template class CheckedAddressRangeGeneric<mach_vm_address_t, mach_vm_size_t>;
 #elif defined(OS_WIN)
 template class CheckedAddressRangeGeneric<WinVMAddress, WinVMSize>;
-#elif defined(OS_LINUX) || defined(OS_ANDROID)
+#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
 template class CheckedAddressRangeGeneric<LinuxVMAddress, LinuxVMSize>;
 #elif defined(OS_FUCHSIA)
 template class CheckedAddressRangeGeneric<zx_vaddr_t, size_t>;
diff --git a/third_party/crashpad/crashpad/util/posix/close_multiple.cc b/third_party/crashpad/crashpad/util/posix/close_multiple.cc
index 4f24df1..0c07832 100644
--- a/third_party/crashpad/crashpad/util/posix/close_multiple.cc
+++ b/third_party/crashpad/crashpad/util/posix/close_multiple.cc
@@ -74,7 +74,7 @@
 bool CloseMultipleNowOrOnExecUsingFDDir(int min_fd, int preserve_fd) {
 #if defined(OS_APPLE)
   static constexpr char kFDDir[] = "/dev/fd";
-#elif defined(OS_LINUX) || defined(OS_ANDROID)
+#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
   static constexpr char kFDDir[] = "/proc/self/fd";
 #endif
 
@@ -135,7 +135,8 @@
   max_fd = std::max(max_fd, getdtablesize());
 #endif
 
-#if !(defined(OS_LINUX) || defined(OS_ANDROID)) || defined(OPEN_MAX)
+#if !(defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)) || \
+    defined(OPEN_MAX)
   // Linux does not provide OPEN_MAX. See
   // https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/commit/include/linux/limits.h?id=77293034696e3e0b6c8b8fc1f96be091104b3d2b.
   max_fd = std::max(max_fd, OPEN_MAX);
@@ -162,7 +163,7 @@
   } else {
     PLOG(WARNING) << "sysctl";
   }
-#elif defined(OS_LINUX) || defined(OS_ANDROID)
+#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
   // See linux-4.4.27/fs/file.c sysctl_nr_open, referenced by kernel/sys.c
   // do_prlimit() and kernel/sysctl.c fs_table. Inability to open this file is
   // not considered an error, because /proc may not be available or usable.
diff --git a/third_party/crashpad/crashpad/util/posix/drop_privileges.cc b/third_party/crashpad/crashpad/util/posix/drop_privileges.cc
index 7c1fe84e..75650d5 100644
--- a/third_party/crashpad/crashpad/util/posix/drop_privileges.cc
+++ b/third_party/crashpad/crashpad/util/posix/drop_privileges.cc
@@ -73,7 +73,7 @@
       CHECK_EQ(setegid(egid), -1);
     }
   }
-#elif defined(OS_LINUX) || defined(OS_ANDROID)
+#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
   PCHECK(setresgid(gid, gid, gid) == 0) << "setresgid";
   PCHECK(setresuid(uid, uid, uid) == 0) << "setresuid";
 
diff --git a/third_party/crashpad/crashpad/util/posix/process_info.h b/third_party/crashpad/crashpad/util/posix/process_info.h
index 439284f..d144c04b 100644
--- a/third_party/crashpad/crashpad/util/posix/process_info.h
+++ b/third_party/crashpad/crashpad/util/posix/process_info.h
@@ -33,7 +33,7 @@
 #include <sys/sysctl.h>
 #endif
 
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
 #include "util/linux/ptrace_connection.h"
 #endif
 
@@ -44,7 +44,7 @@
   ProcessInfo();
   ~ProcessInfo();
 
-#if defined(OS_LINUX) || defined(OS_ANDROID) || DOXYGEN
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) || DOXYGEN
   //! \brief Initializes this object with information about the process whose ID
   //!     is \a pid using a PtraceConnection \a connection.
   //!
@@ -59,7 +59,7 @@
   //!
   //! \return `true` on success, `false` on failure with a message logged.
   bool InitializeWithPtrace(PtraceConnection* connection);
-#endif  // OS_LINUX || OS_ANDROID || DOXYGEN
+#endif  // OS_LINUX || OS_CHROMEOS || OS_ANDROID || DOXYGEN
 
 #if defined(OS_APPLE) || DOXYGEN
   //! \brief Initializes this object with information about the process whose ID
@@ -168,7 +168,7 @@
  private:
 #if defined(OS_APPLE)
   kinfo_proc kern_proc_info_;
-#elif defined(OS_LINUX) || defined(OS_ANDROID)
+#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
   // Some members are marked mutable so that they can be lazily initialized by
   // const methods. These are always InitializationState-protected so that
   // multiple successive calls will always produce the same return value and out
diff --git a/third_party/crashpad/crashpad/util/posix/process_info_mac.cc b/third_party/crashpad/crashpad/util/posix/process_info_mac.cc
index 9e86e08..672e427 100644
--- a/third_party/crashpad/crashpad/util/posix/process_info_mac.cc
+++ b/third_party/crashpad/crashpad/util/posix/process_info_mac.cc
@@ -175,7 +175,14 @@
       return false;
     }
 
-    args_size = args_size_estimate + 1;
+    // TODO(https://crashpad.chromium.org/bug/355): This was increased from + 1
+    // to + 32 to work around a new bug in macOS 11.0db6 20A5364e that has
+    // broken {CTL_KERN, KERN_PROCARGS2} such that it will not work properly
+    // unless provided with a buffer at least 17 bytes larger than indicated in
+    // args_size_estimate. If this bug is fixed prior to the 11.0 release,
+    // remove the workaround and go back to + 1. (A positive offset is needed
+    // for the reasons described above.)
+    args_size = args_size_estimate + 32;
     args.resize(args_size);
     rv = sysctl(mib, base::size(mib), &args[0], &args_size, nullptr, 0);
     if (rv != 0) {
diff --git a/third_party/crashpad/crashpad/util/posix/process_info_test.cc b/third_party/crashpad/crashpad/util/posix/process_info_test.cc
index 56ee356b..78061847 100644
--- a/third_party/crashpad/crashpad/util/posix/process_info_test.cc
+++ b/third_party/crashpad/crashpad/util/posix/process_info_test.cc
@@ -33,7 +33,7 @@
 #include "util/misc/implicit_cast.h"
 #include "util/string/split_string.h"
 
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
 #include "util/linux/direct_ptrace_connection.h"
 #include "test/linux/fake_ptrace_connection.h"
 #endif
@@ -98,7 +98,7 @@
 
   const std::vector<std::string>& expect_argv = GetMainArguments();
 
-#if defined(OS_ANDROID) || defined(OS_LINUX)
+#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
   // Prior to Linux 4.2, the kernel only allowed reading a single page from
   // /proc/<pid>/cmdline, causing any further arguments to be truncated. Disable
   // testing arguments in this case.
@@ -124,7 +124,7 @@
       argv_size > static_cast<size_t>(getpagesize())) {
     return;
   }
-#endif  // OS_ANDROID || OS_LINUX
+#endif  // OS_ANDROID || OS_LINUX || OS_CHROMEOS
 
   std::vector<std::string> argv;
   ASSERT_TRUE(process_info.Arguments(&argv));
@@ -161,13 +161,13 @@
 
 TEST(ProcessInfo, Self) {
   ProcessInfo process_info;
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
   FakePtraceConnection connection;
   ASSERT_TRUE(connection.Initialize(getpid()));
   ASSERT_TRUE(process_info.InitializeWithPtrace(&connection));
 #else
   ASSERT_TRUE(process_info.InitializeWithPid(getpid()));
-#endif  // OS_LINUX || OS_ANDROID
+#endif  // OS_LINUX || OS_ANDROID || OS_CHROMEOS
 
   TestSelfProcess(process_info);
 }
@@ -184,7 +184,7 @@
   // PID 1 is expected to be init or the system’s equivalent. This tests reading
   // information about another process.
   ProcessInfo process_info;
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
   FakePtraceConnection connection;
   ASSERT_TRUE(connection.Initialize(1));
   ASSERT_TRUE(process_info.InitializeWithPtrace(&connection));
@@ -212,7 +212,7 @@
   void MultiprocessParent() override {
     const pid_t pid = ChildPID();
 
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
     DirectPtraceConnection connection;
     ASSERT_TRUE(connection.Initialize(pid));
 
@@ -221,7 +221,7 @@
 #else
     ProcessInfo process_info;
     ASSERT_TRUE(process_info.InitializeWithPid(pid));
-#endif  // OS_LINUX || OS_ANDROID
+#endif  // OS_LINUX || OS_CHROMEOS || OS_ANDROID
 
     EXPECT_EQ(process_info.ProcessID(), pid);
     EXPECT_EQ(process_info.ParentProcessID(), getpid());
diff --git a/third_party/crashpad/crashpad/util/posix/signals.cc b/third_party/crashpad/crashpad/util/posix/signals.cc
index 252aff7..5ba66a3 100644
--- a/third_party/crashpad/crashpad/util/posix/signals.cc
+++ b/third_party/crashpad/crashpad/util/posix/signals.cc
@@ -46,10 +46,10 @@
 #if defined(SIGEMT)
     SIGEMT,
 #endif  // defined(SIGEMT)
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
     SIGXCPU,
     SIGXFSZ,
-#endif  // defined(OS_LINUX)
+#endif  // defined(OS_LINUX) || defined(OS_CHROMEOS)
 };
 
 // These are the non-core-generating but terminating signals.
@@ -86,9 +86,9 @@
     SIGXCPU,
     SIGXFSZ,
 #endif  // defined(OS_APPLE)
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
     SIGIO,
-#endif  // defined(OS_LINUX)
+#endif  // defined(OS_LINUX) || defined(OS_CHROMEOS)
 };
 
 bool InstallHandlers(const std::vector<int>& signals,
@@ -189,22 +189,25 @@
   // pointer), will not reoccur on their own when returning from the signal
   // handler.
   //
-  // Unfortunately, on macOS, when SIGBUS is received asynchronously via kill(),
-  // siginfo->si_code makes it appear as though it was actually received via a
-  // hardware fault. See 10.12.3 xnu-3789.41.3/bsd/dev/i386/unix_signal.c
-  // sendsig(). Asynchronous SIGBUS will not re-raise itself autonomously, but
-  // this function (acting on information from the kernel) behaves as though it
-  // will. This isn’t ideal, but asynchronous SIGBUS is an unexpected condition.
-  // The alternative, to never treat SIGBUS as autonomously re-raising, is a bad
-  // idea because the explicit re-raise would lose properties associated with
-  // the the original signal, which are valuable for debugging and are visible
-  // to a Mach exception handler. Since SIGBUS is normally received
-  // synchronously in response to a hardware fault, don’t sweat the unexpected
-  // asynchronous case.
+  // Unfortunately, on macOS, when SIGBUS (on all CPUs) and SIGILL and SIGSEGV
+  // (on arm64) is received asynchronously via kill(), siginfo->si_code makes it
+  // appear as though it was actually received via a hardware fault. See 10.15.6
+  // xnu-6153.141.1/bsd/dev/i386/unix_signal.c sendsig() and 10.15.6
+  // xnu-6153.141.1/bsd/dev/arm/unix_signal.c sendsig(). Received
+  // asynchronously, these signals will not re-raise themselves autonomously,
+  // but this function (acting on information from the kernel) behaves as though
+  // they will. This isn’t ideal, but these signals occurring asynchronously is
+  // an unexpected condition. The alternative, to never treat these signals as
+  // autonomously re-raising, is a bad idea because the explicit re-raise would
+  // lose properties associated with the the original signal, which are valuable
+  // for debugging and are visible to a Mach exception handler. Since these
+  // signals are normally received synchronously in response to a hardware
+  // fault, don’t sweat the unexpected asynchronous case.
   //
-  // SIGSEGV on macOS originating from a general protection fault is a more
-  // difficult case: si_code is cleared, making the signal appear asynchronous.
-  // See 10.12.3 xnu-3789.41.3/bsd/dev/i386/unix_signal.c sendsig().
+  // SIGSEGV on macOS on x86[_64] originating from a general protection fault is
+  // a more difficult case: si_code is cleared, making the signal appear
+  // asynchronous. See 10.15.6 xnu-6153.141.1/bsd/dev/i386/unix_signal.c
+  // sendsig().
   const int sig = siginfo->si_signo;
   const int code = siginfo->si_code;
 
diff --git a/third_party/crashpad/crashpad/util/posix/signals_test.cc b/third_party/crashpad/crashpad/util/posix/signals_test.cc
index 6b960de..54cc2f1 100644
--- a/third_party/crashpad/crashpad/util/posix/signals_test.cc
+++ b/third_party/crashpad/crashpad/util/posix/signals_test.cc
@@ -51,7 +51,7 @@
 #endif  // !defined(ARCH_CPU_ARM64)
 #if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARMEL)
          sig == SIGILL ||
-#endif  // defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARMEL
+#endif  // defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARMEL)
          sig == SIGPIPE ||
          sig == SIGSEGV ||
 #if defined(OS_APPLE)
@@ -466,12 +466,16 @@
     }
 
 #if defined(OS_APPLE)
-    if (sig == SIGBUS) {
-      // Signal handlers can’t distinguish between SIGBUS arising out of a
-      // hardware fault and SIGBUS raised asynchronously.
-      // Signals::RestoreHandlerAndReraiseSignalOnReturn() assumes that SIGBUS
-      // comes from a hardware fault, but this test uses raise(), so the
-      // re-raise test must be skipped.
+    if (sig == SIGBUS
+#if defined(ARCH_CPU_ARM64)
+        || sig == SIGILL || sig == SIGSEGV
+#endif  // defined(ARCH_CPU_ARM64)
+       ) {
+      // Signal handlers can’t distinguish between these signals arising out of
+      // hardware faults and raised asynchronously.
+      // Signals::RestoreHandlerAndReraiseSignalOnReturn() assumes that they
+      // come from hardware faults, but this test uses raise(), so the re-raise
+      // test must be skipped.
       continue;
     }
 #endif  // defined(OS_APPLE)
@@ -493,12 +497,16 @@
     }
 
 #if defined(OS_APPLE)
-    if (sig == SIGBUS) {
-      // Signal handlers can’t distinguish between SIGBUS arising out of a
-      // hardware fault and SIGBUS raised asynchronously.
-      // Signals::RestoreHandlerAndReraiseSignalOnReturn() assumes that SIGBUS
-      // comes from a hardware fault, but this test uses raise(), so the
-      // re-raise test must be skipped.
+    if (sig == SIGBUS
+#if defined(ARCH_CPU_ARM64)
+        || sig == SIGILL || sig == SIGSEGV
+#endif  // defined(ARCH_CPU_ARM64)
+       ) {
+      // Signal handlers can’t distinguish between these signals arising out of
+      // hardware faults and raised asynchronously.
+      // Signals::RestoreHandlerAndReraiseSignalOnReturn() assumes that they
+      // come from hardware faults, but this test uses raise(), so the re-raise
+      // test must be skipped.
       continue;
     }
 #endif  // defined(OS_APPLE)
diff --git a/third_party/crashpad/crashpad/util/posix/symbolic_constants_posix.cc b/third_party/crashpad/crashpad/util/posix/symbolic_constants_posix.cc
index 13bd7f9..c6e0fec 100644
--- a/third_party/crashpad/crashpad/util/posix/symbolic_constants_posix.cc
+++ b/third_party/crashpad/crashpad/util/posix/symbolic_constants_posix.cc
@@ -64,7 +64,7 @@
     "INFO",
     "USR1",
     "USR2",
-#elif defined(OS_LINUX) || defined(OS_ANDROID)
+#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
 #if defined(ARCH_CPU_MIPS_FAMILY)
     "HUP",
     "INT",
@@ -135,7 +135,7 @@
 #endif  // defined(ARCH_CPU_MIPS_FAMILY)
 #endif
 };
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
 // NSIG is 64 to account for real-time signals.
 static_assert(base::size(kSignalNames) == 32, "kSignalNames length");
 #else
diff --git a/third_party/crashpad/crashpad/util/posix/symbolic_constants_posix_test.cc b/third_party/crashpad/crashpad/util/posix/symbolic_constants_posix_test.cc
index 266b057..74d5b545 100644
--- a/third_party/crashpad/crashpad/util/posix/symbolic_constants_posix_test.cc
+++ b/third_party/crashpad/crashpad/util/posix/symbolic_constants_posix_test.cc
@@ -66,7 +66,7 @@
 #if defined(OS_APPLE)
     {SIGEMT, "SIGEMT", "EMT"},
     {SIGINFO, "SIGINFO", "INFO"},
-#elif defined(OS_LINUX) || defined(OS_ANDROID)
+#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
     {SIGPWR, "SIGPWR", "PWR"},
 #if !defined(ARCH_CPU_MIPS_FAMILY)
     {SIGSTKFLT, "SIGSTKFLT", "STKFLT"},
@@ -123,7 +123,7 @@
                        kSignalTestData[index].short_name);
   }
 
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
   // NSIG is 64 to account for real-time signals.
   constexpr int kSignalCount = 32;
 #else
diff --git a/third_party/crashpad/crashpad/util/stdlib/objc.h b/third_party/crashpad/crashpad/util/stdlib/objc.h
index faaa453..b5e5b6c 100644
--- a/third_party/crashpad/crashpad/util/stdlib/objc.h
+++ b/third_party/crashpad/crashpad/util/stdlib/objc.h
@@ -15,10 +15,10 @@
 #ifndef CRASHPAD_UTIL_STDLIB_OBJC_H_
 #define CRASHPAD_UTIL_STDLIB_OBJC_H_
 
-#include <AvailabilityMacros.h>
+#include <Availability.h>
 #include <objc/objc.h>
 
-#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8
+#if __MAC_OS_X_VERSION_MAX_ALLOWED < __MAC_10_8
 
 // In order for the @NO and @YES literals to work, NO and YES must be defined as
 // __objc_no and __objc_yes. See
diff --git a/third_party/crashpad/crashpad/util/stdlib/strnlen.cc b/third_party/crashpad/crashpad/util/stdlib/strnlen.cc
index 07b0db54..872c0eb 100644
--- a/third_party/crashpad/crashpad/util/stdlib/strnlen.cc
+++ b/third_party/crashpad/crashpad/util/stdlib/strnlen.cc
@@ -14,9 +14,9 @@
 
 #include "util/stdlib/strnlen.h"
 
-#if defined(OS_MAC) && MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
+#if defined(OS_MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_7
 
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_7
 // Redeclare a method only available on Mac OS X 10.7 and later to suppress a
 // -Wpartial-availability warning.
 extern "C" {
@@ -27,7 +27,7 @@
 namespace crashpad {
 
 size_t strnlen(const char* string, size_t max_length) {
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_7
   if (::strnlen) {
     return ::strnlen(string, max_length);
   }
diff --git a/third_party/crashpad/crashpad/util/stdlib/strnlen.h b/third_party/crashpad/crashpad/util/stdlib/strnlen.h
index b88f2da..59253b7 100644
--- a/third_party/crashpad/crashpad/util/stdlib/strnlen.h
+++ b/third_party/crashpad/crashpad/util/stdlib/strnlen.h
@@ -21,7 +21,7 @@
 #include "build/build_config.h"
 
 #if defined(OS_MAC)
-#include <AvailabilityMacros.h>
+#include <Availability.h>
 #endif
 
 namespace crashpad {
@@ -38,7 +38,7 @@
 //!     and not all systems’ standard libraries provide an implementation.
 size_t strnlen(const char* string, size_t max_length);
 
-#if !defined(OS_MAC) || MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7
+#if !defined(OS_MAC) || __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_7
 inline size_t strnlen(const char* string, size_t max_length) {
   return ::strnlen(string, max_length);
 }
diff --git a/third_party/crashpad/crashpad/util/util.gyp b/third_party/crashpad/crashpad/util/util.gyp
index 67722332..6cd8bd9 100644
--- a/third_party/crashpad/crashpad/util/util.gyp
+++ b/third_party/crashpad/crashpad/util/util.gyp
@@ -102,6 +102,8 @@
         'mac/mac_util.h',
         'mac/service_management.cc',
         'mac/service_management.h',
+        'mac/sysctl.cc',
+        'mac/sysctl.h',
         'mac/xattr.cc',
         'mac/xattr.h',
         'mach/child_port.defs',
diff --git a/third_party/crashpad/crashpad/util/util_test.gyp b/third_party/crashpad/crashpad/util/util_test.gyp
index 91ca5112..749c532 100644
--- a/third_party/crashpad/crashpad/util/util_test.gyp
+++ b/third_party/crashpad/crashpad/util/util_test.gyp
@@ -53,6 +53,7 @@
         'mac/launchd_test.mm',
         'mac/mac_util_test.mm',
         'mac/service_management_test.mm',
+        'mac/sysctl_test.cc',
         'mac/xattr_test.cc',
         'mach/child_port_handshake_test.cc',
         'mach/child_port_server_test.cc',
diff --git a/third_party/subresource-filter-ruleset/README.chromium b/third_party/subresource-filter-ruleset/README.chromium
index 866c86b..b729eec4 100644
--- a/third_party/subresource-filter-ruleset/README.chromium
+++ b/third_party/subresource-filter-ruleset/README.chromium
@@ -1,6 +1,6 @@
 Name: EasyList
 URL: https://easylist.to/easylist/easylist.txt
-Version: 202007281111
+Version: 202008181203
 License: Creative Commons Attribution-ShareAlike 3.0 Unported
 License File: NOT_SHIPPED
 Security Critical: no
diff --git a/third_party/subresource-filter-ruleset/data/UnindexedRules.sha1 b/third_party/subresource-filter-ruleset/data/UnindexedRules.sha1
index 0cfcc5e..621db55 100644
--- a/third_party/subresource-filter-ruleset/data/UnindexedRules.sha1
+++ b/third_party/subresource-filter-ruleset/data/UnindexedRules.sha1
@@ -1 +1 @@
-502aa54e29d82495a76757c45531d5ff6c63e6f2
\ No newline at end of file
+232b6053a78a7b257787cea6357a7c5d7615e858
\ No newline at end of file
diff --git a/third_party/wuffs/README.chromium b/third_party/wuffs/README.chromium
index 3ddf4e9..1e25397 100644
--- a/third_party/wuffs/README.chromium
+++ b/third_party/wuffs/README.chromium
@@ -1,8 +1,8 @@
 Name: Wuffs (Wrangling Untrusted File Formats Safely)
 Short name: Wuffs
 URL: https://github.com/google/wuffs
-Version: 0.3.0-alpha.11
-Revision: 67503b5bda0274b637671e277ede1e34dd08b1d7
+Version: 0.3.0-alpha.13
+Revision: ba75ce9c5f224a646d92801b0b8ef74f555d490e
 Security critical: yes
 License: Apache 2.0
 
diff --git a/tools/binary_size/libsupersize/static/index.html b/tools/binary_size/libsupersize/static/index.html
index 12c2c22..1da1a9a 100644
--- a/tools/binary_size/libsupersize/static/index.html
+++ b/tools/binary_size/libsupersize/static/index.html
@@ -140,14 +140,14 @@
           <p class="select-wrapper">
             <button type="submit" class="text-button" id="submit-button">
               Open Size Report
-            </button>
+            </button> <i>(Googlers only)</i>
           </p>
         </form>
       </td>
     </tr>
     <tr>
       <td style="text-align: center" colspan=3>
-        <p>To upload your own .ndjson file, use the upload button within <a href="viewer.html">the viewer</a>.</p>
+        <p>To upload your own .size file, use the upload button within <a href="viewer.html">the viewer</a>.</p>
       </td>
     </tr>
   </table>
diff --git a/tools/cygprofile/check_orderfile.py b/tools/cygprofile/check_orderfile.py
index e8a01bb..d1e98d8a 100755
--- a/tools/cygprofile/check_orderfile.py
+++ b/tools/cygprofile/check_orderfile.py
@@ -46,7 +46,7 @@
   logging.warning('Missing symbols in verification: %d', missing_count)
   if misorder_count:
     logging.warning('%d misordered symbols:\n %s', misorder_count,
-                    '\n '.join(str(x) for x in misordered_syms[:10]))
+                    '\n '.join(str(x) for x in misordered_syms[:threshold]))
     if misorder_count > threshold:
       logging.error('%d misordered symbols over threshold %d, failing',
                     misorder_count, threshold)
@@ -60,8 +60,11 @@
   parser.add_option('--target-arch', action='store', dest='arch', default='arm',
                     choices=['arm', 'arm64', 'x86', 'x86_64', 'x64', 'mips'],
                     help='The target architecture for the binary.')
-  parser.add_option('--threshold', action='store', dest='threshold',
-                    default=20, type=int,
+  parser.add_option('--threshold',
+                    action='store',
+                    dest='threshold',
+                    default=80,
+                    type=int,
                     help='The maximum allowed number of out-of-order symbols.')
   options, argv = parser.parse_args(sys.argv)
   if len(argv) != 3:
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index f9b01e3c..6685586 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -6432,7 +6432,7 @@
   <int value="7" label="CPMD_BAD_ORIGIN_PRESAVE_GENERATED_PASSWORD"/>
   <int value="8"
       label="CPMD_BAD_ORIGIN_SAVE_GENERATION_FIELD_DETECTED_BY_CLASSIFIER"/>
-  <int value="9" label="CPMD_BAD_ORIGIN_SHOW_FALLBACK_FOR_SAVING"/>
+  <int value="9" label="CPMD_BAD_ORIGIN_UPON_USER_INPUT_CHANGE"/>
   <int value="10" label="CPMD_BAD_ORIGIN_AUTOMATIC_GENERATION_STATUS_CHANGED"/>
   <int value="11"
       label="CPMD_BAD_ORIGIN_SHOW_MANUAL_PASSWORD_GENERATION_POPUP"/>
@@ -16336,6 +16336,15 @@
   <int value="8" label="More than 50"/>
 </enum>
 
+<enum name="DevToolsIssuesPanelIssueExpanded">
+  <int value="0" label="CrossOriginEmbedderPolicy"/>
+  <int value="1" label="MixedContent"/>
+  <int value="2" label="SameSiteCookie"/>
+  <int value="3" label="HeavyAd"/>
+  <int value="4" label="ContentSecurityPolicy"/>
+  <int value="5" label="Other"/>
+</enum>
+
 <enum name="DevToolsIssuesPanelOpenedFrom">
   <int value="0" label="Console Info Bar"/>
   <int value="1" label="Learn More Link COEP"/>
@@ -16344,6 +16353,17 @@
   <int value="4" label="Adorner"/>
 </enum>
 
+<enum name="DevToolsIssuesPanelResourceOpened">
+  <int value="0" label="CrossOriginEmbedderPolicy Cookie opened"/>
+  <int value="1" label="CrossOriginEmbedderPolicy Element opened"/>
+  <int value="2" label="MixedContent Request opened"/>
+  <int value="3" label="SameSiteCookie Cookie opened"/>
+  <int value="4" label="SameSiteCookie Request opened"/>
+  <int value="5" label="HeavyAd Element opened"/>
+  <int value="6" label="ContentSecurityPolicy Directive opened"/>
+  <int value="7" label="ContentSecurityPolicy Element opened"/>
+</enum>
+
 <enum name="DevToolsKeybindSets">
   <int value="0" label="devToolsDefault"/>
   <int value="1" label="vsCode"/>
@@ -24623,6 +24643,7 @@
   <int value="24" label="IN_PROGRESS"/>
   <int value="25" label="CRX_FETCH_URL_EMPTY"/>
   <int value="26" label="CRX_FETCH_URL_INVALID"/>
+  <int value="27" label="OVERRIDEN_BY_SETTINGS"/>
 </enum>
 
 <enum name="ExtensionInstallationStage">
@@ -42633,6 +42654,7 @@
   <int value="88437020" label="FeaturePolicy:enabled"/>
   <int value="89785725"
       label="DataReductionProxyEnabledWithNetworkService:disabled"/>
+  <int value="90551098" label="UseWallpaperStagingUrl:enabled"/>
   <int value="91938915" label="enable-suggestions-service"/>
   <int value="92106937" label="CloseTabSuggestions:disabled"/>
   <int value="92327255" label="DisplayMoveWindowAccels:disabled"/>
@@ -43791,6 +43813,7 @@
   <int value="1319024729" label="ServiceWorkerServicification:disabled"/>
   <int value="1319068611" label="SecondaryUiMd:disabled"/>
   <int value="1319498514" label="NewMacNotificationAPI:disabled"/>
+  <int value="1319638975" label="UseWallpaperStagingUrl:disabled"/>
   <int value="1319725131" label="enable-distance-field-text"/>
   <int value="1320201920" label="enable-touchpad-three-finger-click"/>
   <int value="1320450434" label="ArcUsbStorageUI:disabled"/>
@@ -58184,6 +58207,21 @@
   <int value="2" label="ToastButton"/>
 </enum>
 
+<enum name="PrivateSetMembershipHashDanceComparison">
+  <int value="0" label="Equal Results"/>
+  <int value="1" label="Different Results"/>
+  <int value="2" label="PSM Error, Hash Dance Success"/>
+  <int value="3" label="PSM Success, Hash Dance Error"/>
+  <int value="4" label="Both Error"/>
+</enum>
+
+<enum name="PrivateSetMembershipStatus">
+  <int value="0" label="Attempt"/>
+  <int value="1" label="Successful Determination"/>
+  <int value="2" label="Error"/>
+  <int value="3" label="Timeout"/>
+</enum>
+
 <enum name="PrivetNotificationsEvent">
   <int value="0" label="PRIVET_SERVICE_STARTED"/>
   <int value="1" label="PRIVET_LISTER_STARTED"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index ed22f4cc..c67eef8 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -24242,7 +24242,7 @@
 </histogram>
 
 <histogram name="Browser.PaintPreview.Capture.UncompressedOnDiskSize"
-    units="KB" expires_after="2020-10-20">
+    units="KB" expires_after="2021-03-08">
   <owner>ckitagawa@chromium.org</owner>
   <owner>mahmoudi@chromium.org</owner>
   <owner>fredmello@chromium.org</owner>
@@ -24275,7 +24275,7 @@
 </histogram>
 
 <histogram name="Browser.PaintPreview.Player.CompositorProcessStartedCorrectly"
-    units="BooleanSuccess" expires_after="2020-10-20">
+    units="BooleanSuccess" expires_after="2021-03-08">
   <owner>ckitagawa@chromium.org</owner>
   <owner>mahmoudi@chromium.org</owner>
   <owner>fredmello@chromium.org</owner>
@@ -40350,6 +40350,15 @@
   </summary>
 </histogram>
 
+<histogram name="DevTools.IssuesPanelIssueExpanded"
+    enum="DevToolsIssuesPanelIssueExpanded" expires_after="2021-08-27">
+  <owner>yangguo@chromium.org</owner>
+  <owner>jegarc@microsoft.com</owner>
+  <summary>
+    Records which type of issue is expanded in the issues panel.
+  </summary>
+</histogram>
+
 <histogram name="DevTools.IssuesPanelOpenedFrom"
     enum="DevToolsIssuesPanelOpenedFrom" expires_after="2021-01-24">
   <owner>yangguo@chromium.org</owner>
@@ -40359,6 +40368,16 @@
   </summary>
 </histogram>
 
+<histogram name="DevTools.IssuesPanelResourceOpened"
+    enum="DevToolsIssuesPanelResourceOpened" expires_after="2021-08-27">
+  <owner>yangguo@chromium.org</owner>
+  <owner>jegarc@microsoft.com</owner>
+  <summary>
+    Records which resource from what issue category is opened in the issue
+    panel.
+  </summary>
+</histogram>
+
 <histogram name="DevTools.KeybindSetSettingChanged" enum="DevToolsKeybindSets"
     expires_after="2020-10-31">
   <owner>yangguo@chromium.org</owner>
@@ -49532,6 +49551,51 @@
   </summary>
 </histogram>
 
+<histogram base="true" name="Enterprise.AutoEnrollmentHashDanceSuccessTime"
+    units="ms" expires_after="2021-03-01">
+<!-- Name completed by histogram_suffixes name="EnterpriseAutoEnrollmentType". -->
+
+  <owner>amraboelkher@google.com</owner>
+  <owner>mpolzer@google.com</owner>
+  <summary>
+    Duration of the hash dance to determine enrollment state of the device. Only
+    recorded if the hash dance finished successfully.
+  </summary>
+</histogram>
+
+<histogram base="true"
+    name="Enterprise.AutoEnrollmentPrivateSetMembershipHashDanceComparison"
+    enum="PrivateSetMembershipHashDanceComparison" expires_after="2021-03-01">
+  <owner>amraboelkher@google.com</owner>
+  <owner>mpolzer@google.com</owner>
+  <summary>
+    Comparison of hash dance and private set membership results used to
+    determine the initial enrollment state of the device.
+  </summary>
+</histogram>
+
+<histogram base="true"
+    name="Enterprise.AutoEnrollmentPrivateSetMembershipRequestStatus"
+    enum="PrivateSetMembershipStatus" expires_after="2021-03-01">
+  <owner>amraboelkher@google.com</owner>
+  <owner>mpolzer@google.com</owner>
+  <summary>
+    The status of a private set membership request. This request is used to
+    determine the initial enrollment state of the device.
+  </summary>
+</histogram>
+
+<histogram base="true"
+    name="Enterprise.AutoEnrollmentPrivateSetMembershipSuccessTime" units="ms"
+    expires_after="2021-03-01">
+  <owner>amraboelkher@google.com</owner>
+  <owner>mpolzer@google.com</owner>
+  <summary>
+    Duration of the private set membership request to determine enrollment state
+    of the device. Only recorded if it finished successfully.
+  </summary>
+</histogram>
+
 <histogram base="true" name="Enterprise.AutoEnrollmentProtocolTime" units="ms"
     expires_after="2021-03-01">
 <!-- Name completed by histogram_suffixes name="EnterpriseAutoEnrollmentType". -->
@@ -127562,7 +127626,7 @@
 </histogram>
 
 <histogram name="PasswordManager.AccountStorage.ClearedOnStartup"
-    enum="PasswordAccountStoreClearedOnStartup" expires_after="M87">
+    enum="PasswordAccountStoreClearedOnStartup" expires_after="M90">
   <owner>mamir@chromium.org</owner>
   <owner>treib@chromium.org</owner>
   <summary>
@@ -127572,7 +127636,7 @@
 </histogram>
 
 <histogram name="PasswordManager.AccountStorage.ClearedOptInForAllAccounts"
-    units="accounts" expires_after="M87">
+    units="accounts" expires_after="M90">
   <owner>mamir@chromium.org</owner>
   <owner>treib@chromium.org</owner>
   <summary>
@@ -127607,7 +127671,7 @@
 </histogram>
 
 <histogram name="PasswordManager.AccountStorage.NumOptedInAccountsAfterOptIn"
-    units="accounts" expires_after="M87">
+    units="accounts" expires_after="M90">
   <owner>mamir@chromium.org</owner>
   <owner>treib@chromium.org</owner>
   <summary>
@@ -127618,7 +127682,7 @@
 </histogram>
 
 <histogram name="PasswordManager.AccountStorage.NumOptedInAccountsAfterOptOut"
-    units="accounts" expires_after="M87">
+    units="accounts" expires_after="M90">
   <owner>mamir@chromium.org</owner>
   <owner>treib@chromium.org</owner>
   <summary>
@@ -127685,7 +127749,7 @@
 </histogram>
 
 <histogram base="true" name="PasswordManager.AccountStore.AccountsPerSiteHiRes"
-    units="units" expires_after="M87">
+    units="units" expires_after="M90">
   <owner>jdoerrie@chromium.org</owner>
   <owner>mamir@chromium.org</owner>
   <owner>treib@chromium.org</owner>
@@ -127700,7 +127764,7 @@
 
 <histogram base="true"
     name="PasswordManager.AccountStore.BlacklistedSitesHiRes" units="sites"
-    expires_after="M87">
+    expires_after="M90">
   <owner>jdoerrie@chromium.org</owner>
   <owner>mamir@chromium.org</owner>
   <owner>treib@chromium.org</owner>
@@ -127713,7 +127777,7 @@
 </histogram>
 
 <histogram name="PasswordManager.AccountStore.EmptyUsernames.CountInDatabase"
-    units="units" expires_after="M87">
+    units="units" expires_after="M90">
   <owner>vasilii@chromium.org</owner>
   <owner>jdoerrie@chromium.org</owner>
   <owner>mamir@chromium.org</owner>
@@ -127725,7 +127789,7 @@
 </histogram>
 
 <histogram name="PasswordManager.AccountStore.InaccessiblePasswords"
-    units="saved passwords" expires_after="M87">
+    units="saved passwords" expires_after="M90">
   <owner>vasilii@chromium.org</owner>
   <owner>mamir@chromium.org</owner>
   <owner>treib@chromium.org</owner>
@@ -127736,7 +127800,7 @@
 </histogram>
 
 <histogram base="true" name="PasswordManager.AccountStore.TimesPasswordUsed"
-    units="PasswordUses" expires_after="M87">
+    units="PasswordUses" expires_after="M90">
   <owner>battre@chromium.org</owner>
   <owner>jdoerrie@chromium.org</owner>
   <owner>mamir@chromium.org</owner>
@@ -127752,7 +127816,7 @@
 
 <histogram base="true"
     name="PasswordManager.AccountStore.TotalAccountsHiRes.ByType" units="units"
-    expires_after="M87">
+    expires_after="M90">
   <owner>battre@chromium.org</owner>
   <owner>mamir@chromium.org</owner>
   <owner>treib@chromium.org</owner>
@@ -127767,7 +127831,7 @@
 
 <histogram base="true"
     name="PasswordManager.AccountStore.TotalAccountsHiRes.WithScheme"
-    units="accounts" expires_after="M87">
+    units="accounts" expires_after="M90">
   <owner>battre@chromium.org</owner>
   <owner>mamir@chromium.org</owner>
   <owner>treib@chromium.org</owner>
@@ -127782,7 +127846,7 @@
 </histogram>
 
 <histogram name="PasswordManager.AccountStoreVsProfileStore.Additional"
-    units="accounts" expires_after="M87">
+    units="accounts" expires_after="M90">
   <owner>mamir@chromium.org</owner>
   <owner>treib@chromium.org</owner>
   <summary>
@@ -127793,7 +127857,7 @@
 </histogram>
 
 <histogram name="PasswordManager.AccountStoreVsProfileStore.Conflicting"
-    units="accounts" expires_after="M87">
+    units="accounts" expires_after="M90">
   <owner>mamir@chromium.org</owner>
   <owner>treib@chromium.org</owner>
   <summary>
@@ -127805,7 +127869,7 @@
 </histogram>
 
 <histogram name="PasswordManager.AccountStoreVsProfileStore.Identical"
-    units="accounts" expires_after="M87">
+    units="accounts" expires_after="M90">
   <owner>mamir@chromium.org</owner>
   <owner>treib@chromium.org</owner>
   <summary>
@@ -127816,7 +127880,7 @@
 </histogram>
 
 <histogram name="PasswordManager.AccountStoreVsProfileStore.Missing"
-    units="accounts" expires_after="M87">
+    units="accounts" expires_after="M90">
   <owner>mamir@chromium.org</owner>
   <owner>treib@chromium.org</owner>
   <summary>
@@ -128476,7 +128540,7 @@
 </histogram>
 
 <histogram name="PasswordManager.DefaultPasswordStoreSet"
-    enum="PasswordManager.Store" expires_after="M87">
+    enum="PasswordManager.Store" expires_after="M90">
   <owner>mamir@chromium.org</owner>
   <owner>treib@chromium.org</owner>
   <summary>
@@ -129443,7 +129507,7 @@
 </histogram>
 
 <histogram name="PasswordManager.MoveUIDismissalReason"
-    enum="PasswordManagerUIDismissalReason" expires_after="M87">
+    enum="PasswordManagerUIDismissalReason" expires_after="M90">
 <!-- Name completed by histogram_suffixes name="PasswordAccountStorageUserState" -->
 
   <owner>mamir@chromium.org</owner>
@@ -130352,7 +130416,7 @@
 </histogram>
 
 <histogram name="PasswordManager.StoresUsedForFillingInLast28Days"
-    enum="PasswordManagerFillingSource" expires_after="M87">
+    enum="PasswordManagerFillingSource" expires_after="M90">
   <owner>mamir@chromium.org</owner>
   <owner>treib@chromium.org</owner>
   <summary>
@@ -130364,7 +130428,7 @@
 </histogram>
 
 <histogram name="PasswordManager.StoresUsedForFillingInLast7Days"
-    enum="PasswordManagerFillingSource" expires_after="M87">
+    enum="PasswordManagerFillingSource" expires_after="M90">
   <owner>mamir@chromium.org</owner>
   <owner>treib@chromium.org</owner>
   <summary>
@@ -145227,7 +145291,7 @@
 </histogram>
 
 <histogram name="Renderer.PaintPreview.Capture.SubframeBlinkCaptureDuration"
-    units="ms" expires_after="2020-10-20">
+    units="ms" expires_after="2021-03-08">
   <owner>ckitagawa@chromium.org</owner>
   <owner>mahmoudi@chromium.org</owner>
   <owner>fredmello@chromium.org</owner>
@@ -145238,7 +145302,7 @@
 </histogram>
 
 <histogram name="Renderer.PaintPreview.Capture.SubframeSuccess"
-    enum="BooleanSuccess" expires_after="2020-10-20">
+    enum="BooleanSuccess" expires_after="2021-03-08">
   <owner>ckitagawa@chromium.org</owner>
   <owner>mahmoudi@chromium.org</owner>
   <owner>fredmello@chromium.org</owner>
@@ -180435,6 +180499,17 @@
   </summary>
 </histogram>
 
+<histogram name="Tab.Preview.VideoCaptureDuration" units="ms"
+    expires_after="M89">
+  <owner>dfried@chromium.org</owner>
+  <owner>collinbaker@chromium.org</owner>
+  <summary>
+    Measures the total time spent in video capture mode when generating a
+    preview for a background tab. This is emitted at the end of each capture
+    session.
+  </summary>
+</histogram>
+
 <histogram name="Tab.PullDownGesture" enum="PullDownGestureAction"
     expires_after="2020-01-15">
   <owner>gambard@chromium.org</owner>
@@ -194337,6 +194412,9 @@
 
 <histogram name="WebCore.WebSocket.MessageSize.Receive" units="bytes"
     expires_after="2020-09-06">
+  <obsolete>
+    Removed as of 2020-09
+  </obsolete>
   <owner>yhirano@chromium.org</owner>
   <owner>ricea@chromium.org</owner>
   <summary>
@@ -194347,6 +194425,9 @@
 
 <histogram name="WebCore.WebSocket.MessageSize.Send" units="bytes"
     expires_after="2021-02-28">
+  <obsolete>
+    Removed as of 2020-09
+  </obsolete>
   <owner>yhirano@chromium.org</owner>
   <owner>ricea@chromium.org</owner>
   <summary>
@@ -206069,6 +206150,7 @@
   <suffix name="InitialEnrollment" label="Initial Enrollment Exchange"/>
   <affected-histogram name="Enterprise.AutoEnrollmentBucketDownloadTime"/>
   <affected-histogram name="Enterprise.AutoEnrollmentExtraTime"/>
+  <affected-histogram name="Enterprise.AutoEnrollmentHashDanceSuccessTime"/>
   <affected-histogram name="Enterprise.AutoEnrollmentProtocolTime"/>
   <affected-histogram name="Enterprise.AutoEnrollmentRequestNetworkErrorCode"/>
   <affected-histogram name="Enterprise.AutoEnrollmentRequestStatus"/>
@@ -217790,6 +217872,9 @@
 </histogram_suffixes>
 
 <histogram_suffixes name="SmoothnessSequenceTypes.Universal" separator=".">
+  <obsolete>
+    Removed in 9/2020, due to over penalize smoothness.
+  </obsolete>
   <suffix name="Universal" label="All frame production"/>
   <affected-histogram name="Graphics.Smoothness.Checkerboarding"/>
   <affected-histogram name="Graphics.Smoothness.FrameSequenceLength"/>
@@ -219916,12 +220001,18 @@
 </histogram_suffixes>
 
 <histogram_suffixes name="WebSocketMessageSizeReceive" separator=".">
+  <obsolete>
+    Removed as of 2020-09
+  </obsolete>
   <suffix name="ArrayBuffer" label=""/>
   <suffix name="Blob" label=""/>
   <affected-histogram name="WebCore.WebSocket.MessageSize.Receive"/>
 </histogram_suffixes>
 
 <histogram_suffixes name="WebSocketMessageSizeSend" separator=".">
+  <obsolete>
+    Removed as of 2020-09
+  </obsolete>
   <suffix name="ArrayBuffer" label=""/>
   <suffix name="ArrayBufferView" label=""/>
   <suffix name="Blob" label=""/>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index e21e45b3..b929605 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -4726,6 +4726,9 @@
     </summary>
   </metric>
   <metric name="CompositorThread.Universal">
+    <obsolete>
+      Removed in 9/2020, due to over penalize smoothness.
+    </obsolete>
     <summary>
       The throughput of the compositor thread for all frame production.
     </summary>
@@ -4773,6 +4776,9 @@
     </summary>
   </metric>
   <metric name="MainThread.Universal">
+    <obsolete>
+      Removed in 9/2020, due to over penalize smoothness.
+    </obsolete>
     <summary>
       The throughput of the main thread for all frame production.
     </summary>
@@ -4873,6 +4879,9 @@
     </aggregation>
   </metric>
   <metric name="SlowerThread.Universal">
+    <obsolete>
+      Removed in 9/2020, due to over penalize smoothness.
+    </obsolete>
     <summary>
       The worse throughput of the main and the compositor thread for all frame
       production.
diff --git a/tools/perf/core/perf_data_generator.py b/tools/perf/core/perf_data_generator.py
index 4932fa7..30910aee 100755
--- a/tools/perf/core/perf_data_generator.py
+++ b/tools/perf/core/perf_data_generator.py
@@ -97,8 +97,7 @@
     'android-go-perf', 'android-pixel2-perf', 'android-pixel2_webview-perf',
     'linux-perf', 'mac-10_12_laptop_low_end-perf',
     'mac-10_13_laptop_high_end-perf', 'win-10-perf',
-    'win-10_laptop_low_end-perf', 'android-pixel2-perf-fyi', 'linux-perf-fyi',
-    'win-10_laptop_low_end-perf_HP-Candidate'
+    'win-10_laptop_low_end-perf'
 ]
 
 FYI_BUILDERS = {
@@ -222,18 +221,6 @@
             'device_type': 'kevin',
         },
     },
-    'linux-processor-perf-fyi': {
-        'platform': 'linux',
-        'perf_processor': True,
-    },
-    'android-pixel2-processor-perf-fyi': {
-        'platform': 'linux',
-        'perf_processor': True,
-    },
-    'win-10_laptop_low_end-perf_HP-Candidate-processor': {
-        'platform': 'linux',
-        'perf_processor': True,
-    },
 }
 
 # These configurations are taken from chromium_perf.py in
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index 9e11c33..02e1816 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -200,8 +200,6 @@
 crbug.com/1017244 [ desktop ] rendering.desktop/youtube_2018 [ Skip ]
 crbug.com/1017244 [ desktop ] rendering.desktop/youtube_pinch_2018 [ Skip ]
 crbug.com/1044962 [ win ] rendering.desktop/camera_to_webgl [ Skip ]
-crbug.com/1122037 [ mac ] rendering.desktop/fill_shapes [ Skip ]
-crbug.com/1122037 [ mac ] rendering.desktop/balls_javascript_canvas [ Skip ]
 
 # Benchmark: rendering.mobile
 crbug.com/785485 [ android-webview ] rendering.mobile/kevs_3d [ Skip ]
diff --git a/ui/message_center/views/message_popup_view.cc b/ui/message_center/views/message_popup_view.cc
index f7a568e..19b670c 100644
--- a/ui/message_center/views/message_popup_view.cc
+++ b/ui/message_center/views/message_popup_view.cc
@@ -39,7 +39,7 @@
   if (!message_view_->IsManuallyExpandedOrCollapsed())
     message_view_->SetExpanded(message_view_->IsAutoExpandingAllowed());
   AddChildView(message_view_);
-  set_notify_enter_exit_on_child(true);
+  SetNotifyEnterExitOnChild(true);
 }
 
 MessagePopupView::MessagePopupView(MessagePopupCollection* popup_collection)
diff --git a/ui/message_center/views/notification_view_md.cc b/ui/message_center/views/notification_view_md.cc
index 723a763..8964ff5 100644
--- a/ui/message_center/views/notification_view_md.cc
+++ b/ui/message_center/views/notification_view_md.cc
@@ -629,7 +629,7 @@
   CreateOrUpdateViews(notification);
   UpdateControlButtonsVisibilityWithNotification(notification);
 
-  set_notify_enter_exit_on_child(true);
+  SetNotifyEnterExitOnChild(true);
 
   click_activator_ = std::make_unique<ClickActivator>(this);
   // Reasons to use pretarget handler instead of OnMousePressed:
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn
index d38c2dfd6..6f5884d5 100644
--- a/ui/views/BUILD.gn
+++ b/ui/views/BUILD.gn
@@ -120,8 +120,8 @@
     "controls/button/menu_button_controller.h",
     "controls/button/radio_button.h",
     "controls/button/toggle_button.h",
+    "controls/color_tracking_icon_view.h",
     "controls/combobox/combobox.h",
-    "controls/combobox/combobox_listener.h",
     "controls/combobox/combobox_util.h",
     "controls/editable_combobox/editable_combobox.h",
     "controls/focus_ring.h",
@@ -332,6 +332,7 @@
     "controls/button/menu_button_controller.cc",
     "controls/button/radio_button.cc",
     "controls/button/toggle_button.cc",
+    "controls/color_tracking_icon_view.cc",
     "controls/combobox/combobox.cc",
     "controls/combobox/combobox_util.cc",
     "controls/combobox/empty_combobox_model.cc",
diff --git a/ui/views/bubble/bubble_dialog_model_host.cc b/ui/views/bubble/bubble_dialog_model_host.cc
index 45432082..3dfde015 100644
--- a/ui/views/bubble/bubble_dialog_model_host.cc
+++ b/ui/views/bubble/bubble_dialog_model_host.cc
@@ -295,7 +295,17 @@
   combobox->SetAccessibleName(model->accessible_name(GetPassKey()).empty()
                                   ? model->label(GetPassKey())
                                   : model->accessible_name(GetPassKey()));
-  combobox->set_listener(this);
+  combobox->set_callback(base::BindRepeating(
+      [](ui::DialogModelCombobox* model,
+         util::PassKey<DialogModelHost> pass_key, Combobox* combobox) {
+        // TODO(pbos): This should be a subscription through the Combobox
+        // directly, but Combobox right now doesn't support listening to
+        // selected-index changes.
+        model->OnSelectedIndexChanged(pass_key, combobox->GetSelectedIndex());
+        model->OnPerformAction(pass_key);
+      },
+      model, GetPassKey()));
+
   // TODO(pbos): Add subscription to combobox selected-index changes.
   combobox->SetSelectedIndex(model->selected_index());
   auto* combobox_ptr = combobox.get();
@@ -325,23 +335,6 @@
       ->OnTextChanged(GetPassKey(), textfield->GetText());
 }
 
-void BubbleDialogModelHost::NotifyComboboxSelectedIndexChanged(
-    Combobox* combobox) {
-  view_to_field_[combobox]
-      ->AsCombobox(GetPassKey())
-      ->OnSelectedIndexChanged(GetPassKey(), combobox->GetSelectedIndex());
-}
-
-void BubbleDialogModelHost::OnPerformAction(Combobox* combobox) {
-  // TODO(pbos): This should be a subscription through the Combobox directly,
-  // but Combobox right now doesn't support listening to selected-index changes.
-  NotifyComboboxSelectedIndexChanged(combobox);
-
-  view_to_field_[combobox]
-      ->AsCombobox(GetPassKey())
-      ->OnPerformAction(GetPassKey());
-}
-
 void BubbleDialogModelHost::OnViewCreatedForField(View* view,
                                                   ui::DialogModelField* field) {
 #if DCHECK_IS_ON()
diff --git a/ui/views/bubble/bubble_dialog_model_host.h b/ui/views/bubble/bubble_dialog_model_host.h
index 56d174a..a506fb0 100644
--- a/ui/views/bubble/bubble_dialog_model_host.h
+++ b/ui/views/bubble/bubble_dialog_model_host.h
@@ -12,7 +12,6 @@
 #include "ui/base/models/dialog_model.h"
 #include "ui/views/bubble/bubble_dialog_delegate_view.h"
 #include "ui/views/controls/button/button.h"
-#include "ui/views/controls/combobox/combobox_listener.h"
 
 namespace views {
 class Combobox;
@@ -30,8 +29,7 @@
 // DialogModel::host(). This helps minimize platform-specific code from
 // platform-agnostic model-delegate code.
 class VIEWS_EXPORT BubbleDialogModelHost : public BubbleDialogDelegateView,
-                                           public ui::DialogModelHost,
-                                           public ComboboxListener {
+                                           public ui::DialogModelHost {
  public:
   // Constructs a BubbleDialogModelHost, which for most purposes is to used as a
   // BubbleDialogDelegateView. The BubbleDialogDelegateView is nominally handed
@@ -52,9 +50,6 @@
   void SelectAllText(int unique_id) override;
   void OnFieldAdded(ui::DialogModelField* field) override;
 
-  // ComboboxListener:
-  void OnPerformAction(views::Combobox* combobox) override;
-
  private:
   void OnWindowClosing();
 
@@ -72,7 +67,6 @@
   void OnViewCreatedForField(View* view, ui::DialogModelField* field);
 
   void NotifyTextfieldTextChanged(views::Textfield* textfield);
-  void NotifyComboboxSelectedIndexChanged(views::Combobox* combobox);
 
   View* FieldToView(ui::DialogModelField* field);
 
diff --git a/ui/views/controls/color_tracking_icon_view.cc b/ui/views/controls/color_tracking_icon_view.cc
new file mode 100644
index 0000000..f1fadd8
--- /dev/null
+++ b/ui/views/controls/color_tracking_icon_view.cc
@@ -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.
+
+#include "ui/views/controls/color_tracking_icon_view.h"
+
+#include "ui/gfx/paint_vector_icon.h"
+#include "ui/native_theme/native_theme.h"
+
+namespace views {
+
+ColorTrackingIconView::ColorTrackingIconView(const gfx::VectorIcon& icon,
+                                             int icon_size)
+    : icon_(icon), icon_size_(icon_size) {}
+
+void ColorTrackingIconView::OnThemeChanged() {
+  ImageView::OnThemeChanged();
+  const SkColor color = GetNativeTheme()->GetSystemColor(
+      ui::NativeTheme::kColorId_DefaultIconColor);
+  SetImage(gfx::CreateVectorIcon(icon_, icon_size_, color));
+}
+
+}  // namespace views
diff --git a/ui/views/controls/color_tracking_icon_view.h b/ui/views/controls/color_tracking_icon_view.h
new file mode 100644
index 0000000..4ab7a54
--- /dev/null
+++ b/ui/views/controls/color_tracking_icon_view.h
@@ -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.
+
+#ifndef UI_VIEWS_CONTROLS_COLOR_TRACKING_ICON_VIEW_H_
+#define UI_VIEWS_CONTROLS_COLOR_TRACKING_ICON_VIEW_H_
+
+#include "ui/views/controls/image_view.h"
+
+namespace gfx {
+struct VectorIcon;
+}
+
+namespace views {
+
+// An ImageView that displays |icon| at |icon_size|. Tracks theme changes so the
+// icon is always the correct color.
+class VIEWS_EXPORT ColorTrackingIconView : public ImageView {
+ public:
+  ColorTrackingIconView(const gfx::VectorIcon& icon, int icon_size);
+
+  // ImageView:
+  void OnThemeChanged() override;
+
+ private:
+  const gfx::VectorIcon& icon_;
+  const int icon_size_;
+};
+
+}  // namespace views
+
+#endif  // UI_VIEWS_CONTROLS_COLOR_TRACKING_ICON_VIEW_H_
diff --git a/ui/views/controls/combobox/combobox.cc b/ui/views/controls/combobox/combobox.cc
index 3e3d3289..d763e86 100644
--- a/ui/views/controls/combobox/combobox.cc
+++ b/ui/views/controls/combobox/combobox.cc
@@ -676,7 +676,7 @@
   NotifyAccessibilityEvent(ax::mojom::Event::kValueChanged, true);
   SchedulePaint();
 
-  callback_.Run();
+  callback_.Run(this);
 
   // Note |this| may be deleted by |callback_|.
 }
diff --git a/ui/views/controls/combobox/combobox.h b/ui/views/controls/combobox/combobox.h
index d0afff6..4815c16 100644
--- a/ui/views/controls/combobox/combobox.h
+++ b/ui/views/controls/combobox/combobox.h
@@ -15,7 +15,6 @@
 #include "ui/base/models/combobox_model.h"
 #include "ui/base/models/combobox_model_observer.h"
 #include "ui/views/controls/button/button.h"
-#include "ui/views/controls/combobox/combobox_listener.h"
 #include "ui/views/controls/prefix_delegate.h"
 #include "ui/views/style/typography.h"
 
@@ -45,7 +44,8 @@
  public:
   METADATA_HEADER(Combobox);
 
-  using PerformActionCallback = base::RepeatingClosure;
+  using PerformActionCallback =
+      base::RepeatingCallback<void(Combobox* combobox)>;
 
   static constexpr int kDefaultComboboxTextContext = style::CONTEXT_BUTTON;
   static constexpr int kDefaultComboboxTextStyle = style::STYLE_PRIMARY;
@@ -66,25 +66,19 @@
 
   const gfx::FontList& GetFontList() const;
 
-  // TODO(pbos): Migrate users of this to set_callback().
-  void set_listener(ComboboxListener* listener) {
-    if (!listener) {
-      set_callback(base::DoNothing());
-      return;
-    }
-
-    set_callback(base::BindRepeating(
-        [](ComboboxListener* listener, Combobox* combobox) {
-          listener->OnPerformAction(combobox);
-        },
-        listener, this));
-  }
-
   // Sets the callback which will be called when a selection has been made.
   void set_callback(PerformActionCallback callback) {
     callback_ = std::move(callback);
   }
 
+  // Version of set_callback() that takes a RepeatingClosure by discarding the
+  // argument.
+  void set_closure(base::RepeatingClosure closure) {
+    set_callback(base::BindRepeating(
+        [](base::RepeatingClosure closure, Combobox*) { closure.Run(); },
+        std::move(closure)));
+  }
+
   // Gets/Sets the selected index.
   int GetSelectedIndex() const { return selected_index_; }
   void SetSelectedIndex(int index);
diff --git a/ui/views/controls/combobox/combobox_listener.h b/ui/views/controls/combobox/combobox_listener.h
deleted file mode 100644
index 1c5c4b6..0000000
--- a/ui/views/controls/combobox/combobox_listener.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) 2012 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 UI_VIEWS_CONTROLS_COMBOBOX_COMBOBOX_LISTENER_H_
-#define UI_VIEWS_CONTROLS_COMBOBOX_COMBOBOX_LISTENER_H_
-
-#include "ui/views/views_export.h"
-
-namespace views {
-
-class Combobox;
-
-// Interface used to notify consumers when something interesting happens to a
-// Combobox.
-class VIEWS_EXPORT ComboboxListener {
- public:
-  // Invoked when the user does the appropriate gesture that some action should
-  // be performed. This is invoked if the user clicks on the menu button and
-  // then clicks an item, and also when the menu is not showing and the does a
-  // gesture to change the selection (for example, presses the home or end
-  // keys). This is not invoked when the menu is shown and the user changes the
-  // selection without closing the menu.
-  virtual void OnPerformAction(Combobox* combobox) = 0;
-
- protected:
-  virtual ~ComboboxListener() = default;
-};
-
-}  // namespace views
-
-#endif  // UI_VIEWS_CONTROLS_COMBOBOX_COMBOBOX_LISTENER_H_
diff --git a/ui/views/controls/combobox/combobox_unittest.cc b/ui/views/controls/combobox/combobox_unittest.cc
index 3737d9b..8260527d 100644
--- a/ui/views/controls/combobox/combobox_unittest.cc
+++ b/ui/views/controls/combobox/combobox_unittest.cc
@@ -29,7 +29,6 @@
 #include "ui/events/keycodes/keyboard_codes.h"
 #include "ui/events/test/event_generator.h"
 #include "ui/events/types/event_type.h"
-#include "ui/views/controls/combobox/combobox_listener.h"
 #include "ui/views/style/platform_style.h"
 #include "ui/views/test/ax_event_counter.h"
 #include "ui/views/test/combobox_test_api.h"
@@ -148,13 +147,12 @@
   DISALLOW_COPY_AND_ASSIGN(VectorComboboxModel);
 };
 
-class EvilListener : public ComboboxListener {
+class EvilListener {
  public:
   EvilListener() = default;
-  ~EvilListener() override = default;
+  ~EvilListener() = default;
 
-  // ComboboxListener:
-  void OnPerformAction(Combobox* combobox) override {
+  void OnPerformAction(Combobox* combobox) {
     delete combobox;
     deleted_ = true;
   }
@@ -167,12 +165,12 @@
   DISALLOW_COPY_AND_ASSIGN(EvilListener);
 };
 
-class TestComboboxListener : public views::ComboboxListener {
+class TestComboboxListener {
  public:
   TestComboboxListener() = default;
-  ~TestComboboxListener() override = default;
+  ~TestComboboxListener() = default;
 
-  void OnPerformAction(views::Combobox* combobox) override {
+  void OnPerformAction(views::Combobox* combobox) {
     perform_action_index_ = combobox->GetSelectedIndex();
     actions_performed_++;
   }
@@ -539,7 +537,8 @@
   // |combobox| will be deleted on change.
   TestCombobox* combobox = new TestCombobox(&model);
   auto evil_listener = std::make_unique<EvilListener>();
-  combobox->set_listener(evil_listener.get());
+  combobox->set_callback(base::BindRepeating(
+      &EvilListener::OnPerformAction, base::Unretained(evil_listener.get())));
   ASSERT_NO_FATAL_FAILURE(ComboboxTestApi(combobox).PerformActionAt(2));
   EXPECT_TRUE(evil_listener->deleted());
 }
@@ -548,7 +547,8 @@
   InitCombobox(nullptr);
 
   TestComboboxListener listener;
-  combobox_->set_listener(&listener);
+  combobox_->set_callback(base::BindRepeating(
+      &TestComboboxListener::OnPerformAction, base::Unretained(&listener)));
   combobox_->Layout();
 
   // Click the left side. The menu is shown.
@@ -563,7 +563,8 @@
   InitCombobox(nullptr);
 
   TestComboboxListener listener;
-  combobox_->set_listener(&listener);
+  combobox_->set_callback(base::BindRepeating(
+      &TestComboboxListener::OnPerformAction, base::Unretained(&listener)));
 
   combobox_->Layout();
   combobox_->SetEnabled(false);
@@ -579,7 +580,8 @@
   InitCombobox(nullptr);
 
   TestComboboxListener listener;
-  combobox_->set_listener(&listener);
+  combobox_->set_callback(base::BindRepeating(
+      &TestComboboxListener::OnPerformAction, base::Unretained(&listener)));
 
   // The click event is ignored. Instead the menu is shown.
   PressKey(ui::VKEY_RETURN);
@@ -592,7 +594,8 @@
   InitCombobox(nullptr);
 
   TestComboboxListener listener;
-  combobox_->set_listener(&listener);
+  combobox_->set_callback(base::BindRepeating(
+      &TestComboboxListener::OnPerformAction, base::Unretained(&listener)));
 
   // The click event is ignored. Instead the menu is shwon.
   PressKey(ui::VKEY_SPACE);
@@ -638,7 +641,8 @@
   InitCombobox(nullptr);
 
   TestComboboxListener listener;
-  combobox_->set_listener(&listener);
+  combobox_->set_callback(base::BindRepeating(
+      &TestComboboxListener::OnPerformAction, base::Unretained(&listener)));
 
   combobox_->Layout();
 
@@ -757,7 +761,8 @@
   InitCombobox(nullptr);
 
   TestComboboxListener listener;
-  combobox_->set_listener(&listener);
+  combobox_->set_callback(base::BindRepeating(
+      &TestComboboxListener::OnPerformAction, base::Unretained(&listener)));
   ui::TextInputClient* input_client =
       widget_->GetInputMethod()->GetTextInputClient();
 
diff --git a/ui/views/controls/scroll_view.cc b/ui/views/controls/scroll_view.cc
index 79ade55..1242d34 100644
--- a/ui/views/controls/scroll_view.cc
+++ b/ui/views/controls/scroll_view.cc
@@ -167,7 +167,7 @@
       corner_view_(std::make_unique<ScrollCornerView>()),
       scroll_with_layers_enabled_(base::FeatureList::IsEnabled(
           ::features::kUiCompositorScrollWithLayers)) {
-  set_notify_enter_exit_on_child(true);
+  SetNotifyEnterExitOnChild(true);
 
   // Since |contents_viewport_| is accessed during the AddChildView call, make
   // sure the field is initialized.
diff --git a/ui/views/controls/scrollbar/overlay_scroll_bar.cc b/ui/views/controls/scrollbar/overlay_scroll_bar.cc
index 49efa4d6..e58df08 100644
--- a/ui/views/controls/scrollbar/overlay_scroll_bar.cc
+++ b/ui/views/controls/scrollbar/overlay_scroll_bar.cc
@@ -127,7 +127,7 @@
 }
 
 OverlayScrollBar::OverlayScrollBar(bool horizontal) : ScrollBar(horizontal) {
-  set_notify_enter_exit_on_child(true);
+  SetNotifyEnterExitOnChild(true);
   SetPaintToLayer();
   layer()->SetMasksToBounds(true);
   layer()->SetFillsBoundsOpaquely(false);
diff --git a/ui/views/controls/styled_label_unittest.cc b/ui/views/controls/styled_label_unittest.cc
index dfd5ba7..4e5b2cd 100644
--- a/ui/views/controls/styled_label_unittest.cc
+++ b/ui/views/controls/styled_label_unittest.cc
@@ -22,7 +22,6 @@
 #include "ui/gfx/font_list.h"
 #include "ui/views/border.h"
 #include "ui/views/controls/link.h"
-#include "ui/views/controls/styled_label_listener.h"
 #include "ui/views/style/typography.h"
 #include "ui/views/test/test_layout_provider.h"
 #include "ui/views/test/test_views.h"
diff --git a/ui/views/examples/box_layout_example.h b/ui/views/examples/box_layout_example.h
index 54cc9bb..ad38ddf 100644
--- a/ui/views/examples/box_layout_example.h
+++ b/ui/views/examples/box_layout_example.h
@@ -28,14 +28,14 @@
   // Set the border insets on the current BoxLayout instance.
   void UpdateBorderInsets();
 
-  // ComboboxListener
+  // LayoutExampleBase:
   void OnPerformAction(Combobox* combobox) override;
 
-  // TextfieldController
+  // TextfieldController:
   void ContentsChanged(Textfield* sender,
                        const base::string16& new_contents) override;
 
-  // LayoutExampleBase
+  // LayoutExampleBase:
   void ButtonPressedImpl(Button* sender) override;
   void CreateAdditionalControls(int vertical_start_pos) override;
   void UpdateLayoutManager() override;
diff --git a/ui/views/examples/combobox_example.cc b/ui/views/examples/combobox_example.cc
index 79f9c20..f5351f01 100644
--- a/ui/views/examples/combobox_example.cc
+++ b/ui/views/examples/combobox_example.cc
@@ -46,12 +46,14 @@
 
   combobox_ = container->AddChildView(
       std::make_unique<Combobox>(std::make_unique<ComboboxModelExample>()));
-  combobox_->set_listener(this);
+  combobox_->set_callback(base::BindRepeating(&ComboboxExample::OnPerformAction,
+                                              base::Unretained(this)));
   combobox_->SetSelectedIndex(3);
 
   auto* disabled_combobox = container->AddChildView(
       std::make_unique<Combobox>(std::make_unique<ComboboxModelExample>()));
-  disabled_combobox->set_listener(this);
+  disabled_combobox->set_callback(base::BindRepeating(
+      &ComboboxExample::OnPerformAction, base::Unretained(this)));
   disabled_combobox->SetSelectedIndex(4);
   disabled_combobox->SetEnabled(false);
 }
diff --git a/ui/views/examples/combobox_example.h b/ui/views/examples/combobox_example.h
index e48f4c1..41d9a14b 100644
--- a/ui/views/examples/combobox_example.h
+++ b/ui/views/examples/combobox_example.h
@@ -7,14 +7,13 @@
 
 #include "base/macros.h"
 #include "ui/base/models/combobox_model.h"
-#include "ui/views/controls/combobox/combobox_listener.h"
 #include "ui/views/examples/example_base.h"
 
 namespace views {
+class Combobox;
 namespace examples {
 
-class VIEWS_EXAMPLES_EXPORT ComboboxExample : public ExampleBase,
-                                              public ComboboxListener {
+class VIEWS_EXAMPLES_EXPORT ComboboxExample : public ExampleBase {
  public:
   ComboboxExample();
   ~ComboboxExample() override;
@@ -23,8 +22,7 @@
   void CreateExampleView(View* container) override;
 
  private:
-  // ComboboxListener:
-  void OnPerformAction(Combobox* combobox) override;
+  void OnPerformAction(Combobox* combobox);
 
   Combobox* combobox_ = nullptr;
 
diff --git a/ui/views/examples/dialog_example.cc b/ui/views/examples/dialog_example.cc
index b0fc72f..ca6e2ba3 100644
--- a/ui/views/examples/dialog_example.cc
+++ b/ui/views/examples/dialog_example.cc
@@ -153,7 +153,8 @@
 
   StartRowWithLabel(layout, "Modal Type");
   mode_ = layout->AddView(std::make_unique<Combobox>(&mode_model_));
-  mode_->set_listener(this);
+  mode_->set_closure(base::BindRepeating(&DialogExample::OnPerformAction,
+                                         base::Unretained(this)));
   mode_->SetSelectedIndex(ui::MODAL_TYPE_CHILD);
 
   StartRowWithLabel(layout, "Bubble");
@@ -274,12 +275,12 @@
       LogStatus("You nearly always want Child Modal for bubbles.");
     }
     persistent_bubble_->SetEnabled(bubble_->GetChecked());
-    OnPerformAction(mode_);  // Validate the modal type.
+    OnPerformAction();  // Validate the modal type.
 
     if (!bubble_->GetChecked() && GetModalType() == ui::MODAL_TYPE_CHILD) {
       // Do something reasonable when simply unchecking bubble and re-enable.
       mode_->SetSelectedIndex(ui::MODAL_TYPE_WINDOW);
-      OnPerformAction(mode_);
+      OnPerformAction();
     }
     return;
   }
@@ -310,7 +311,7 @@
   ResizeDialog();
 }
 
-void DialogExample::OnPerformAction(Combobox* combobox) {
+void DialogExample::OnPerformAction() {
   bool enable = bubble_->GetChecked() || GetModalType() != ui::MODAL_TYPE_CHILD;
 #if defined(OS_APPLE)
   enable = enable && GetModalType() != ui::MODAL_TYPE_SYSTEM;
diff --git a/ui/views/examples/dialog_example.h b/ui/views/examples/dialog_example.h
index 3731846..a4c89058 100644
--- a/ui/views/examples/dialog_example.h
+++ b/ui/views/examples/dialog_example.h
@@ -8,7 +8,6 @@
 #include "base/macros.h"
 #include "ui/base/models/simple_combobox_model.h"
 #include "ui/views/controls/button/button.h"
-#include "ui/views/controls/combobox/combobox_listener.h"
 #include "ui/views/controls/textfield/textfield_controller.h"
 #include "ui/views/examples/example_base.h"
 
@@ -27,8 +26,7 @@
 // An example that exercises BubbleDialogDelegateView or DialogDelegateView.
 class VIEWS_EXAMPLES_EXPORT DialogExample : public ExampleBase,
                                             public ButtonListener,
-                                            public TextfieldController,
-                                            public ComboboxListener {
+                                            public TextfieldController {
  public:
   DialogExample();
   ~DialogExample() override;
@@ -50,6 +48,9 @@
                          const char* value);
   void AddCheckbox(GridLayout* layout, Checkbox** member);
 
+  // Checkbox callback
+  void OnPerformAction();
+
   // Interrogates the configuration Views for DialogDelegate.
   ui::ModalType GetModalType() const;
   int GetDialogButtons() const;
@@ -67,9 +68,6 @@
   void ContentsChanged(Textfield* sender,
                        const base::string16& new_contents) override;
 
-  // ComboboxListener:
-  void OnPerformAction(Combobox* combobox) override;
-
   DialogDelegate* last_dialog_ = nullptr;
   Label* last_body_label_ = nullptr;
 
diff --git a/ui/views/examples/examples_window.cc b/ui/views/examples/examples_window.cc
index 8b0a5ae3..b023a17c 100644
--- a/ui/views/examples/examples_window.cc
+++ b/ui/views/examples/examples_window.cc
@@ -21,7 +21,6 @@
 #include "ui/base/ui_base_paths.h"
 #include "ui/views/background.h"
 #include "ui/views/controls/combobox/combobox.h"
-#include "ui/views/controls/combobox/combobox_listener.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/examples/create_examples.h"
 #include "ui/views/layout/fill_layout.h"
@@ -109,8 +108,7 @@
   DISALLOW_COPY_AND_ASSIGN(ComboboxModelExampleList);
 };
 
-class ExamplesWindowContents : public WidgetDelegateView,
-                               public ComboboxListener {
+class ExamplesWindowContents : public WidgetDelegateView {
  public:
   ExamplesWindowContents(base::OnceClosure on_close, ExampleVector examples)
       : on_close_(std::move(on_close)) {
@@ -122,7 +120,8 @@
     auto combobox = std::make_unique<Combobox>(std::move(combobox_model));
 
     instance_ = this;
-    combobox->set_listener(this);
+    combobox->set_callback(base::BindRepeating(
+        &ExamplesWindowContents::OnPerformAction, base::Unretained(this)));
 
     SetBackground(CreateThemedSolidBackground(
         this, ui::NativeTheme::kColorId_DialogBackground));
@@ -181,10 +180,9 @@
     return size;
   }
 
-  // ComboboxListener:
-  void OnPerformAction(Combobox* combobox) override {
+  void OnPerformAction(Combobox* combobox) {
     DCHECK_EQ(combobox, combobox_);
-    int index = combobox->GetSelectedIndex();
+    int index = combobox_->GetSelectedIndex();
     DCHECK_LT(index, combobox_model_->GetItemCount());
     example_shown_->RemoveAllChildViews(false);
     example_shown_->AddChildView(combobox_model_->GetItemViewAt(index));
diff --git a/ui/views/examples/flex_layout_example.h b/ui/views/examples/flex_layout_example.h
index def9045..640028cd 100644
--- a/ui/views/examples/flex_layout_example.h
+++ b/ui/views/examples/flex_layout_example.h
@@ -8,7 +8,6 @@
 #include "base/macros.h"
 #include "ui/views/controls/button/button.h"
 #include "ui/views/controls/button/label_button.h"
-#include "ui/views/controls/combobox/combobox_listener.h"
 #include "ui/views/controls/textfield/textfield_controller.h"
 #include "ui/views/examples/layout_example_base.h"
 #include "ui/views/layout/flex_layout.h"
@@ -27,14 +26,10 @@
   ~FlexLayoutExample() override;
 
  private:
-  // ComboboxListener
+  // LayoutExampleBase:
   void OnPerformAction(Combobox* combobox) override;
-
-  // TextfieldController
   void ContentsChanged(Textfield* sender,
                        const base::string16& new_contents) override;
-
-  // LayoutExampleBase
   void ButtonPressedImpl(Button* sender) override;
   void CreateAdditionalControls(int vertical_start_pos) override;
   void UpdateLayoutManager() override;
diff --git a/ui/views/examples/label_example.cc b/ui/views/examples/label_example.cc
index 61c25bb..4628850 100644
--- a/ui/views/examples/label_example.cc
+++ b/ui/views/examples/label_example.cc
@@ -143,6 +143,8 @@
 }
 
 void LabelExample::OnPerformAction(Combobox* combobox) {
+  // TODO(pbos): Provide different callbacks for alignment_ and elide_behavior_
+  // instead.
   if (combobox == alignment_) {
     custom_label_->SetHorizontalAlignment(
         static_cast<gfx::HorizontalAlignment>(combobox->GetSelectedIndex()));
@@ -229,7 +231,8 @@
   auto combobox = std::make_unique<Combobox>(
       std::make_unique<ExampleComboboxModel>(strings, count));
   combobox->SetSelectedIndex(0);
-  combobox->set_listener(this);
+  combobox->set_callback(base::BindRepeating(&LabelExample::OnPerformAction,
+                                             base::Unretained(this)));
   return layout->AddView(std::move(combobox));
 }
 
diff --git a/ui/views/examples/label_example.h b/ui/views/examples/label_example.h
index 2cbe96c..597ce92a 100644
--- a/ui/views/examples/label_example.h
+++ b/ui/views/examples/label_example.h
@@ -7,13 +7,13 @@
 
 #include "base/macros.h"
 #include "ui/views/controls/button/button.h"
-#include "ui/views/controls/combobox/combobox_listener.h"
 #include "ui/views/controls/textfield/textfield_controller.h"
 #include "ui/views/examples/example_base.h"
 
 namespace views {
 
 class Checkbox;
+class Combobox;
 class GridLayout;
 class Label;
 
@@ -21,7 +21,6 @@
 
 class VIEWS_EXAMPLES_EXPORT LabelExample : public ExampleBase,
                                            public ButtonListener,
-                                           public ComboboxListener,
                                            public TextfieldController {
  public:
   LabelExample();
@@ -33,8 +32,7 @@
   // ButtonListener:
   void ButtonPressed(Button* button, const ui::Event& event) override;
 
-  // ComboboxListener:
-  void OnPerformAction(Combobox* combobox) override;
+  void OnPerformAction(Combobox* combobox);
 
   // TextfieldController:
   void ContentsChanged(Textfield* sender,
diff --git a/ui/views/examples/layout_example_base.cc b/ui/views/examples/layout_example_base.cc
index dabba6a..6f64367 100644
--- a/ui/views/examples/layout_example_base.cc
+++ b/ui/views/examples/layout_example_base.cc
@@ -169,7 +169,8 @@
       gfx::Point(label->x() + label->width() + kLayoutExampleVerticalSpacing,
                  *vertical_pos));
   combo_box->SizeToPreferredSize();
-  combo_box->set_listener(this);
+  combo_box->set_callback(base::BindRepeating(
+      &LayoutExampleBase::OnPerformAction, base::Unretained(this)));
   label->SetSize(gfx::Size(label->width(), combo_box->height()));
   control_panel_->AddChildView(std::move(label));
 
diff --git a/ui/views/examples/layout_example_base.h b/ui/views/examples/layout_example_base.h
index 7e41f98..fe34e50d 100644
--- a/ui/views/examples/layout_example_base.h
+++ b/ui/views/examples/layout_example_base.h
@@ -10,12 +10,13 @@
 #include "ui/views/controls/button/button.h"
 #include "ui/views/controls/button/checkbox.h"
 #include "ui/views/controls/button/label_button.h"
-#include "ui/views/controls/combobox/combobox_listener.h"
 #include "ui/views/controls/textfield/textfield_controller.h"
 #include "ui/views/examples/example_base.h"
 #include "ui/views/view.h"
 
 namespace views {
+class Combobox;
+
 namespace examples {
 
 // Provides an example of a layout manager with arbitrary specific manager and
@@ -23,7 +24,6 @@
 // manager of choice.
 class VIEWS_EXAMPLES_EXPORT LayoutExampleBase : public ExampleBase,
                                                 public ButtonListener,
-                                                public ComboboxListener,
                                                 public TextfieldController {
  public:
   // Grouping of multiple textfields that provide insets.
@@ -127,6 +127,9 @@
   // common controls is done.
   virtual void ButtonPressedImpl(Button* sender);
 
+  // Combobox callback defined by child classes.
+  virtual void OnPerformAction(views::Combobox* combobox) = 0;
+
   // Performs layout-specific update of the layout manager.
   virtual void UpdateLayoutManager() = 0;
 
diff --git a/ui/views/examples/text_example.cc b/ui/views/examples/text_example.cc
index 7e0e015..85a8f8bd 100644
--- a/ui/views/examples/text_example.cc
+++ b/ui/views/examples/text_example.cc
@@ -154,7 +154,8 @@
   auto combobox = std::make_unique<Combobox>(
       std::make_unique<ExampleComboboxModel>(strings, count));
   combobox->SetSelectedIndex(0);
-  combobox->set_listener(this);
+  combobox->set_callback(base::BindRepeating(&TextExample::OnPerformAction,
+                                             base::Unretained(this)));
   return layout->AddView(std::move(combobox), kNumColumns - 1, 1);
 }
 
diff --git a/ui/views/examples/text_example.h b/ui/views/examples/text_example.h
index fc0f5c42..8913a58 100644
--- a/ui/views/examples/text_example.h
+++ b/ui/views/examples/text_example.h
@@ -10,18 +10,17 @@
 
 #include "base/macros.h"
 #include "ui/views/controls/button/button.h"
-#include "ui/views/controls/combobox/combobox_listener.h"
 #include "ui/views/examples/example_base.h"
 
 namespace views {
 class Checkbox;
+class Combobox;
 class GridLayout;
 
 namespace examples {
 
 class VIEWS_EXAMPLES_EXPORT TextExample : public ExampleBase,
-                                          public ButtonListener,
-                                          public ComboboxListener {
+                                          public ButtonListener {
  public:
   TextExample();
   ~TextExample() override;
@@ -39,12 +38,11 @@
                         const char* const* strings,
                         int count);
 
+  void OnPerformAction(Combobox* combobox);
+
   // ButtonListener:
   void ButtonPressed(Button* button, const ui::Event& event) override;
 
-  // ComboboxListener:
-  void OnPerformAction(Combobox* combobox) override;
-
   class TextExampleView;
   // The content of the scroll view.
   TextExampleView* text_view_;
diff --git a/ui/views/view.cc b/ui/views/view.cc
index 3f0483f..759495d 100644
--- a/ui/views/view.cc
+++ b/ui/views/view.cc
@@ -1316,6 +1316,14 @@
 
 void View::OnGestureEvent(ui::GestureEvent* event) {}
 
+void View::SetNotifyEnterExitOnChild(bool notify) {
+  notify_enter_exit_on_child_ = notify;
+}
+
+bool View::GetNotifyEnterExitOnChild() const {
+  return notify_enter_exit_on_child_;
+}
+
 const ui::InputMethod* View::GetInputMethod() const {
   Widget* widget = const_cast<Widget*>(GetWidget());
   return widget ? const_cast<const ui::InputMethod*>(widget->GetInputMethod())
@@ -3013,6 +3021,7 @@
 ADD_READONLY_PROPERTY_METADATA(gfx::Size, MaximumSize)
 ADD_READONLY_PROPERTY_METADATA(gfx::Size, MinimumSize)
 ADD_PROPERTY_METADATA(bool, Mirrored)
+ADD_PROPERTY_METADATA(bool, NotifyEnterExitOnChild)
 ADD_PROPERTY_METADATA(bool, Visible)
 END_METADATA
 
diff --git a/ui/views/view.h b/ui/views/view.h
index c63089d..32032125 100644
--- a/ui/views/view.h
+++ b/ui/views/view.h
@@ -1069,12 +1069,8 @@
   virtual bool OnMouseWheel(const ui::MouseWheelEvent& event);
 
   // See field for description.
-  void set_notify_enter_exit_on_child(bool notify) {
-    notify_enter_exit_on_child_ = notify;
-  }
-  bool notify_enter_exit_on_child() const {
-    return notify_enter_exit_on_child_;
-  }
+  void SetNotifyEnterExitOnChild(bool notify);
+  bool GetNotifyEnterExitOnChild() const;
 
   // Convenience method to retrieve the InputMethod associated with the
   // Widget that contains this view.
diff --git a/ui/views/view_unittest.cc b/ui/views/view_unittest.cc
index 33cf87d..798f71c 100644
--- a/ui/views/view_unittest.cc
+++ b/ui/views/view_unittest.cc
@@ -1698,7 +1698,7 @@
   TestView* v = new TestView;
   v->SetBounds(0, 0, 100, 100);
   root_view->AddChildView(v);
-  v->set_notify_enter_exit_on_child(true);
+  v->SetNotifyEnterExitOnChild(true);
 
   TestView* v_child = new TestView;
   v_child->SetBounds(0, 0, 20, 30);
@@ -1857,7 +1857,7 @@
   TestView* v1 = new TestView;
   v1->SetBounds(0, 0, 100, 100);
   root_view->AddChildView(v1);
-  v1->set_notify_enter_exit_on_child(true);
+  v1->SetNotifyEnterExitOnChild(true);
 
   TestView* v11 = new TestView;
   v11->SetBounds(0, 0, 20, 30);
diff --git a/ui/views/widget/root_view.cc b/ui/views/widget/root_view.cc
index be4c65d5..87beb3fb 100644
--- a/ui/views/widget/root_view.cc
+++ b/ui/views/widget/root_view.cc
@@ -506,7 +506,7 @@
   if (v && v != this) {
     if (v != mouse_move_handler_) {
       if (mouse_move_handler_ != nullptr &&
-          (!mouse_move_handler_->notify_enter_exit_on_child() ||
+          (!mouse_move_handler_->GetNotifyEnterExitOnChild() ||
            !mouse_move_handler_->Contains(v))) {
         MouseEnterExitEvent exit(event, ui::ET_MOUSE_EXITED);
         exit.ConvertLocationToTarget(static_cast<View*>(this),
@@ -531,7 +531,7 @@
       }
       View* old_handler = mouse_move_handler_;
       mouse_move_handler_ = v;
-      if (!mouse_move_handler_->notify_enter_exit_on_child() ||
+      if (!mouse_move_handler_->GetNotifyEnterExitOnChild() ||
           !mouse_move_handler_->Contains(old_handler)) {
         MouseEnterExitEvent entered(event, ui::ET_MOUSE_ENTERED);
         entered.ConvertLocationToTarget(static_cast<View*>(this),
@@ -728,7 +728,7 @@
     View* view,
     View* sibling) {
   for (View* p = view->parent(); p; p = p->parent()) {
-    if (!p->notify_enter_exit_on_child())
+    if (!p->GetNotifyEnterExitOnChild())
       continue;
     if (sibling && p->Contains(sibling))
       break;
diff --git a/ui/views/widget/root_view_unittest.cc b/ui/views/widget/root_view_unittest.cc
index 024f2ff..a733d70 100644
--- a/ui/views/widget/root_view_unittest.cc
+++ b/ui/views/widget/root_view_unittest.cc
@@ -695,7 +695,7 @@
   subchild->SetBounds(0, 0, 100, 100);
 
   // Make mouse enter and exit events get propagated from |subchild| to |child|.
-  child->set_notify_enter_exit_on_child(true);
+  child->SetNotifyEnterExitOnChild(true);
 
   internal::RootView* root_view =
       static_cast<internal::RootView*>(widget->GetRootView());
diff --git a/weblayer/browser/password_manager_driver_factory.cc b/weblayer/browser/password_manager_driver_factory.cc
index 8bdf396..2b59c275 100644
--- a/weblayer/browser/password_manager_driver_factory.cc
+++ b/weblayer/browser/password_manager_driver_factory.cc
@@ -38,16 +38,16 @@
       const std::vector<autofill::FormData>& visible_forms_data,
       bool did_stop_loading) override {}
   void PasswordFormSubmitted(const autofill::FormData& form_data) override {}
-  void ShowManualFallbackForSaving(
-      const autofill::FormData& form_data) override {
+  void InformAboutUserInput(const autofill::FormData& form_data) override {
     if (!password_manager::bad_message::CheckChildProcessSecurityPolicyForURL(
             render_frame_host_, form_data.url,
             password_manager::BadMessageReason::
-                CPMD_BAD_ORIGIN_SHOW_FALLBACK_FOR_SAVING)) {
+                CPMD_BAD_ORIGIN_UPON_USER_INPUT_CHANGE)) {
       return;
     }
 
-    if (site_isolation::SiteIsolationPolicy::
+    if (FormHasNonEmptyPasswordField(form_data) &&
+        site_isolation::SiteIsolationPolicy::
             IsIsolationForPasswordSitesEnabled()) {
       // This function signals that a password field has been filled (whether by
       // the user, JS, autofill, or some other means) or a password form has
@@ -59,7 +59,6 @@
           form_data.url);
     }
   }
-  void HideManualFallbackForSaving() override {}
   void SameDocumentNavigation(autofill::mojom::SubmissionIndicatorEvent
                                   submission_indication_event) override {}
   void RecordSavePasswordProgress(const std::string& log) override {}
diff --git a/weblayer/shell/android/shell_apk/res/layout/main.xml b/weblayer/shell/android/shell_apk/res/layout/main.xml
index eb1c9c1..bf49ade6 100644
--- a/weblayer/shell/android/shell_apk/res/layout/main.xml
+++ b/weblayer/shell/android/shell_apk/res/layout/main.xml
@@ -3,28 +3,32 @@
      Use of this source code is governed by a BSD-style license that can be
      found in the LICENSE file. -->
 
-<RelativeLayout
+<LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
-    <ImageButton
-        android:id="@+id/controls_menu_button"
-        android:layout_width="25dp"
-        android:layout_height="25dp"
-        android:scaleType="fitXY"
-        android:paddingLeft="5px"
-        android:paddingRight="5px"
-        android:src="@android:drawable/ic_menu_more"
-        android:background="@android:color/transparent" />
-    <TextView
-        android:id="@+id/version_text"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_toRightOf="@id/controls_menu_button"
-        android:paddingTop="5px" />
+    <LinearLayout
+        android:orientation="horizontal"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+        <ImageButton
+            android:id="@+id/controls_menu_button"
+            android:layout_width="25dp"
+            android:layout_height="25dp"
+            android:scaleType="fitXY"
+            android:paddingLeft="5px"
+            android:paddingRight="5px"
+            android:src="@android:drawable/ic_menu_more"
+            android:background="@android:color/transparent" />
+        <TextView
+            android:id="@+id/version_text"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:paddingTop="5px" />
+    </LinearLayout>
     <FrameLayout
         android:id="@+id/weblayer"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_below="@id/controls_menu_button" />
-</RelativeLayout>
+        android:layout_height="match_parent" />
+</LinearLayout>